- Guest Lecture: JavaScript, Ajax & DOM Manipulation
Zach has asked me to give a JavaScript guest lecture in his Web Programming class. We’ll cover: JS basics, node manipulation, DOM traversal, AJAX, JavaScript libraries, and myPlymouth implementations of those topics. Here are the slides (get the .ppt here):
A few resources that are mentioned:
Note: this is an updated talk on the workshop I led two years ago
- hello. iamthenode and I’m here to make you vomit
Oracle EMEA has launched a pilot Web 2.0 program where a character called ‘The Oracle Node” can do a search on the entire OTN website for content you are interested in. This was created and aimed at developers to help encourage registration and downloads on OTN.
The program has a strong web 2.0 aspect with details about the Node on many of the networking websites. Since this is a pilot program, we thought you might be interested in getting involved with the project by suggesting new sources of information, building up and spreading of the Node virally. We welcome your feedback, suggestions and ideas you may have to help improve the Node.
Go ahead, click through and form your own opinion… All I can say is what the hell is Oracle thinking? If you can stomach the orbiting pod long enough to navigate to the end of one of these paths you’ll be faced with a sliding wall of nausea which may somehow contain some relevant information, but with no discernible organization.
I have come up with two acceptable explanations… Someone at Oracle just finished a class on Flash and needed a project, or someone at Oracle just finished a study on motion sickness and needed a project.
You can grow a beautiful garden out of a pile of shit, but it’s hard to see anything fertile about iamthenode.com at this point.
- CSS Selector Browser Support
As many web developers know, CSS support is highly varied amongst browsers. I often find myself hunting for which selectors are more heavily supported. As such, I thought I’d post a direct link to a quality resource here so I wouldn’t have to hunt anywhere besides on BorkWeb.
Here’s some decent resources:
- CSS selector and pseudo element support from kimblim.dk. The format on this page is a bit odd, and it lacks granular details on older browsers.
- The browser support charts at dev.l-c-n.com are more detailed but a bit stale.
- Oracle 10g: Using The Returning Clause With ADOdb
Plymouth State University uses Oracle heavily due to its Student Information System of choice - SungardHE Banner. As such, I play around in Oracle a lot (sometimes a lot more than I’d like) and I occasionally find functionality that seems more cumbersome than it should.
Once such item is selecting the last inserted value on an auto-incrementing column.
Historically, when you are inserting into a table with auto incrementing values (via a sequence) you have always been able to grab the last value with a simple SELECT statement (line 22):
SQL:-
– setup a table
-
CREATE TABLE bork (id INTEGER NOT NULL PRIMARY KEY, DATA VARCHAR2(10) NOT NULL);
-
-
– create the sequence
-
CREATE SEQUENCE sq_bork INCREMENT BY 1 START WITH 1;
-
-
– create a trigger for auto-incrementing the sequence’
-
CREATE OR REPLACE TRIGGER tr_sq_bork
-
BEFORE INSERT
-
ON bork
-
REFERENCING NEW AS NEW
-
FOR EACH ROW
-
BEGIN
-
SELECT sq_bork.NEXTVAL INTO :NEW.id FROM DUAL;
-
END;
-
/
-
-
– insert a record into the table
-
INSERT INTO bork (name) VALUES (‘Matt’);
-
-
– retrieve last inserted id
-
SELECT sq_bork.CURRVAL FROM dual;
As you see there, two statements must be executed to get that new id. The INSERT and the SELECT. Well, as of Oracle 10g you can utilize the RETURNING clause like so:
SQL:-
INSERT INTO bork (name) VALUES (‘Matt’) RETURNING id INTO i_id;
That statement inserts a record into “bork” and returns the value of “id” into the “i_id” variable. Pretty sexy and all with one DML statement. Here’s what we do at Plymouth to utilize the RETURNING clause with the PHP library ADOdb:
PHP:-
<?php
-
//do your database object initialization here:
-
//$db = new ADONewConnection…
-
-
$sql = “BEGIN INSERT INTO bork (data) VALUES (’Matt’) RETURNING id INTO :i_id; END;”;
-
$stmt = $db->PrepareSP($sql);
-
$db->OutParameter($stmt, $inserted_id, ‘i_id’);
-
$db->Execute($stmt);
-
?>
Yup. 4 lines of PHP but only 1 statement sent to the database! I’d take the extra lines any day over the latency of data retrieval.
-
- Get ready for metered bandwidth
Not since the early days of dial-up Internet have we had to worry about how much we use our Internet access, but today Internet service providers are searching for a way to make the folks who use the most bandwidth either pay up or get out!
As I wrote on InternetEvolution recently, it’s time we start treating the Internet like every other utility.
Using the utility model, an ISP could charge for the maximum bit rate available (many already offer several maximum bit rates at graduated prices), then a reasonable price for each gigabyte used. To simplify the user experience and reduce concern about overages, it makes sense to include a generous amount of leeway with the service — say, 200 Gbytes — but it will be essential to give the user a way to monitor how it’s consumed.
Ideally, enough bandwidth and storage would be included with the basic plan to more than satisfy the typical user, including allowance for downloading a reasonable amount of video and audio. (For reference, movies available on iTunes tend to run just a bit over 1 Gbyte.) With packages in the hundreds of Gbytes, the average user’s Internet experience and usage pattern is unlikely to be affected at all. But customers should not hesitate to stay up to date on their system updates and virus software.
Check out the full article and feel free to comment on Internet Evolution or here and let me know what you think!
Update: As Gary points out in a comment below, this is a very USA-centric view. I know internet rates and billing policies vary quite a bit around the world. Please leave a comment if your area already has bandwidth restrictions and let us know how it’s working out!
- Delete/Backspace Stops Working in Oracle SQLDeveloper
I a huge fan of Oracle SQL Developer but I ran into an issue a while back that left me scratching my head and re-installing. The issue? Most key strokes other than letters and numbers failed to function. Yeah…no delete or backspace.
When this issue happened a second time I did a little playing with the app and figured out what to do. If you find yourself in a similar predicament simply do this:
- Open SQL Developer
- Click on the Tools > Preferences menu
- Click on Accelerators on the left
- Click the Load Preset… button
Yup. That’s it. The only lame part about that is all your custom key bindings go away and must be re-done. But that is much nicer than re-installing!
- Google Chrome on the Mac - a la CodeWeavers
Google launched its new browser Chrome on September 2nd and the web was abuzz with talk of a new contender in the browser space. My choice to pepper my house and cube at work with Macs rather than Windows boxes left me complaining about the lack of a native Mac version of Chrome…which Google assures us is coming.
Code Weavers, however, has just released Crossover Chromium built from build 21 of the Chromium Open Source browser.
The initialization of Chromium the first time I opened it took a while but once it was up and running, things were pretty solid. The browser has all the JavaScript and DOM debugging tools but it seems the process manager tool isn’t fully functional..which is really my draw to the browser (when I get dead set on playing with the Process Manager tool, I’ll break down and install Chrome with Parallels). I suppose I’ll be following CodeWeaver’s suggestion:
Q. Should I run CrossOver Chromium as my main browser?A. Absolutely not! This is just a proof of concept, for fun, and to showcase what Wine can do. Chromium itself is just beginning. As the Chromium project progresses, they will be providing more compelling support for Mac OS and Linux, particularly with process security and memory management. Those future versions from Chromium will be better suited for daily use than this version.
Until Google launches its official Mac native Chrome, Chromium will satisfy me for now.
- 10 Good PHP Principles from Nettuts
The recent article from Nettuts.com, 10 Principles of the PHP Masters has some solid concepts that are worth reading about.
The description synopsis of the article is:
With PHP’s widespread adoption,it’s almost too easy to find a script or snippet to do exactly what you need. Unfortunately, there’s no filter as to what is a “good practice” and what’s, well… not so good when writing a PHP script. We need trustworthy sources, who have proven they have a solid grasp on the best practices of PHP.We need PHP masters to show us the best principles to follow for high-grade PHP programming.
Good stuff.
Update: This article on CSS is equally valuable - 10 Principles of the CSS Masters.
- USB Gadgets - USB bear and food
Now that USB flash drives are cheap and common producers clearly need to get creative to compete. Here are a couple great ideas for storage with a more personal touch:

Stuff this cuddly USB bear with 1GB of photos, music or documents.
I have to admit this is the first blue fortune cookie I’ve ever seen, but imagine how many fortunes you could fit in this USB fortune cookie
Also from the freshly baked line the USB Hamburger may not be a half-pound burger, but it is a 2GB drive!Of course none of these beat the USB Humping Dog but you can’t store files on that (and let’s face it, it might not quite be appropriate for that executive board meeting.)
Thanks to Don for the USB bear.
- Smart Phones & Cell Service: Prepare for Internet Everywhere
There’s a lot of buzz around smartphones right now. With falling prices and service improvements it’s becoming clear that cellular providers will beat municipal Wi-Fi in all but a few areas.
That’s the idea I explored in my recent article for Internet Evolution.
At the same time, smart phones like the iPhone have crossed over from being business tools to consumer products. Indeed, they are quickly becoming the mobile device of choice.
And why not? More than just phones with PDA functionality, these devices have now become full-fledged platforms. Web browsing, chat, email, and games are their core competencies, and applications for them are just getting more interesting from there.
Read my full article for more of my thoughts on how these new devices and services will shape our lives in the near future.
- Silverback - Usability Testing
I have always been very interested in doing serious usability testing of applications or web sites. However, it is complicated and associated software to make it easier is usually quite costly.Silverback appears to change that.
I have yet to have a chance to put it through it’s paces, but watching the video demo, this has great potential. With only a $49.95 price tag, this will be easy to justify with our next major project.
Described by Clearleft as:
Spontaneous, unobtrusive usability testing software for designers and developers.- Capture screen activity
- Video the participant’s reactions
- Record the participant’s voice
- Add chapter markers on the fly
- Control recording with the remote
- Export to Quicktime
- Oracle Shell Scripting: an “Excellent presentation”
Well, things have been busy for me (hence the break from blogging) but interest in my Oracle Shell Scripting book remains strong! Just today this (5 star) review showed up on Amazon from Srinivas Gaddam:
Excellent presentation
If you are working on Oracle products, you know problems can get complex and the internet will have million possible solutions, but if you are looking for just one that works you should own this book.Thanks a lot Srinivas! This comment hits on one of the reasons I wrote the book: to give a coherent but concise treatment of shell scripting for Oracle while giving plenty of usable scripts to get people started quickly!
- iPhone App: pTerm
At long last a Terminal application is available on the iPhone, and pTerm is its name! Based on the desktop client PuTTY, you can SSH, Telnet, and raw TCP from your iPhone/iPod Touch!Its features are:
- xterm terminal emulation
- Standard 80×24 screen
- SSH, Telnet, or “raw” TCP connections
- Ctrl key support
- Landscape and Portrait modes
- Works over Edge, 3G, or WiFi
- Stores your list of host/port/protocol for convenient access
- Terminal supports pinch and zoom
- Based on PuTTY, a stable and feature-rich code base
All in all, the app seems pretty solid. My only gripe is the lack of a tab key for tab completion. Now I’ll be able to debug stuff remotely WITHOUT using VNCLite for the iPhone. Check pTerm out, it is well worth the $4.99.
Update:
There are some more things that I find annoying:- No tab key - no tab completion…
- No arrow keys - this makes navigating around a line a little bit of a pain.
- You can’t hide the keyboard. It’d be nice to see a full screen of top.
- No color customization
Despite the annoyances, the app is still pretty solid. Lets just hope new versions come out sooner than later with some of my hopes and dreams attached.
- Teleport For Mac
For a log time I have been a reasonably happy Synergy user. However, I have also been working in a mixed Windows/OSX environment. Recently I replaced my Dell laptop with a new MacBook Pro. This opened up a new option for keyboard and mouse sharing in my environment.I have recently learned that Teleport is a far superior product for a purely mac environment. Here are a few of my favorite features:
- The setup has a great GUI that makes setup trivial.
- You can establish a certificate on each host and have all the traffic nicely encrypted between them.
- There is an option that requires you to hold a key whenever switching screens, handy if rarely used.
- There are great indicators to what computer your keyboard and mouse are currently operating.
- You can drag and drop files between machines.
- Of course it also has the same kick ass shared clipboard that Synergy had.
There are probably a ton of other options that are useful, but these are my favorites. Synergy was great, but in a purely Mac based environment, I don’t see how teleport can be beat.
- Sudoku v Sudoku for iPhone

EA Sudoku ($7.99)

Free Sudoku
I like playing sudoku. I got hooked on it with the Nintendo DS version that is included with the first Brain Age. It’s a fun and challenging puzzle game that’s great if you are seeking a few minutes of distraction.I was asked to do a review of the EA created iPhone Sudoku game. I wanted some casual games for my phone anyway, so why not?
Frankly, EA’s implementation of sudoku for the iPhone is wonderful. The graphics are polished and appealing. The game play is exactly what should be expected, with a few options to keep it interesting. Well worth the $7.99.
With everything there is room for improvement though. First, there should bs some social features to allow score sharing or puzzle sharing with friends. There were also some minor stabilty issues causing the game to crash a few times. I would hope that will be fixed I’m a future patch. Finally, I wish that I could save multiple partial puzzles. All considered, solid and enjoyable.
To adequately evaluate this, must also compare against the free sudoku iPhone app as well. Honestly, if you plan on playing sudoku for more than 15 minutes total, pay the money. The differences between these implementations is fun v frustration. Unless the free sudoku sees a major set of enhancements, do not waste your time.
- WordPress For iPhone
The WordPress iPhone application has been released. It seems to work well. It supports the following features:
- basic blogging
- tagging
- categories
- password protecting posts
- adding images from phone or camera
- local draftsA couple of significant restrictions:
- no rich text editing
-can’t add an image to a postadding an image to a post automatically puts it at the end
- no landscape mode - Ever wonder what your DBAs really do?
Ever wonder what your DBAs do when they’re not dealing with your crisis of the day? Friend and coworker Bob Watkins highlights the DBA’s main tasks in this recent article on Tech Republic.
It’s been said that the database administrator (DBA) has three basic tasks. In decreasing order of importance, they are: protect the data, protect the data, and protect the data.
Although data integrity is clearly the #1 job (who cares if the database is available or fast if the data isn’t good), the DBA has many other jobs as well. Here’s a list of the actual tasks that a DBA performs. (Some duties are common to all DBAs, and others are only required in some database environments.)
Check out the full article where Bob goes on to touch on all the major areas of the typical DBA job including backup and recovery, security, upgrades, tuning and troubleshooting. If you’re looking for a job description for a DBA this is a very good one.
- Compiling Invalid Objects in PL/SQL
While I do a lot of and prefer PHP and JavaScript development, my daily job has a darker side…PL/SQL. At times the packages that I oversee invalidate during upgrades or poor compilations of a package that ends up having a ripple effect.
Here’s a query I wrote to find the invalid objects and generate compile statements to attempt to fix whatever is busted.
SQL:-
SELECT CASE object_type
-
WHEN ‘PACKAGE’ THEN
-
‘ALTER ‘||object_type||‘ ‘||owner||‘.’||object_name||‘ COMPILE;’
-
ELSE
-
‘ALTER PACKAGE ‘||owner||‘.’||object_name||‘ COMPILE BODY;’
-
END
-
FROM dba_objects
-
WHERE STATUS = ‘INVALID’
-
AND object_type IN (‘PACKAGE’,‘PACKAGE BODY’,‘FUNCTION’,‘PROCEDURE’);
-
- Content Owners Make a Hash of Online Distribution
Why do content owners and distributors continue to make consumers jump through hoops to buy their content? Are they really protecting their content or just pushing people to illegal sources? My article Content Owners Make a Hash of Online Distribution takes a quick look at the current status of online content distribution.
Online content distribution has exploded over the past 10 years, but the entertainment industry has been slow to embrace this new means of doing business. Even now, as the music industry is finally starting to adopt the new model, they continue to apply artificial restrictions to content distribution, making it harder for people to purchase and use their content legitimately.
Check out the full article on Internet Evolution.
- List of Great Web Dev Optimization Tools
Six Revisions has a bunch of great web development tips and tricks. Today he put out 15 Tools to Help You Develop Faster Web Pages, which is a great list worth reading. In addition to the standard fare (YSlow, Firebug, etc) he also lists some good stuff I hadn’t heard of like Cuzillion and DBMonster.
- Luminis: Forcing CSS/JavaScript Updates to Clients
Contents:
Introduction
I gave a talk at SunGard Summit in Anaheim this spring on Plymouth State’s portal (myPlymouth). There were a number of really great questions that came up following my presentation, one of which is the topic of this post:
“How do you force a client’s browser to always use the correct version of CSS and/or JavaScript in Luminis?”When upgrading Plymouth State’s Luminis installation from III to IV, we had to tackle this same issue and after banging my head against the wall a number of times, I found our answer. I wanted to:
- Ensure that the JavaScript and CSS that is being served up to our users can be cached by their browser in order to optimize their download speeds.
- Control when a user’s browser has to re-download a new version of the code.
- Do the above within the bounds of the very restrictive caching provided by the Luminis product.
All of it was super easy to do, although I must admit I knocked my head against the wall a few times coming up with the solution to the 3rd in that list.
Step 1: Basic Browser Caching
When I sat down to tackle this problem, I knew that the inline JavaScript within nested_tables.xsl was an unforgiving issue - if I wanted to make a change to some of the inline JavaScript, those changes would not be forced upon the users until Luminis decided to let go of its cached nested_tables.xsl.
That didn’t work for me. So I ripped the inline styles out and combined a few JavaScript files into one…called combined.js.
My header within the regularLayout template in nested_tables.xslnow looked something like this:
HTML:-
<head …….>
-
<title>………</title>
-
<script type=“text/javascript” src=“/js/clientsniffer.js”></script>
-
<script type=“text/javascript” src=“/js/util.js”></script>
-
<script type=“text/javascript” src=“/psu/js/combined.js”></script>
-
<script type=“text/javascript” src=“/psu/js/behavior.js”></script>
-
<link rel=“stylesheet” type=“text/css” href=“/psu/style.css”/>
-
</head>
The files clientsniffer.js and util.js are SunGard delivered and I did not touch those two. As I mentioned before, I yanked out all the inline JavaScript (provided by SunGard) and dropped that into combined.js along with a number of jQuery code. Our own custom Luminis JavaScript that controls a lot of our Ajax-like functionality in myPlymouth is in behavior.js. And of course, style.css holds the CSS for our portal.
All of these files could now be cached by users’ browsers. Yay. I bounced the development portal and saw my changes in all their glory. Life was good.
Step 2: Browser Cache, Code Changes, and You
Invigorated by my recent success of effectively doing nothing, I grabbed a soda and began tackling the next objective. I had done this numerous times in my PHP applications and it was as simple as placing a version number at the end of the URLs used in the link and script tags. As such:
HTML:-
<head …….>
-
<title>………</title>
-
<script type=“text/javascript” src=“/js/clientsniffer.js”></script>
-
<script type=“text/javascript” src=“/js/util.js”></script>
-
<script type=“text/javascript” src=“/psu/js/combined.js?v=1.0.0″></script>
-
<script type=“text/javascript” src=“/psu/js/behavior.js?v=1.0.5″></script>
-
<link rel=“stylesheet” type=“text/css” href=“/psu/style.css?v=1.0.5″/>
-
</head>
Once again, I bounced our portal, saw the changes, and danced around the room. Step 2. Accomplished.
Step 3: Taming Versioning/Cache Expiration in Luminis
The goal of taming this versioning/cache expiration was to do so without the need for bouncing the portal so I could make changes on the fly without planning for down times. Step 2 - as I detailed above - only gets you so far. With Step 2 in place, I could easily make a change in my CSS file and edit nested_tables.xsl to one-up my version number. But, because nested_tables is cached by Luminis, that wasn’t good enough. Here’s what I came up with:
I removed the script and link tags in the header of the regularLayout template in nested_tables, created a file called load.js, and dropped the homeless script/link tags as document.writes in load.js…as so:
Start of a Solution: load.js
JavaScript:-
document.write(‘<script type=”text/javascript” src=”/js/clientsniffer.js”></script>’);
-
document.write(‘<script type=”text/javascript” src=”/js/util.js”></script>’);
-
document.write(‘<script type=”text/javascript” src=”/psu/js/combined.js?v=1.0.0″></script>’);
-
document.write(‘<script type=”text/javascript” src=”/psu/js/behavior.js?v=1.0.5″></script>’);
-
document.write(‘<link rel=”stylesheet” type=”text/css” href=”/psu/style.css?v=1.0.5″/>’);
But wait…
This gave me a file with all of my script/link tags and their appropriate versions. However…I couldn’t simply replace all those script/link tags with a script tag that pointed at load.js because load.js itself would be cached by users’ browsers. So this got past the Luminis caching, but not our end users. So I came up with this:
Final Solution: pre_load.js
So…I wanted to cache all my sub-files and prevent load.js from caching so that I could version my scripts easily without bouncing the portal. The solution? Yet another file! I called it pre_load.js and it looks something like this:
JavaScript:-
document.write(‘<script type=”text/javascript” src=”/psu/js/load.js?nocache=’ + (new Date()).getTime() + ‘”></script>’);
A simple document.write of a script tag with an appended variable based on time in order to prevent caching on the browser side. Yup…load.js is never cached, but it is a small price to pay.
Now my header in the regularLayout template in nested_tables.xsl looks like this:
HTML:How it works
- Luminis happily caches the pre_load.js script tag in the nested_tables.xsl.
- The JavaScript within pre_load.js writes another script tag to the document at render time. That script’s URL is a call to load.js along with a variable that changes each page load thus preventing load.js from being cached.
- load.js then document.writes the appropriately versioned script/link tags into the document.
- The individual script/link tags load the associated JavaScript/CSS files. If the browser has already cached that script/link URL (remember, we change the version numbers when we make changes to the JS or CSS), then the cached file is loaded…otherwise the new version is retrieved from the server.
Summary
The set-up is fairly basic but the results just what we were hoping! And all it took was:
- Placing inline JavaScript into a file (combined.js)
- Creating load.js to document.write script/link tags
- Creating pre_load.js to document.write a script tag that uses a cache-free URL call to load.js
To date, we have not had any reported issues with local or server-side caching of our JS/CSS files using this method! You just need to make sure you remember to version your URLs in load.js!
- Making your online presence speak for you
Recently I have been asked to become a contributor to the Internet Evolution blog. My first article there, Making Your Online Presence Speak for You discusses how things like forum contributions, an online resume and a personal website (like this one) can have act as an extension of your resume.
In a Web 2.0 era where a prospective employer is more likely to Google your name than to check your references, what is your online presence saying about you?
A surprising number of people still seem to fall into one of two categories when it comes to posting their profiles online: they either indiscriminately post everything about their lives, blissfully ignorant of how it may affect them in the future, or they avoid putting their name on anything online, blissfully ignorant of how an online presence could help them. If you fall into either of these categories it may be time for a change.
Check out the full article on www.internetevolution.com and join in the great discussion on the topic.
- Shell conditions and if statements
Since the contents of variables will, well, vary it is often useful to be able to make decisions based on them. Strings and numbers can be easily compared to explicit values or other variables. Here is a simple example:
$ i=107
$ if [ $i -gt 100 ]
> then
> echo “Wow, i got all the way up to $i”
> else
> echo “i is only up to $i”
> fi
Wow, i got all the way up to 107
$ i=22
$ if [ $i -gt 100 ]
> then
> echo “Wow, i got all the way up to $i”
> else
> echo “i is only up to $i”
> fi
i is only up to 22Here we see a simple
ifstatement. When executed the expression within the brackets is evaluated to either true or false. If the expression is found to be true the commands after the then will be executed, otherwise the commands after the else are executed.The expression shown here is the greater than expression (
>). The symbols we typically use for greater than and less than have specific significance in the UNIX shell, so to compare values we use-gtfor greater than and-ltfor less than. Comparisons can also be made between strings of text. More information about comparing text and numbers can be found in my book.
For more information like this check out my book Oracle Shell Scripting, only $34.95 from Rampant TechPress.
- Blogged.com rates Life After Coffee an 8.0!
Another nice little bit of recognition showed up in my inbox recently… Blogged.com has rated Life After Coffee an 8.0 in the category of Technology Blogs!OK, so 8.0 isn’t the greatest rating ever, but given that they take into account relevance of content (relevant to what I don’t know) and frequency of updates (there is no April) I’m pretty happy with it.
Now, if you’re interested in the best technology blogs around, check out their Technology Blog Directory. Many of the top picks are focused, professional blogs, not like the crap you’ll find here. There’s some great stuff to check out though and in general I would agree with their rankings.
- The Best Photoshop Tutorials Ever
My Damn Channel, an entertainment studio, has a series of Photoshop tutorials that are hilarious and…well…really good. I saw You Suck At Photoshop #8 via Digg and ended up watching them all. Really good stuff.
Here’s #7:





Leave a Reply
Comments should show a courteous regard for the presence of other voices in the discussion. We reserve the right to edit or delete comments that are deemed inappropriate.