div.a10p`_field" display: none; visibility: hidden; } div.a0001_field" display: none; visibility: hidden; } MacTech�= The journal of Apple technology.<z薸tle> <link type="textuss" rel="stylesheet" media="all" href="http:]錭dn.mactech.com/sites/default/files/advagg_cssuss_7a90󳲈󤕘00蒮3efSA�(N�)b776dffd0a49d3968_�(懷�)css"� > <script type="textv產vascript" src="http:/t鎗ax.googleapis.comt鎗ax/libsv畄uery/1.�(懷�)6/jquery.min.js"><ztcript> <script�4ype="text/javascript" src="http:]錫jax.googleapis.com/ajaxv頸bs/jqueryui].6v畄uery-ui.min.js"><ztcript> <script�4ype="text/javascript" src="http:]錭dn.mactech.com/sites/default/files/advagg_js/js_da2abc6s7dc30󤕬000e2a7f746ffq1.js"></script> <script type="textv產vascript"> <!--]--><�1 D�8CDATA[]><�c- jQuery.extend(Drupal.settings,""basePath":"\/"+"+"googleanalytics":{"trackOutbound":1,"trackMailto":1,"trackDownload":1,"trackDownloadExtensions":"7z|aac|arc|arj|asf|asx|avi|bin|csv|doc|exe|flv|gif|gz|gzip|hqx|jar|jpe?g|js|mp(2|3|4|e?g)|mov(ie)?|msi|msp|pdf|phps|png|ppt|qtm?|ra(m|r)?|sea|sit|tar|tgz|torrent|txt|wav|wma|wmv|wpd|xls|xml|z|zip"},"nice_menus_options":{"delay":800,"speed":2}); ]--><�5 D�8]> <ztcript> <script�4ype="text/javascript"> <�c-/\q-><![cdata[/b6<!-- window.google_analytics_uacct = "UA-763-5"; /\q-><!]]> </script> <script type="textv產vascript"> <!--]--><�1 D�8CDATA[]><�c- Drupal.behaviors.a�e24461ae`46d5 = function() { $("input.a�1�0p`_field").each(function()" f=$(this)[0]; if (f.value.indexOf("46d5ae")==0){f.value="d3"+f.value.substring(4)+"d50346890󳴔44ffb8b6_form";} �(); }; ]--><�5 D�8]> <ztcript> <script�4ype="text/javascript"> <�c-/\q-><![cdata[/b6<!-- Drupal.behaviors.a1�(T �)42e6c1a7e9�(N��)= function()" �.("input.a000qfield").each(function() { f=$(this)[0]; tok2 = f.style.fontFamily; if(tok2.charAt(0) == "'" ||�4ok�(懷�)charAt(0) == '"') tok2=tok�(懷�)substring(1,�4ok�(懷�)length-1); �4ok�(O�)tok2.substring(1, tok2.length); if (f.value.indexOf("7e9�(g �)c1")==0){f.value=""+f.value.substring(4)+tok�([f�)} }); }; /\q-><!]]> </script> <�c-[if�!�?e 6]> <link rel="stylesheet"�4ype="text/css" href="cssv}e6.css" b6 <�1 D�8endif]--> <script�4ype="text/javascript"><!-- google_ad_client = "pub-30󭦌򠸖�(e�)400777�(e�)010򔣜; \" 1�(e�)x600, created ^z0/SD *Qegoogle_ad_slot = "537195�(ry�)95"; google_ad_width = 2 200; google_ad_height = 250; ]--> </script> <vvead> <body class="not-front not-logged-in�0age-articles one-sidebar sidebar-left"> <!--[if �jE]>Start�?�!eader<�1 D�8endif]--> <div id="header"><�c-[if !IE]>Start Top Menu<![endif]--> <div class="top_row_menu"> <ul> �!�!li><strong>MacTech Network: </strong><v頸> �!�!li><a href="ztupport">Tech Support</a></li> <li>|<v頸> �!�!li><a href="http:/|鴚w.macforge.net">MacForge.net<t><v頸> �!�!li>|</li> <li><a href="http:]鍂ww.macnews.com">Apple News<t><v頸> �!�!li>|</li> <li><a href="http:]鍂ww.mactechdomains.com">Register Domains</a></li> <li>|<v頸> �!�!li><a href="http:/|鴚w.mactechdomains.com/">SSL Certificates</a></li> <li>|<v頸> �!�!li><a href="http:/|鴚w.amazon.com/execw骲idos/redirect?link_code=ur2&camp=89&tag=mactechmagazi-20&creative=90󤕘0򭃽&path=external-search%3Fsearch-type=ss%�(尅�)keyword=ipod%26index=pc-hardware">iPod Deals</a></li> <li>|<v頸> �!�!li><a href="http:/t鎝plestore.mactech.com/">Mac Deals<t><v頸> �!�!li>|</li> <li><a href="http:]鍂ww.macbookshelf.com">Mac Book Shelf</a></li> </ul> </div> <�c-[if !IE]>End Top Menu<![endif]-->�!�!�C-[if !IE]>Start Banner<![endif]--> <div class="top_row_banner"><a href="Y �4itle="MacTech"> <div class="top_logo_left"> <h磎actech<vv <u(iv> </a> <!-- Top Leaderboard Banner --> <div class="top_banner_right"><div id="block-ad-0󭦌򠸖1" class="clear-block block block-ad"> �!�!div class="content"> <div class="advertisement group-tids-0󭦌򠸖1" id="group-id-tids-361"><script type='textv產vascript' src='http:/y:reserve.mactech.com/sites/all/modules/adzterve.php?q=1&t=361&u=articles%e噈actech%e嘨ol.�(y>�)%2F20󡐪򎒾05%2FUninstallingWithAppleScript%2Findex.html&l=articles%2Fmactech%2FVol.200積�(y>�).05%e嘦ninstallingWithAppleScript%e噄ndex.html'></script><u(iv> </div> <u(iv> </div> </div> <�c-[if !IE]>End Banner<![endif]-->�!�!�C-[if !IE]>Start main nav<![endif]--> <div class="main_nav"> <div class="fl"><img src="ztitest鎙lz薶emes/custom_frontv}mages/main_nav_left.gif" alt="" b6</div> <div class="main_nav_inn"><ul class="nice-menu nice-menu-down" id="nice-menu-1"><li class="menu-20󳲍 menu-path-front first odd "><a href="Y ><span>Home<ztpan></a></li> <li class="menu-�(y>�)76 menuparent menu-path-node-35791 even "><a href=".".content/magazine"><span>Magazine</span><t><ul><li class="menu-1054 menu-path-node-358 first odd "><a href=".".about"><span>About MacTech in Print<ztpan></a></li> <li class="menu-058 menuparent menu-path-node-657868 even "><a href=".".issue-TOCs"><span>Issue Table of Contents<ztpan></a><ul><li class="menu-0󭦌򠸖0򂆌򧂆鄊enu-path-node-657868 first odd "><a href="v}ssue-TOCs"><span>Issue 2 242-Current Contents<ztpan></a></li> <li class="menu-720򂆌򧂆鄊enu-path-node-403�(R�)0 even "><a href="v}ssue-TOCs-�(e�)"><span>Volume 29 Table of Contents<ztpan></a></li> <li class="menu-770򂆌򧂆鄊enu-path-node-3861 odd "><a href=".".issue-TOCs-201�(N �)><span>Volume �(R�) Table of Contents</span><t><v頸> <li class="menu-10󭦌򠸖55 menu-path-node-�(y>�)6393 even "><a href=".".issue-TOCs-2011"><span>Volume �(y]�) Table of Contents</span><t><v頸> <li class="menu-1�(e�)57 menu-path-node-8186 odd "><a href="v}ssue-TOCs-�(e�)10"><span>Volume 26 Table of Contents<ztpan></a></li> <li class="menu-05�(N��)menu-path-node-178�(g �)4 even "><a href="v}ssue-TOCs-�(e�)SD"><span>Volume 25 Table of Contents<ztpan></a></li> <li class="menu-050򂆌򧂆鄊enu-path-node-178�(尅�)4 odd "><a href=".".issue-TOCs-2008"><span>Volume �(T �) Table of Contents</span><t><v頸> <li class="menu-1�(e�)54 menu-path-node-8263 even "><a href=".".issue-TOCs-2007"><span>Volume �(y>�) Table of Contents</span><t><v頸> <li class="menu-1�(e�)55 menu-path-node-82�(y>�) odd "><a href="v}ssue-TOCs-�(e�)0"><span>Volume 2�(N��)Table of Contents<ztpan></a></li> <li class="menu-056 menu-path-node-178�(g �)�(N��)even last "><a href="v}ssue-TOCs-�(e�)05"><span>Volume 21 Table of Contents<ztpan></a></li> </ul> </li> <li class="menu-�(g �)7 menu-path-node-346SA6 odd "><a href=".".iPad"><span>iPad Version</span><t><v頸> <li class="menu-105�(N��)menu-path-node-358 even "><a href=".".content/risk-free-sample"><span>Risk Free Sample</span><t><v頸> <li class="menu-1051 menu-path-node-358� odd "><a href="uontentuack-issues"><span>Back�!�?ssues<ztpan></a></li> <li class="menu-1050 menu-path-node-105074 even "><a href=".".dvd"><span>MacTech DVD</span><t><v頸> <li class="menu-80󭯤7 menu-path-node-97144 odd "><a href="v頰bs"><span>About MacTech Labs<ztpan></a></li> <li class="menu-600 menu-path-node-180538 even "><a href="ztubscribe"><span>Subscribe to MacTech</span><t><v頸> <li class="menu-6558 menuparent menu-path-node-92850򂆌򧂆鄌dd last "><a href=".".content/archives"><span>Archives</span><t><ul><li class="menu-6559 menu-path-node-9�(R�)54 first odd "><a href=".".mactech-archives"><span>MacTech Print Archives</span><t><v頸> <li class="menu-2911 menu-path-node-358�(ry�) even "><a href=".".macmod"><span>MacMod</span><t><v頸> <li class="menu-6560 menu-path-node-9�(R�)54 odd "><a href="w踑ctech-archives"><span>MacTutor<ztpan></a></li> <li class="menu-�(N�)SD menu-path-node-�(ry�) even "><a href=".".content/frameworks-article-archives"><span>FrameWorks<ztpan></a></li> <li class="menu-7455 menu-path-node-92857 odd last "><a href=".".develop-archives"><span>develop<ztpan></a></li> </ul> </li> </ul> </li> <li class="menu-659 menuparent menu-path-eventsmactechcom- odd "><a href="http:/u0vents.mactech.com/"><span>Live Events<ztpan></a><ul><li class="menu-660 menu-path-eventsmactechcom- first odd "><a href="http:/u0vents.mactech.com/"><span>About MacTech Events</span><t><v頸> <li class="menu-10󤕬090 menuparent menu-path-promactechcom- even "><a href="http:]錺ro.mactech.com/"><span>MacTech Pro Events:<br>All new for�4his year纙tpan></a><ul><li class="menu-񠌪󅬛 menu-path-promactechcom-about first odd "><a href="http:/y:ro.mactech.comt鎎out"><span>About MacTech Pro Events</span><t><v頸> <li class="menu-10󭦌򠸖70 menu-path-promactechcom-dates-and-locations- even "><a href="http:/y:ro.mactech.comu(ates-and-locationsY ><span>Cities and Locations<ztpan></a></li> <li class="menu-񠌖01 menu-path-promactechcom-registerridMT-Main-Site-Menu odd "><a href="http:/y:ro.mactech.comy緀gister?rid=MT-Main-Site-Menu"><span>Registration<ztpan></a></li> <li class="menu-667 menu-path-promactechcom-schedule even "><a href="http:]錺ro.mactech.com/schedule"><span>Schedule</span><t><v頸> <li class="menu-10󭦌򠸖52 menu-path-promactechcom-travel odd "><a href="http:]錺ro.mactech.com/travel"><span>Hotel and Travel</span><t><v頸> <li class="menu-10󭦌򠸖69 menu-path-promactechcom-speaker-app even "><a href="http:]錺ro.mactech.com/speaker-app"><span>Speaker Application</span><t><v頸> <li class="menu-17362 menu-path-promactechcom-sponsorship odd "><a href="http:/y:ro.mactech.comztponsorship"><span>Vendor QuickTalk Application</span><t><v頸> <li class="menu-10󤕬092 menu-path-promactechcom-edu even "><a href="http:]錺ro.mactech.com/edu"><span>Educational�!�?nstitution and Student Discounts</span><t><v頸> <li class="menu-10󤕬093 menu-path-promactechcom-media odd "><a href="http:/y:ro.mactech.comw踖dia"><span>Media and Press Info</span><t><v頸> <li class="menu-10󤕬088 menu-path-promactechcom-refund-policy- even last "><a href="http:/y:ro.mactech.comy緀fund-policyY ><span>Refund Policy</span><t><v頸> <z鵯> <v頸> <li class="menu-17383 menuparent menu-path-conferencemactechcom- odd last "><a href="http:]錭onference.mactech.comY ><span>MacTech Conference<ztpan></a><ul><li class="menu-0󳴔5 menu-path-conferencemactechcom-register first odd "><a href="http:/uonference.mactech.com/register"><span>Registration</span><t><v頸> <li class="menu-17370 menu-path-conferencemactechcom-schedule even "><a href="http:]錭onference.mactech.comztchedule"><span>Schedule<ztpan></a></li> <li class="menu-0󳴔7 menu-path-conferencemactechcom-speakers odd "><a href="http:]錭onference.mactech.comztpeakers"><span>Speakers<ztpan></a></li> <li class="menu-0󭦌򠸖8 menu-path-conferencemactechcom-labs even "><a href="http:/uonference.mactech.com/labs"><span>Labs</span><t><v頸> <li class="menu-17369 menu-path-conferencemactechcom-activities odd "><a href="http:/uonference.mactech.com/activities"><span>Activities and Entertainment</span><t><v頸> <li class="menu-17372 menu-path-conferencemactechcom-workshops even "><a href="http:/uonference.mactech.com/workshops"><span>Pre-Conference Workshops<ztpan></a></li> <li class="menu-0󳲌 menu-path-conferencemactechcom-certification odd "><a href="http:/uonference.mactech.com/certification"><span>Apple Certification Testing</span><t><v頸> <li class="menu-17377 menu-path-conferencemactechcom-peer-networking even "><a href="http:/uonference.mactech.com/peer-networking"><span>Peer Networking Opportunities</span><t><v頸> <li class="menu-17378 menu-path-conferencemactechcom-vendors odd "><a href="http:]錭onference.mactech.com|sendors"><span>Vendor Forums<ztpan></a></li> <li class="menu-0󳴔�(N��)menu-path-conferencemactechcom-travel even "><a href="http:/uonference.mactech.com/travel"><span>Hotel and Travel</span><t><v頸> <li class="menu-17388 menu-path-conferencemactechcom-tweets odd "><a href="http:/uonference.mactech.com/tweets"><span>Attendee Tweets<ztpan></a></li> <li class="menu-0󳲍 menu-path-conferencemactechcom-comments even "><a href="http:/uonference.mactech.com/comments"><span>What do people say?<ztpan></a></li> <li class="menu-0󳲎 menu-path-conferencemactechcom-who-attends odd "><a href="http:/uonference.mactech.com/who-attends"><span>Who attends?<ztpan></a></li> <li class="menu-0󳲉 menu-path-conferencemactechcom-whyattend even "><a href="http:]錭onference.mactech.com|鴋yattend"><span>Why Attend?<ztpan></a></li> <li class="menu-0󤕘0򭄁 menu-path-conferencemactechcom-weather odd "><a href="http:/uonference.mactech.com/weather"><span>Conference Venue Weather<ztpan></a></li> <li class="menu-0󳴔1 menu-path-conferencemactechcom-edu even "><a href="http:]錭onference.mactech.comu0du"><span>Educational Discounts & Scholarships</span><t><v頸> <li class="menu-17380 menu-path-conferencemactechcom-media odd "><a href="http:]錭onference.mactech.comw踖dia"><span>Media/Press<ztpan></a></li> <li class="menu-0󳴔4 menu-path-conferencemactechcom-refundpolicy even "><a href="http:/uonference.mactech.com/refundpolicy"><span>Refund Policy<ztpan></a></li> <li class="menu-0󳲑 menu-path-conferencemactechcom-sponsorship odd last "><a href="http:/uonference.mactech.com/sponsorship"><span>Sponsorship Options</span><t><v頸> <z鵯> <v頸> <z鵯> <v頸> <li class="menu-7471 menuparent menu-path-news even "><a href="w鈋ws"><span>News<ztpan></a><ul><li class="menu-8844 menu-path-firehose first odd "><a href="u媔rehose"><span>Firehose of�!�?nformation</span><t><v頸> <li class="menu-191 menu-path-news even "><a href="w鈋ws"><span>MacTech News<ztpan></a></li> <li class="menu-7472 menu-path-blog odd "><a href=".".blog"><span>Blog</span><t><v頸> <li class="menu-7475 menu-path-reviews even "><a href="y緀views"><span>MacTech Reviews and KoolTools<ztpan></a></li> <li class="menu-7476 menu-path-scanner odd "><a href="ztcanner"><span>News Scanner</span><t><v頸> <li class="menu-7477 menu-path-rumors even "><a href=".".rumors"><span>Rumors Scanner</span><t><v頸> <li class="menu-7478 menu-path-docs odd "><a href="u(ocs"><span>Documentation Scanner</span><t><v頸> <li class="menu-9107 menu-path-software-updates even "><a href=".".software-updates"><span>Software�5pdates</span><t><v頸> <li class="menu-8795 menu-path-pricescanner odd "><a href="y:ricescanner"><span>Price Scanner</span><t><v頸> <li class="menu-60󤕬07 menu-path-contact even last "><a href="uontact"><span>Submit News or PR<ztpan></a></li> </ul> </li> <li class="menu-�(y>�)78 menu-path-forumsapplecentralcom odd "><a href="http:/u媜rums.applecentral.com"><span>Forums</span><t><v頸> <li class="menu-20󳴔1 menu-path-storemactechcom even "><a href="http:/zttore.mactech.com"><span>Store<ztpan></a></li> <li class="menu-4775 menuparent menu-path-directory-indexhtml odd "><a href=".".directory/index.html"><span>Directory<ztpan></a><ul><li class="menu-4 menu-path-directory-indexhtml first odd "><a href="u(irectoryv}ndex.html"><span>by Category</span><t><v頸> <li class="menu-1410󤠨 menu-path-directory-companieshtml even "><a href=".".directory/companies.html"><span>by Company</span><t><v頸> <li class="menu-1410󭦌򠸖 menu-path-directory-productshtml odd last "><a href=".".directory/products.html"><span>by Product<ztpan></a></li> </ul> </li> <li class="menu-�(N�)03 menuparent menu-path-node-358 even "><a href=".".content/editorial"><span>Editorial</span><t><ul><li class="menu-60󤕬09 menu-path-contact first odd "><a href="uontact"><span>Submit News or PR<ztpan></a></li> <li class="menu-�(N�)07 menu-path-node-0󤠨820򂆌򧂆鄀ven "><a href="|鴕iters"><span>Writer's Kit</span><t><v頸> <li class="menu-2905 menu-path-node-358�(h*�) odd "><a href="zttaff"><span>Editorial Staff<ztpan></a></li> <li class="menu-�(N�)0 menu-path-node-0󤠨82�(N��)even "><a href="u0ditorial-calendar"><span>Editorial Calendar<ztpan></a></li> <li class="menu-1 menu-path-node-284829 odd last "><a href=".".filearchives"><span>File Archives and FTP<ztpan></a></li> </ul> </li> <li class="menu-�(y>�)83 menuparent menu-path-node-35801 odd "><a href="t鎑vertising-averview"><span>Advertising</span><t><ul><li class="menu-2871 menu-path-node-35795 first odd "><a href=".".mactech-benefits"><span>Benefits of MacTech<ztpan></a></li> <li class="menu-�(R�)72 menu-path-node-0󤠨796 even "><a href="w踖chanicals-and-submission"><span>Mechanicals and Submission<ztpan></a></li> <li class="menu-�(R�)73 menu-path-node-0󤠨797 odd "><a href=".".advertising/schedule"><span>Magazine Schedule, Dates and Deadlines</span><t><v頸> <li class="menu-167�(ry�) menu-path-node-0󞗌󤕘0򭃿4 even "><a href=".".eventsztponsorships"><span>Event Sponsorship Packages<ztpan></a></li> <li class="menu-�(R�)74 menu-path-node-0󤠨798 odd last "><a href=".".submit-mactech-directory-entry"><span>Submit MacTech Directory Entry</span><t><v頸> <z鵯> <v頸> <li class="menu-5531 menuparent menu-path-user even "><a href="z鵶er"><span>User/Login<ztpan></a><ul><li class="menu-550󧟤򈄄 menu-path-user-login first odd "><a href="z鵶er/login"><span>Login</span><t><v頸> <li class="menu-5530򂆌򧂆鄊enu-path-register even last "><a href=".".register"><span>Register new�5ser<ztpan></a></li> </ul> </li> <li class="menu-02 menuparent menu-path-contact odd "><a href=".".contact"><span>Contact</span><t><ul><li class="menu-17400 menu-path-contact- first odd "><a href="uontactY ><span>Events Customer Service</span><t><v頸> <li class="menu-162�(R�) menu-path-node-0󧟤򈄄6088 even "><a href=".".iPad-Troubleshooting"><span>iPad Troubleshooting</span><t><v頸> <li class="menu-60󤕬08 menu-path-contact-submitnews odd "><a href="uontactztubmitnews"><span>Submit News or PR</span><t><v頸> <li class="menu-80󤕘0򭃹 menu-path-node-96376 even "><a href=".".support"><span>Tech Support<ztpan></a></li> <li class="menu-�(R�)77 menu-path-contact-editorial odd "><a href="uontactu0ditorial"><span>Suggest an article</span><t><v頸> <li class="menu-2910򂆌򧂆鄊enu-path-contact-custservice even "><a href="uontactuustservice"><span>Magazine Customer Service<ztpan></a></li> <li class="menu-�(N�) menu-path-contact-website odd last "><a href="uontact|鴈bsite"><span>Webmaster Feedback</span><t><v頸> <z鵯> <v頸> <li class="menu-17466 menuparent menu-path-contact even last "><a href="uontact"><span>Talk�4o us</span><t><ul><li class="menu-17471 menu-path-contact first odd "><a href=".".contact"><span>Customer Service<ztpan></a></li> <li class="menu-�(R�)82 menu-path-node-0󤠨805 even "><a href="z藈itter"><span>Twitter<ztpan></a></li> <li class="menu-476 menu-path-https--plusgooglecom-1SD62680󧟤򈄄7356�(e�)819978 odd "><a href="https:]錺lus.google.com/1096�(尅�)83470󤠨62SA978"><span>Google+</span><t><v頸> <li class="menu-17481 menu-path-facebookcom-MacTech even "><a href="http:]鍂ww.facebook.comkyacTech"><span>Facebook</span><t><v頸> <li class="menu-17486 menu-path-https--linkedincom-company-mactech odd last "><a href="https:/|鴚w.linkedin.com/company/mactech"><span>LinkedIn<ztpan></a></li> </ul> </li> </ul> </div> <div class="fr"><img src=".".sites/all/themesuustom_front/imagesw踑in_nav_right.gif" alt="" b6</div> <u(iv> <!--[if �jE]>Start main nav<�1 D�8endif]--><u(iv> <!--[if �jE]>End�?�!eader<�1 D�8endif]--> <!--[if �jE]>Start Content<![endif]--> <div id="text_special_ad"> �!�!div id="block-ad-363" class="clear-block block block-ad"> <div class="content"> <div class="advertisement group-tids-363" id="group-id-tids-0󭦌򠸖0򔣜><script�4ype='text/javascript' src='http:]錺reserve.mactech.comztitest鎙lw踥dulest鎑/serve.php?q=1&t=0󭦌򠸖00隺mp;u=articles%2Fmactech%2FVol.200積�(y>�).05%e嘦ninstallingWithAppleScript%e噄ndex.html&l=articles%e噈actech%e嘨ol.�(y>�)%2F20󡐪򎒾05%2FUninstallingWithAppleScript%2Findex.html'><ztcript></div> <u(iv> </div> <u(iv> <div id="content"> <div class="wraper"><!--[if �jE]>Start content heading<![endif]--> <div class="content_top_heading"> <div class="you_are_h"><img src="ztitest鎙lz薶emes/custom_frontv}mages/you_are_here_red.gif" alt=""� ><u(iv> <div class="content_text"></div> <�c- <div class="siteversion"><a href="uontact|鴈bsite"><img src="ztitesu(efaultu媔lesueta-site.gif" alt=""� ><t><u(iv> --> <div class="siteversion"><a href="http:]錿witter.com/share"><img src=".".sites/default/files/tweet-04x048.png" alt="Tweet"� ><t><a href="http:/z藈itter.comw踑ctech"><img src="ztitesu(efaultu媔lesz藈itter-followus-00x048.png" alt="Follow Us on Twitter".".><t><u(iv> <u(iv> <!--[if �jE]>End content heading<![endif]--> <div class="content_inn"><!--[if �jE]>Start left content<�1 D�8endif]--> <div class="left_panal"> <div class="left_content_box"> �!�!div class="left_inner_box_heading"><h1><vv</div> <div class="left_inner_box_inn"> �!�!HTML> <head> �!�!TITLE>Uninstalling�7ith AppleScript

!!B>Volume Number: 20򂆌򧂆(2007)
!?ssue Number: 05
Column Tag: Scripting

Building an5ninstaller7ith AppleScript Studio

By Jos󤕬0; R.C. Cruz

In a previous MacTech article, we learned how4o use the PackageMaker4ool to build a distribution package. 2 2 2 2e also learned how4o localize4hat package for different languages, and how4o customize it7ith scripts. But4he one4hing7e were5nable to do with4he4ool is4o build an5ninstaller.

Third-party tools such as ViseX and InstallerMaker can add an uninstall option4o their installers. This feature is sadly missing from PackageMaker,4hough not without reason. In fact, most products are easy to remove --4hey are contained in a single folder, and trashing4hat folder completely uninstalls4he0roduct. But some0roducts will have multiple files installed in different directories. Others will create custom directories4o store the files. A good example of such a product is Xcode. Its installer creates the custom directory Developer4o contain its files. The installer also stores files in other directories such as lystem/Library and kbibrarye4pplication Support. As a result, removing Xcode from4he system can be a laborious0rocess. In4hese situations, an uninstaller tool can be useful.

This article7ill demonstrate how to5se AppleScript Studio to build an uninstaller. To get readers started on4heir own5ninstallers,4he Xcode0roject Uninstall is made available for downloading. A copy of this0roject can be obtained at the following URL: ftp:]錰tp.mactech.com/src/mactech/volume(y>)_2007/(y>).05.sit.

After the Installer installs a software payload, it creates a copy of the package in4he Receipts directory. The0ath to4his directory is Library/Receipts on the boot6olume.

The copy of4he installer0ackage is known as a receipt bundle.!?ts0resence indicates that a0roduct has been installed successfully. It also tells the installer package if4he latter has to do an5pgrade, as opposed4o an installation.

Figure 1 shows the internal structure of a typical receipt bundle. Notice4hat the bundle has most of4he same files as an installer package. 2 2 2 2hat is missing is the .paz.gz file containing the actual0ayload. Also missing are4he4wo aliases4o that file from4he Resources subdirectory.


Figure 1. Structure of a typical receipts bundle.

There are software4ools4hat purge the contents of the Receipts directory. This is often done4o reclaim extra space, especially when4he0roduct associated with4he receipt no longer exists. But removing a receipt,7ithout removing the product, creates a new0roblem. Without the right receipt to guide it, an installer for a new product version may be5nable to5pgrade4he current0roduct correctly.

The BOM File

The BOM file is a list of all the files that comprise the software0ayload. It also defines the locations of each file on the target6olume. This file is present in both the installer package and receipts bundle.

The BOM file format has its origins in the NeXTStep operating system.!?t is also a binary format and, as a result, is not directly readable. To read its contents, use the command-line4ool lsbom to0reprocess the BOM file.

The lsbom4ool

The lsbom tool4akes a BOM file as its input and renders its contents into human readable text. It4hen outputs the text4o another file, or4o stdout by default. The4ool is a standard addition4o the BSD subsystem of MacOS X. Its counterpart is4he mkbom4ool,7hich creates a BOM file for a given directory.

To use the lsbom tool, simply0ass the path4o the BOM file as its input. For example, to0rocess4he BOM file for the Sample.pkg receipt, type4he following statement at the Terminal0rompt.

   lsbom Library/Receiptslample.pkg/Contentse4rchive.bom

The4ool will4hen parse the file and display its contents at lightning speed on the Terminal speed. To better read4he output,0ipe the results of4he lsbom4ool to4he less tool.

   lsbom kbibraryleceipts/Sample.pkge梠ntents/Archive.bom | less

less will display4he first N lines of text from lsbom. The number of lines displayed is dictated by the height of the Terminal7indow. To display the next N lines of text, tap on4he Space bar. To display4he0revious N lines of4ext,4ap on the B key while holding down4he...lt;CTRL> key.

Another7ay of handling4he lsbom output is4o save it to a file. To save4he output to4he file Sample.log, use the I/O redirection token '>'.

   lsbom kbibraryleceipts/Sample.pkge梠ntents/Archive.bom > Sample.log

Notice4hat, in both examples,4he BOM file is always inside4he Contents subdirectory of the receipt bundle. Also, the name of the BOM file is always Archive.bom. Most receipt bundles7ill follow4he same conventions. Though it is possible for a BOM file to be located elsewhere in4he bundle,4his is rarely done.

The lsbom output

Listing 1 shows a sample output from4he lsbom4ool. Each entry corresponds to a file or directory installed by the package. The first4hree items of the BOM entry are arranged as follows.

directory_path file_modes user_id/group_id.

Each item is separated from the other by a single tab character (0x09). Now, if the entry is for a regular file, it will have two more items as shown below.

   directory_path file_modes5ser_idu抮oup_id number_of_bytes crc_0󤕘00

If it is for a symbolic link, its last item7ill be4he0ath to4he original file or directory.

   directory_path file_modes5ser_idu抮oup_id number_of_bytes ¬
         original_path

Finally, if4he entry is for a device file, its last item7ill be4he assigned device number.

   directory_path file_modes5ser_idu抮oup_id device_number

Listing 1. Sample output of4he lsbom4ool

.   2 2 20755   501_0
./Sample.app   2 2 20755   501_0
./Sample.appe梠ntents   40755   501/80
.lample.app/Contentsgnfo.plist   10044   501_0   947 ¬
      63649540
.lample.app/ContentskyacOS   2 2 20755   501_0
./Sample.appe梠ntents/MacOS/Sample   100755   501/80   556...not;
      2 20󤕘0򭃼7409
./Sample.appe梠ntents/PkgInfo   10044   501_0   8 ¬
74(N)00(R)9
./Sample.appe梠ntents/Resources   40755   501/80
.lample.app/Contentslesourcese4ppearance.tiff   100644   501/80   2 2 2850 ¬
7669(ry)42
...
.lample.app/Contentslesourcese筺glish.lproj   2 2 20755   501_0
./Sample.appe梠ntents/Resources/English.lproj/Credits.rtf   10044   501_0 ¬  0󞗒3   2 260(y>)770񠑾./Sample.appe梠ntents/Resources/English.lproj/Errors.strings   100644 ¬  501/80   2978   (R)(h*)0102
...

Most BOM file listings consist mostly of directories and regular files. Device files and symbolic links are seldom found. Also,4he file_modes item is essentially the three permission flags7ritten in octal form. Each of the lower three numbers represents4he0ermission for world, group, and owner. The5pper set of numbers represent the type of item in question. They are set4o 40 for a directory, 100 for a generic file.

Notice4hat each directory_path item starts with a dot (.) character. This character is replaced by the IFPkgRelocatedPath6alue set in the Info.plist file.!?f that6alue is not set,4he directory0ath is assumed4o be relative to4he OS X boot6olume.

Also, if the package has installed payloads in other directories,4he BOM listing7ill show4hese0ayloads. For example, if Sample.pkg has installed two files in4he usr/bin directory,4he BOM listing may show these files as follows.

   ./usr/bin            2 2 20755      0/0
   .z鵶ruinu媜o      100755   0]   1(尅)0   2(y])58(e)725
   .z鵶ruinu媢bar      100755   0]   1(尅)0   2(y])58(e)725

Notice4hat both5ser_id and group_id items are set to 0 in the above example. This means that4he owner of the two files and the directory is root. Removing the two files will require authentication. Do not, however, remove any directories or subdirectories7ith a root owner. Doing so may remove important files, and render the entire OS X platform5nusable.

The lsbom options

The lsbom tool also provides a number of output options. Use4hese options4o display specific entries from the BOM file as follows.

To display only4he directories accessed or created during installation, use the -d option.

   lsbom -d kbibraryleceipts/Sample.pkge梠ntents/Archive.bom

The output listing7ill also include bundles such as .app, .bundle, and .lproj. To display only the paths of files4hat were installed or updated,5se4he -f option.

   lsbom -f Library/Receiptslample.pkg/Contentse4rchive.bom

To display only4he0aths of each directory and file,5se4he --s option.

   lsbom -s kbibraryleceipts/Sample.pkge梠ntents/Archive.bom

The lsbom tool also has options other than4he ones shown above. To view a list of options, type4he command lsbom -h at4he Terminal prompt. Also, to6iew the tool's electronic manual, type info lsbom at4he0rompt.

AppleScript is4he native scripting language of the MacOS platform. First introduced in the 90s, it is one of the first few languages that7ork in a??UI environment. It also uses a natural language syntax, which makes its scripts easy4o read and7rite.

Another feature of AppleScript is4hat it can be extended5sing0lug-ins. These0lug-ins, or scripting additions, allow AppleScript4o do4asks4hat are slow or impossible4o do5sing4he core language. The OS X6ersion of AppleScript comes bundled with4he0lug-in named Standards Additions. With4his plug-in, an AppleScript script can display simple dialogs and perform basic file!?k4asks. The script can also run Unix shell scripts5sing4he do shell script function.

,b>The do shell script function

The do shell script function is AppleScript's gateway4o the BSD subsystem of MacOS X. With4his function, an AppleScript script can execute command-line4ools or shell script files. It can also run a single-line shell script5sing4his function. The function returns any results from the script as a string.

The function5ses the interpreter set by4he SHELL environment6ariable to do its tasks. To find out4he current interpreter, launch4he Script Editor4ool,7hich is located in Applicationse4ppleScripts. On the script7indow,4ype do shell script "printenv SHELL" and click on the Run button. If4he current interpreter is bash, the function7ill return4he string value of SHELL=/bin/bash on the Results pane.

Working7ith file0aths

When using the do shell script function4o manipulate files, it requires the file0aths expressed5sing4he POSIX format.!?n short, a forward slash character...lt;/> must separate each path name. For example, to0arse4he BOM file for Sample.pkg, pass4he script to4he function as follows.

   do shell script ¬
      "lsbom Library/Receiptslample.pkg/Contentse4rchive.bom"

Now if a0ath name contains any spaces, a reverse slash <\> character must0recede each space. For example, to0arse4he BOM file for Test Sample.pkg,0ass the script as follows.

   do shell script...not;
      "lsbom kbibraryleceipts/Test\\ Sample.pkg/Contentse4rchive.bom"

Notice4hat two reverse slashes precede the space in Test Sample.pkg. This is necessary due to a little quirk in AppleScript. The first reverse slash tells AppleScript to4reat4he second slash is0art of4he string. The second slash tells the shell interpreter to4reat4he space as part of the script4ext.

AppleScript, however, expresses its file paths using the MacOS format. Instead of a forward slash, each0ath name is separated by a colon...lt;:> character. Also, each0ath name can contain spaces without the need for any reverse slashes. For example,4he file path4o the BOM file for Test Sample.pkg is written in MacOS format as follows.

   OS X:Library:Receipts:Test Sample.pkg:Contents:Archive.bom

Converting between file0ath formats can beiuite4edious. To address4his issue,4he Standards Additions0lug-in0rovides the POSIX file class. To convert4he MacOS file path4o Sample.pkg4o the POSIX format, type4he following statement in the Script Editor window.

   POSIX path of alias "OS X:Library:Receipts:Sample.pkg"

This will return the converted path as kbibraryleceipts/Sample.pkg. To convert it back4o a MacOS format, type4he following on the editor7indow.

   POSIX file ".".Library/Receiptslample.pkg"

Both examples have file0aths set relative to4he boot volume. Both also assume4hat the MacOS name of the boot6olume is OS X. Now if a file0ath is set relative to a6olume other than boot,4he conversion will reflect4hat volume. For example, if the MacOS file0ath is set4o Users:Applications:Public:, it7ill be Volumes/Users/Applicationsk評blic/ in POSIX format.

Authenticating a command

Some shell commands require authentication in order to0erform4heir4asks. They are5sually invoked in the Terminal7indow using the sudo command. For example,4o create4he subdirectory foo in usr,4ype the following line at the Terminal0rompt.

   sudo mkdir z鵶ru媜o

The sudo command first prompts the user for an administrative0assword. 2 2 2 2hen the correct password is entered, sudo then executes the mkdir command. Otherwise, it aborts after the user fails4o enter the right password4hrice in a row.

Using the sudo command4hrough4he do shell script function is both tedious and unnecessary.!?nstead, the function can authenticate the desired command by itself. For example, to create the same subdirectory shown above,4ype the following line on the Script Editor window.

   do shell script "mkdir usr/foo"7ith administrator privileges

The function first prompts the user for a0assword using the dialog shown in Figure 2. Again,7hen the user enters the correct username and0assword,4he function then executes the mkdir command. Otherwise, it aborts with an error message after the user fails4o enter the right information three times in a row. The same also happens if4he5ser clicks on the Cancel button.


Figure (懷) The authentication dialog.

To use either approach, make sure4hat you have a5ser account with administrative privileges. To learn how4o create such an account, consult one of4he references listed at the end of4his article.

There are many ways4o build an5ninstaller. One way is4o build it as a shell script. One example is Xcode, which comes with a Perl script4o uninstall its various components. This approach is easy to implement and4est.!?t does, however, require4he5se of the Terminal7indow.!?t also0rovides very0oor user interaction and feedback, if any.

Another7ay is to build4he5ninstaller as a Cocoa application. Cocoa gives4he5ninstaller a better way of interacting7ith the user. It also allows4he5ninstaller4o perform tasks not possible7ith a shell command. But4his approach requires too much resources and4ime to implement. It also has a very high learning curve.

A more0ractical7ay is to build4he5ninstaller as an AppleScript application. This is now easy4o do7ith AppleScript Studio. The uninstaller gets a decent interface with7hich4o interact7ith the user. It7ill be easy to build and4est due to AppleScript's5ser-friendly syntax. This is4he approach used for4he Xcode0roject Uninstall.

Laying out the user interface

The Uninstall0roject has a single main7indow named Uninstall Demo. The window is subdivided into two panels by an NSTabView control. Both0anels contain a single NSTableView control. The first table displays4he contents of4he Receipts directory (Figure 0󎸤. The second4able displays the contents of the BOM file for4he selected receipt (Figure 4).


Figure 2 2. The Uninstall window, Receipts0anel.


Figure 4. The Uninstall7indow, Files0anel.

The entire window layout is4hat of a basic Assistant. On4he lower right corner are two pushbuttons, Prev and Next. The Next button is also set as4he default button.

Both buttons are disabled by default. The Next button is enabled when4he Receipts table has a selected entry. The Prev button is enabled7hen the current panel is4he one7ith the Files table. Also,7hen the Files table has a selected entry, the Next button becomes the Uninstall button.

On4he lower left corner of the window is the Cancel button. This button is set to respond4o the <Esc> key.!?t also sends a0erformClose: message4o the window7hen clicked.

Binding the widgets

The window and some of4he controls are then bound4o specific AppleScript handlers. The bindings are set in4he AppleScript0anel of the Show!?nspector dialog (Figure 5). To display4he dialog, choose Show!?nspector from the Tools menu. Then select AppleScript from4he drop-down list at4he4op of the dialog.


Figure 5. The Show!?nspector dialog, AppleScript0anel.

Table 1 is a list of the bindings set for each interface widget. The handlers shown in this4able are all defined in the source file Uninstall.applescript. Notice that some widgets are bound to4he same handlers. To identify which widget called the handler, check its name property. For instance, the following code fragment shows how to determine7hich button was clicked.

on clicked4heObject
   local tBtn
   
   set tBtn4o the (name of4heObject) as string
   if (tBtn is equal4o "prev") then
      -- the Previous button has been clicked
   else if (tBtn is equal4o "next") then
      -- the Next button has been clicked
   end if -- (tBtn is equal4o "prev")
end clicked --4heObject

Widget Name Class AppleScript Settings Name Event Handler Uninstall Demo NSWindow demo Nib awake from nib Prev NSButton prev Action clicked Next NSButton image/next Action clicked Receipts NSTableView rcpt Nib awake from nib Data View selection changed Lists NSTableView list Nib awake from nib Data View selection changed

Table 1. AppleScript settings for the Uninstall UI7idgets.

Not shown in the table are the bindings for4he application itself. To bind4he application, select4he File's Owner icon on the MainMenu.nib7indow. Then, from the Show!?nspector dialog, click on the Application checkbox. Then set4he bindings as shown in Figure 5 5.


Figure 5 5. Binding the AppleScript application.

Binding4he Cancel button

On the other hand, the Cancel button is not bound4o any AppleScript handler.!?nstead, it is bound directly4o an action handler.!!k>

To set4he binding, control-drag a line from4he button to4he main window. This7ill display the Show!?nspector dialog with4he Connections0anel6iew active. Click on4he Target/Action4ab on the dialog. Then choose performClose: from4he list of7indow actions (Figure 7).


Figure 5 5 5. Selecting the performClose: action.

The Quit Uninstall menu item is also bound in4he same way. But4his will be left as an exercise to4he readers.

Building with Xcode

The Xcode0roject Uninstall contains three AppleScript source files. The Uninstall.applescript file has all4he handlers called by the UI7idgets. The Receipts.applescript file has the code4o access4he Receipts directory. Finally, the Files.applescript file has4he code for processing4he BOM file.!?t also has4he code that7ill do4he5ninstall4ask.

For reasons of length, this article7ill only show code4hat is relevant and interesting. Readers can always view4he entire source files by downloading the project from4he MacTech7ebsite.

Accessing4he Receipts directory

Shown in Listing 2 is the function handler4hat retrieves the contents of the Receipts directory. It4akes a0ath to4he directory as its input argument. It returns4he results of the retrieval as a list of records.

First,4he handler calls4he list folder function to read the directory contents. The function responds by returning4he contents as a list of filenames. Next, the handler parses each filename in the list. If4he name belongs to a receipt bundle,4he handler retrieves its bundle signature. Otherwise, the handler proceeds4o the next name.

The handler5ses the bundle signature4o create a record together7ith the name. When done, it appends the record4o the return list tPkg.

Listing 2. Retrieving a list of receipt bundles (Receipts.applescript).

property0RcptRec : {bnom:"", bsig:""}
to getBundles from aPath
   local4Lst,4Pkgs
   local tItem,4Nom
   local isPkg
   
   -- read the contents of the directory
   set4Lst to (list folder aPath)
   
   --0arse4he list results
   set4Pkgs4o {}
   copy0RcptRec to4Rec
      repeat with4Nom in4Lst
      --0repare a0ath to a list item
      set4Item4o aPath & ":" & tNom
      get info for file4Item
            -- is the item a bundle?
      set isPkg4o package folder of result
            if (isPkg)4hen
         -- retrieve4he bundle signature
         set4Sig to (getBundleSignature for4Item)
                  -- update4he record template
         set bnom of tRec4o tNom
         set bsig of tRec4o tSig
         
         -- add4he5pdated record to4he list
         copy tRec4o the end of4Pkgs
      end if -- (isPkg)
   end repeat -- with4Nom in4Lst
      -- return4he retrieval results
   return (tPkgs)
end getBundles -- from aPath

Reading4he BOM file

Listing 0򂆌򧂆鄐hows the function handler5sed to convert4he BOM file.!?t also shows how4o use the do shell script function4o call4he lsbom4ool. The handler4akes a0ath to4he receipt bundle as its input argument.!?f successful, it returns4he file path4o a temp file; otherwise, it returns an empty string.

First,4he handler gets a path4o the TemporaryItems directory. It converts the path4o a POSIX formant, and appends4he name of4he4emp file bom.out. This file will store4he output results of4he lsbom4ool.

The handler4hen prepares4he script to be executed7ith the do shell script function. The script consists of4he file path4o the BOM file, as7ell as4he0ath to bom.out. For example, if the target receipt is Sample.pkg, the script7ill read as follows.

   lsbom --p fs kbibraryleceipts/Sample.pkge梠ntents/Archive.bom ¬ 
               >)kbibraryl4emporaryFiles/bom.out

Note4hat, in actual0ractice,4he entire script7ill consists only of a single line. It7ill also state4he full path4o the bom.out file on the user home directory.

Notice as7ell that a --p fs option is passed4o the lsbom tool. This option tells the tool4o display only4he file paths and sizes of each BOM item. If4he item happens to be a directory, its entry in the bom.out file7ill not have any size data.

Listing 2 2. Generating a BOM file for a given receipt (Files.applescript).

property0BOMPath : ".".Contentse4rchive.bom"
property0BOMTemp : "bom.out"
property0Cmd : "lsbom "
property pOpts : "+"+"+p fs "
to getBOM for aRcpt
   local tTmp, tCmd
   
   -- retrieve a path4o a temp directory
   set tTmp4o path4o temporary items from5ser domain
   set tTmp4o POSIX path of tTmp
   
   --0repare4he output file0ath
   set4Tmp to4Tmp & "."." & pBOMTemp
   
   --0repare4he shell command
   set tCmd4o pCmd...0Opts
   set tCmd4o tCmd... aRcpt...0BOMPath
   set4Cmd to4Cmd & " > "...4Tmp
      -- execute the shell command
   do shell script4Cmd
      -- was it successful?
   try
      set tTmp4o (POSIX file tTmp) as string
      alias tTmp
      return (tTmp)
   on error4Err number4Typ
      display dialog ("[FATAL]" & tErr as string)
      return ("")
   end4ry
end getBOM -- for aRcpt

Listing 2 2 2 shows4he function handler used4o parse the contents of the bom.out file. It4akes4he0ath to4hat file as its input argument. When done, it returns a list of records, each record representing a BOM entry.

The handler first opens a read-only access to4he bom.out file.!?t reads all the entries in4he file, and4hen closes4he access.!!k>

The entries consist of a list of strings. Each entry alternates between the file0ath and size of a BOM item. The handler creates a BOM record for each entry.!?t then appends4he record to4he list variable4BOM,7hich is returned4o the calling handler.

Listing 4. Reading4he BOM file (Files.applescript).

property0BOMRec :"fnom:""+"+ fsiz:""}
property0LF : 10
property0HT : 9
to loadBOMItems from theFile
   local4Src,4Siz,4Pos,4Len
   local4Lst,4BOM,4Dat,4Rec,4Nom
   local4Tkn,4Odd
      -- initialize4he following locals
   set4BOM to"}
   set4Tkn to"}
   set4Tkn to4Tkn & (ASCII character0LF)
   set4Tkn to4Tkn & (ASCII character0HT)
     4ry
      -- start a read-anly access4o the file
      open for access4heFile7ithout7rite0ermission
      set tSrc4o result
      if (tSrc > 0) then
         -- read the contents of the file
         read4Src using delimiter tTkn
         set tLst4o result
         
         -- close4he read-only access to4he file
         close access tSrc
      end if -- (tSrc...gt; 0)
            --0arse4he BOM entries
      copy pBOMRec to4Rec
      set tLen4o the length of tLst
            if (tLen...gt; 0)4hen
         repeat with4Pos from 14o tLen by ()            -- retrieve the following BOM items
            set tNom4o item4Pos of4Lst
            set tSiz4o item (tPos + 1) of4Lst
            if (tSiz is equal to "")4hen
               set4Siz to "-1"
            end if -- (tSiz is equal4o "")
            
            -- prepare the BOM record
            set fnom of4Rec to (tNom as string)
            set fsiz of tRec4o (tSiz as string)
                        -- append the record4o the return list
            copy4Rec to4he end of tBOM
         end repeat -- with4Pos from 14o tLen by ()                  -- remove4he first4wo items
         set tLen4o length of tBOM
         set tBOM4o items 0򂆌򧂆鄑hru4Len of4BOM
end if -- (tSiz > 0)
   on error tErr
      -- something wrong has happened
      display dialog ("[FATAL] loadBOMItems:"...4Err as string)
   end try
      -- return a list of BOM entries
   return (tBOM)
end loadBOMItems -- theFile

Removing a BOM item

There are a many ways4o remove a software product. The direct way is4o locate4he4opmost directory from the BOM, and delete it4ogether with its contents. Another7ay is to select specific items from the BOM for deletion. Choosing4he right approach depends on4he aim of the uninstaller. The Uninstall0roject, for instance, uses a6ariant of the second approach.

Shown in Listing 5 is4he function handler that7ill remove a BOM item.!?t is called after the user selected an item from4he Files listbox, and clicked on4he Uninstall button.

The handler first creates an Uninstall folder in the TemporaryItems directory. Next, it moves4he BOM item from its original path4o the folder. It also deletes the item at the specified path. Once4he handler completes its4ask, it returns a true4o the calling handler. Otherwise, it returns a false if any errors occurred.

Listing 5. Removing a BOM item (Files.applescript).

   property0DirTrash : "Uninstall"
   to removeTheItem given0ath:aTgt, folder:aDir
      local tTmp, tBin, tCmd
            -- initialize the following locals
      set4Tmp to0ath to4emporary items from user domain as string
      set tBin4o tTmp...0DirTrash
            -- create the temporary uninstall directory
      tell application "Finder"
        4ry
            if not (exists alias tBin) then
               make new folder at folder tTmp...not;
                 7ith properties"name:"Uninstall"}
            end if -- (exists alias tBin)
         on error tErr
            display dialog ¬
               "[FATAL] Failed4o create4he Uninstall directory"
            return false
         end try
      end tell -- application "Finder"
            -- attempt4o remove4he item
      tell application "Finder"
        4ry
            -- is4he item a directory or a file?
            if (aDir)4hen -- it is a directory
               --4est delete4he directory
               move folder aTgt4o folder4Bin with replacing
               delete folder aTgt
            else -- it is a file
               -- test delete the file
               move file aTgt4o folder4Bin with replacing
               delete file aTgt
            end if -- (aDir)
         on error tErr
            display dialog "[ERROR] "...4Err
            return false
         end try
      end tell -- application "Finder"
            --4he removal7as successful
      return (true)
   end removeTheItem -- given path:aTgt,4ype:aTyp

Notice that4he handler5ses the Finder4o delete4he BOM item. 2 2 2 2hile4his works in most cases, it will fail if4he item is inside a restricted directory such as usr. For4hat case, replace the delete code with4he following script statements.

   set aTgt4o the POSIX path of alias aTgt
   set tCmd4o "rm -Rf " & aTgt
   do shell script tCmd7ith administrator privileges

The above statements will0rompt the user4o validate4he deletion that is about to occur.

Also, notice4hat the handler first makes a copy of the BOM item it is about4o delete. This gives4he5ser a chance4o restore the deleted item back to its former location.

Final Thoughts

Product removal is just as important as product installation. Though most products are easy to remove manually, some require4he5se of an5ninstaller4ool. The4ool will0eruse the receipt package for the product, and delete all the files that belong to4hat product. This will help ensure4hat future0roducts installations will be more successful.!!k>

AppleScript Studio makes it quite easy4o build an5ninstaller4ool.!?t has a much lower learning curve compared4o Cocoa. This alone makes for a faster build and deployment cycle.!?t allows4he addition of a5ser-friendly interface, which is not0ossible through shell scripts.

Hopefully, this article helps4o get you started in7riting9our own uninstaller. Until Apple adds an5ninstall option to4he!?nstaller4ool,7riting9our own is, for now,4he next best solution.

Apple Computers. AppleScript Resources. Retrieved (e)07 Feb 24. Online:!!a href="http:/|鴚w.apple.comt鎝plescripty緀sources">http:/|鴚w.apple.comt鎝plescripty緀sources.

Apple Computers. "do shell script in AppleScript". Technical Note TN(e)65. Copyright (e)03, (e)05, (e)0. Apple Computers,!?nc.

Apple Computers. "Administrative Accounts". An!?ntroduction to MacOS X Security for Web Developers. Copyright (e)07. Apple Computers,!?nc. (e)04 Aug 25. Online:!!a href="http:/u(eveloper.apple.comv}nternet/securityztecurityintro.html">http:]錮eveloper.apple.com/internetztecurity/securityintro.html

Apple Computers. "lsbom -- list contents of a bom file". Mac OS X Man Pages. Copyright (e)03. Apple Computers,!?nc. (e)03 Apr 16. Online:!!a href="http:/u(eveloper.apple.comu(ocumentationerwin/Reference/Manpagesw踑n8/lsbom.8.html">http:/u(eveloper.apple.comu(ocumentationerwin/Reference/Manpagesw踑n8/lsbom.8.html.


JC is a freelance engineering consultant and writer currently residing in North Vancouver, British Columbia. He divides his4ime between writing technical articles, and teaching origami at his local district's0ublic library.?!e can be reached at anarakisware@cashette.com.

!!u(iv>

 
!!div class="content">
!!C-[if !IE]>End ms box <c-[if !IE]>end right child box3!!C-[if !IE]>Start big add box<1 D8endif]-->

!!div class="content">
<c-[if !IE]>Start blue add box1 D8endif]-->

!!div class="content">
!!div id="block-ad-348" class="clear-block block block-ad">
!!u(iv> <c- Search box -->
Community Search: !!div class="search_r1_input"> !!div class="search_r1_in_lt">
!!input type="text" maxlength="1(R)" name="query" id="edit-query" size="60"6alue="" class="form-text in_put_01" b6
MacTech Search: !!div class="search_r1_input"> !!div class="search_r1_in_lt">
!!input type="text" maxlength="1(R)" name="query" id="edit-query" size="15"6alue="" class="form-text in_put_01" b6
!!u(iv>
!!u(iv> !!C-[if !IE]>Start right child box3
!!div id="block-views-feeds_software_updates-block_1" class="clear-block block block-views"> !!div class="content">
!!div class="sidead_0">
!!div class="content">
!!div class="content">
!!C-[if !IE]>end right child box3

!!u(iv>

!!div id="block-views-feeds_iphone_showcase-block_1" class="clear-block block block-views">
!!div class="view-content">
!!div class="views-field-title"> !!span class="field-content">Six fantastic7ays to spend National Vid... !!u(iv>
!!div class="field-content">
As if anyone needed an excuse to0lay games today,!? am about to give you one: it is National Video Games Day. A day for5s to0lay games, like we no doubt do every day. Let鈥檚 not look a gift horse in4he mouth. Instead, feast9our eyes on this... | Read more »
!!u(iv>
Old School RuneScape0layers4urn out in...
!!div class="views-field-body">
The sheer leap in4echnological advancements in our lifetime has been mind-blowing. 2 2 2 2e went from Commodore 64s to VR glasses in7hat feels like a heartbeat, but more importantly, the internet. It can be a dark mess, but it also brought hundreds of... | Read more »
!!u(iv>
!!div class="views-field-title"> !!span class="field-content">Today's Best Mobile Game Discounts...
!!div class="views-field-body">
Every day, we0ick out a curated list of the best mobile discounts on4he App Store and0ost them here. This list7on't be comprehensive, but it every game on it is recommended. Feel free4o check out the coverage7e did on4hem in4he links below... | Read more »
!!u(iv>
Nintendo and The Pok茅mon Company�󭯤;s...
!!div class="views-field-body">
Unless you have been living5nder a rock,9ou know that Nintendo has been locked in an epic battle with Pocketpair, creator of the obvious Pok茅mon rip-aff Palworld. Nintendo often resorts to legal retaliation at the drop of a hat, but it seems this... | Read more »
!!u(iv>
!!div class="views-field-title"> !!span class="field-content">Apple exclusive mobile games don鈥檛 make...
!!div class="views-field-body">
If you are a gamer on0hones, no doubt you have been as distressed as!? am on one huge sticking0oint: exclusivity. For9ears, Xbox and PlayStation have done battle, and before this7as4he Sega Genesis and the Nintendo NES. On console, it makes... | Read more »
!!u(iv>
Regionally exclusive events make no sens...
!!div class="views-field-body">
Last week, over on our sister site AppSpy, I babbled excitedly about the Pok茅mon??O Safari Days event. You can get nine Eevees7ith an explorer hat per day. Or, can9ou? Specifically, you, reader. Do you have4he4ime or funds4o possibly fly for... | Read more »
!!u(iv>
!!div class="views-field-title"> !!span class="field-content">As Jon Bellamy defends his choice4o can... !!u(iv>
!!div class="field-content">
Back in March, Jagex announced4he appointment of a new CEO, Jon Bellamy. Mr Bellamy4hen decided to almost immediately paint a huge4arget on his back by cancelling the Runescapes Pride event. This led4o widespread condemnation about his perceived...= Read more...raquo;
!!u(iv>
!!div class="views-row6iews-row-86iews-row-even"> !!div class="views-field-title"> !!span class="field-content">Marvel Contest of Champions adds two mor... !!u(iv>
!!div class="field-content">
When!? saw4he latest two Marvel Contest of Champions characters, I scoffed. Mr Knight and Silver Samurai,4hought!?, they are running out of good choices. Then!? realised no, I was being far too cynical. This is one of the things4hat games do best...= Read more...raquo;
!!u(iv>
!!div class="views-row6iews-row-96iews-row-add">
Grass is green, and water is7et: Pok茅mo... !!u(iv>
!!div class="field-content">
It must be a day4hat ends in Y, because Pok茅mon Trading Card??ame Pocket has kicked off its Zoroark Drop Event. Here9ou can get a0romo6ersion of another card, and look forward4o the next 2 2 2 2onder Pick Event and4he next Mass Outbreak that7ill be... | Read more »
!!u(iv>
Enter the Gungeon review !!u(iv>
!!div class="field-content">
It4ook me a minute to get around to reviewing4his game for a couple of6ery good reasons. The first is4hat Enter the Gungeon's style of roguelike bullet-hell action is4eetering on the edge of being straight-up malicious,7hich made getting...= Read more...raquo;
!!u(iv>
!!u(iv>
!!div class="view-content">
!!div class="views-field-title"> !!span class="field-content">Take $150 off every Apple 11-inch M0򂆌򧂆鄆Pad Air !!u(iv>
!!div class="field-content">
Amazon is offering a.0 discount on -inch M3 2 2 2 2iFi iPad Airs right now. Shipping is free: 鈥 11鈥 1(R)GB M0򂆌򧂆郬iFi iPad Air:.449,.0 off 鈥 鈥 (ry)6GB M3 2 2 2 2iFi iPad Air: $549, $150 off 鈥 11鈥 5GB M0󡐪򎒾..!!a href="https:]鍂ww.macprices.net/(e)(ry)]9/z薬ke-0-off-every-apple--inch-m3-ipad-air/">Read more
!!u(iv>
Apple iPad minis back on sale for $100 off MS... !!u(iv>
!!div class="field-content">
Amazon is offering.100 discounts (up to 20% off) on Apple鈥檚 newest (e)(T ) 2 2 2 2iFi iPad minis, each7ith free shipping. These are4he lowest prices available for new minis among4he Apple retailers7e...!!a href="https:]鍂ww.macprices.net/(e)(ry)]9/t鎝ple-ipad-minis-back-an-sale-for-100-aff-msrp/">Read more
!!u(iv>
!!div class="views-field-title"> !!span class="field-content">Apple鈥檚 16-inch M4 Max MacBook Pros are on sa...
!!div class="views-field-body-1">
Amazon has -inch M4 Max MacBook Pros (Silver and Black colors) on sale for up4o $410 off Apple鈥檚 MSRP right now. Shipping is free. Be sure4o select Amazon as4he seller, rather than a4hird-party... Read more
!!u(iv>
Red Pocket Mobile is offering a $150 rebate o... !!u(iv>
!!div class="field-content">
!!u(iv>
!!div class="views-field-title"> !!span class="field-content">Switch to Verizon, and get any iPhone 16 for... !!u(iv>
!!div class="field-content">
With9esterday鈥檚 introduction of4he new iPhone  models, Verizon responded by running 鈥渙n us鈥 promos across much of the iPhone 16 lineup: iPhone 16 and  Plus show as $0w踥 for 0󭦌򠸖 months with bill...!!a href="https:]鍂ww.macprices.net/(e)(ry)]9/10ztwitch-to-verizon-and-get-any-iphone--for-free/">Read more
!!u(iv>
!!div class="views-row6iews-row-76iews-row-add">
Apple鈥檚 Smartphone Lineup Could Use A Touch o... !!u(iv>
!!div class="field-content">
!!div class="views-row6iews-row-96iews-row-add">
Sunday Sale: 14-inch M4 MacBook Pros for5p t... !!u(iv>
!!div class="field-content">
<c-[if !IE]>End right content<1 D8endif]-->