<?xml version="1.0" ?>

                <rss version="2.0"
            xmlns:content="http://purl.org/rss/1.0/modules/content/"
            xmlns:wfw="http://wellformedweb.org/CommentAPI/"
            xmlns:dc="http://purl.org/dc/elements/1.1/">
        <channel>
                <title>Neptune Web Blog</title>
                <link><![CDATA[http://www.neptuneweb.com/blog/?rss=true]]></link>
                <description><![CDATA[Neptune Web Blog: 
]]></description>                <pubDate>Thu, 23 May 2013 11:44:43 -0400</pubDate>
                <language>en-US</language><item>
                         <title><![CDATA[Using Amazon CloudFront to Improve Global Web Site Performance]]></title><link>http://www.neptuneweb.com/blog/36-using-amazon-cloudfront-to-improve-global-web-site-performance.html</link><pubDate>Mon, 18 Mar 2013 00:00:00 -0400</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=36</guid>                      <description><![CDATA[Neptune recently migrated a large, multilingual, international web site to Amazon CloudFront. Charlie gives a few tips he picked up along the way.]]></description>
                 <content:encoded><![CDATA[Neptune recently migrated a large, multilingual, international web site to <a href="http://aws.amazon.com/cloudfront/" target="_blank">Amazon CloudFront</a>.<br />
<br />
It&#39;s not perfect. But <a href="http://aws.amazon.com/cloudfront/" target="_blank">Amazon CloudFront</a><a href="http://aws.amazon.com/cloudfront/" target="_blank"> </a>is a service we&#39;d definitely recommend to our clients. Here&#39;s why:<br />
<ol>
	<li>
		Improved website response time - giving a faster, slicker web experience for all users.</li>
	<li>
		Improved website response time specifically for international web users.</li>
	<li>
		Low-cost to configure compared to adding additional infrastructure.</li>
	<li>
		Allows you to keep your existing hosting infrastructure, c/o &quot;Custom Origin&quot; option.</li>
	<li>
		No need to change URLs (assuming &quot;custom domain&quot; is configured).</li>
	<li>
		Nearly unlimited &quot;bursting&quot; traffic capacity without having to setup new infrastructure.</li>
	<li>
		You retain complete control over your DNS. (A competing service, CloudFlare, requires domain control.)</li>
	<li>
		A better performing site may increase search traffic and sales.</li>
	<li>
		Minimal commitment.</li>
</ol>
Amazon CloudFront is a fairly new cloud-based service. Competitors include CloudFlare and Akamai.The service places geographically located, HTTP caches &quot;in front&quot; of your existing site, caching or proxying both static and dynamic content. CloudFront is like having an HTTP cache (examples include Squid or Varnish) in most major cities of the world. It also includes a dynamic DNS system to request users to the nearest &quot;Edge&quot; location based on their DNS resolver&#39;s IP. When requests require no caching, the request is passed (or proxied) back to the origin server.<br />
<br />
Since both static and dynamic content is served, the changes to your site are theoretically quite minimal. In reality, this depends on how dynamic and complex your site is. Here is a checklist of things that may need to change:<br />
<br />
<strong>1. POST data cannot be passed through CloudFront.</strong><br />
<br />
This is probably the most difficult one. If  you have forms that require POST (and can&#39;t be easily converted to GET), I recommend setting up a new domain name for your site where forms can be posted. If your original site was &quot;www.acme.com&quot;, you&#39;ll need to set up a new domain such as &quot;origin.acme.com&quot; (this can be any domain you choose, such as &quot;secure.acme.com&quot;, &quot;post.acme.com&quot; etc.). You&#39;ll need to change all form actions to POST to this URL or update links to forms to go to the origin site. Once the form is complete, I recommend redirecting the user back to the www site to make use of CloudFront.<br />
<br />
<strong>2. You&#39;ll need to change your domain name for your SSL site.</strong><br />
<br />
Another tough one. If you were hosting https://www.acme.com, you will need to purchase a new certificate to https://origin.acme.com. You can host your SSL content at https://d1dkq6joi5aul.cloudfront.net (the distribution URL), but you probably don&#39;t want a URL which looks like that. Don&#39;t forget that https://www.acme.com links may be linked all over the Internet in the form of external blog links and comments.<br />
<br />
DNS for http:// and https:// can only point to once location. Once you make the switch - https://www.acme.com will print out a nasty &quot;This Connection is Untrusted&quot; for all users if you have not completely disabled it.<br />
<br />
<strong>3. You&#39;ll need to carefully modify the HTTP cache-control, Expires and Last-Modified headers on your existing pages. </strong><br />
<br />
When I first started researching CloudFront, I was under the impression that setting the TTL within the &quot;Behaviors&quot; would mean I didn&#39;t have to modify  headers on my site. This is <strong>not </strong>the case. You need to become an expert on these 3 headers and gain complete control over what your existing pages use. I found the TTLs that Amazon provides to be fairly useless. I was a bit disappointed that I can&#39;t use the simple web interface to adjust caching reactively during high-traffic times. I have to make a programming change to do this.<br />
<br />
First of all, you&#39;ll want to give all static content a far-future expires header. e.g. I typically do this in a global Apache rule.<br />
<pre>
# force caching for more speed of static content
&lt;FilesMatch &quot;\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$&quot;&gt;
Header set Expires &quot;Thu, 15 Apr 2020 20:00:00 GMT&quot;
&lt;/FilesMatch&gt;</pre>
That&#39;s easy. Pages are more difficult.<br />
<br />
(This example uses PHP. Other platforms will be similar.)<br />
<br />
First, I added an included file at the top of all pages. <br />
<br />
<img alt="" src="http://www.neptuneweb.com/blog/cloudfront_include.png" style="width: 807px; height: 82px;" /><br />
<br />
For pages I wanted to cache for only a few minutes, I include cache-control.php as below. Notice that I only modify the caching if the User Agent is Amazon CloudFront. This ensures that my existing site doesn&#39;t break.<br />
<br />
<img alt="" src="http://www.neptuneweb.com/blog/cloudfront_include2.png" style="width: 686px; height: 175px;" /><br />
<br />
For pages that I never want to cache, I call session_start() in my PHP. Most of my dynamic pages happen to do this anyway, and this gives me the default Expires and cache-control headers which prevent all caching. Of course, these headers can be set using &quot;header()&quot; if you don&#39;t need the overhead of session_start().<br />
<br />
On a page which should never cache, CloudFront gets the following headers:<br />
<pre>
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0</pre>
You&#39;ll always see a &quot;<code class="focusRow subFocusRow " role="listitem">Miss from cloudfront</code>&quot; in the &quot;X-Cache&quot; header of these hits.<br />
<br />
On a page which should cache for maximum of 120 seconds, CloudFront receives these headers:<br />
<pre>
Expires: Sun, 24 Mar 2013 02:48:30 GMT
Cache-Control: public, max-age=120
Last-Modified: Sun, 24 Mar 2013 02:46:30 GMT</pre>
<p>
	I can then test my headers using wget, using the options -S (show headers) and --header (set user-agent). e.g.<br />
	<br />
	wget -S http://www.acme.com --header=&quot;User-Agent: Amazon CloudFront&quot; <br />
	<br />
	I highly recommend starting out with very limited caching of your page. You don&#39;t want to deploy this; feel like a hero because your site is faster; and then slowly watch the bugs start coming in as you start desparately rolling back caching. These bugs are hard to track down because no one notices them at first.<br />
	<br />
	<strong>4. </strong> <strong>IP addresses and User Agents will no longer be present to your site and will not be found in logs.</strong></p>
<p>
	All user agent strings will come in as &quot;Amazon CloudFront&quot;. IP addresses will not be your user&#39;s IP addresses. This  may require programming changes if your content is location based.<br />
	<br />
	Log based web statistics will no longer be accurate. You should expect these statistics to change dramatically anyway since so much traffic is off of your server.<br />
	<br />
	<strong>5. If you set up an additional domain, such as origin.acme.com, you&#39;ll need to track sessions across sub-domains.</strong><br />
	<br />
	This is easy in PHP.</p>
<pre>
# for cloudfront integration and use of origin.acme.com
php_value session.cookie_domain acme.com
</pre>
<p>
	<strong>6. If you set up an additional domain, you&#39;ll need to make sure Google analytics tracks both sub-domains as one.</strong></p>
<p>
	<span>Just use:</span></p>
<pre id="line1">
<span>_gaq.push([&#39;_setDomainName&#39;, &#39;acme.com&#39;]);</span>
</pre>
<p>
	<br />
	<strong>7. Social Media sharing links may need to be configured differently if a second domain is used.<br />
	8. You will need to make DNS changes. </strong><br />
	<br />
	Simply CNAME your domain to the distribution domain provided by Amazon.<br />
	<br />
	<strong>9.</strong> <strong>Canonical redirects (www.) redirects will not work through CloudFront. </strong><br />
	<br />
	For SEO purposes, the &quot;base domain&quot; e.g. &quot;acme.com&quot; usually is 301 redirected to the www. domain. My approach was to use www. site for CloudFront, but leave the &quot;acme.com&quot; site at the origin IP. When users access &quot;acme.com&quot; they are redirected back to www.acme.com by the origin server.<br />
	 </p>
<hr />
<h2>
	Troubleshooting</h2>
You will inevitably find yourself troubleshooting to figure out why something did or did not cache. Here are some tips.<br />
<br />
<strong>1. Age header.</strong><br />
<br />
Watch the headers from responses in Firefox Firebug or Chrome Network view. The &quot;Age&quot; header will tell you how old the content is.<br />
<br />
<strong>2. X-Cache header.</strong><br />
<br />
Will tell you whether CloudFront hit or missed the cache.<br />
<br />
<strong>3. Amazon support provided this tip. Trace-routing CloudFront domain first. </strong><br />
<pre>
traceroute d1dkq56j3333dl.cloudfront.net
</pre>
<p>
	This allows you to identify the major geographic location your content will be fetched from. For example, the traceroute shows this request is going to the France data center (d1dkq56joi5aul.fra6.cloudfront.net).</p>
<p>
	Next, use curl with Host option  to see what is returned from that edge location.</p>
<pre>
curl -I -H &quot;Host: d1dkq56j3333dl.cloudfront.net&quot; <a class="external free" href="http://d1dkq56joi5aul.fra6.cloudfront.net/it" rel="nofollow">http://d1dkq56joi5aul.fra6.cloudfront.net/services</a>/index.html
</pre>
<strong> </strong><strong>4. Develop a script you can host in multiple geographical locations, which fetches URLs from edge locations it finds. </strong><br />
<br />
I&#39;ve included the version we used - <a href="/blog/remote_test_cloudfront.php.zip">remote_test_cloudfront.php</a> (zip, GNU licensed). This script can be invaluable when testing a site as seen from multiple locations.<br />
<br />
<hr />
<h2>
	Peeves</h2>
Here are a few issues I found with CloudFront.<br />
<p>
	1. When invalidating content - &quot;/&quot; is not the same as /index.html - even if you specify your &quot;Default Root Object&quot; to be &quot;index.html&quot; with Distribution settings.<br />
	2. Documentation is thin and not that clearly written.<br />
	3. Configuration options are very basic.<br />
	4. No ability to accurately change length of caching via CloudFront interface - requires technical changes to headers in site.<br />
	<br />
	Yet, despite the &quot;peeves&quot;, this is a really useful service.<br />
	<br />
	Best of luck with your CloudFront migration. As always let us know if you&#39;d like us to assist.<br />
	 </p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[How Web Developers can Build Apps in HTML5 (and natively on Android )]]></title><link>http://www.neptuneweb.com/blog/35-how-web-developers-can-build-apps-in-html5-and-natively-on-android-.html</link><pubDate>Tue, 20 Sep 2011 00:00:00 -0400</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=35</guid>                      <description><![CDATA[In June,  Neptune Web  launched a new version of T-on-Time, the web app which takes advantage of MassDot’s new real-time data feed for the commuter rail. This article describes some of the techniques used in that app, and explains how to get rolling your own apps using web technologies you already know.]]></description>
                 <content:encoded><![CDATA[<p>
	<script language="javascript" type="text/javascript" src="/scripts/jquery.js"></script><script language="javascript" type="text/javascript" src="/scripts/thickbox-compressed.js"></script></p>
<link href="/styles/thickbox.css" media="screen" rel="stylesheet" type="text/css" />
<a class="thickbox" href="/blog/android_app/tontime-mobile.png"><img alt="T-on-Time Android" src="http://www.neptuneweb.com/blog/android_app/tontime-mobile.png" style="width: 140px; float: right;" /></a>
<p>
	In June,  Neptune Web  launched a new version of <a href="http://www.t-on-time.com/tontime.html" target="_blank">T-on-Time</a>, the web app which takes advantage of MassDot&rsquo;s new real-time data feed for the commuter rail. I&rsquo;m proud to say we were the first app to do this, since we released the app within a matter of days after the feed was announced.*</p>
<div>
	*Contrary to &ldquo;apps have already been released&rdquo; in the press releases, it did not take 2 days to develop this app. We participated in an open, MassDOT, trial feed. The actual app and its constituent parts took months to develop and test.</div>
<p>
	 </p>
<p>
	<a href="http://www.neptuneweb.com/blog/discuss/7-why-i-like-adobe-air.html" target="_blank">In a previous post</a>, I had talked about the Desktop version of T-on-Time, developed in Adobe Air &ndash; a platform which I still feel has great promise. T-on-Time Desktop was a contest entry, done mostly on &ldquo;personal time&rdquo;, and was more of an amateur (as in &ldquo;not full time&rdquo; - not as in &ldquo;rookie&rdquo;) effort.</p>
<p>
	The new T-on-Time &ldquo;Suite&rdquo; was a corporate effort, and was much more complete in its approach. </p>
<p>
	In this version, the addition was the mobile version. However, to retain the value of the original Adobe AIR Desktop version, we combined Desktop with mobile to create a &ldquo;suite&rdquo; of commuter tools. The entire &ldquo;Suite&rdquo; now consists of:</p>
<ul>
	<li>
		The original desktop version re-branded as part of the suite</li>
	<li>
		An HTML5/web/mobile app, sized to fit hand-held devices</li>
	<li>
		Android native app</li>
	<li>
		Android store presence</li>
	<li>
		<a href="http://www.t-on-time.com">A web site to tie both Desktop and Mobile version together.</a></li>
</ul>
<p>
	For web developers, it should be noted that each of these pieces can take a lot of time, and can affect the cost of your project. For example, one would think that developing an Android app code, you automatically get Android store presence. However, you still need to market your app within the store. Developing the images, copy and configuring your account within Google store are fairly time-consuming tasks. Developing that 3-4 page &ldquo;app&rdquo; marketing web site can be misleadingly time consuming. Although &ldquo;app sites&rdquo; are more or less templatized, coming up with something everyone agrees on is another story entirely.  If you take this approach, be sure to add that time into your estimates.</p>
<p>
	That covers the background. Why did we decide to cover HTML5/web , followed by Android native, first? Why not cover iPhone or Blackberry?</p>
<p>
	As I mentioned in my previous posts, I have focused on technology web developers are familiar with first. Learning Objective C and XCode  gets web developers (who are familiar with Javascript/HTML/CSS and web server-side languages such as PHP or ASP.NET) way overextended. This is a big problem with the iPhone platform for me. Blackberry poses the same problem. Although Android has a similar environment, I find it much more open than xCode/iPhone, using the Java language, and with a faster growth projection.</p>
<p>
	HTML/JavaScript is really the &ldquo;first&rdquo; platform for web developers. I hope someday the Android market and iPhone store become mere marketing vehicles for people to find your apps - no longer the only way to deliver your app. I&rsquo;m sure Google and Apple don&rsquo;t feel the same way.</p>
<p>
	Anyway, here&rsquo;s how the HTML5/Android app works.</p>
<ol>
	<li>
		First, develop for HTML5/web only, developed in the browser. You can use all the familiar tools. Firebug or Chrome debugger. No need to compile or run a (very slow) emulator. Just reload your page to see your changes using local HTML/CSS and JavaScript. (See note below about disabling cross domain restrictions for local code).</li>
	<li>
		Build an Android &ldquo;shell&rdquo; to hold the HTML5 app, using WebView classes.</li>
	<li>
		Convert your data storage to use native Android. Use the JavaScript integration to make functions available to conscript, which call native Android features.</li>
	<li>
		Load your local content, containing Javascript and even jQuery, found in the /assets/ folder like this webview.loadUrl(&quot;file:///android_asset/tontime.html&quot;);</li>
	<li>
		Possibly build an iPhone shell</li>
	<li>
		Share code with web version and &ldquo;assets&rdquo; folder of Android app</li>
</ol>
<p>
	A sample <a href="/blog/android_app/sample_android_shell.zip" target="_blank">Android resource, src and Manifest.xml</a> (Zip Format) to get you started with your Android version is included here.</p>
<p>
	A few things worth mentioning:</p>
<ol>
	<li>
		Never rely on the Internet unless you really need it. For example, don&rsquo;t use cookies just because they are familiar to you. If you just need a place to store data, use local storage instead.</li>
	<li>
		When testing your app in the browser, you can avoid XSS/Ajax cross-domain limitations by testing in Chrome like this:</li>
</ol>
<p>
	 </p>
<pre>
C:\Users\me\AppData\Local\Google\Chrome\Application\chrome.exe --allow-file-access-from-files --disable-web-security
                Be sure to run as Administrator on windows.</pre>
<ol>
	<li value="3">
		Repeated downloads of XML content from the Internet can make your Android cache HUGE, and I found no way to reduce size of the Android cache (there were examples for Android 2.2, it&rsquo;s just that none worked). I chose to clear the cache myself, by calling a Javascript interface function periodically e.g.</li>
</ol>
<pre>
                public void clearcache() {
                                // trick to keep cache from getting huge since turning if off doesn&#39;t work.
                                Activity t;
                                t = (Activity) mContext;
                                WebView wv = ((tontime) mContext).getWebView();
                                wv.clearCache(true);
                }</pre>
<ol>
	<li value="4">
		When using the Javascript Interface, be sure to check the values returned from Android functions. Type mismatches between conscript and native functions cause very difficult-to-troubleshoot bugs.</li>
</ol>
<p>
	This type of development can also be achieved using frameworks. However, don&#39;t forget there is a huge hidden cost to using frameworks. The costs are a) steep learning curve for you (and others. Never forget the others who will maintain your code after you) b) lack of ability to troubleshoot deep technical problems due to the layer between which hides things from you.</p>
<p>
	Well gotta run (to catch a train). Best of luck with your Android/HTML5 apps!</p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[Batch Find and Replace for the Neptune Web Edit CMS]]></title><link>http://www.neptuneweb.com/blog/34-batch-find-and-replace-for-the-neptune-web-edit-cms.html</link><pubDate>Fri, 03 Jun 2011 00:00:00 -0400</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=34</guid>                      <description><![CDATA[Neptune Web's content management system, Neptune Web Edit (TM), has both free-form static content and dynamic content built into the design. However, static content can leave redundant copies of content if it was not structured properly to begin with, or if requirements of the site change. This is where Batch Find and Replace comes in...]]></description>
                 <content:encoded><![CDATA[<script language="javascript" type="text/javascript" src="/scripts/jquery.js"></script><script language="javascript" type="text/javascript" src="/scripts/thickbox-compressed.js"></script>
<link href="/styles/thickbox.css" media="screen" rel="stylesheet" type="text/css" />
<p>
	I&#39;d like to introduce the recently launched, &quot;Batch Find and Replace&quot; feature, for Neptune Web Edit CMS. <br />
	<br />
	This feature was designed to:<br />
	<br />
	1. Make changes to a large number of static files by performing repeated &quot;Find and Replace&quot; matches within the CMS.<br />
	2. Quickly <strong>scan </strong>files throughout the CMS using a keyword string or file-path match. This allows an initial set of files or &quot;batch&quot; to be created, which could later be used for subsequent matches.<br />
	3. Add <strong>more</strong> search/replace matches until all files in the &quot;match criteria&quot; are matched.<br />
	4. Use <strong>regular expressions, reverse file, back reference interpolation</strong>. See &quot;<a href="http://www.neptuneweb.com/find_and_replace.html" target="_blank">Better Find and Replace on HTML Content</a>&quot; for an explanation of these options.<br />
	5. Preview possible matched differences until the <strong>last minute before actual changes are made</strong>.<br />
	6. If changes were made, the ability to <strong>roll back </strong>the changes.</p>
<h3>
	Start by Finding Files for a &quot;Batch&quot;</h3>
<p>
	The Batch Replace feature is found under the &quot;TOOLS&quot; link in the top frame. Next, click &quot;Site Search/Batch Find and Replace&quot;.<br />
	<br />
	This initial search screen is where you perform a &quot;scan&quot; of all files for the text you want. You can also choose &quot;.html&quot; or &quot;.asp&quot; to identify the types of files you want to include in the batch. &quot;Files, Directories and Extensions&quot; allow you to include or exclude folders such as &quot;/includes/&quot; or &quot;.cfm&quot; or pages which contain the text &quot;/oldfile/badlink.html&quot; in them (the latter example is for fixing broken links or renaming pages or folders).<br />
	<br />
	Please note that &quot;Include&quot; and &quot;Exclude&quot; are based on substring pattern matches against both file name and folder name. Keywords are also a direct substring of the source code of the documents - this is not a keyword search like &quot;Google&quot;, for example. It&#39;s behavior is more like the UNIX utility, &quot;grep&quot;.<br />
	<br />
	Multiple lines can be entered in both &quot;Include&quot; and &quot;Exclude&quot; boxes.</p>
<p style="text-align: center;">
	<a class="thickbox" href="/blog/batchfindandreplace/searchscreen.png" title="Find and Replace Initial Search Screen. Use this screen to perform an initial scan for files to be replaced."><img alt="Find and Replace Initial Search Screen" src="http://www.neptuneweb.com/blog/batchfindandreplace/searchscreen-thumb.png" style="width: 425px; height: 178px; " /></a></p>
<p>
	Once you have the files you want to match, enter a title and click &quot;create batch&quot;. This will create the batch and save the filenames with the batch. Since this is an initial scan, you will be able to remove individual files from the batch later on.</p>
<h3>
	Backup and Checking File Consistency</h3>
<p>
	Now that you have a &quot;batch&quot;, your next step should be to backup and check the consistency of the files. Both steps are optional. We recommended you do both.</p>
<p>
	Backing up is simple. Just click &quot;Backup Files&quot; and a zip file will be generated containing all files in the batch.</p>
<p>
	The consistency check goes through all files in the batch, and reports on any problems which might occur when saving the files. You&#39;ll want to make sure that the replacement works on all files, so that you don&#39;t have errors saving some files in a very large batch. This can be difficult to sort out afterwards.</p>
<p>
	Why would the files not be consistent? The most common reason is that files have already been modified within the CMS, and could be overwritten by the batch replace. This could be because you weren&#39;t aware some other person was working on the site. If the changes were made by another user, you might have to notify them that you are planning to make changes to their pages. If you are sure the person is finished making changes, click &quot;Publish&quot;, check the files reported with problem (you may have to write the file names down) and either click &quot;Check in&quot; or &quot;Publish Selected&quot;.<br />
	<br />
	Less frequently, files can become &quot;inconsistent&quot; because file permissions or corruptions can occur in particular files during site development or installation of the CMS. These problems cannot be fixed through the CMS, and you will need to contact the <a mailto="support@neptuneweb.com">support staff</a> to resolve them.</p>
<h3>
	Replacing Text within Files</h3>
<p>
	Now that you have a batch and a backup and you know the files are &quot;consistent&quot;, it&#39;s time to perform the final replacement. Click &quot;Replace Text&quot; to begin. The screen (shown below) will appear. At the top of the page, the &quot;Old&quot; and &quot;New&quot; text boxes are where you place the old text (matched) with the new text (replace). You can do up to 10 replacements at once, by clicking the &quot;more&quot; button to reveal additional boxes.</p>
<p>
	The idea of this screen is simple. Paste in the text you want to match. Paste in the text you want to replace. (This can include HTML content, urls, or include files.) Click &quot;Verify&quot; to see how many pages have matches and how the replacement will affect your pages. Use the &quot;Diff&quot; button to see the differences your change will make (prior to actually making the changes.). Click &quot;Finalize&quot; to complete the changes.</p>
<p style="text-align: center;">
	<a class="thickbox" href="/blog/batchfindandreplace/findandreplace2.png" title="Find and Replace Screen. Use this screen to finalize your search and replace."><img alt="Find and Replace Replace Text Screen" src="http://www.neptuneweb.com/blog/batchfindandreplace/findandreplace2-thumb.png" style="width: 425px; height: 173px;" /></a></p>
<p>
	 </p>
<p>
	A few notes:</p>
<ol>
	<li>
		Only pages which actually have changes will be changed. In this way, you can use &quot;Publish&quot; to undo all changes made in that match.</li>
	<li>
		Matches are &quot;whitespace&quot; insensitive by default, that is a match will be found if you put in two spaces but your file only has one. We designed it this way because HTML doesn&#39;t care about spaces.</li>
</ol>
<p>
	Things get more complicated when you start using options. Each replacement has options associated with it. These include &quot;isregexp&quot; (is regular expression), reverse file (reverse the file during matching, and then reverse it back), case sensitive (turn on case sensitivity), interpolation (replace back substitutions with $1, $2, $3 etc.) If you are unsure of how these work, see the article &quot;<a href="http://www.neptuneweb.com/find_and_replace.html" target="_blank">Better Find and Replace on HTML Content</a>&quot;.<br />
	<br />
	We&#39;ll be rolling out this feature to our clients in the next few months. Once it&#39;s installed, you can modify title tags en-masse, update footers, or restructure your page entirely when you have static content. I hope you can make use of this feature. As always <a href="mailto:support@neptuneweb.com">let us know</a> if you are having problems with your installation.<br />
	 </p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[SEO Module Launched]]></title><link>http://www.neptuneweb.com/blog/33-seo-module-launched.html</link><pubDate>Tue, 24 May 2011 00:00:00 -0400</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=33</guid>                      <description><![CDATA[One of the challenges we face at Neptune Web when optimizing a site is collecting and keeping track of the myriad of reports and integrity checks we perform.  Our process involves more than just keyword positioning and page optimization.  We also validate a number of on-site and off-site metrics and even review the user interface to insure a complete optimization, not just tweaking what search engines see.]]></description>
                 <content:encoded><![CDATA[<script language="javascript" type="text/javascript" src="/scripts/jquery.js"></script><script language="javascript" type="text/javascript" src="/scripts/thickbox-compressed.js"></script>
<link href="/styles/thickbox.css" media="screen" rel="stylesheet" type="text/css" />
<h2>
	Introduction</h2>
<p>
	Here at Neptune Web, our SEO process starts with a strategic analysis of a website to determine areas that need improvement. After creating a strategy for enhancement, we make changes that range from superficial (such as changing a page title) to fundamental (such as changing the information architecture of an entire site). <br />
	<br />
	During this process, one of the challenges we face is collecting and keeping track of the myriad of reports and integrity checks we perform - because the process involves more than just keyword positioning and page optimization. We validate a number of on-site and off-site metrics and even review the user interface to insure a complete optimization. Recently, we launched an SEO module to help our clients understand our SEO process and ensure that they can continue the success of their SEO campaigns after our changes have launched.<br />
	 </p>
<h2>
	SEO Module for Neptune Web Edit&trade;</h2>
<p>
	The SEO Module is an easy add-on for Neptune Web Edit users.  The module automatically scans and updates site metrics using a variety of algorithms and bots. If it cannot automatically update a specific metric or item, the module calculates the length of time since the last manual update and flags stale items for review.  Items are grouped into similar categories, which helps users focus additional traffic-driving efforts on specific categories and areas of the site.  Additionally, the module continually tracks and graphs keyword positions for the organization, as well as their competitors, making it simple to keep an eye on many keywords with a few clicks.</p>
<h2>
	Checklists</h2>
<p>
	The best way to keep things organized is with a checklist.  Our SEO module offers a comprehensive checklist &ndash; first, tasks are organized into logical groupings and then a computer automatically scans these tasks for completeness, while simultaneously marking items that need attention. The checklists are laid out to help make the process less overwhelming and this enables the site adminstrator&#39;s work to be very focused and prioritized as they work within the module. By suggesting small pieces of work, the module allows users can chip away at the list of tasks piece by piece. Ultimately, they are able to invest time into a process that will continue to reap rewards as more items are marked complete.</p>
<p style="text-align: center;">
	<a class="thickbox" href="/blog/seomodule/checklist.jpg" title="SEO Module checklist, general section."><img alt="SEO Module checklist, general section." src="http://www.neptuneweb.com/blog/seomodule/checklist-thumb.jpg" style="width: 430px; height: 196px;" /></a></p>
<h2>
	Keyword Position and Competition Graphing</h2>
<p>
	The keyword position tracker and competition monitoring is my favorite feature. Users can monitor positions of specific keywords and identify keywords for which improvements can be made. Best of all, if users find that a new competitor has suddenly pushed down their rankings, they can add the competitor and get a back-populated graph showing when this new site entered the rankings and how they have moved historically (back to the initial keyword addition date). Users can focus on specific keyword optimizations and see daily position movements, enabling them to make and monitor slight tweaks to the site. With this feedback it is easier than ever to fine-tune optimizations.</p>
<p style="text-align: center;">
	<a class="thickbox" href="/blog/seomodule/position_graph.jpg" title="Keyword position and competition graph"><img alt="Keyword position and competition graph" src="http://www.neptuneweb.com/blog/seomodule/position_graph-thumb.jpg" style="width: 430px; height: 239px;" /></a></p>
<h2>
	Document Organization</h2>
<p>
	Over the course of the SEO consultation process, we generate several documents to compliment the SEO process. In the past, we would review these documents back and forth with our clients via email. The Documents section in our SEO module allows all reports to be uploaded to a single spot and downloaded whenever they are needed. No more sifting through emails or having multiple copies of spreadsheets saved all over your computer. The master copies of all reports are now kept in a single location that is easy to browse and access.</p>
<p style="text-align: center;">
	<a class="thickbox" href="/blog/seomodule/documents.jpg" title="Documents section of SEO module"><img alt="Documents section of SEO module" src="http://www.neptuneweb.com/blog/seomodule/documents-thumb.jpg" style="width: 430px; height: 72px;" /></a></p>
<h2>
	SEO Consultation</h2>
<p>
	One of the sections in the checklist is an &quot;Initial SEO Consultation&quot;.  We help by kicking off the process and laying down a solid foundation.  We review the site for current traffic, any crawling errors, and then we explore potential keywords with clients to help them focus their content and SEO plan.  As we finish steps, we mark them as completed in the checklist so users can see where we are in the process and what&#39;s yet to come.  Any reports created by Neptune Web are uploaded into the Documents section and can be retrieved at any time for review.</p>
<p style="text-align: center;">
	<a class="thickbox" href="/blog/seomodule/consultation.jpg" title="SEO Module consultation checklist section."><img alt="SEO Module consultation checklist section" src="http://www.neptuneweb.com/blog/seomodule/consultation-thumb.jpg" style="width: 430px; height: 185px;" /></a></p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[Add Extensive Video Capabilities to Your Site - for Free!]]></title><link>http://www.neptuneweb.com/blog/32-add-extensive-video-capabilities-to-your-site---for-free.html</link><pubDate>Tue, 17 May 2011 00:00:00 -0400</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=32</guid>                      <description><![CDATA[YouTube is an excellent, free tool for giving your site video capabilities.  Its administrative interface is a snap to use and standard features making uploading, hosting and presenting videos a very simple process.]]></description>
                 <content:encoded><![CDATA[<p>
	Videos are excellent marketing tools when used on a website -- they help demonstrate a product or service, engage site visitors and encourage them to stay on your site longer, and depending on the subject matter and popularity, help increase SEO. </p>
<p>
	Implementation of multiple videos on a single page, on the other hand, is not as easy as listing out benefits in text: considerations for video formatting, hosting/serving and actual coding all need to be made.  Most FCK/CK-style editors that are packaged with CMS solutions like Joomla, Drupal or Wordpress do not make it easy for pin-point placement of video, or ideal formatting/styling of how videos are presented.  Adding videos into a coherent, compact player (instead of stacking videos one on top of another) usually means custom development.</p>
<p>
	In this article we&#39;ll provide steps how YouTube can quickly provide both hosting and front-end solutions to presenting videos on your site.  Best of all, YouTube is free and you have the choice to make your videos ad-free.</p>
<h2>
	Video size and shape matter</h2>
<p>
	A video&#39;s size and quality will determine its filesize -- depending on your hosting package, videos on your site may be a pricey proposition.  Most lower-end hosting solutions allow  terrabyte-level or unlimited file transfer -- meaning you do not need to worry about the amount of data coming from your hosted site to a visitor&#39;s browser -- but still maintain low storage limits that might only allow for five to six high quality videos.  Moving from a lower-level hosting solution to mid-or-high level can often increase your hosting costs 50 or 100%. </p>
<p>
	One way to increase your storage space for video is to go with a dedicated video hosting provider like Rackspace or Brightcove.  One large drawback with this method is the technical nature of getting videos to their host and technical know-how needed for actual video delivery to the user.  There is also a cost associated with these services.  One large benefit to all the above-mentioned solutions is that you have total control over the size, quality and length of your videos. </p>
<h2>
	Let YouTube do all the heavy lifting</h2>
<p>
	YouTube (as of this writing) has no limits to the number of hosted videos you can have. Currently there is a 15-minute video length limit, however users in &quot;Good Standing&quot; will soon be allowed to upload clips longer than 15 minutes (<a href="http://youtube-global.blogspot.com/2010/12/up-up-and-away-long-videos-for-more.html">http://youtube-global.blogspot.com/2010/12/up-up-and-away-long-videos-for-more.html</a>).  On a fast Internet connection, videos will load fairly quickly. YouTube &quot;streams&quot; videos, which means that as soon as enough video has loaded into your browser, it will begin to play, even though downloading has not yet completed.  YouTube also accepts several video formats and will process your files to fit in a variety of player sizes and shapes.</p>
<h2>
	Embed Playlists - Not Just Single Videos</h2>
<p>
	The trend in page design/IA is to layer information - why present a page that is 2 screens tall when you can make use of hidden content areas such as in-page scrolling or tabbed-content?  This approach de-clutters a page&#39;s layout while reducing the visitor&#39;s need to scroll for information.  The same approach is often taken with videos -- you will not often find a video player that does not include a playlist or some way for a user to watch multiple videos from a single screen, rather than going from page-to-page.  Any logged in YouTube user can create a playlist, either from videos they are browsing or videos they&#39;ve uploaded.  One nice feature of embedded YouTube playlists is that updates to the playlist you make on YouTube are automatically reflected in any embedded player.  There is no need to do any manual updating of code you are embedding. </p>
<h2>
	Options to make your YouTube videos less &quot;YouTube-y&quot;</h2>
<p>
	A typical user experience on a YouTube video page is an auto-playing video, active commenting section, related videos section, and even more related videos displayed once the video is finished player.  Embedding a video directly on your site pages eliminates all the extra information surrounding the media and allows users to focus on just what&#39;s happening within the video&#39;s frame.  YouTube even provides embedding options to allow/disallow the autoplay feature as well as the releated videos at the end of the clip, replacing them with a simple, large &quot;Replay&quot; button.  YouTube will often display adds over playing videos -- this is the owner of the video&#39;s choice, so if you are the owner of any uploaded clips, you can turn this on or off.</p>
<p>
	If your goal is to provide video content with a minimal amount of programming or technical effort, YouTube is an ideal solution.  Services such as Vimeo provide similar solutions, for a fee, with additional user-controled options available.</p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[Problems with Order Reporting in Magento]]></title><link>http://www.neptuneweb.com/blog/31-problems-with-order-reporting-in-magento.html</link><pubDate>Tue, 22 Mar 2011 00:00:00 -0400</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=31</guid>                      <description><![CDATA[We've identified a possible bug in Magento Enterprise 1.8 which is causing the order report to become inaccurate under certain conditions after performing the last day refresh. The issue is causing orders not to be included in the report.]]></description>
                 <content:encoded><![CDATA[We&#39;ve identified a possible bug in Magento Enterprise 1.8 which is causing the order report to become inaccurate under certain conditions after performing the last day refresh. The issue is causing orders not to be included in the report if the order was created within the requested date range and updated after the selected end date. Here are our findings regarding the issue.<br />
<br />
The order report with the &quot;Match Period To&quot; filter set to &quot;Order Created Date&quot; is generated using the sales_order_aggregated_created database table.<br />
<br />
This table is populated when a Refresh Statistics action is performed, either Last Day or Lifetime refresh. The refreshLifetime and refreshRecent actions are defined here:<br />
<br />
/app/code/core/Mage/Adminhtml/controllers/Report/StatisticsController.php<br />
<br />
The aggregate() function (that reads the main order table sales_flat_order) used by the refresh actions is here:<br />
<br />
/app/code/core/Mage/Sales/Model/Mysql4/Report/Order.php<br />
<br />
By analyzing the aggregate() function you can see that for a last day refresh it&#39;s deleting some table rows using the _clearTableByDateRange() function found here:<br />
<br />
/app/code/core/Mage/Reports/Model/Mysql4/Report/Abstract.php<br />
<br />
The condition for what is deleted and recreated is coming from the _getTableDateRangeSelect() function. However, if you look at the parameters and the sql query it creates it seems that the deleted rows depend on the updated_at column in the sales_flat_order table. So it seems that the last day refresh action is refreshing orders updated within the last day as opposed to created within the last day. Since this refreshRecent action is invoked periodically by cron it means that the order report is constantly wrong and only correct after the lifetime refresh.<br />
<br />
The workaround is to disable using the last day refresh. The refresh can be invoked from cron or from the admin interface.<br />
<br />
For cron we change it to invoke the lifetime refresh instead. This is done by changing the file /app/code/core/Mage/Sales/Model/Observer.php.<br />
<br />
In the function aggregateSalesReportOrderData() we need to change:<br />
<br />
    public function aggregateSalesReportOrderData($schedule)<br />
    {<br />
        Mage::app()-&gt;getLocale()-&gt;emulate(0);<br />
        $currentDate = Mage::app()-&gt;getLocale()-&gt;date();<br />
        $date = $currentDate-&gt;subHour(25);<br />
        Mage::getResourceModel(&#39;sales/report_order&#39;)-&gt;aggregate($date);<br />
        Mage::app()-&gt;getLocale()-&gt;revert();<br />
        return $this;<br />
    }<br />
<br />
to:<br />
<br />
    public function aggregateSalesReportOrderData($schedule)<br />
    {<br />
        Mage::app()-&gt;getLocale()-&gt;emulate(0);<br />
        $currentDate = Mage::app()-&gt;getLocale()-&gt;date();<br />
#        $date = $currentDate-&gt;subHour(25);<br />
$date = null;<br />
        Mage::getResourceModel(&#39;sales/report_order&#39;)-&gt;aggregate($date);<br />
        Mage::app()-&gt;getLocale()-&gt;revert();<br />
        return $this;<br />
    }<br />
<br />
<br />
To disable invoking it from the web interface we add this to .htaccess:<br />
<br />
# block access to refreshing recent statistics<br />
RewriteEngine on<br />
RewriteRule index.php/admin/report_sales/refreshRecent/ /magento-bug.html [R,L]<br />
RewriteRule index.php/admin/report_statistics/refreshRecent/ /magento-bug.html [R,L]<br />
<br />
And create a file magento-bug.html that will be shown when user tries to refresh last day statistics. Sample content for magento-bug.html:<br />
<br />
&lt;html&gt;<br />
&lt;body&gt;<br />
Do not try to refresh daily statistics. This is broken. Refresh lifetime statistics instead.<br />
&lt;/body&gt;<br />
&lt;/html&gt;<br />
<p>
	We hope this may help if you are experiencing similar problems. Feel free to contact us with any Magento programming projects you may have.</p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[Generating EDI 850 Purchase Order Documents in Magento]]></title><link>http://www.neptuneweb.com/blog/30-generating-edi-850-purchase-order-documents-in-magento.html</link><pubDate>Thu, 17 Feb 2011 00:00:00 -0500</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=30</guid>                      <description><![CDATA[Quite often we need to generate EDI purchase order files (850) and accept EDI ASN files (856) to exchange data between a web store and an external system when processing orders.

Working with EDI files may be quite involving especially if support for all possible scenarios and data elements is required.]]></description>
                 <content:encoded><![CDATA[Quite often we need to generate EDI purchase order files (850) and accept EDI ASN files (856) to exchange data between a web store and an external system when processing orders.<br />
<br />
Working with EDI files may be quite involving especially if support for all possible scenarios and data elements is required. However, when working with a specific vendor and their needs it&#39;s possible to simplify things and make some assumptions or exclude data elements that are not used in specific cases.<br />
<br />
The code to generate the EDI document will be invoked once an invoice is created. This means once the order is paid. We create a new module for this containing a new observer class called NeptuneWeb_ExportEdiOrder_Model_Observer with the following config.xml file:<br />
<pre>
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
&lt;modules&gt;
&lt;NeptuneWeb_ExportEdiOrder&gt;
&lt;version&gt;0.1&lt;/version&gt;
&lt;/NeptuneWeb_ExportEdiOrder&gt;
&lt;/modules&gt;
&lt;global&gt;
&lt;models&gt;
&lt;nwExportEdiOrder&gt;
&lt;class&gt;NeptuneWeb_ExportEdiOrder_Model&lt;/class&gt;
&lt;/nwExportEdiOrder&gt;
&lt;/models&gt;
&lt;events&gt;
&lt;sales_order_invoice_pay&gt;
&lt;observers&gt;
&lt;nwExportEdiOrder&gt;
&lt;type&gt;singleton&lt;/type&gt;
&lt;class&gt;nwExportEdiOrder/observer&lt;/class&gt;
&lt;method&gt;sales_order_invoice_pay&lt;/method&gt;
&lt;/nwExportEdiOrder&gt;
&lt;/observers&gt;
&lt;/sales_order_invoice_pay&gt;
&lt;/events&gt;
&lt;/global&gt;
&lt;/config&gt;
</pre>
<br />
Then in its Model/Observer.php file:<br />
<br />
<div style="overflow: auto;">
	class NeptuneWeb_ExportEdiOrder_Model_Observer {<br />
	public function sales_order_invoice_pay($observer) {<br />
	<br />
	function cleanForEdi($string) {<br />
	# replace `<br />
	$string = preg_replace(&#39;/`/&#39;, &#39;&#39;, $string);<br />
	# replace the following characters * ~ &gt;<br />
	return preg_replace(&#39;/[\*~&gt;]/&#39;, &#39;-&#39;, $string);<br />
	}<br />
	<br />
	# gather necessary variables<br />
	$invoice = $observer-&gt;getEvent()-&gt;getInvoice();<br />
	$order = $invoice-&gt;getOrder();<br />
	$storeId = $order-&gt;getStoreId();<br />
	$orderItems = $order-&gt;getAllItems();<br />
	$orderId = $order-&gt;getIncrementId();<br />
	$customer = Mage::getModel(&#39;customer/customer&#39;)-&gt;load($order-&gt;getCustomerId());<br />
	$streetBA=$order-&gt;getBillingAddress()-&gt;getStreet();<br />
	$streetSA=$order-&gt;getShippingAddress()-&gt;getStreet();<br />
	$shippingMethod = $order-&gt;getShippingMethod();<br />
	# format is carrier_method<br />
	# eg: fedex_FEDEXGROUND<br />
	$data = explode(&#39;_&#39;, $shippingMethod);<br />
	$shippingCarrier = $data[0];<br />
	$shippingCarrierMethod = $data[1];<br />
	<br />
	$ServiceLevelCode = &quot;&quot;;<br />
	switch ($shippingCarrierMethod) {<br />
	case &quot;FEDEXGROUND&quot;:<br />
	$ServiceLevelCode = &quot;SG&quot;;<br />
	break;<br />
	case &quot;FEDEX2DAY&quot;:<br />
	$ServiceLevelCode = &quot;SE&quot;;<br />
	break;<br />
	}<br />
	<br />
	$date = date(&quot;ymd&quot;);<br />
	$date2 = date(&quot;Ymd&quot;);<br />
	$time = date(&quot;Hi&quot;);<br />
	$InterchangeSenderID = &quot;MYWEB1234&quot;;<br />
	$InterchangeSenderIDISA = &quot;MYWEB1234 &quot;; # must be 15 characters<br />
	$InterchangeReceiverID = &quot;MYID12345678&quot;;<br />
	$InterchangeReceiverIDISA = &quot;MYID12345678 &quot;; # must be 15 characters<br />
	#$InterchangeControlNumber = $orderId; # need to be incremented, unique id - will use order id from magento<br />
	$InterchangeControlNumber = $order-&gt;getId(); # need to use id from the db because it must be numeric (and magento is creating numbers like 10000123-1)<br />
	# $InterchangeControlNumber must be 9 digits, need to pad with zeros<br />
	if (strlen($InterchangeControlNumber) &lt; 9) {<br />
	$InterchangeControlNumber = str_pad($InterchangeControlNumber, 9, &#39;0&#39;, STR_PAD_LEFT);<br />
	}<br />
	$PoNumber = $orderId; # order id from magento<br />
	$ProductionOrTest = &quot;P&quot;;<br />
	<br />
	# the entire ISA line must be 106 characters long<br />
	print &quot;ISA*00* *00* *08*$InterchangeSenderIDISA*14*$InterchangeReceiverIDISA*$date*$time*:*00501*$InterchangeControlNumber*0*$ProductionOrTest*&gt;~\n&quot;;<br />
	print &quot;GS*PO*$InterchangeSenderID*$InterchangeReceiverID*$date2*$time*$InterchangeControlNumber*X*005010~\n&quot;;<br />
	<br />
	$TransactionSetControlID = $InterchangeControlNumber;<br />
	$segmentCount = 1;<br />
	<br />
	print &quot;ST*850*$TransactionSetControlID~\n&quot;;<br />
	$segmentCount++;<br />
	<br />
	$orderNumber = $PoNumber;<br />
	$orderDate = date(&quot;Ymd&quot;, strtotime($order-&gt;getCreatedAt()));<br />
	<br />
	print &quot;BEG*00*SA*$orderNumber**$orderDate~\n&quot;;<br />
	$segmentCount++;<br />
	<br />
	# shipping method<br />
	print &quot;TD5**2*FDEG**$shippingCarrierMethod*******$ServiceLevelCode~\n&quot;;<br />
	$segmentCount++;<br />
	<br />
	$shipToName = cleanForEdi($order-&gt;getShippingAddress()-&gt;getFirstname() . &quot; &quot; . $order-&gt;getShippingAddress()-&gt;getLastname());<br />
	$customerId = $customer-&gt;getId(); # unique customer id<br />
	<br />
	# get id for shipping address<br />
	$shippingAddressId = $order-&gt;getShippingAddress()-&gt;getId();<br />
	print &quot;N1*ST*$shipToName*92*$shippingAddressId~\n&quot;;<br />
	$segmentCount++;<br />
	<br />
	$address1 = cleanForEdi($streetSA[0]);<br />
	$address2 = cleanForEdi((count($streetSA)==2)?$streetSA[1]:&#39;&#39;);<br />
	print &quot;N3*$address1*$address2~\n&quot;;<br />
	$segmentCount++;<br />
	<br />
	$city = cleanForEdi($order-&gt;getShippingAddress()-&gt;getCity());<br />
	$state = cleanForEdi($order-&gt;getShippingAddress()-&gt;getRegionCode());<br />
	$zip = cleanForEdi($order-&gt;getShippingAddress()-&gt;getPostcode());<br />
	$country = cleanForEdi($order-&gt;getShippingAddress()-&gt;getCountry());<br />
	print &quot;N4*$city*$state*$zip*$country~\n&quot;;<br />
	$segmentCount++;<br />
	<br />
	# phone must be 10 digits<br />
	$phone = cleanForEdi($order-&gt;getShippingAddress()-&gt;getTelephone());<br />
	$phone = preg_replace(&#39;/[^\d]/&#39;, &#39;&#39;, $phone);<br />
	$phone = substr($phone, 0, 10);<br />
	print &quot;PER*BD**TE*$phone~\n&quot;;<br />
	$segmentCount++;<br />
	<br />
	foreach ($orderItems as $item) {<br />
	$qty = intval($item-&gt;getQtyOrdered());<br />
	$sku = cleanForEdi($item-&gt;getSku());<br />
	<br />
	$unitPrice = sprintf(&quot;%.06f&quot;, ($item-&gt;getRowTotal() - $item-&gt;getDiscountAmount()) / $qty);<br />
	$total = sprintf(&quot;%.02f&quot;, $item-&gt;getRowTotal() - $item-&gt;getDiscountAmount());<br />
	<br />
	print &quot;PO1**$qty*EA*$unitPrice*LE*VN*$sku~\n&quot;;<br />
	$segmentCount++;<br />
	<br />
	print &quot;AMT*1*$total~\n&quot;;<br />
	$segmentCount++;<br />
	}<br />
	<br />
	# line item for shipping<br />
	$totalShipping = sprintf(&quot;%.02f&quot;, $order-&gt;getShippingAmount() - $order-&gt;getShippingDiscountAmount());<br />
	print &quot;PO1**1*EA*$totalShipping*LE*VN*SNHDL~\n&quot;;<br />
	$segmentCount++;<br />
	<br />
	print &quot;AMT*1*$totalShipping~\n&quot;;<br />
	$segmentCount++;<br />
	<br />
	$NumberofDetailLines = count($orderItems) + 1;<br />
	print &quot;CTT*$NumberofDetailLines~\n&quot;;<br />
	$segmentCount++;<br />
	<br />
	$orderTotal = sprintf(&quot;%.02f&quot;, $order-&gt;getGrandTotal() - $order-&gt;getTaxAmount());<br />
	print &quot;AMT*GV*$orderTotal~\n&quot;;<br />
	$segmentCount++;<br />
	<br />
	print &quot;SE*$segmentCount*$InterchangeControlNumber~\n&quot;;<br />
	print &quot;GE*1*$InterchangeControlNumber~\n&quot;;<br />
	print &quot;IEA*1*$InterchangeControlNumber~\n&quot;;<br />
	<br />
	$string = ob_get_clean();<br />
	$ouputDirectory = &quot;/tmp/edi-outgoing&quot;;<br />
	$outFile = $ouputDirectory . &quot;/edi-&quot;. $orderId . &quot;.txt&quot;;<br />
	$fp = fopen($outFile, &quot;a&quot;);<br />
	fwrite($fp, $string);<br />
	fclose($fp);<br />
	}<br />
	}</div>
<br />
<br />
In the above file we define a class and a method that will be invoked when invoices are paid. This will get all the order information and create an EDI purchase order document. The data being generated need to be customized with specific vendor information and additional error handling or validation can be added on top of the basic cleanForEdi() method.<br />
<br />
<br />
<br />]]></content:encoded>

        </item><item>
                         <title><![CDATA[Improving Magento Checkout Performance with Large Number of Cart Rules]]></title><link>http://www.neptuneweb.com/blog/29-improving-magento-checkout-performance-with-large-number-of-cart-rules.html</link><pubDate>Tue, 18 Jan 2011 00:00:00 -0500</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=29</guid>                      <description><![CDATA[This is the fourth of a series on the Open Source e-commerce software, Magento. In this post, we show how to solve a problem we experienced with a client of ours - the cart and checkout process would get extremely slow if there are a large number of cart rules.]]></description>
                 <content:encoded><![CDATA[If you&#39;ve had problems with performance in your Enterprise 1.8 Magento cart and checkout process, it could be due to a large number of sales cart rules.<br />
<br />
We&#39;ve found more than 25 rules will make performance completely unacceptable. The problem occurs when large # of sales cart rules, combined with the number of items in your cart. This is exacerbated when there is a large number of attributes on products.<br />
<br />
Try removing all of your cart rules to see if this is the source of your problem.<br />
<br />
Each cart sales rule makes a call to the product load() function which (in our dedicated environment) costs .100 (1/10) second. This function is very slow, because it has to compose the Entity-Attribute-Value (EAV) records from many tables (<a href="http://www.magentocommerce.com/wiki/2_-_magento_concepts_and_architecture/magento_database_diagram#the_magento_eav_data_model" target="_blank">see details on EAV on Magento&#39;s site</a>).<br />
<br />
Multiply products in the cart by number of rules to estimate how slow your cart or checkout page will be.<br />
<br />
To fix this, just override the product-&gt;load() function. Create a simple global to store previously loaded products. (Obviously, this &quot;cache&quot; is valid for 1 request only).<br />
<br />
Now, calls to load() are based on the number of items in cart only. This can make a huge difference in performance - and in your users&#39; shopping cart experience.<br />
<br />
Here is a code sample of how your overridden Product class should look:<br />
<br />
<div style="width: 400px; height: 200px; overflow: scroll;">
	<pre>
	public function load($id, $field=null) {
	global $ECV_GLOBAL_CACHE;
	if (isset($ECV_GLOBAL_CACHE)) {

	} else {
			$ECV_GLOBAL_CACHE = array();
	}
	if (isset($ECV_GLOBAL_CACHE[$id])) {
					//error_log(&quot;since $id was already loaded, we return global version - cache it&quot;);
					return $ECV_GLOBAL_CACHE[$id];
	} else {
					$ECV_GLOBAL_CACHE[$id] = parent::load($id,$field);
					//error_log(&quot; $id was NOT already loaded, call ev tables - no cache&quot;);
					return $ECV_GLOBAL_CACHE[$id];
	}
}

</pre>
</div>
<p>
	<br />
	<br />
	I hope this helps you out. As always, <a href="/firm/contact_us.html">contact us</a> know if there is anything we can do to help support your Magento installation!</p>
<br />
Charlie<br />]]></content:encoded>

        </item><item>
                         <title><![CDATA[Identifying Magento Performance Problems with the Magento Profiler]]></title><link>http://www.neptuneweb.com/blog/24-identifying-magento-performance-problems-with-the-magento-profiler.html</link><pubDate>Sun, 02 Jan 2011 00:00:00 -0500</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=24</guid>                      <description><![CDATA[This is the third of a series on the Open Source e-commerce software, Magento. Neptune recently launched 2 major web sites using highly customized versions of Magento. 

The Magento Profiler is used to identify performance problems on the server side.  The Profiler can help you find PHP functions which use up too much CPU or functions with slow database queries.]]></description>
                 <content:encoded><![CDATA[<p>
	The Magento Profiler is used to identify performance problems on the server side.  The Profiler can help you find PHP functions which use up too much CPU or functions with slow database queries.</p>
<p>
	These problems will first be noticed if you have high load on your server. Apache processes can be seen using &ldquo;top&rdquo;, where you will see apache or httpd processes jumping to the &quot;top&quot; using a large percentage of CPU.</p>
<p>
	Using the Profiler requires a fairly deep (e.g. time consuming) analysis, so make sure you are barking up the right tree before proceeding with this. You&rsquo;ll want to eliminate any front-end issues (such as loading large png files, too many css or javascript files, content compression, unnecessary Javascirpt, etc.) to be sure your problem is really server side (The &ldquo;YSlow&rdquo; firebug plugin is a good resource for client side problems).</p>
<p>
	Magento is very resource intensive, and many shared hosts will not be able to run it with decent performance.</p>
<p>
	Make sure your problems are not related to your database. Login to MysQL. Run show &ldquo;process list&rdquo;, as you go browse through the slow areas of the site. If any queries stay on the screen as you watch, you probably have a database performance problem.</p>
<p>
	Finally, make sure your problem is not a networking relating issue, such as a slow or faulty internet connection, or firewall.</p>
<p>
	Generally, look for the first page hit using Firebug Net view to see the total server side time required to generate the page. The Magento profiler is limited to this first page hit - so make sure you know how much performance you can actually gain. Focus on the greatest performance as a percentage of the overall time to view the page, to be sure you are getting low-hanging fruit first.</p>
<p>
	Be sure you know what&#39;s going on with your cache. If you are using caching, the difference between the first and subsequent hits can be huge, and will throw confusion into the mix, giving you meaningless results. I recommend adding some comments using PHP error_log() function, (tail -f the web error log), so you know when the Full Page Cache is used. See my <a href="http://www.neptuneweb.com/blog/discuss/25-getting-magento-enterprise-full-page-cache-to-work-on-your-store-home-page.html" target="_blank">previous blog post</a> on the Full Page Cache.</p>
<p>
	As with many Magento problems, I&rsquo;ve given up trying to find documentation or explanations online.  Although the architecture is technically beautiful and the code very well written, documentation can be very spotty. You can occasionally strike gold on the community site, but I&rsquo;ve found the most direct way to approach many Magento problems is to read the source. Once you go through the code, you find out that the feature wasn&rsquo;t as complicated as you thought it was. It&rsquo;s this way with the Magento Profiler.</p>
<p>
	However, in this post, I&rsquo;ll try to save you some pain reading the source, by sharing some experiences on how I&rsquo;ve used the Profiler.</p>
<p>
	I&rsquo;m assuming your running Magento Enterprise 1.8.</p>
<p>
	First, enable the profiler via System -&gt; Configuration -&gt; Developer -&gt; Profile (yes). This enables the profiler, but does not fill in any of the benchmark times.</p>
<p>
	Comment out the following line in <install path="">/index.php</install></p>
<pre>
# toggle this to enable profiler.
Varien_Profiler::enable();
</pre>
<p>
	Next, refresh the page you are optimizing. At the bottom of the page, you will see the performance table.</p>
<p>
	<img alt="Magento Profiler at Bottom of Page" height="92" src="http://www.neptuneweb.com/blog/blog-magento-profiler1.png" width="400" /></p>
<p>
	Fig 1: Magento profile data at bottom of page.</p>
<p>
	This table is impossible to read directly inline, since the HTML is placed outside of any HTML or body tags. Go into the source and copy the entire page contents. Paste in Notepad or any other text editor. Eliminate the regular page HTML , leaving only the HTML which builds up the performance data table. Save to a temporary HTML file and then view via Internet Explorer to view the static page. (IE allows you to copy the table from HTML to Excel)</p>
<p>
	<a href="/blog/blog-magento-profiler2.png" target="_blank"><img alt="" src="http://www.neptuneweb.com/blog/blog-magento-profiler2.png" style="width: 405px; height: 103px;" /></a></p>
<p>
	Fig. 2: Magento stats loaded into Excel. (Click to enlarge.)</p>
<p>
	The call to Mage::app should be at the top of the list. This is the full time of your request is taking to run on the server (minus process startup). It&rsquo;s what you want to reduce as much as possible. The code found in app/Mage.php is what &quot;marks&quot; the start and end points to profile.</p>
<pre>
Varien_Profiler::start(&#39;mage&#39;);
... core magento code ...
Varien_Profiler::stop(&#39;mage&#39;);
</pre>
<p>
	I Ignore the memory usage stats. (If you&rsquo;ve figured out how to make these egregiously large numbers have any meaning, leave me a comment.) Under normal conditions, Magento chews up around 50 Megs of memory per process. If you are running data loading  scripts, it can use up much more memory if there are repeated instantiations of Magento objects (users, products, etc).</p>
<p>
	The number of instantiations is very meaningful, as it will tell you if there are unnecessary objects) being made, possibly through some customizations you&#39;ve made. But don&rsquo;t assume the Magento code is perfect either. We found out that any more than 10 shopping cart rules will slow the performance of the cart to a crawl, due to repeated calls to EAV load table. (NOTE: EAV load calls are very expensive, performance wise. Each one costs about 1/10 of a second. I&#39;ll post another blog article on that solution if it will help someone - let me know.)</p>
<p>
	The column &quot;Time&quot; indicates the total time spent between the &quot;start&quot; and &quot;stop&quot; calls within &quot;Cnt&quot; instantiations. To resolve your performance problem, look for large numbers of instantiations, resulting in large &quot;Time&quot; values within this report.</p>
<p>
	Use recursive grep on the source to find out what is being measured within the profile report. E.g.</p>
<pre>
grep -r &quot;Varien_Profiler::start(&#39;mage&#39;&quot; *</pre>
<p>
	Also, you should be able to add your own Varien_Profiler::start() and stop calls within the code (though I haven&#39;t done that).</p>
<p>
	Good luck and I hope this article helps with troubleshooting your Magento performance problem. Leave me a comment if you have more information or need some help.</p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[Using CSS3 to Embed Fonts on Web Pages]]></title><link>http://www.neptuneweb.com/blog/27-using-css3-to-embed-fonts-on-web-pages.html</link><pubDate>Thu, 23 Dec 2010 00:00:00 -0500</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=27</guid>                      <description><![CDATA[We explain a cross-browser-supported method for embedding fonts into web pages to add flair to designs without the use of any graphic/CSS tricks.]]></description>
                 <content:encoded><![CDATA[<p><a href="http://www.neptuneweb.com/blog/discuss/9-seo-approaches-in-html-design-and-development.html">As previously covered in this blog</a>, &quot;fancy&quot; font use in web page headlines usually requires no font use at all &ndash; a  combination of images and creative CSS swaps text out for graphic  representation. </p>
<p>The CSS3 language, which is supported at least partially by  all modern browsers provides an option to embed actual fonts into a site  visitor&rsquo;s rendered page, presenting headlines as actual text and not as a  swapped-and-replaced text/graphic combination.   This can be accomplished in just three or four lines of code in a CSS  file:</p>
<code> @font-face { </code><br />
<blockquote><code>   font-family: &quot;Sketch  Rockwell&quot;;  <br />
src: url(../fonts/SketchRockwell-Bold.ttf);  /* for IE browsers */  <br />
src: local(&quot;Sketch Rockwell&quot;),  url(../fonts/SketchRockwell-Bold.ttf) format(&quot;truetype&quot;); /* for non-IE  browsers */</code></blockquote> <code>}</code>
<p>To have a particular tag or selector use the font you&rsquo;ve  just embedded, the property is such:</p>
<code>h1 { font-family:&quot;Sketch Rockwell&quot;;}</code>
<p>It makes sense to include the other font properties here &ndash;  color, size, margin, line-height, etc can all be applied to the embedded font.  It&rsquo;s also a good idea to list alternate, backup fonts in the &ldquo;font-family&rdquo;  property:</p>
<code>h1 {color:#603292; font-size:32px; line-height:32px;  margin-left:16px; font-family:&quot;Sketch Rockwell&quot;, &quot;Trebuchet  MS&quot;, Trebuchet, Helvetica, sans-serif;}</code>
<p><a href="http://www.shawsheentech.org/vocational-programs/index.html" target="_blank">An example of this CSS can be seen here</a>.  The &ldquo;Vocational Programs&rdquo; headline is actual  text displayed with an embedded font with other properties for size and color.</p>
<p>The above CSS works all the way down  to IE6 and works fine on both Safari, Chrome and FF on PC and Safari and FF on  the Mac.</p>
<p>A few things to be aware of:</p>
<ul>
    <li>Firefox does not allow for the  importation of fonts that aren&rsquo;t served on the same machine as the CSS  file. </li>
    <li>Know your font licensing  rules.  Just because you can embed a font  doesn&rsquo;t mean you should &ndash; fonts, like other pieces of software are usually not  meant to be shared unless the organization your purchased it from offers it as  rights free.  By including the above CSS  in your style sheets, which are accessible to anyone who visits you site, you  are also making the font file itself accessible.  </li>
    <li>Also consider the font format.  There are several formats out there &ndash; most modern browsers support just  TrueType and OpenType fonts.</li>
</ul>
<p> </p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[Solving Magento Unirgy Drop Ship USPS Flat Rate Shipping Problem]]></title><link>http://www.neptuneweb.com/blog/26-solving-magento-unirgy-drop-ship-usps-flat-rate-shipping-problem.html</link><pubDate>Fri, 10 Dec 2010 00:00:00 -0500</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=26</guid>                      <description><![CDATA[This is the second of a series on the Open Source e-commerce software, Magento. Neptune recently launched 2 major web sites using highly customized versions of Magento. This article explains how to fix a specific problem with the Drop Ship module and USPS Priority Mail Flat Rates.]]></description>
                 <content:encoded><![CDATA[<p>Assuming you are running Magento 1.8 Enterprise, you may have noticed  that certain shipping methods never appear in the checkout. These include USPS Flat Rate methods, but could include any method with a long name.</p>
<p>The problem is that Magento's Unirgy Drop Ship module will not display shipping methods with method codes greater than 30 characters.</p>
<p>(Around) line 72 of app/code/community/Unirgy/DropshipSplit/Model/Carrier.php (A similar problem occurs in non-Split module code) the carriers and methods within Drop Ship are validated against the vendors shipping methods. e.g.</p>
<pre>
foreach ($vRates as $rate) {
                    if (empty($systemMethods
[$rate-&gt;getCarrier()][$rate-&gt;getMethod()])) { continue; 
/* shipping method is skipped */</pre>
The method, being truncated at 30 characters, will fail on this test and the shipping method will not appear.<br />
<pre>
mysql&gt; desc udropship_shipping_method;
+--------------+------------------+------+-----+---------+
| Field        | Type             | Null | Key | Default |
+--------------+------------------+------+-----+---------+
| shipping_id  | int(10) unsigned | NO   | MUL | NULL    |
| carrier_code | varchar(30)      | NO   |     | NULL    |
| method_code  | varchar(30)      | NO   |     | NULL    |
+--------------+------------------+------+-----+---------+
</pre>
<p>As you can see from the data, below, the full name of the shipping method is &quot;Priority Mail Small Flat Rate Box&quot;. It is being cut off at 30 characters. The same thing happens with medium and large boxes.</p>
<p><a href="/blog/blog_drop_ship_magento.png"><img height="48" border="1" width="416" src="http://www.neptuneweb.com/blog/blog_drop_ship_magento.png" alt="Missing &quot;Box&quot;" /></a><br />
<br />
To resolve, simply give more space in the column and update the records. E.g.</p>
<pre>
# give more space to column
mysql&gt; alter table udropship_shipping_method
 modify method_code varchar(100) default null;
# update truncated shipping methods. 
#This may also occur with Medium and Large boxes. 
mysql&gt; update udropship_shipping_method set method_code = 
'Priority Mail Small Flat Rate Box' where method_code =
 'Priority Mail Small Flat Rate ';
</pre>
<p>This one was so blatant, but took a long time to dig out, so I had to share it. Send me a comment (below) if this article helped.</p>
<p>If there is anything Neptune Web can help you with regarding Drop Shipping and Magento, <a href="/firm/contact_us.html">give us a call</a>.</p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[Getting Magento Enterprise Full Page Cache to work on your Store Home Page]]></title><link>http://www.neptuneweb.com/blog/25-getting-magento-enterprise-full-page-cache-to-work-on-your-store-home-page.html</link><pubDate>Tue, 23 Nov 2010 00:00:00 -0500</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=25</guid>                      <description><![CDATA[This is the first of a series on the Open Source e-commerce software, Magento. Neptune recently launched 2 major web sites using highly customized versions of Magento. 

This article explains how to get the Magento Full Page Cache (from Enterprise version) for the home page of your store/site.]]></description>
                 <content:encoded><![CDATA[<p>Assuming you are running Magento 1.8 Enterprise, you may have noticed that the home page does not cache by default, even though System -&gt; Configuration -&gt; Cache Management -&gt; Page Cache is set.</p>
<p>Only catalog and product pages make use of the full page cache by default.* </p>
<p>*Update: On a second Magento installation, with different modules installed, this was not true. On the installation where this problem occurred, it appears the core module handles the homepage request.</p>
<p>Run the find command to see which full pages are cached (REQEST - yes misspelled) indicates the page was cached.</p>
<p>find var/cache -name &quot;*REQEST_*&quot; -print</p>
<p>In the file app/code/core/Enterprise/PageCache/etc/config.xml, you will see the section which you can configure to get other pages cached. The relevant section is as follows:</p>
<pre><cache>&lt;cache&gt;<br />&lt;requests&gt;<br />&lt;cms&gt;enterprise_pagecache/processor_default&lt;/cms&gt;<br />&lt;catalog&gt;&lt;category&gt;&lt;view&gt;...&lt;/view&gt;&lt;/category&gt;&lt;/catalog&gt;<br />&lt;catalog&gt;&lt;product&gt;&lt;view&gt;...&lt;/view&gt;&lt;/product&gt;&lt;/catalog&gt;<br />&lt;/requests&gt;<br />&lt;/cache&gt;        </cache>

Add the following line between the &lt;requests&gt;&lt;/requests&gt; tags:</pre>
<pre>
&lt;core&gt;&lt;index&gt;enterprise_pagecache/processor_default
&lt;/index&gt;&lt;/co<requests><catalog>re&gt;</catalog></requests>
</pre>
<p>However, this still isn't going to work. There is a bug within Magento, which returns a &quot;1&quot; (yes, the number 1) as a result of:</p>
<pre>
$request-&gt;getModuleName()</pre>
<p>(I didn't have time to research the origin of this bug, as mentioned above it may have been a module we installed). So, add a single code line to the file:</p>
<pre>
app/code/core/Enterprise/PageCache/Model/
Processor.php (around line 320)
... $module = $request-&gt;getModuleName(); // existing code
if ($module == '1') { $module = 'core'; } 
// THE ABOVE LINE IS THE FIX TO GET THIS CACHE TO 
// WORK ON HOMEPAGE.
if (isset($configuration[$module])) {    //existing code
//  etc..
</pre>
<p>A file over-ride (clone file and directory structure in app/code/local) would probably be best here.</p>
<p>Once you've made those changes, clear your config cache, and the homepage will now cache.</p>
<p>This small change can have a dramatic effect on the performance of your web site, since a good percentage of people enter the site from the home page and never add anything to the cart (which invalidates the cache*). Therefore, the entire session can make use of the full page cache.</p>
<p> </p>
<p>* See app/code/core/Enterprise/PageCache/Model/Processor.php isAllowed function (modified with comments below) to see what other conditions invalidate the cache for the user. E.g. the request must NOT have the cookie NO_CACHE set (that cookie is set when a session is started - an item is added to cart), it must not be secure (https), and it must not have the GET variable no_cache set. Adding logging below is a good idea to see if your page is caching.</p>
<p>Assuming you're on fast hardware a 200-400ms page request time means you're making use of the page cache. 800-1200ms hits mean your probably not making use of the page cache.</p>
<pre>
public function isAllowed()
    {
        if (!$this-&gt;_requestId) {
        error_log(&quot;page cache not used because NO REQUEST for request &quot; . $_SERVER[&quot;PATH_INFO&quot;]);
            return false;
        }
        if (isset($_SERVER['HTTPS']) &amp;&amp; $_SERVER['HTTPS'] == 'on') {
                error_log(&quot;page cache not used because sECURE for request &quot; . $_SERVER[&quot;PATH_INFO&quot;]);
            return false;
        }
        if (isset($_COOKIE['NO_CACHE'])) {
                error_log(&quot;page cache not used because cache cookie set for request &quot; . $_SERVER[&quot;PATH_INFO&quot;]);
            return false;
        }
        if (isset($_GET['no_cache'])) {
                error_log(&quot;page cache not used because of cache GETVAR set for request &quot; . $_SERVER[&quot;PATH_INFO&quot;]);
            return false;
        }
        return true;
    }
               
</pre>
<p> </p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[Google Font API Gives Developers More Page Design Options]]></title><link>http://www.neptuneweb.com/blog/23-google-font-api-gives-developers-more-page-design-options.html</link><pubDate>Thu, 29 Jul 2010 00:00:00 -0400</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=23</guid>                      <description><![CDATA[One of newest APIs out of Google Labs, the Google Font API, allows designers and developers to use more than just the standard 'web safe' fonts as part of a page's look and feel.  This tool helps promote SEO without limiting a site's look and feel.]]></description>
                 <content:encoded><![CDATA[<p>The Google font API is a simple tool that will let a production developer insert what are traditionally considered 'non web safe' fonts safely into a page's set of styles for a creative twist on what have otherwise become a bland set of options for font faces over the past 15+ years of web page design.  This presents a new method for creating unique, SEO-friendly headlines and text elements. (<a href="http://www.neptuneweb.com/blog/discuss/9-seo-approaches-in-html-design-and-development.html">see this previous post for other SEO-friendly alternative font methods</a>).</p>
<p>The API itself is simple:</p>
<ol>
    <li>Call to the API in the &lt;head&gt; tag of your page with this line:<br />
    <pre>
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot;
href=&quot;http://fonts.googleapis.com/css?family=<var>Font+Name</var>&quot;&gt;</pre>
    </li>
    <li>Where &quot;Font+Name&quot; is in the &lt;link&gt; tag is where you can choose your font.</li>
    <li>Use the font you've chosen as part of the normal font-family property in your CSS. Ex.:
    <pre>
font-family:'Font Name', serif</pre>
    </li>
</ol>
<p>Google has even made it easy for you to browse and configure fonts via its <a href="http://code.google.com/webfonts/preview#font-family=Lobster" target="_blank">Font Previewer</a> that will dynamically output the code you can cut and paste into your own page. Options include standard CSS properties like letter and line spacing.  The font API is compatabile all the way down to Internet Explorer 6, though designers should keep in mind IE6 (and all other browser) CSS support -- for example, no Internet Explorer browser supports the 'text-shadow' property.</p>
<p><a href="http://code.google.com/webfonts" target="_blank">The font directory</a> is small right now, but growing.  Be weary, however: all fonts are available under an open source license, so don't expect to see any Adobe or Microsoft fonts.</p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[How PCI Compliance and MA Data Standards are Affecting Web Developers in Massachusetts]]></title><link>http://www.neptuneweb.com/blog/22-how-pci-compliance-and-ma-data-standards-are-affecting-web-developers-in-massachusetts.html</link><pubDate>Wed, 30 Jun 2010 00:00:00 -0400</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=22</guid>                      <description><![CDATA[There are two important standards which web developers and their clients in Massachusetts need to know about. They are: Massachusetts 201 CMR 17.00 and PCI Compliance.]]></description>
                 <content:encoded><![CDATA[<p>There are two important standards which web developers and their clients in Massachusetts need to know about. They are:</p>
<ul>
    <li><b>PCI Compliance. </b>This affects everyone who stores or processes credit cards. It can also affect anyone who is doing any form of e-commerce online.<br />
     </li>
    <li><b>Massachusetts 201 CMR 17.00 </b>or Standards for the Protection of Personal Information of Residents in the Commonwealth. These standards can affect anyone who stores or processes electronic (or paper) information about Massachusetts residents.</li>
</ul>
<p>Let me provide a quick overview of these two changes, and then mention how they will affect small to medium sized businesses in regards to their web development needs.</p>
<p>The <b>PCI Security Standards Council </b>is a policy entity founded by representatives from the major credit card companies. Its purpose is to ensure that all vendors who process card information comply with standards and reporting regulations, for the purpose of keeping cardholder data secure. The Council defines <b>PCI Compliance </b>and helps organizations to become PCI Compliant.<b> </b></p>
<p>PCI Compliance requires that you identify your security level (on a 1-5 basis, 5 being the most demanding requirements because card data is stored) by completing a self assessment questionnaire (SAQ). See <u><a target="_blank" href="https://www.pcisecuritystandards.org/saq/instructions_dss.shtml">www.pcisecuritystandards.org/saq/instructions_dss.shtml</a></u><br />
Depending on your SAQ level, you must comply with certain standards, such as having a verified 3rd party (or qualified security assessor, QSA) scan your site for vulnerabilities, encrypting all card data with strong encryption, and using dedicated (vs shared or virtual servers). The most difficult level will be level 5 (D) vendors, who are storing card data for &quot;one-click&quot; ordering.</p>
<p><a target="_blank" href="https://www.pcisecuritystandards.org/qsa_asv/become_qsa.shtml">https://www.pcisecuritystandards.org/qsa_asv/become_qsa.shtml</a></p>
<p>In order to work with the QSA, you need to go through process which will involve your hosting company as well as your web developer. They will expect the self-assessment questionnaire to be completed. Then, they will also perform a web scan on your site, which will affect your web host, as the scan may require some changes in server configuration. There may be some back and forth during that process, which can slow things down for some organizations. To remain PCI compliant, the QSA must continually scan your site. They will notify you if known vulnerabilities are detected.<br />
<br />
States have adopted their own sets of standards. In Massachusetts, it is called <b> Massachusetts 201 CMR 17.00 </b>or &ldquo;Standards for the Protection of Personal Information of Residents in the Commonwealth &quot;, http://www.mass.gov/Eoca/docs/idtheft/201CMR1700reg.pdf requires the protection of personal user information for state residents*. Also not actively enforced, these standards might only be used post-facto were a breach to occur (e.g. as a basis for a law suit). They could also form the basis for future regulation. Fortunately, if you are PCI compliant levels 4 or 5, you should also be complaint with CMR 17.00.</p>
<p><b>*Massachusetts 201 CMR 17.00 </b>defines &ldquo;Personal Information&rdquo;  as &ldquo;a Massachusetts resident's first name and last name or first initial and last name in combination with any one or more of the following data elements that relate to such resident: (a) Social Security number; (b) driver's license number or state-issued identification card number; or (c) financial account number, or credit or debit card number.&rdquo;</p>
<p>There are several notable stipulations in<b> Massachusetts 201 CMR 17.00. </b>Compliant organizations are required to:</p>
<ul>
    <li>Encrypt forms which collect personal information on the site; a 1024 bit SSL certificate will satisfy this requirement.<br />
     </li>
    <li>Block access to non-public sites after multiple unsuccessful login attempts.<br />
     </li>
    <li>Encrypt data stored on laptops (of interest, but not affecting the web).<br />
     </li>
    <li>Have Firewall software, Anti-virus software, &amp; Operating system patches (less notable because most IT systems have this in place)<br />
     </li>
    <li>Comply with a variety of employee reviews and procedural requirements, such as maintaining a &ldquo;comprehensive security program&rdquo;.</li>
</ul>
<p> </p>
<hr />
<p><b>Impact on Small and Mid-Sized Businesses</b></p>
<p>So how are PCI and CMR17.00 recommendations affecting small and medium sized businesses (SMBs) who are our clients here at Neptune Web?</p>
<p>Generally, PCI compliance is the most difficult hurdle for SMBs to deal with. Since it only affects customers doing e-commerce transactions, many businesses are not affected at all. CMR17.00 has generally been less of a burden for SMBs, since many companies aren&rsquo;t storing or transmitting credit cards or social security numbers, and since PCI compliance covers nearly all of the CMR17.00 requirements, depending on the level. Since both recommendations are good practice, businesses have already taken many of the steps required by both CMR17.00 and PCI compliance.</p>
<p>Some businesses are concerned that any form found on their site must have an SSL certificate &ndash; even a simple &ldquo;contact us&rdquo; form. This seems a bit absurd given the promiscuous information sharing on the Internet today. An SSL certificate is not required by CMR17.00 as long as &ldquo;personal information&rdquo; (credit card, social security number, bank account, not found in any public resource, see definition above) is not being passed or stored through those forms.</p>
<p>Making your site PCI compliant site can increase hosting costs because any site that processes card data (transmitted) needs a dedicated server and a firewall. (To store cards, at least 2 dedicated servers are required. ) For small businesses who are taking a few transactions, the cost $700/month or more is prohibitive, and they just don&rsquo;t want to deal with the security of credit cards. We&rsquo;ve seen many of our customers convert their card processing to an offsite system hosted by a third party such as Paypal or Authorize.net. In this scenario, the user is redirected to the 3<sup>rd</sup> party site to enter their card information. Usability is negatively affected, but for these customers it&rsquo;s still worth it because they can continue to host on a shared host, which is much less expensive than dedicated and easier to maintain.</p>
<p>Lately, I&rsquo;ve found customers have been more inclined to avoid the problem altogether and use a end-to-end, hosted system such as Yahoo store or Amazon&rsquo;s E-commerce service.</p>
<p>We&rsquo;ve seen businesses that aren&rsquo;t doing &ldquo;big time&rdquo; e-commerce moving their payment processes to offsite vendors at the cost of reduced usability. The risk just outweighs the benefits (mainly usability) for these customers. Any customer using a shared or virtual web host fits into the &ldquo;small time&rdquo; category. Only customers who have an e-commerce component, which is a big enough part of their business that the usability really matters, will become PCI compliant as level 4. Very few clients will become level 5 vendors due to the high hosting costs (which will be as much as most Boston area apartments &ndash; $1500-2000/month).  Those that do tend to have in-house web development and IT staff.<br />
<br />
<b>Our eCommerce Recommendations</b></p>
<p>For e-commerce sites, Neptune generally does not recommend storing credit card data, due to the increased cost, risk and regulatory burden imposed by these standards. If you decide to become a level 5 vendor, the requirements will be very difficult to fulfill. This is important because storage of card data is necessary for &quot;one-click&quot; ordering. For level 5 vendors, at least 2 dedicated servers must be used to store cards - one for the web host and the other for the database. All card data must be encrypted. In addition, at least one firewall must be in place. These requirements will increase hosting costs significantly.</p>
<p>A level 4 (vs. level 5) designation means that e-commerce projects our client do with us will be significantly smaller, as you will not have to deal with encryption of cards, the systems administration required for 2 machines, and the overall complexity this introduces.</p>
<p>Generally, I think both PCI and CMR 17.00 requirements are pretty reasonable. We&rsquo;ve been doing most of these things for years anyway, but without a formal &ldquo;checklist&rdquo; by an outside organization. The requirements are helping psychologically - by keeping security first in people&rsquo;s minds. We&rsquo;re seeing a lot more SSL certificates being requested, which can mean more management, costs, and another thing for clients to remember. Until now, support for SSL over a shared IP address (virtual hosting) has not been well supported. I expect that to change soon. SSL should become more available and more widely used.</p>
<p>FYI: We&rsquo;ve been a Rackspace fan for years and recommend Rackspace's PCI compliance toolkit, whether cards are stored or not. For more info see:</p>
<p><a href="http://www.rackspace.com/managed_hosting/services/security/pci.php" target="_blank">http://www.rackspace.com/managed_hosting/services/security/pci.php</a></p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[6 Reasons Small and Mid-sized Businesses should be Participating in Social Media]]></title><link>http://www.neptuneweb.com/blog/21-6-reasons-small-and-mid-sized-businesses-should-be-participating-in-social-media.html</link><pubDate>Wed, 21 Apr 2010 00:00:00 -0400</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=21</guid>                      <description><![CDATA[Social media is a powerful tool that can, and should, be used by small and mid-sized companies to grow their business. It is a cost effective method for engaging with customers in the more personalized space of Web 2.0 and building strong relationships while also increasing reach.]]></description>
                 <content:encoded><![CDATA[<p>As the web continues to develop, it becomes more interactive and user centered. Web 2.0 is a revolution in the way people make use of the internet with a more user-centered design. It is characterized by a focus on people, communication, information sharing, collaboration, and usability. Users control their own experience and the information they receive.</p>
<p>Social media plays an important role in Web 2.0 because it enables people to use the internet to connect in a personal way. You can participate in social media by creating a blogs or podcasts or by engaging with social networking sites like Facebook, Twitter, and LinkedIn. Social media is a conversation &ndash; by engaging with social media you can participate in conversations users are having about topics related to your business, instead of using traditional marketing techniques and interrupting them to talk about your products or services.</p>
<p>Social media is a powerful tool that can, and should, be used by small and mid-sized companies to grow their business. Engaging with social media does take time and effort, but it is a very low-cost endeavor that can yield significant results. Small and mid-sized businesses can use social media to engage with customers in the more personalized space of Web 2.0 and build strong relationships while also increasing their reach. If you&rsquo;re already using social media, these tips should still be useful in pointing out the objectives and goals you should have for your social media engagement.</p>
<p><b>6 Reasons to use Social Media:</b></p>
<p><b>1. Cost Effective</b></p>
<p>Social media and social networking sites are free and generally easy to use. It does take time to put information on these sites, but chances are you already have short company summaries and value propositions prepared for other purposes. This information forms the basis of a profile on a social media site and then you just need to one person or a few people to add interesting and relevant content. It may be implausible to expect that you can post something every day or even every week, but even once a month is better than not engaging with social media at all.</p>
<p><b>2. Build Reach</b></p>
<p>By engaging with current customers and clients in the more personalized space of social media, you widen your reach significantly. Research recently by Nielsen has shown that social media is becoming more popular than email as a consumer activity. Loyal and satisfied customers will likely give positive reviews through social media channels. Their interactions with you and your brand will be viewed by other users.</p>
<p>Social media provides a space for powerful online word-of-mouth that can bring you qualified leads. If you create interesting and valuable content, it will likely be shared by customers and prospects. All of your interactions on social media enable you to reach more people, as you increase the number of people in your network, you will likely increase your leads and generate more customers.</p>
<p>The example below depicts the company profile of Exe Castle Integration on LinkedIn. As I access information about the company, I am able to see if I am connected to any of the employees, and if so, how I am connected. This represents a powerful networking and reference opportunity that all small businesses can use to their advantage.</p>
<p style="text-align: center;"><img src="http://www.neptuneweb.com/images/ecilinkedin.png" style="width: 424px; height: 361px;" alt="" /></p>
<p><b>3. Strengthen Relationships</b></p>
<p>Social media sites provide a unique opportunity for you and your business to interact with customers on a personal basis. The strength of social media comes from this personal contact, which encourages users to return frequently. Customers are more interested in dealing with real people and getting to know the people behind the brand, than learning about products or services.</p>
<p>In tough economic times, it is especially important to establish trust with your potential customers and create a relationship. By giving a face to your business, you will begin to establish trust. As you provide unique and valuable information to your contacts over time, you build this trust and foster relationships. As you strengthening your relationships with potential customers you make them more comfortable with your company, which should in turn give them peace of mind about doing business with you and encourage them to do so even when budgets may be limited.</p>
<p>Social media is a great space for developing this relationship with potential customers &ndash; use it to interact with customers and prospects to provide feedback about their questions and concerns.</p>
<p>The example below portrays an interaction on Facebook. Biotek posted a link referring to a event in their industry. A few people demonstrated interest and Biotek provided a helpful answer to one user&rsquo;s question, building interest and trust in their company.</p>
<p align="center"><img src="http://www.neptuneweb.com/images/biotekresponse.png" style="width: 444px; height: 255px;" alt="" /></p>
<p><b>4. Establish Thought Leadership</b></p>
<p>By continually create unique and relevant information to share with your contacts, you will not only build trust, but also establish yourself and your company as a thought leader. Most of your competitors are probably engaging with social media in some way. If you fail to do so, you risk being out of the loop.</p>
<p>Write about topics that are relevant to your industry, even if you are just expressing opinion, to show that you are thinking about current issues and willing to contribute your ideas to the community. This will create relevance with the people you are connected to via social media channels - when they think about topics related to your business they will think of your company and have a personal connection.</p>
<p>In the example below, NICHQ used Twitter to send a quick Tweet about CEO Charles Homer being featured in an ABC News article. This is an interesting article for followers to read, and also demonstrates that Homer is an important thought leader in their industry.</p>
<p align="center"><img src="http://www.neptuneweb.com/images/nichqtwitter.png" style="width: 323px; height: 212px;" alt="" /></p>
<p><b>5. Faster, More Efficient Connection</b></p>
<p>Social media channels shorten the path from your to your customers and give customers faster access to new company information. Users on social networks (Facebook, Twitter, LinkedIn, etc.) have landing pages that give immediate updates about other users, so a company&rsquo;s latest content is actually fed into the user&rsquo;s entry page with each of these services. A user no longer has to visit a company&rsquo;s website for new information, but instead has access to this info in one convenient spot.</p>
<p>For example, some restaurants are notifying followers of nightly specials, events and coupons via social media channels. </p>
<p align="center"><b><img src="http://www.neptuneweb.com/images/tupelotwitter.png" style="width: 276px; height: 148px;" alt="" /><br />
</b></p>
<p><b>6. Improve Search Engine Positioning</b></p>
<p>Creating more content to put on your website and more inbound links from social media sites will help to improve your search engine positioning. As long as you are adding relevant content and not strictly using a blog or social media sites for advertising purposes, the association of this content with your company should help move you up within the search results. As you create more significant content, Google and other search engines will find more information to index. Just make sure you're not creating content for the sole purpose of associating more information with your website; relevant and useful content will best serve you and your customers.</p>
<p><b>Final Thoughts</b></p>
<p>Social media is a powerful marketing tool with several advantages that apply to small and mid-sized businesses. Participating in the social web is a cost effective method of brand building. By creating interesting content and maintaining a personal, human touch, small businesses can compete with large organizations with bigger budgets. Word-of-mouth and customer feedback are important aspects of social media, so if you have a great product or provide exceptional services, you should already have the satisfied customers who will be willing to say good things and refer their friends.</p>
<p>The best way to start or strengthen a social media campaign is to do a bit of research. The most popular social networking sites are Facebook, Twitter, and LinkedIn. You should have a profile on each site. Additionally, your website should have a blog. Videos and podcasts are interesting content that will draw users into your website and create curiosity. All of this content should be created to spark interest in your company and help you connect with current and potential customers. Stay tuned for our next blog - advice on how and where to get started with a social media campaign!</p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[Implementing Generic Site Search using mnoGoSearch]]></title><link>http://www.neptuneweb.com/blog/20-implementing-generic-site-search-using-mnogosearch.html</link><pubDate>Sun, 18 Apr 2010 00:00:00 -0400</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=20</guid>                      <description><![CDATA[This will show how easy it is to set up a keyword site search.]]></description>
                 <content:encoded><![CDATA[<script language="javascript" type="text/javascript" src="/scripts/jquery.js"></script> <script language="javascript" type="text/javascript" src="/scripts/thickbox-compressed.js"></script>
<link rel="stylesheet" type="text/css" href="/styles/thickbox.css" media="screen" />
<p>I wanted to provide a quick but accurate search on a website. In the past we've used programs such as htdig and swish, which while good, became outdated or difficult to set up the way we wanted. My latest attempt includes implementing mnogosearch.</p>
<h3>Installation</h3>
<p>For our purposes we used the latest version of mnogosearch and downloaded it here:</p>
<p>wget http://www.mnogosearch.org/Download/mnogosearch-3.3.9.tar.gz</p>
<p>After unpacking I configure it to use mysql database only and set a prefix where everything will be installed:</p>
<p>./configure --with-mysql --prefix=/neptune/mnogosearch-3.3.9</p>
<p>Note that on a Red Hat Enterprise Linux AS release 4 with the x86_64 architecture the configure script wasn't able to find required mysql libraries. Therefore we need to provide the path in the environment variable and invoke configure like this:</p>
<p>LDFLAGS=-L/usr/lib64/mysql ./configure --with-mysql --prefix=/neptune/mnogosearch-3.3.9</p>
<h3>Setup</h3>
<p>Next step is to create a database in mysql that will be used by the site search. In mysql you simply need to create a database and grant full access to it to a user of your choice. In the example below we create a database called &quot;mnogosearch_neptuneweb&quot; and give full access to it to the user called &quot;neptuneuser&quot; with the password &quot;neptunepass&quot;. Full database access will be needed for the mnogosearch  indexer to create database tables.</p>
<p>mysql&gt; create database mnogosearch_neptuneweb;<br />
mysql&gt; grant all on mnogosearch_neptuneweb.* to neptuneuser@localhost identified by 'neptunepass';</p>
<h3>Configuration</h3>
<p>We'll need to have two configuration files for the search to work: one for the indexer and another for the search.</p>
<p>The indexer configuration file called &quot;indexer.conf&quot; can be as simple as in the following example:</p>
<p>DBAddr  mysql://neptuneuser:neptunepass@localhost/mnogosearch_neptuneweb/?dbmode=single<br />
Server http://www.neptuneweb.com/<br />
Disallow *.gif  *.jpg  *.jpeg *.png *.css *.js *.flv *.swf<br />
Section body                    1       150000 html<br />
Section title                   2       255<br />
LocalCharset UTF-8<br />
RemoteCharset UTF-8</p>
<p>The other configuration file is called &quot;search.htm&quot; and is basically a set of html code portions to use on the search and results page. It is recommended to create a copy of the search.htm-dist file provided with mnogosearch as /neptune/mnogosearch-3.3.9/etc/earch.htm-dist and update it to your needs. The only required modifications to make it work is the DBAddr parameter to point it to the correct mnogosearch database. It has to match the same parameter in the indexer.conf file.</p>
<h3>Running it</h3>
<p>To index the site you need to invoke the indexer program three times as below: first to drop any old database tables, then to create new database structure and finally to index the website:</p>
<p>/neptune/mnogosearch-3.3.9/sbin/indexer -Edrop indexer.conf<br />
/neptune/mnogosearch-3.3.9/sbin/indexer -Ecreate indexer.conf<br />
/neptune/mnogosearch-3.3.9/sbin/indexer -a -d indexer.conf</p>
<p>On the search page we need to invoke the mnogosearch search.cgi program to return results. Below is an example of php code for the search page. This will take the search.htm configuration template and output the search form and search results.</p>
<p>$queryString = $_SERVER[&quot;QUERY_STRING&quot;];<br />
putenv(&quot;QUERY_STRING=&quot; . $queryString);<br />
putenv(&quot;UDMSEARCH_TEMPLATE=&quot; . &quot;/path/to/search.htm&quot;);<br />
putenv(&quot;UDMSEARCH_SELF=&quot; . $_SERVER[&quot;PHP_SELF&quot;]);<br />
$cmd = &quot;/neptune/mnogosearch-3.3.9/bin/search.cgi&quot;;<br />
exec($cmd, $searchOutput);<br />
for($searchIndex=1; $searchIndex&lt;count($searchOutput); $searchIndex++) {<br />
$line = $searchOutput[$searchIndex];<br />
print $line;<br />
}</p>
<p>The following are two examples of rendering the results on the page:</p>
<p><a href="/blog/mnogosearch/search_example1.png" class="thickbox"><img height="294" width="425" src="http://www.neptuneweb.com/blog/mnogosearch/search_example1-thumb.gif" alt="" /></a></p>
<p><a href="/blog/mnogosearch/search_example2.png" class="thickbox"><img height="419" width="425" src="http://www.neptuneweb.com/blog/mnogosearch/search_example2-thumb.gif" alt="" /></a></p>
<h3>Conclusions</h3>
<p>It takes a bit of work to set up and configure the search this way but once you do it once it's just a matter of making a copy next time. However, the mnogosearch program is very powerful and allows to create a very custom search engine. Worth noting are some advanced features  including indexing database content directly, ability to use external parsers, categorizing content by site sections, support for indexing content in multiple languages.</p>
<p> </p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[Form Builder module for the Neptune Web Edit CMS - Part 2]]></title><link>http://www.neptuneweb.com/blog/19-form-builder-module-for-the-neptune-web-edit-cms---part-2.html</link><pubDate>Thu, 11 Mar 2010 00:00:00 -0500</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=19</guid>                      <description><![CDATA[More details about the upcoming form builder module for the Neptune Web Edit CMS.]]></description>
                 <content:encoded><![CDATA[<script language="javascript" type="text/javascript" src="/scripts/jquery.js"></script> <script language="javascript" type="text/javascript" src="/scripts/thickbox-compressed.js"></script>
<link rel="stylesheet" type="text/css" href="/styles/thickbox.css" media="screen" />
<p>Last time we introduced some features of the upcoming Form Builder module for the Neptune Web Edit CMS. Now I will describe it in more detail and give more information on its usage and setup.</p>
<p>In our sample CMS site the module is located in the usual place along with other modules under &quot;Manage Files&quot; and in this case is called &quot;Contact Forms&quot;. Each item in the module is a separate submission form. There are two forms created in the screenshot below: &quot;Campaign one&quot; and &quot;Small form&quot;.</p>
<p style="text-align: center;"><a title="A sample module with two forms created" class="thickbox" href="/blog/formbuilder/form-list.png"><img width="425" height="178" src="http://www.neptuneweb.com/blog/formbuilder/form-list-thumb.gif" alt="" /></a></p>
<h3>How to create a form</h3>
<p>In the Forms Database click on &quot;Add New Item&quot;. You are taken to the Form settings screen.</p>
<p style="text-align: center;"><a title="Add form screen" class="thickbox" href="/blog/formbuilder/add-form.png"><img width="425" height="290" src="http://www.neptuneweb.com/blog/formbuilder/add-form-thumb.gif" alt="" /></a></p>
<p> </p>
<ul>
    <li>Enter the form name in the subject field. Select a template file on which the form will appear. Optionally enter an SEO URL of the form.</li>
    <li>In the &quot;Confirmation message or redirect URL&quot; field please enter either a message that will be displayed after the form is submitted (a thank you message) or a URL where the visitor will be redirected after submitting the form.</li>
    <li>You can add captcha validation to the form by selecting the &quot;Include reCAPTCHA&quot; checkbox and providing your public and private keys for the reCAPTCHA service.</li>
    <li>Finally each submission can be emailed to a predefined administrative address when you provide the Admin Email Address and Subject.</li>
</ul>
<p> </p>
<p>Once the form information is entered you click on &quot;Save Item&quot; which takes you back to the page listing all forms. There, you want to click on &quot;Edit Components...&quot; to add form fields.</p>
<p style="text-align: center;"><a href="/blog/formbuilder/new-form-components.png" class="thickbox" title="Form components screen"><img width="425" height="130" alt="" src="http://www.neptuneweb.com/blog/formbuilder/new-form-components-thumb.gif" /></a></p>
<p> </p>
<p>On the Form Components screen you will see a list of existing fields of your form. To add a new field please enter its Name (this will be the label displayed next to the field), then select its Type from the dropdown and click on &quot;Add&quot;. This will take you to the Component Edit screen.</p>
<p>Once on the Component Edit screen you will enter information about the specific form field you are adding. Please note that depending on the field type you are editing the edit page will have slightly different choices.</p>
<p>For example a text field will have the following options:</p>
<p style="text-align: center;"><a href="/blog/formbuilder/text-field-options.png" class="thickbox" title="Text field options"><img width="425" height="300" alt="" src="http://www.neptuneweb.com/blog/formbuilder/text-field-options-thumb.gif" /></a></p>
<p> </p>
<ul>
    <li>Label - name/title of the field eg. First Name</li>
    <li>Default value - the initially prefilled text</li>
    <li>Description - additional text displayed next to the field</li>
    <li>Field Key - unique field identifier (used as the field's name attribute in HTML)</li>
    <li>Label placed to the left of the textfield - text displayed before the field eg. $</li>
    <li>Label placed to the right of the textfield - text displayed after the field</li>
    <li>Maxlength - the number of characters allowed to enter into the field (same as the maxlength attribute in HTML)</li>
    <li>Width - field width (same as the size attribute in HTML)</li>
    <li>Mandatory - where a value must be entered into the field</li>
</ul>
<p>On the other hand, a select (eg. drop down) field has the following options:</p>
<p style="text-align: center;"><a href="/blog/formbuilder/select-field-options.png" class="thickbox" title="Select field options"><img width="425" height="338" src="http://www.neptuneweb.com/blog/formbuilder/select-field-options-thumb.gif" alt="" /></a></p>
<p> </p>
<ul>
    <li>Label</li>
    <li>Default value</li>
    <li>Description</li>
    <li>Field Key</li>
    <li>Options - list of items to select from, one per line</li>
    <li>Multiple - whether to allow choosing more than one item</li>
    <li>Listbox - whether to display the field as a list (drop down) or a set of check boxes</li>
    <li>Mandatory</li>
</ul>
<h3>Example renderings</h3>
<p>Once you create a form you want to go to see it on the actual web page. Below are two sample renderings of two forms.</p>
<p>A submission form in the center area of the page, including captcha validation:</p>
<p style="text-align: center;"><a href="/blog/formbuilder/render1.png" title="Sample rendering - form in the center area" class="thickbox"><img width="425" height="391" src="http://www.neptuneweb.com/blog/formbuilder/render1-thumb.gif" alt="" /></a></p>
<p style="text-align: left;">A form in the right hand column of the page:</p>
<p style="text-align: center;"><a href="/blog/formbuilder/render2.png" title="Sample rendering - form in the side column" class="thickbox"><img width="425" height="296" src="http://www.neptuneweb.com/blog/formbuilder/render2-thumb.gif" alt="" /></a></p>
<p> </p>
<h3>How to view results</h3>
<p>The submissions are stored in the database and available to list or download from the &quot;View Results...&quot; link on the Form Listing page.</p>
<h3>Page set up</h3>
<p>A page where the form appears needs to have the form invocation code added on it. It is referred to as a template file. It is basically a web page on which the form will appear and is specially prepared to handle forms from the module. Each template file can handle just one form (you cannot assign the same template file to more than one form). If you need to create a new form then you typically also need to create a new template file for it. The easiest way is to create a copy of the existing template file under a new name.</p>
<p>The following PHP code will be included where the form should appear:</p>
<pre><code>&lt;?php<br /><br />getModule(&quot;webformsdatabase&quot;);<br />$nwWebForm = new webformsForm();<br />$nwWebForm-&gt;renderForm();<br /><br />?&gt;<br /></code></pre>
<p>The above code will search through the forms database to find the first form item where the template name matches the current page url.</p>
<h3>CMS configuration</h3>
<p>Here is a sample of config.ini settings:</p>
<p>[webformsdatabase]<br />
sections=Contact Forms<br />
uploaddir=/home/form-uploads/<br />
dbhost=localhost<br />
dbpassword=password<br />
dbuser=username<br />
dbname=database_name</p>
<p>The fields worth mentioning:</p>
<dl> <dt>uploaddir:</dt> <dd>
<p>Specifies where the submitted files (uploaded using the file form field) will be saved.</p>
</dd> <dt>dbhost, dbuser, dbpassword, dbname:</dt> <dd>
<p>Live database connection. This is where submissions will be saved.</p>
</dd> </dl>
<p>[webformsdatabase Contact Forms]<br />
fields=subject,url,template,pubdate,redirect,captcha,adminemailaddress,adminemailsubject<br />
preview=/nw_content_manager/modules/webformsdatabase/html/index.php?section=Contact%20Forms<br />
inputfiles=_genseo1.php<br />
outputfiles=.htaccess</p>
<p>The fields worth mentioning:</p>
<dl> <dt>redirect field</dt> <dd>
<p>Enable the redirect field on the Form Edit page in the CMS to define a url to redirect to after submitting the form. If the field value doesn't look like a url then it's assumed to be a thank you message text that is displayed after submitting the form.</p>
</dd> <dt>inputfiles and ouputfiles:</dt> <dd>
<p>This is the mechanism that we use to create SEO redirects. The input file will generate a standard .htaccess file for Apache that will contain the rewrite rules for redirects. If there is another module, section or mechanism which uses the .htaccess file then it will have to write to another file (both sections can not write to the same .htaccess file). The Apache configuration will need to be updated for this case to read both files, using for example the Apache Include directive. </p>
</dd> </dl>
<p> </p>
<p>As you can see from the above presentation, the module adds a valuable function to the Neptune Web Edit CMS that allows CMS users to have more control over the forms and easily create new forms typical for contact or landing pages. Once set up, using the module is really easy and will save hours of work that would be needed to maintain form pages.</p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[iPhone and Future of Mobile Web Application Development]]></title><link>http://www.neptuneweb.com/blog/18-iphone-and-future-of-mobile-web-application-development.html</link><pubDate>Wed, 03 Mar 2010 00:00:00 -0500</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=18</guid>                      <description><![CDATA[Charlie talks about his experience developing an application for the desktop vs. mobile, and explains why iPhone/AppStore may not be the dominant platform for mobile web development going forward.]]></description>
                 <content:encoded><![CDATA[<h2>
	<i>Can iPhone applications be described as accessible, either now or in the future?</i></h2>
<p>
	<br />
	Last December, I blogged about <a href="http://www.neptuneweb.com/blog/discuss/7-why-i-like-adobe-air.html"><i>T-on-Time</i></a>, the Neptune Web contest entry to the MassDOT&#39;s Developer Contest. Although I was disappointed T-on-Time didn&#39;t win, the winners, <a href="http://www.sparkfishcreative.com/" target="_blank">MassTransit</a>  and <a href="http://iphonembta.org/" target="_blank">OpenMBTA </a>deserved it. Both of these applications were wide in scope, and comprehensive in the MassDOT services they covered (commuter rail, MBTA, bus, boat etc.). They were beautiful looking. They worked well.</p>
<p>
	In comparison, T-on-Time (my entry) focused only on the commuter rail, and was just a smaller undertaking at all levels. T-on-Time was of high quality and bug free. However, I estimated T-on-Time to have taken about 100 hours (including learning Adobe AIR), while the other apps were easily in the 400+ hr range.<a href="http://www.massdotdevelopersconference09.com/applications" target="_blank"><img align="right" alt="Various Apps that were submitted" border="1" height="160" hspace="10" src="http://www.neptuneweb.com/blog/massdot.gif" vspace="10" width="200" /></a></p>
<p>
	Since then I&#39;ve continued to use T-on-Time every time I use the rail. It&#39;s prevented me from missing my train a number of times (without overcompensating and wasting work time by arriving 10 minutes early to the station every day). I am satisfied the bugs are out of it.</p>
<p>
	A few weeks ago, MassDOT has announced a new contest. The rules are completely different this time, and the contest is focused around the real-time data feeds. A number of hardware based solutions (signs, LEDs) are expected c/o the <a href="http://groups.google.com/group/massdotdevelopers/browse_thread/thread/11f453c6ba70200b" target="_blank">MIT Hackathon</a> which preceded it.</p>
<p>
	Unfortunately, I won&#39;t be submitting to the &quot;real-time&quot; contest. The time line (1 month from announcement to submission) was ridiculously short!</p>
<h2>
	<i>What is an &quot;app&quot;?</i></h2>
<p>
	 <br />
	One &quot;criticism&quot; I have regarding the first contest, is that the contest winners were not &quot;open&quot; or accessible in any way. Since the contest was ostensibly about openness of data, I assumed that the accessibility criteria would be high on the list. The two winning applications, MassTransit and OpenMBTA, should have been judged low in those requirements. As a Blackberry user, I wasn&#39;t even able to size up the winners, because you needed an iPhone to even see them. Sort of makes one feel like an outsider.</p>
<p>
	The word &quot;app&quot;, which was used in the contest terms, and defined to be an application for any platform, seemed to mean &quot;any iPhone application&quot;. I went back to re-read the rules - was all my work wasted because I mis-read the contest rules? (I had not.)</p>
<p>
	Since November, I payed an expensive Verizon cancellation fee and bought my wife an iPhone for Christmas. That&#39;s because I know the iPhone is going to be a player in the future, and as a web developer, I need to be involved with it. Like me, a lot of people went out this Christmas and bought an iPhone.</p>
<p>
	The big question is whether the iPhone&#39;s (and it&#39;s applications) will be dominant enough in future markets to reach the majority of people in this country. In Nov 2009 I wasn&#39;t ready to throw all my eggs in the iPhone basket to develop T-on-Time. This was largely because I didn&#39;t want to bother with learning Objective-C, and getting pulled into the all-encompassing &quot;Mac thing&quot;. Instead, I chose small, desktop &quot;apps&quot; with Adobe Air, using the web technologies I already knew (albeit without any present possibility of mobile support).</p>
<p>
	Yet, still I would argue that iPhone apps are not &quot;accessible&quot; now, except for a very small portion of the population who own iPhones. This is particularly true for public agencies such as the MasssDOT which is continually working with a lowest common denominator, in terms of the public having high-tech gadgets available to them.</p>
<p>
	But in 2009 it seemed that all the edgiest and hippest developers were developing for the iPhone. It felt as if the desktop was passe - even though the app I had developed had a footprint which could easily fit on a mobile device. It was close, but not quite ready for mobile.</p>
<p>
	And so I was unsure back then. It&#39;s March. 2010, I am staying the course.</p>
<h2>
	<i>Lately, cool doesn&#39;t feel as cool anymore.</i></h2>
<p>
	<br />
	First, I started noticing a lot of articles like this:</p>
<p>
	<a href="http://www.sitepoint.com/blogs/2010/01/27/7-reasons-developers-desert-iphone-apps/" target="_blank">7 Reasons Why Developers are Deserting iPhone Apps</a> (Site Point)</p>
<p>
	And then I started reading sites like <a href="http://nerdvittles.com" target="_blank">nerdvittles.com</a> - an outstanding blog, by the way. (<a href="http://nerdvittles.com/?p=647" target="_blank">It disses iPhone</a>.)</p>
<p>
	And I just don&#39;t think iPhone/AppStore is going to be the dominant mobile platform in the future. It certainly will not be adapted by enough people to be considered accessible any time soon. In regards to web and application development, I believe something like Adobe AIR will be the unifying technology during this period of rapid change and an explosion of competing platforms. Here&#39;s why I believe this:</p>
<ul>
	<li>
		the mobile phone business is exploding with a diversity of protocols, languages, personalities, technologies.</li>
	<li>
		it&#39;s easier to clone a smaller device than a big device like a desktop, and everything is easier to knock off. Everything in the mobile device space moves faster.</li>
	<li>
		the competitors are good, and they will carve out niches in the market. Think HTC, Palm, Motorola, Nexus.</li>
	<li>
		Apple has not chosen an open OS or application platform, and this is a problem. These smaller competitors will look to openness as their advantage. Think about choosing your carrier, tethering your connection to your laptop, being able to automatically switch to VOIP when you are on wireless spot to reduce your phone bill. Openness lets you do this</li>
</ul>
<p>
	If you don&#39;t think openness is a big deal, just check out how many people are buying the Palm today because you aren&#39;t tied to a service plan. It&#39;s a much less sophisticated platform than iPhone, but openness is being used as a competitive edge against iPhone. Besides who needs all those fancy sliders and faders to make a simple phone call anyhow?</p>
<p>
	At the same time, the battle over rich media (audio and video) on the Internet has become more intense. Apple, released the iPad - another device without Flash. It&#39;s absence is starting to become more than a bit annoying. I believe Apple is hoping to shift web developers to the HTML5 canvas (vector based drawing) and video support, and away from Flash. Apple is probably smart enough to know this can&#39;t be done all at once - it will be an incremental shift, followed by a tidal wave if enough early adopters get on board. Apple should not underestimate the weight (and cost) of all the work that developers have done on Flash in the past 10 years or so.</p>
<h2>
	<i>Summary?</i></h2>
<p>
	<br />
	I&#39;d like to thank everyone involved in the MassDOT effort. I concur with<a href="http://groups.google.com/group/massdotdevelopers/msg/712a1e697554c7bd" target="_blank"> David&#39;s post today</a>,  to quote <i>&quot;It&#39;s certainly proof that just knowing where a bus might be, and not<br />
	standing around in the cold with no certainty as to whether you&#39;ll ever be picked up or not, improves the public transport experience to an immense degree. Thanks again for putting it together.&quot;</i></p>
<p>
	I really hope Adobe Air does get &quot;picked up&quot; by the mobile phones. It&#39;s the ideal platform for mobile development because it unifies all the mobile environments around standard XHTML/CSS/Javascript web development languages and technologies. With AIR your web site can be your &quot;app&quot;- very little change is needed. Who knows, if AIR does win out in the future, then T-on-Time will just start working on mobile devices! I&#39;ll keep my fingers crossed ;).</p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[Email Marketing Design and Development Best Practices]]></title><link>http://www.neptuneweb.com/blog/17-email-marketing-design-and-development-best-practices.html</link><pubDate>Tue, 02 Mar 2010 00:00:00 -0500</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=17</guid>                      <description><![CDATA[This article discusses tips and guidelines for developing email marketing messages that will appear consistent across multiple email clients and web services, as well as how to get a message from your outbox, past a recipient's junk filter, to their inbox.]]></description>
                 <content:encoded><![CDATA[<p>Email marketing is a tricky practice, with many limitations and several barriers between sender and recipient. Though there is never a guarantee that an intended recipient will actually open and <i>read</i> a message, by following certain design and content guidelines and best practices, you can at least get more messages past spam filters and visible to your actual recipient list.</p>
<h2>Part 1: How to make sure an email appears the same to all recipients.</h2>
<p>In web page development, designers benefit from browser standards &mdash; page elements will appear in a consistent manner from Firefox to older versions of Internet Explorer to Safari and beyond. The same cannot be said for email clients &mdash; depending on what program or online service a recipient uses, what they see could range from a fully-fleshed out newsletter-type layout or a stripped down text-only document.</p>
<p>There is no clear reason why desktop email application, web-based email service and mobile email application developers have not come up with a unified approach to standards and accessibility &mdash; the situation does not appear to be close to resolution. What&rsquo;s more troubling is that Hotmail/Windows Live and Gmail, <a target="_blank" href="http://weblogs.hitwise.com/us-heather-hopkins/2009/03/yahoo_mail_more_than_one_third.html">a combined 30% of the free webmail market</a>, rate &lsquo;average&rsquo;-to-&lsquo;poor &lsquo;in the support of email standards, according to the <a target="_blank" href="http://www.email-standards.org/">Email Standards Project</a>. Outlook 2007, Microsoft&rsquo;s current flagship email client also rates &lsquo;poor&rsquo;.</p>
<p>What does this mean for the groups that actually design email layouts for mass email marketing efforts? Background-less content areas, table-based layouts and a return to the early days of HTML (before CSS) are the keys to a positive, consistent recipient experience.</p>
<h3>Inline images vs. background images.</h3>
<p>Inline images are actual objects within the content of your email, through the standard HTML &lt;img&gt; tag &mdash; text can wrap around this type of image, and oftentimes an email client will require its user to &lsquo;click here to download images&rsquo; &mdash; this is a security measure. Unless a recipient has extra security enabled on their client, clicking to download will display all inline images in the body of an email.</p>
<p>Background images are just that &mdash; images that appear behind the email&rsquo;s normal content. Text will not wrap around background images, but it will appear visually in front of these images. Be aware: According to this <a target="_blank" href="http://www.campaignmonitor.com/css/#p">handy chart</a>, Gmail, Hotmail, Outlook 2007 and Lotus notes do not support background images. Consider what would happen if you have light or white text against a dark, gradient background in the body of an email. The above mentioned clients would not render the background, but would render the text &mdash; against a blank, white background. That does not make for an easy reading experience.</p>
<p><a target="_blank" href="http://www.welove72.com/_email/0809_Digital_Heart/newsletter.html">This email</a> is a good example of a mix of both inline and background images. The blue headlines are actual inline images, so even if a recipient&rsquo;s client fails to show the wood and paper backgrounds, it will at least show the blue headlines (if the user &lsquo;clicks to download&rsquo;) and the text itself.</p>
<h3>Table-based layouts</h3>
<p>In the early days of web development, table-based layouts were the standard way of presenting content. Developers would create columns and rows and populate cells with text and images for desired, grid-like effect. Though easy and popular, it also proved limiting &mdash; there could be no visual overlap of page elements and content would appear stuck in the grid-like format. CSS solved this problem for designers, allowing them to float elements or even position them manually anywhere they saw fit.   Taking another look at the <a target="_blank" href="http://www.campaignmonitor.com/css/#p">chart provided by Campaign Monitor</a>, it appears that email client support for positioned elements in spotty at best &mdash; almost none of the clients support the &lsquo;position&rsquo; property and rightfully so: absolutely positioned elements need a point of reference in order to display at particular coordinated in relation to that reference. What is your point of reference, especially in a web-based interface that is essentially a frame-within-frame display?</p>
<p>With positioned elements not consistently supported across all email clients, developers must rely on the next best thing, table-based layout, which also happens to be universally supported across all email clients. Usually this does not present a problem, but just be aware of the columns and rows that are created by this layout &mdash; even if they&rsquo;re not all visible upon final rendering of code.</p>
<p>Believe it or not, the <a target="_blank" href="http://www.welove72.com/_email/0809_Digital_Heart/newsletter.html">same email</a> that is a good example of inline/background images is also done entirely in table-based layout. Nesting tables to create the appearance misaligned elements is a common and acceptable practice in email HTML development.</p>
<p>Another good practice is to include a link to view the email as a web page (&ldquo;Having trouble viewing this email? Click here.&rdquo;). Not only will this ensure that recipients have the option to see the email fully rendered in their web browsers, it helps get your email past spam filters.</p>
<h2>Part 2: Avoiding junk mail filters</h2>
<p>Once you have an email design that you&rsquo;re sure will appear consistent for all recipients, how do you ensure your email marketing efforts to not get caught by a spam filter?  Look no further than your own junk mail folder.</p>
<p>Littered amongst the undesirable messages are subject lines indicating &ldquo;URGENT&rdquo;, &ldquo;SALE&rdquo;, &ldquo;50% off&rdquo;, &ldquo;Save!&rdquo; and other terms meant to grab the attention of unsuspecting eyes.   The bodies of these spam message will often consist of a single image &mdash; since junk filters can&rsquo;t &lsquo;read&rsquo; images, spammers replace all their actual text with images-as-text.</p>
<p>Some guidelines to follow:</p>
<ul>
    <li>A high text-to-image (actual file size) ratio is a must in order to get past spam filters. Prove to your recipient&rsquo;s inbox that you&rsquo;re not sending them junk mail by letting it read your text &mdash; and provide lots of it!</li>
    <li>Be careful in crafting a subject line &mdash; percentages and the word &lsquo;sale&rsquo; might be red flags. Use a thesaurus to find alternate words.</li>
    <li>Include contact information and an unsubscribe link &mdash; make it obvious that you are a legitimate organization that does not mind being contacted by the people to which it markets.</li>
</ul>
<p>Also consider running your message through a spam filter test like <a target="_blank" href="http://spamassassin.apache.org/">SpamAssassin</a> or <a target="_blank" href="http://www.barracudanetworks.com">Barracuda Networks</a>.  Neptune Web uses an Apache command line program from SpamAssassin that will output a numerical spam rating, with line-by-line explanation of what email elements (images, text, etc) and how they contributed to that rating.</p>
<h2>Conclusion</h2>
<p>Development for email marketing is a multi-pronged approach that requires diligence not only with your content, but how it's constructed. By keeping things simple and taking a standards-based approach, you do not need to sacrifice style for substance.</p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[Form Builder module for the Neptune Web Edit CMS]]></title><link>http://www.neptuneweb.com/blog/15-form-builder-module-for-the-neptune-web-edit-cms.html</link><pubDate>Sat, 16 Jan 2010 00:00:00 -0500</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=15</guid>                      <description><![CDATA[Read about the upcoming form builder module in the Neptune Web Edit CMS.]]></description>
                 <content:encoded><![CDATA[<p>Here at Neptune Web we always make efforts to improve our Neptune Web Edit CMS with suggestions from clients and the latest addition, although still in development, is the form builder module.</p>
<p>The form builder will allow to interactively create submission forms for web pages and automatically process submissions. We know from experience, developing web sites and supporting them, that one of the most frequent tasks requested by clients is creating new forms or making changes to existing forms. With the help of the form builder module, this task will be fully available in the CMS, without the need for server side programming each time a form is updated.</p>
<p><img alt="" src="http://www.neptuneweb.com/blog/formbuilder/preview-1.gif" /></p>
<p>Additionally the module will provide SEO improvements as the forms can be used on landing pages along with calls to action used for various campaigns.</p>
<p>The new module will have the following features:</p>
<ul>
    <li>standard form fields: text, textarea, select dropdown, file upload, check/radio boxes</li>
    <li>captcha support</li>
    <li>default field values, mandatory fields and email field validation</li>
    <li>ability to specify a page where the form will appear</li>
    <li>a custom thank you message on the page or redirect to another URL once the form is submitted</li>
    <li>generate an email notification to an administrative address containing submitted form data</li>
    <li>submissions will be saved in a database, with the ability to view and download submissions</li>
    <li>style the generated form using standard CSS programming</li>
</ul>
<p>We plan to integrate additional functionality in the future so this list will get updated if needed.</p>
<p>Please stay tuned for the second part of this artcile. We'll provide more details on the module usage and specific functions.</p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[HTML Search and Replace Tool]]></title><link>http://www.neptuneweb.com/blog/14-html-search-and-replace-tool.html</link><pubDate>Tue, 12 Jan 2010 00:00:00 -0500</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=14</guid>                      <description><![CDATA[An update to "dwreplace", a command-line, Open Source, search and replace utility for performing searching against free-form HTML files.]]></description>
                 <content:encoded><![CDATA[<p><a href="/portfolio/sysadmin-large.jpg"><img hspace="10" height="167" border="1" align="right" width="125" vspace="10" src="http://www.neptuneweb.com/portfolio/sysadmin-small.png" alt="SysAdmin March 2006 HTML Search and Replace Article" /></a>In March 2006, Neptune Web developed a simple command-line, Open Source, search and replace utility for performing searching against free-form HTML files. </p>
<p>We knew it would be useful to others, so we wrote a magazine article about it. The article appeared in Sysadmin Magazine, as <a href="/find_and_replace.html">Better Find and Replace on HTML Content</a>.The latest version of the script can be found here: <a href="/portfolio/dwreplace.pl">dwreplace.pl</a>.</p>
<p>Dwreplace isn't something that we need to change much. It does the job and doesn't require much maintenance. However, there have been a few updates since the article appeared.</p>
<p>We have added the --null option, which allows you to run <i>find </i>in conjunction with dwreplace.  e.g.</p>
<pre>
find . -print0 | dwreplace --rfile=blah.rfile --null</pre>
<p>However, you don't need to null terminated filenames to stdin (I prefer this method instead, because its simpler). You can also use regular newline terminated filenames like this:</p>
<pre>
e.g. find . -print | dwreplace --ffile=blah.rfile                  </pre>
<p>This works just like &quot;zip&quot; using the -@ option. (-@ is one of my favorite options to zip which you should know about if you don't already)</p>
<p>For example:</p>
<pre>
# make a backup, reading from newline terminated lines</pre>
<pre>
find . | zip -@ backup.zip</pre>
<pre>
# then list the files and replace the HTML text.</pre>
<pre>
zip -l | dwreplace --ffile=blah.rfile</pre>
<p>There is also a new --m option, which shows matches only, do not show unmatched files.Thanks for Joseph Lamoree for that contribution.</p>
<div>Run dwreplace --e to see an example rfile and dwreplace.pl without any options to see the options available.<br />
 </div>
<p>The script is a small contribution to Open Source, but it proves to be a useful utility which people use again and again. Last year, I was surprised to have someone send me a free T-shirt. The person ran a bamboo clothing store e-commerce site, and the script saved him a few hours.</p>
<p>If you have any contributions, questions or comments (or free t-shirts) please leave below, or email me at charles dot dalsass at neptuneweb.com.</p>
<p>Charlie</p>
<p> </p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[Optimizing Your Calls to Action]]></title><link>http://www.neptuneweb.com/blog/11-optimizing-your-calls-to-action.html</link><pubDate>Mon, 11 Jan 2010 00:00:00 -0500</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=11</guid>                      <description><![CDATA[This article explores ways to optimize your calls to action to improve your website's lead generation capabilities.]]></description>
                 <content:encoded><![CDATA[<p>An effective website is a tool that optimizes your business by drawing in visitors and encouraging them to return. From a user perspective, it is very frustrating to have to search around in order to find out how and where to buy a product or how to connect with a company for more information. From a business perspective, the last thing you want is to drive visitors away, discourage them from making the purchase or in any way deter the process of converting visitors to leads.</p>
<p>In order to prevent this, you need to make it very easy for your visitors to take the next step. Strong and effective calls to action are the most important aspect of your website, yet this area is often forgotten by web designers. Remember, the reason you have the website is to encourage visitors to DO something. The strength or your calls to action and lead conversion rates can be improved by following a few simple tips:</p>
<h2>Placement:</h2>
<p>Place your call to action where it can be seen without difficulty. It should be above the fold so that visitors can see it without scrolling down over the site. The call to action should be just next to or within the relevant content so that visitors see it as they are ready to take the next action, such as making a purchase or signing up for more info. It should go without saying that if visitors have trouble finding your calls to action you will be losing opportunities and leads.</p>
<h2>Color:</h2>
<p>The most important thing to remember in regard to color is that your call to action needs to stand out on the page. If you have a light background, use a dark, contrasting color to enhance the call to action and draw the visitor&rsquo;s eye.</p>
<h2>Images:</h2>
<p>You can also try using images to draw attention to your calls to action. Make the image a link to draw visitors to a new landing page where you can capture information.</p>
<h2>Wording:</h2>
<p>Give an appealing description of the action a visitor is about to take such as &lsquo;send me free offers&rsquo;. The wording should explain to the visitor the benefit of clicking on the link or submitting their information, so that the visitor feels they are being rewarded instead of pestered for information. To this end, try to use descriptive language in the links, while avoiding use of ordinary language like &lsquo;submit info&rsquo;. This is also a great opportunity to for inserting keywords to improve search engine optimization. In addition to the descriptive language, you should attempt to use softer tones. Instead of using a phrase along the lines &lsquo;buy&rsquo;, use a phrase such as &lsquo;try it&rsquo;. Lastly, convey the immediacy of the action using phrases such as &lsquo;start free trial now&rsquo;.  These suggestions about phrasing elements are meant to put the visitor at ease and should increase the chances of a visitor responding to your calls to action.</p>
<h2>Size:</h2>
<p>Bigger buttons do tend to have the highest response rate and are therefore more likely to convert visitors to leads. However, this advice should be taken within reason. Use your best judgment to create a button big enough to draw the visitors eye, but not so flashy or huge as to push the visitor away.</p>
<h2>Testing:</h2>
<p>Most importantly, you need to test to find best call to action for your particular site by experimenting a bit. Try a variation of locations, colors, sizes. The best way to find out what works for your audience is to try different modifications and encourage users to give feedback. You can also use a tool like the Google Website Optimizer, a free testing tool that allows you to test different aspects of website to improve conversion rates. Find out which calls to action produce the best results for your business and then put them to use.</p>
<p>Calls to action are intended to convert visitors to leads to strengthen your website. The tips listed above can be used to form a coherent strategy for bringing your visitors closer to their objective, while also improving your conversion rates and ultimately increase your ROI. A successful website will help you do just that &ndash; improve your ROI to optimize your business. <br />
 </p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[Best Practices for Popular User Interface Elements]]></title><link>http://www.neptuneweb.com/blog/10-best-practices-for-popular-user-interface-elements.html</link><pubDate>Mon, 11 Jan 2010 00:00:00 -0500</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=10</guid>                      <description><![CDATA[This article identifies best practices to follow to create a positive and compelling user experience.]]></description>
                 <content:encoded><![CDATA[<p>Interface design is just as important as the quality of the content on your website. When creating a website, attention must be paid to the most significant interface elements- appearance and usability. A design that does not take these elements into account will drive your audience away and as a result, your ROI will suffer. To yield results, the design should be clean and succinct, so that visitors can access information quickly and without hassle. Below, we have listed a few tips about best practices for user interface elements to help you maintain a compelling and effective website:</p>
<h2>1.      Appearance of search box</h2>
<p>On large sites, visitors are more inclined to use the search box instead of navigation bars; therefore the search box should be immediately visible. If not, the visitor may be able to find it after a frustrating hunt, but more likely the visitor will assume there is no search function. The search box should be easy to see and large enough to stand out amongst other elements on the page. Unless the audience is quite unique, the box should be placed in the customary position on the upper right side because this is where visitors have become accustomed to finding it. You may want to include a magnifying glass graphic, as it has become understood universally as the search symbol.</p>
<h2>2.      Location of shopping cart and log-in register functions</h2>
<p>Visitors tend to look to the top-right corner of the page when searching for &lsquo;shopping cart&rsquo; or &lsquo;register now&rsquo; links. Unless you have a reason to place it somewhere else, this element should be kept in this familiar location so as not to slow down or disrupt the user experience.</p>
<h2>3.      Placement of opt-in form</h2>
<p>Placement of the opt-in form on the upper left leads to the highest number of opt-ins. Most cultures read right to left. The visitor&rsquo;s eye begins at the top left corner of the site and will return to rest there. The opt-in should be placed in this area of high visibility because visitors will be more likely to fill it out.</p>
<h2>4.      Clearly marked collapsible/expandable content</h2>
<p>Collapsible panels can make for a positive user experience because they tend to make the layout look simpler. However, if you use collapsible panels make sure they are clearly marked or they prove detrimental to usability. Your website should clearly differentiate between normal links and links that reveal new content via JavaScript. Collapsible content should be indicated with symbol such as a plus/minus or an arrow, etc.</p>
<h2>5.      AJAX Loading Indicator</h2>
<p>If your site uses Ajax, be sure to let the visitor know when an Ajax request is being processed or they may become frustrated and leave your site. You can do this by highlighting a &lsquo;loading&rsquo; or similar message in the area near the action or simply using the hourglass symbol.</p>
<h2>6.      Use of Javacript &amp; IFrames</h2>
<p>Javascript and IFrames increase the amount of time it takes for your site to load, so in this area, more is not necessarily better. You want your site to load as fast as possible because visitors decide in a matter of seconds whether they will stay to engage with the site or navigate away. If your site takes more than 20 seconds to load, you are probably losing half of your visitors immediately. Check your websites stats for bounce rates, exit pages and other data to see whether the load time is optimal.</p>
<h2>7.      Use of Flash</h2>
<p>Flash pieces will look good on your site, but keep in mind that flash pieces and large images will contribute to long loading times and will also use up a visitor&rsquo;s actual computer resources (like CPU and memory). It is important to include a &lsquo;skip&rsquo; button on any flash piece that does not immediately present useful content or navigation, or a flash piece that appears as the first page of a site before directing a user to the true homepage so that visitors are able to skip the flash piece if they are short on time.  A volume control and/or mute button is also a good idea on flash pieces that use sound, but don&rsquo;t necessarily rely on it &ndash; you never know what kind of physical environment your visitor is actually in. It could be a busy airport terminal or a library.</p>
<h2>8.      Advertising</h2>
<p>Be careful about the amount of advertising on your site. If you have too much advertising on your website, interested visitors may not stay to find the important content. Some large sites do have a lot of ads, but this is because they have a high amount of traffic. Most sites should stick to as little advertising as possible.</p>
<h2>9.      Easily Identifiable Links</h2>
<p>Visitors should never have trouble differentiating regular texts and links. Links should be made a different color and underlined so that they stand out. This will enable visitors to find the links they are searching for, while also helping them avoid the frustration of inadvertently navigating away from a page.</p>
<p>User interface elements should be simple and well-organized. Good technical design and content design go hand in hand for successful website. While some creativity is ok, it is usually best to follow the customs of the industry because visitors have often become familiar with a certain type of design or architecture. Taking the time to carefully design your site for your audience will improve the visit stats and lead generation capabilities. Your website is likely intended to improve or grow your business in some form, so careful site design is essential for creating a successful, advantageous website.</p>
<p> </p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[SEO approaches in HTML design and development]]></title><link>http://www.neptuneweb.com/blog/9-seo-approaches-in-html-design-and-development.html</link><pubDate>Wed, 30 Dec 2009 00:00:00 -0500</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=9</guid>                      <description><![CDATA[The article explores ways to optimize your content for search engine visibility without sacrificing style.]]></description>
                 <content:encoded><![CDATA[<p>More and more, production design has become a game of trade-offs it when comes to developing a unique site look and feel while maintaining search engine optimization (SEO) basics.  A site that relies on Flash or images-used-as-text might elicit &ldquo;oohs&rdquo; and &ldquo;aahs&rdquo; from page visitors, but also risks the ignorance of search engine robots and spiders.</p>
<p>Here are some areas that are considered aesthetically limited by SEO requirements, but don&rsquo;t necessarily have to be:</p>
<h2>Headline text</h2>
<p>Headline text, H1 and H2 tags specifically, are very important to SEO &ndash; they provide context for your content in the eyes of search engines as well as act as visual indicators for actual page visitors.  A page without an H1 tag is like a newspaper article without a headline &ndash; how would one know what it&rsquo;s about without reading part or all of the article itself?</p>
<p>Like most page text, headlines have traditionally been limited to web safe fonts &ndash; a set of approximately 10 system fonts that are installed by default on Mac and Windows PC systems.  If a site headline font is set to be something a site visitor does not have installed on their system, their browser will default to a very generic serif or sans-serif font.</p>
<p>How does a developer create exciting, unique headline when your options are limited to 10 fonts?  The surprising answer is images. By using four Cascading Style Sheet (CSS) properties, This headline:</p>
<h2 style="color: rgb(136, 0, 0); font-size: 32px; font-weight: bold; font-family: Arial,Helvetica,sans-serif;">My Great Website Headline</h2>
<p>can turn into this headline:</p>
<h2 style="width: 412px; line-height: 43px; background: url(&quot;/blog/headline_2.gif&quot;) repeat scroll 0% 0% transparent; text-indent: -999em;">My Great Website Headline</h2>
<p>without losing any search engine visibility.</p>
<p>The approach is to realize that search engines and humans view web pages differently.  Whereas Joe Site Visitor sees a page as it&rsquo;s rendered by a web browser, search engine robots and spiders see it for something different: pure code.  CSS allows site designers to manipulate a sites layout and visual styles, without necessarily requiring a manipulation of code.  In the example above, the code for each headline to appear is the same:</p>
<p><font face="Courier New, Courier, monospace">&lt;h1&gt;My Great Website Headline&lt;/h1&gt;</font></p>
<table hspace="5" cellspacing="1" cellpadding="5" border="0" bgcolor="#000000" align="right" width="195" title="What are Cascading Style Sheets?">
    <tbody>
        <tr>
            <td>
            <h3>What Are Cascading Style Sheets?</h3>
            </td>
        </tr>
        <tr>
            <td>
            <p>Cascading Style Sheets (CSS) is a language that, among other things, defines web page styles based on existing markup languages. CSS allows developers to set universal or specific styles for text, images and hundreds of other page elements.</p>
            </td>
        </tr>
    </tbody>
</table>
<p>However, in the second example, CSS in the pages header area is used to create a special style for the H1 tag:</p>
<p><font face="Courier New, Courier, monospace">h1 {<br />
width: 412px;<br />
line-height: 43px;<br />
background: url (mygreatwebsite.gif); <br />
text-indent: -999em;<br />
}</font></p>
<p>CSS code gives the actual output of the tag a width (412px) and a height (43px), moves the text out of view (text-indent:-999em;), and inserts an image to fill in the defined space (mygreatwebsite.gif).  The H1 tag remains intact without the use of images or other non-compliant methods &ndash; indicating to search engines exactly how important that text is.</p>
<p>This method is very handy for adding a little flair to your page text, but keep in mind the amount of work needed for each headline &ndash; each would be a custom piece of code that would require a background image to be created.  This could get daunting for sites with many pages, or sites that use a content management system that has hard-to-use set of styles or limited customization.</p>
<h2>Animations</h2>
<p>Flash animations or applications have added a new layer of interactivity and creativity to web development over the last 10 years, however one area in which the technology is severely lacking is SEO.  Though Google has made the recent announcement that its search engine will be able to &lsquo;crawl Flash&rsquo;, there is still the matter of optimized Flash output, pagination, proper syntax, proper tags and linking, to name a few items &ndash; search engine technology is quite a ways off from indexing Flash elements into something usable.</p>
<p>Is Flash the end-all, be-all of site animation?  Not at all.  JavaScript libraries like jQuery and MooTools allow developers to incorporate animations and other graphical effects that give page elements a Flash-like appearance, without being Flash. Take a look at Lahive&rsquo;s homepage animation -- http://www.lahive.com/.  Done entirely in jQuery, the home page banner auto-animates with a fading transition between case studies.  Users can manipulate which frame they&rsquo;re on and even highlight text.  Best of all, text in this banner area is visible to search engine spiders.</p>
<h2>Have Your Cake and Eat It Too</h2>
<p>As shown in examples above, search engine optimized-pages do not have be vanilla affairs that lack creativity.  By using a range of tools from standard XHTML/CSS coding to more advanced plug-ins like jQuery and MooTools, developers can achieve something both developmentally sound and visually appealing.</p>]]></content:encoded>

        </item><item>
                         <title><![CDATA[What to Look for in a Multilingual CMS for your Web Site]]></title><link>http://www.neptuneweb.com/blog/8-what-to-look-for-in-a-multilingual-cms-for-your-web-site.html</link><pubDate>Mon, 28 Dec 2009 00:00:00 -0500</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=8</guid>                      <description><![CDATA[This video shows how the Neptune Web Edit CMS enables you to work with multilingual content.]]></description>
                 <content:encoded><![CDATA[<p>Having spent some time working on multiple (foreign) language web sites, I&rsquo;d like explain a few things that I think differentiate multilingual CMS systems. And (being a bit biased) I will demonstrate each of the following advantages using Neptune Web&rsquo;s CMS software, Neptune Web Edit and its accompanying &ldquo;localization module&rdquo;.</p>
<p> &ldquo;Localization module &ldquo; is a technical name for the apparatus which enables you to add, edit and manage content on a multilingual web site. It is a great tool for turning your site from a single language site into an international web site.</p>
<p>Before I go into the details, I&rsquo;d like to start with a basic assumption:</p>
<p>The process of Internationalization can mean a number of things to people. For certain types of sites, adding a Google &ldquo;Translate&rdquo; widget to every page on your site is sufficient. We love the computer translation provided by Google, but at times these translations can be, well, embarrassing. I&rsquo;m assuming you aren&rsquo;t interested in this type of internationalization effort, which although very rapid to implement, is not of high enough quality for most commercial applications. I&rsquo;m assuming you are willing to pay translators to q/a these computer translations because the risk of having a word turn into another word is just too great.</p>
<p>Ok, so here are the features I&rsquo;d like to emphasize as being very important when choosing a multilingual CMS system for your website.</p>
<ul>
    <li>The CMS should &ldquo;play well&rdquo; with your web sites server-side language or web environment (Neptune Web Edit is PHP/MySQL or &quot;LAMP&quot; based).</li>
    <li>Ability to edit static content as static content. Ability to post ad-hoc multilingual content, such as a random PDF or web page, without being constrained by a monolithic system which expects all language sites to be the same.</li>
    <li>An understandable file and folder system, which makes referencing, web content simple.</li>
    <li><span><span><span> </span></span></span>Ability to see when the lead language has changed, and the workflow to let the translators know.</li>
    <li>The ability to have computer based translation services assist translation, but not dictate the entire translation. Real human translators must be able to review and edit the computer assisted translations.</li>
    <li>The ability to define your choose language widget in whatever way you like. No restrictions on design.</li>
    <li>As much independence from the CMS as possible.</li>
    <li>For dynamic content, the ability to filter content according to logical, database based groups. I.e. 10 fields per record, with the fields grouped together by record. The ability to group translation strings into logical, meaningful groups.</li>
    <li>The ability to translate in WYSIWIG format.</li>
    <li>The ability to publish content for a single language only.</li>
    <li>Content should default to the &ldquo;lead language&rdquo; (typically English) if it has not been translated.</li>
    <li>Each multilingual site should appear like a separate site as much as possible. This will enhance your search engine ranking because you will appear to be 5 sites, for example, instead of one.</li>
</ul>
<p>Now that you&rsquo;ve read the list, let me demonstrate each of the features in the video below.</p>
<p> </p>
<object id="csSWF" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="498" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,115,0">
                <param name="src" value="blogentryforcms_controller.swf"/>
                <param name="bgcolor" value="#1a1a1a"/>
                <param name="quality" value="best"/>
                <param name="allowScriptAccess" value="always"/>
                <param name="allowFullScreen" value="true"/>
                <param name="scale" value="showall"/>
                <param name="flashVars" value="autostart=false"/>
                <embed name="csSWF" src="blogentryforcms_controller.swf" width="640" height="498" bgcolor="#1a1a1a" quality="best" allowScriptAccess="always" allowFullScreen="true" scale="showall" flashVars="autostart=false&thumb=FirstFrame.png&thumbscale=45&color=0x000000,0x000000" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"></embed>
            </object>]]></content:encoded>

        </item><item>
                         <title><![CDATA[Why I like Adobe AIR]]></title><link>http://www.neptuneweb.com/blog/7-why-i-like-adobe-air.html</link><pubDate>Thu, 12 Nov 2009 00:00:00 -0500</pubDate>
                        <dc:creator>NeptuneWeb.com</dc:creator><guid>http://www.neptuneweb.com/blog/?id=7</guid>                      <description><![CDATA[I recently had time to experiment with Adobe's AIR technology and was very optimistic about its potential.]]></description>
                 <content:encoded><![CDATA[<p>
	<a href="http://www.neptuneweb.com/mbta"><img align="right" alt="" border="0" height="424" src="http://www.neptuneweb.com/blog/fullview.png" width="169" /></a>Neptune Web recently submitted an entry to the <a href="http://www.eot.state.ma.us/default.asp?pgid=content/developer&amp;sid=about">MassDOT Developer&#39;s Challenge</a>. You can read about our entry, T-on-Time, at <a href="http://www.neptuneweb.com/mbta">http://www.neptuneweb.com/mbta</a>.You can see the other submissions as well from the <a href="http://www.massdotdevelopersconference09.com/applications">MassDOT Developers Challenge Applications page</a>.<b> </b></p>
<p>
	We chose to develop the application using Adobe AIR, for the following reasons;</p>
<p>
	We wanted a widget style format, because the application needs to be always-present (the point of it is to constantly keep you aware of your uncoming train while at work). We did not want to clutter the desktop with stand-alone applications. We looked at various widget toolkits such as Yahoo! widgets and Mac&#39;s Dashboard widgets, but they were all too closed format to be able to distribute easily. We didn&#39;t want to learn a new language because of the short time line. All the platforms worked once you downloaded the widget platform they offered, but who really wants to download a huge Yahoo! or Google software filled with all kinds of ads and marketing tracking? It&#39;s really a challenge to distribute your application when you need to overcome a barrier like that.</p>
<p>
	Adobe Air was our choice mostly because Adobe has a certain reputation of open-ness (think PDF which has the reputation to be entirely non-proprietary) that the other widget platforms didn&#39;t offer. Adobe keeps it really simple, and makes it very straightforward to get a quick desktop application up and running. And, you don&#39;t have to learn any new technologies.</p>
<p>
	If you are web developer, then all the tricks you mastered with Javascript, HTML and CSS work within AIR. You will really feel comfortable on the platform, with the only difference being that you are programming for the desktop. A pop up window is as simple as creating a link with a window.open() function, just like you do on the web. You do need to run the runtime each time you modify your program, but I pretty quickly figured out you could add a &quot;reload&quot; link to every screen, which allows you to reload your application without running the environment from a DOS prompt.</p>
<p>
	One very nice thing about this type of development is browser bugs are a thing of the past. Well, mostly at least. It&#39;s just that only a single &quot;browser&quot; (Safari Web Kit) needs to be targeted, making the HTML/CSS debugging process very, very short. T-on-Time was a moderately complex CSS layout, but after getting it working on a PC it ran without flaw on Mac OSX. I was quite (happily) surprised by this. Good thing because I didn&#39;t have time to fix bugs with the deadline anyway! I would recommend not to get too lazy with these types of layout bugs, however, since applications written in AIR can quite easily be ported to the web - and someone will probably ask for a web version! Porting to the web will mean switching out any proprietary desktop-only extensions you may have used.</p>
<p>
	In addition to your standard HTML/CSS and Javascript, AIR provides Javascript extensions which allows you to save user information in a small, SQL-Lite database. You can query the database just like you do in a PHP or ASP environment.</p>
<p>
	One final comment about the platform - there are many cases today where restrictions to remote web resources prevent you from developing the applications you want to. For example, many web services can&#39;t be directly accessed through Javascript XMLHTTPRequest objects, which force you to proxy them back through the website of origin. This can get you into trouble with rate restrictions, such as Twitter&#39;s rate limitations on number of requests per hour, which will all come from a single IP address. It&#39;s much nicer to distribute your application to users and have them request the resource, limiting the impact a single IP has on an external site or service.</p>
<p>
	Overall this is a great platform. It really brings the web back &quot;home&quot;. Although I do miss testing my applications using Firebug, I don&#39;t miss having to spend half my time on incredibly annoying IE6 css layout bugs.</p>]]></content:encoded>

        </item></channel></rss>