<?xml version="1.0" encoding="UTF-8"?>
<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/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>blogs.teztech.com &#187; T3city</title>
	<atom:link href="http://blogs.teztech.com/category/t3city/feed" rel="self" type="application/rss+xml" />
	<link>http://blogs.teztech.com</link>
	<description>Programming, Rock Climbing and Running</description>
	<lastBuildDate>Mon, 27 May 2013 23:47:36 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.9.1</generator>
	<item>
		<title>Free DNS Servers on Amazon Web Services (AWS)?</title>
		<link>http://blogs.teztech.com/2013/05/27/free-dns-servers-on-amazon-web-services-aws</link>
		<comments>http://blogs.teztech.com/2013/05/27/free-dns-servers-on-amazon-web-services-aws#comments</comments>
		<pubDate>Mon, 27 May 2013 23:47:36 +0000</pubDate>
		<dc:creator><![CDATA[pj]]></dc:creator>
				<category><![CDATA[Networking]]></category>
		<category><![CDATA[T3city]]></category>

		<guid isPermaLink="false">http://blogs.teztech.com/?p=97</guid>
		<description><![CDATA[Recently, I was researching how to run Ubuntu instances on AWS. I found http://aws.amazon.com/free. The free tier includes 750 hours for EC2 Linux Micro Instances and 30GB of EBS storage. After clicking around, I figured out this is what you get with the Micro EC2 Instance running Ubuntu 12.04 LTS: The default Ubuntu 12.04 LTS AWS image boots [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Recently, I was researching how to run Ubuntu instances on AWS. I found <a href="http://aws.amazon.com/free/">http://aws.amazon.com/free</a>. The free tier includes 750 hours for EC2 Linux Micro Instances and 30GB of EBS storage. After clicking around, I figured out this is what you get with the Micro EC2 Instance running Ubuntu 12.04 LTS:</p>
<ul>
<li>The default Ubuntu 12.04 LTS AWS image boots on a 8GB  root partition created on EBS. This allows you to run a a normal Ubuntu server. If you create a larger EBS partition, Ubuntu will automatically expand the file system on first boot, but 8GB should be plenty for a typical DNS server.</li>
<li>The Micro Instances includes 600MB of RAM</li>
<li>I thought I read that the Micro Instance includes 2 CPU cores, but the image I booted only shows 1 CPU.</li>
</ul>
<p>This should be fine for a backup DNS server.<span id="more-97"></span></p>
<p>The AWS documentation is large and intimidating. In the past, AWS encouraged a lot of specialized AWS development to create paravirtualized kernels that worked under Xen combined with VM instances that booted up and automatically configured  themselves to use S3 storage. This is a great model for web sites and other Internet based services that require scaling across many nodes, it seemed like overkill for something like DNS that typically only requires a couple of high availability servers. Fast forward several years later and now AWS lets you easily create VM backed by EBS storage that can be managed like a typical server. Here are the steps I followed to create my AWS based DNS server:</p>
<ol>
<li>Opened an AWS account  - credit card is required (!)</li>
<li>Configure and start a new Ubuntu 12.04 LTS micro instance. The free instance is clearly identified and the defaults end up with an EBS backed server with a 8GB root partition.</li>
<li>Add a public IP address: <a href="http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html">http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html</a></li>
<li>Login to the new instance with the AWS generated SSH key pair: <a href="http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AccessingInstancesLinux.html">http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AccessingInstancesLinux.html</a></li>
<li>Configure your new instance normally</li>
</ol>
<p>Now we just have to wait and see if it is really free!</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.teztech.com/2013/05/27/free-dns-servers-on-amazon-web-services-aws/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>New Domain Name Scams</title>
		<link>http://blogs.teztech.com/2013/03/12/new-domain-name-scams</link>
		<comments>http://blogs.teztech.com/2013/03/12/new-domain-name-scams#comments</comments>
		<pubDate>Tue, 12 Mar 2013 18:11:48 +0000</pubDate>
		<dc:creator><![CDATA[pj]]></dc:creator>
				<category><![CDATA[Abuse]]></category>
		<category><![CDATA[T3city]]></category>

		<guid isPermaLink="false">http://blogs.teztech.com/?p=93</guid>
		<description><![CDATA[Most people know about Cybersquatting, but there are plenty of other scams involving domain names. Here are a few: http://en.wikipedia.org/wiki/Domain_tasting http://en.wikipedia.org/wiki/Domain_name_front_running A friend forwarded me an email yesterday with a scam I haven&#8217;t seen before. He received domain name spam that looked like this: Take time to secure friendsdomainnamewithans.com today. We understand the importance of capturing [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Most people know about <a href="http://en.wikipedia.org/wiki/Cybersquatting">Cybersquatting</a>, but there are plenty of other scams involving domain names. Here are a few:</p>
<ul>
<li>http://en.wikipedia.org/wiki/Domain_tasting</li>
<li>http://en.wikipedia.org/wiki/Domain_name_front_running</li>
</ul>
<p>A friend forwarded me an email yesterday with a scam I haven&#8217;t seen before. He received domain name spam that looked like this:<span id="more-93"></span></p>
<blockquote><p>Take time to secure friendsdomainnamewithans.com today.</p>
<p>We understand the importance of capturing all similar Domain Names in alignment with your business. Make an offer today in order for us to go after the domain name for you.<br />
To confirm interest in owning this domain, fill out form here:</p>
<p>http://dr-gs.com/24343840mavidu-MCI</p>
<p>[...]</p></blockquote>
<p>When I checked yesterday, the domain name was registered to a company with a name something like  &#8220;China Domains&#8221; (too bad I didn&#8217;t save the page). The domain was set to expire in a year. When I checked the domain name today, it was unregistered. It looks like somebody is combining spam with domain tasting&#8230; so creative!</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.teztech.com/2013/03/12/new-domain-name-scams/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Web Service for Document Conversion &#8211; an Odyssey</title>
		<link>http://blogs.teztech.com/2009/06/28/web-service-for-document-conversion-an-odyssey</link>
		<comments>http://blogs.teztech.com/2009/06/28/web-service-for-document-conversion-an-odyssey#comments</comments>
		<pubDate>Sun, 28 Jun 2009 18:02:25 +0000</pubDate>
		<dc:creator><![CDATA[pj]]></dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[T3city]]></category>

		<guid isPermaLink="false">http://teztech.com/?p=28</guid>
		<description><![CDATA[A couple of years ago, I needed a way to convert Microsoft Word documents to Pdf from a C# program. The application I was working on processed hundreds of documents and was run by the system scheduler every day at around 3am, so manual conversion was not an option. I wasn&#8217;t in control of the [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><a href="http://teztech.com/wp-content/uploads/2009/06/convertdemopdf.png"></a><a href="http://teztech.com/wp-content/uploads/2009/06/convertdemo.png"></a>A couple of years ago, I needed a way to convert Microsoft Word documents to Pdf from a C# program. The application I was working on processed hundreds of documents and was run by the system scheduler every day at around 3am, so manual conversion was not an option. I wasn&#8217;t in control of the source documents, so I had to accept the documents the way they were given to me. I needed to do additional processing on the documents, so I wanted to convert them into a universal format. I already had a <a href="http://itextsharp.sourceforge.net/">good library for reading Pdf files</a>.  After researching my options, I settled on using <a href="http://www.openoffice.org/">OpenOffice</a> to do the conversion. OpenOffice has a pretty good Word filter, the ability to create Pdfs and an automation interface accessible to all .Net languages, including C#, so it was a good fit. I know there are commercial solutions and ways to automate Microsoft Office, but the OpenOffice solution was free and fairly easy to use.</p>
<p>Recently, I upgraded my development system from OpenOffice 2.x to OpenOffice 3.1. I can&#8217;t remember now the main reason I upgraded, but I was looking forward to being able to add the ability to convert docx to pdf (Office Open XML support was added in OpenOffice 3.x). I figured the upgrade might require some minor changes to my document conversion code, but it turned out not to be so simple.<br />
<span id="more-28"></span></p>
<p style="text-align: center;"><a href="http://teztech.com/wp-content/uploads/2009/06/convertdemosmall.png"><img class="alignnone size-medium wp-image-31" title="Conversion Server Demo" src="http://teztech.com/wp-content/uploads/2009/06/convertdemosmall-300x196.png" alt="Conversion Server Demo" width="300" height="196" /></a><a href="http://teztech.com/wp-content/uploads/2009/06/convertdemopdf.png"><img class="alignnone size-medium wp-image-30" title="Converted Pdf" src="http://teztech.com/wp-content/uploads/2009/06/convertdemopdf-300x228.png" alt="" width="300" height="228" /></a></p>
<p>The first problem was that OpenOffice no longer showed up under &#8220;Add Reference&#8221; in Visual Studio. After some Google searches, I finally <a href="http://blog.nkadesign.com/2008/net-working-with-openoffice-3/">stumbled across a solution</a>.  OK, wow, digging though install cab files for DLLs, hacking the registry and manipulating the PATH is ugly, but it worked &#8211; at least once. Almost as soon as my test program ran successfully, Visual Studio locked up. The only way to get control back was to kill the Visual Studio process, then restart it. Every time I opened the solution file, after just a few seconds, Visual Studio would lock up again. Removing every trace of the OpenOffice DLL references would prevent the lockups, but without OpenOffice, I could not convert documents. I eventually figured out that the problem was that the library project that used OpenOffice was also included in my web site project. Because the web site uses the library, too, the OpenOffice reference is automatically copied to the web site project. Normally, this would be no big deal &#8211; just a couple of small DLL files in the web site bin folder that would not be used &#8211; but in this case, Visual Studio could not successfully build the web site project as long as the OpenOffice DLLs were referenced.</p>
<p>Now that using OpenOffice was no longer as simple as &#8220;Add Reference&#8221;, it was time to take a look at a way to decouple my application from the OpenOffice DLLs. The API my application needs is pretty simple: Given the bytes of a file in Doc (or .docx) format, return the bytes of the file in Pdf format. Also, there are security risks whenever you open a file in a complicated piece of software like OpenOffice. These two facts pointed me to turning the Pdf conversion into a web service. The client application and web service can be partitioned across computers, so, if I wanted to, I could run the Pdf conversion service on a virtual machine with its own install of OpenOffice and tight security and resource control. The web service API didn&#8217;t need fancy XML: Clients could post the Doc file via a standard HTTP MIME encoded form. The result would be a the PDF byte stream returned via HTTP. This would make the service easy to develop, test and use from clients on many platforms.</p>
<p>I typically develop my large web based applications in C# and Asp.Net. However, for small services like document conversion, I often use PHP. Simple PHP applications can be just a file or two and I can move a PHP based service over to any web server that supports PHP. So, my first attempt at a document conversion service was written in PHP and used the OpenOffice COM API. Using my earlier OpenOffice API code as a guide and some PHP sample code I found on the web, I was able to quickly create a command line PHP application that could perform Pdf conversions. With this proof of concept working, I coded up the PHP web service. But the web service wouldn&#8217;t work. I could see in Task Manager that the OpenOffice executables were launched, but any code running under the web server that tried to access the OpenOffice COM objects would freeze up.</p>
<p>I spent a lot of time trying different security settings for various files and DCOM. I even tried creating a dedicated user and configuring DCOM to run OpenOffice as the dedicated user when the OpenOffice COM objects were activated. I changed Windows event log settings to log all security violations. Nothing would work and I couldn&#8217;t see anything useful in Event Viewer. I tried coding up a simple Asp.Net application and got the same results under the .Net OpenOffice API. Under both PHP/COM and C#/.Net, OpenOffice could be automated by a command line program but would not run under IIS. Right now, I develop on Vista and deploy to Windows Server 2008, so one might think the problem was trying to use IIS 7, but OpenOffice 2 didn&#8217;t have similar problems.</p>
<p>Finally, I gave up trying to run OpenOffice directly under IIS. The problem was either some type of security issue or that OpenOffice was trying to pop up registration dialogs. In Windows, the simple way to run a program under a given user account is to run the program as a Windows Service. It turns out that it is <a href="http://www.codeproject.com/KB/system/WindowsService.aspx">pretty easy to create a Windows Service in C#</a>. The basic idea I came up is was:</p>
<ol>
<li>Install OpenOffice</li>
<li>Create a Windows user account dedicated to Pdf conversion.</li>
<li>Login as the Pdf conversion user and make sure that OpenOffice opens without prompting for registration, crash feedback, etc. (I suspect that the reason OpenOffice 3 won&#8217;t run properly under IIS is that it is prompting the user to register).</li>
<li>Create a Windows Service with a simple API to convert documents</li>
<li>Install the Windows Service and configure it to run as Pdf conversion user</li>
<li>Access the Windows Service from my document conversion Web Service</li>
</ol>
<p>Here is how the API calls flow: <em>Application -&gt; Web Service -&gt; Windows Service</em></p>
<p>As I mentioned earlier, the API between the application and the web service was standard a HTTP Post. Between the Web Service and the Windows Service, I originally planned to use a simple, proprietary TCP/IP protocol. As long as you aren&#8217;t try to get too fancy coding thread pools and asynchronous I/O, at least in C/C++, it&#8217;s pretty easy to open a TCP socket and communicate between client and server with a line oriented protocol (like HTTP, POP3, SMTP, etc.). But, since both the Web Service and the Windows Service were going to run on Windows (at least for now), I decided to take a look at .Net Remoting. The .Net remoting solution was easy to code and use so I ended up sticking with it.</p>
<p>Below is some code to show you how everything fits together:</p>
<p>The C# interface <em>IConverter</em> is compiled into a DLL. The DLL is referenced by the client (Web Service) and server (Windows Service).</p>
<p><!-- BEGIN IConverter --></p>
<pre class="csharpcode">
    <span class="kwrd">public</span> <span class="kwrd">class</span> ConverterEndpoints
    {
        <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">int</span>    Port = 7047;
        <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">string</span> Uri  = <span class="str">"DocumentToPdf"</span>;
    }

    <span class="kwrd">public</span> <span class="kwrd">interface</span> IConverter
    {
        <span class="kwrd">void</span> Convert(<span class="kwrd">string</span> srcDocument, <span class="kwrd">string</span> destPdf);
    }
</pre>
<p><!-- END IConverter --></p>
<p>The class <em>ConverterEndpoints</em> holds a couple of constants that the client and server use to setup the TCP port and service name. The code below demonstrates how <em>ConverterEndpoints</em> is used in the Windows Service. I&#8217;ve included code for the entire class so you can see how easy it is to program a Windows Service and access the Windows Event Log in C# &#8211; no 3rd party libraries are required.</p>
<p>The original version of this interface passed the files as simple byte[] variables. Theoretically, the files never need to be written to disk (input and output is via HTTP). But, I found that I could easily pass small byte[] variables across .Net remoting but large byte[] variables failed. Since the Web Service and the Windows Service run on the same machine and the file has to be written to disk for OpenOffice to do the conversion, I settled for creating temporary files and passing the names of the files between the Web Service and Windows Service.</p>
<p><!-- BEGIN WindowsService --></p>
<pre class="csharpcode">
   <span class="kwrd">class</span> WindowsService : ServiceBase
    {
        <span class="kwrd">protected</span> EventLog _log;
        <span class="kwrd">protected</span> TcpChannel _channel;

        <span class="kwrd">public</span> WindowsService()
        {
            ServiceName = <span class="str">"Teztech Document Conversion"</span>;
            EventLog.Source = <span class="str">"Teztech Document Conversion"</span>;
            EventLog.Log = <span class="str">"Application"</span>;
            
            <span class="rem">// These Flags set whether or not to handle that specific</span>
            <span class="rem">//  type of event. Set to true if you need it, false otherwise.</span>
            CanHandlePowerEvent = <span class="kwrd">false</span>;
            CanHandleSessionChangeEvent = <span class="kwrd">false</span>;
            CanPauseAndContinue = <span class="kwrd">true</span>;
            CanShutdown = <span class="kwrd">true</span>;
            CanStop = <span class="kwrd">true</span>;

            <span class="kwrd">if</span> (!EventLog.SourceExists(<span class="str">"Teztech Document Conversion"</span>))
                EventLog.CreateEventSource(<span class="str">"Teztech Document Conversion"</span>, <span class="str">"Application"</span>);

            _log = <span class="kwrd">new</span> EventLog();
            _log.Source = <span class="str">"Teztech Document Conversion"</span>;

            _channel = <span class="kwrd">new</span> TcpChannel(ConvertInterface.ConverterEndpoints.Port);
            ChannelServices.RegisterChannel(_channel, <span class="kwrd">false</span>);

            RemotingConfiguration.RegisterWellKnownServiceType(<span class="kwrd">typeof</span>(DocumentToPdf), ConvertInterface.ConverterEndpoints.Uri, WellKnownObjectMode.Singleton);
        }

        <span class="kwrd">static</span> <span class="kwrd">void</span> Main()
        {
            ServiceBase.Run(<span class="kwrd">new</span> WindowsService());
        }

        <span class="rem">/// &lt;summary&gt;</span>
        <span class="rem">/// Dispose of objects that need it here.</span>
        <span class="rem">/// &lt;/summary&gt;</span>
        <span class="rem">/// &lt;param name="disposing"&gt;Whether or not disposing is going on.&lt;/param&gt;</span>
        <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Dispose(<span class="kwrd">bool</span> disposing)
        {
            <span class="kwrd">base</span>.Dispose(disposing);
        }

        <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnStart(<span class="kwrd">string</span>[] args)
        {
            _log.WriteEntry(<span class="str">"Service Starting"</span>);

            _channel.StartListening(<span class="kwrd">null</span>);

            <span class="kwrd">base</span>.OnStart(args);

            _log.WriteEntry(<span class="str">"Service Running"</span>);
        }

        <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnStop()
        {
            _log.WriteEntry(<span class="str">"Service Stopping"</span>);

            _channel.StopListening(<span class="kwrd">null</span>);

            <span class="kwrd">base</span>.OnStop();
        }

        <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnPause()
        {
            _channel.StopListening(<span class="kwrd">null</span>);
            <span class="kwrd">base</span>.OnPause();
        }

        <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnContinue()
        {
            _channel.StartListening(<span class="kwrd">null</span>);
            <span class="kwrd">base</span>.OnContinue();
        }
    }
</pre>
<p><!-- END WindowsService --></p>
<p>Below is the code behind file for the Web Service client. As you can see, .Net makes this type of Web Service easy to create.</p>
<p><!-- BEGIN PdfCodeBehind --></p>
<pre class="csharpcode">
<span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> Pdf : System.Web.UI.Page
{
    <span class="kwrd">protected</span> TcpChannel _channel;

    <span class="kwrd">protected</span> <span class="kwrd">void</span> Page_Load(<span class="kwrd">object</span> sender, EventArgs e)
    {
        <span class="kwrd">try</span>
        {
            <span class="kwrd">if</span> (Request[<span class="str">"Username"</span>] == <span class="kwrd">null</span> || Request[<span class="str">"Password"</span>] == <span class="kwrd">null</span>)
                <span class="kwrd">throw</span> <span class="kwrd">new</span> ApplicationException(<span class="str">"Username and Password are required"</span>);

            HttpPostedFile postedFile = Request.Files[<span class="str">"InputFile"</span>];
            <span class="kwrd">if</span> (postedFile == <span class="kwrd">null</span> || postedFile.FileName == <span class="kwrd">null</span> || postedFile.FileName == <span class="str">""</span>)
                <span class="kwrd">throw</span> <span class="kwrd">new</span> ApplicationException(<span class="str">"InputFile was not supplied or file name is empty."</span>);

            <span class="kwrd">string</span> inputFileExtension = Path.GetExtension(postedFile.FileName);
            <span class="kwrd">if</span> (inputFileExtension.Length &lt; 2)
                <span class="kwrd">throw</span> <span class="kwrd">new</span> ApplicationException(<span class="str">"InputFile does not have a valid file name extension."</span>);
            inputFileExtension = inputFileExtension.Substring(1);

            <span class="kwrd">string</span> outputFileName = Request[<span class="str">"OutputFileName"</span>];
            <span class="kwrd">if</span> (outputFileName == <span class="kwrd">null</span> || outputFileName == <span class="str">""</span>)
                outputFileName = Path.GetFileNameWithoutExtension(postedFile.FileName) + <span class="str">".pdf"</span>;

            DbRequest.CheckAuthorization(Request[<span class="str">"Username"</span>], Request[<span class="str">"Password"</span>]);

            <span class="kwrd">if</span> (_channel == <span class="kwrd">null</span>)
            {
                Dictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; channelProperties = <span class="kwrd">new</span> Dictionary&lt;<span class="kwrd">string</span>,<span class="kwrd">string</span>&gt;();
                channelProperties[<span class="str">"name"</span>] = <span class="str">""</span>;
                _channel = <span class="kwrd">new</span> TcpChannel(channelProperties, <span class="kwrd">null</span>, <span class="kwrd">null</span>);
                ChannelServices.RegisterChannel(_channel, <span class="kwrd">false</span>);
            }

            <span class="kwrd">string</span> url = <span class="kwrd">string</span>.Format(<span class="str">"tcp://localhost:{0}/{1}"</span>, ConvertInterface.ConverterEndpoints.Port, ConvertInterface.ConverterEndpoints.Uri);

            ConvertInterface.IConverter converter = (ConvertInterface.IConverter)Activator.GetObject(<span class="kwrd">typeof</span>(ConvertInterface.IConverter), url);

            <span class="kwrd">string</span> path = MapPath(<span class="str">"."</span>);
            path = Path.Combine(Path.GetDirectoryName(path), <span class="str">"Temp"</span>);

            <span class="kwrd">using</span> (TempFileCollection tempFiles = <span class="kwrd">new</span> TempFileCollection(path))
            {
                <span class="kwrd">string</span> inputFile  = tempFiles.AddExtension(inputFileExtension);
                <span class="kwrd">string</span> outputFile = tempFiles.AddExtension(<span class="str">"pdf"</span>);

                postedFile.SaveAs(inputFile);
                converter.Convert(inputFile, outputFile);

                Response.Clear();
                Response.ContentType = <span class="str">"application/pdf"</span>;
                Response.AddHeader(<span class="str">"content-disposition"</span>, <span class="kwrd">string</span>.Format(<span class="str">"inline; filename={0}.pdf"</span>, <span class="str">"sample"</span>));

                <span class="kwrd">byte</span>[] pdfBytes = File.ReadAllBytes(outputFile);

                Response.OutputStream.Write(pdfBytes, 0, pdfBytes.Length);
            }
        }        
        <span class="kwrd">catch</span> (Exception ex)
        {
            Response.Clear();
            Response.Write(<span class="kwrd">string</span>.Format(<span class="str">"&lt;HTML&gt;&lt;HEAD&gt;&lt;/HEAD&gt;&lt;BODY&gt;&lt;H1&gt;Conversion Error&lt;/H1&gt;&lt;P&gt;{0}&lt;/P&gt;&lt;/BODY&gt;&lt;/HTML&gt;"</span>, ex.Message));
            Response.StatusCode = 500;
            Response.StatusDescription = ex.Message;
        }
    }
</pre>
<p><!-- END PdfCodeBehind --></p>
<p>For completeness, I have included the code for the actual Web Service&#8217;s .aspx file below. As you can see, it&#8217;s just standard .aspx. boilerplate &#8211; all HTTP output is generated in the code behind file&#8217;s Page_Load event (which will be invoked when the Web Service client posts to the page). This is quick and dirty, but it works.</p>
<p><!-- BEGIN Pdf.aspx --></p>
<pre class="csharpcode">
<span class="asp">&lt;%@ Page Language="C#" AutoEventWireup="true" CodeFile="Pdf.aspx.cs" Inherits="Pdf" EnableViewState="false" %&gt;</span>

<span class="kwrd">&lt;!</span><span class="html">DOCTYPE</span> <span class="attr">html</span> <span class="attr">PUBLIC</span> <span class="kwrd">"-//W3C//DTD XHTML 1.0 Transitional//EN"</span> <span class="kwrd">"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"</span><span class="kwrd">&gt;</span>

<span class="kwrd">&lt;</span><span class="html">html</span> <span class="attr">xmlns</span><span class="kwrd">="http://www.w3.org/1999/xhtml"</span> <span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">head</span> <span class="attr">runat</span><span class="kwrd">="server"</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">title</span><span class="kwrd">&gt;</span>Untitled Page<span class="kwrd">&lt;/</span><span class="html">title</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">head</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">body</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">form</span> <span class="attr">id</span><span class="kwrd">="form1"</span> <span class="attr">runat</span><span class="kwrd">="server"</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">div</span><span class="kwrd">&gt;</span>
    
    <span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">form</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">body</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">html</span><span class="kwrd">&gt;</span>
</pre>
<p><!-- END Pdf.aspx --></p>
<p>Here And here is the code for a little PHP application I used to test my conversion Web Service:</p>
<p><!-- BEGIN demo.php --></p>
<pre class="csharpcode">
<span class="kwrd">&lt;?</span><span class="html">php</span> $<span class="attr">ErrorMessage</span> = <span class="kwrd">''</span>; ?<span class="kwrd">&gt;</span>

<span class="kwrd">&lt;!</span><span class="html">DOCTYPE</span> <span class="attr">html</span> <span class="attr">PUBLIC</span> <span class="kwrd">"-//W3C//DTD XHTML 1.0 Transitional//EN"</span> <span class="kwrd">"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">html</span> <span class="attr">xmlns</span><span class="kwrd">="http://www.w3.org/1999/xhtml"</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">head</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">title</span><span class="kwrd">&gt;</span>
File Conversion Server Demo
<span class="kwrd">&lt;/</span><span class="html">title</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">head</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">body</span><span class="kwrd">&gt;</span>

<span class="kwrd">&lt;</span><span class="html">h1</span><span class="kwrd">&gt;</span>File Conversion Server Demo<span class="kwrd">&lt;/</span><span class="html">h1</span><span class="kwrd">&gt;</span>

<span class="kwrd">&lt;</span><span class="html">form</span> <span class="attr">name</span><span class="kwrd">="Demo"</span> <span class="attr">method</span><span class="kwrd">="POST"</span> <span class="attr">enctype</span><span class="kwrd">="multipart/form-data"</span> <span class="attr">action</span><span class="kwrd">="/demo.pdf"</span><span class="kwrd">&gt;</span>

    <span class="kwrd">&lt;?</span><span class="html">php</span> <span class="attr">if</span>($<span class="attr">ErrorMessage</span>)<span class="attr">:</span> ?<span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">p</span><span class="kwrd">&gt;&lt;</span><span class="html">font</span> <span class="attr">size</span><span class="kwrd">="5"</span> <span class="attr">color</span><span class="kwrd">="#008000"</span><span class="kwrd">&gt;&lt;?</span><span class="html">php</span> <span class="attr">echo</span> $<span class="attr">ErrorMessage</span>; ?<span class="kwrd">&gt;&lt;/</span><span class="html">font</span><span class="kwrd">&gt;&lt;/</span><span class="html">p</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;?</span><span class="html">php</span> <span class="attr">endif</span>; ?<span class="kwrd">&gt;</span>
    
    <span class="kwrd">&lt;</span><span class="html">table</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">tr</span><span class="kwrd">&gt;</span>
            <span class="kwrd">&lt;</span><span class="html">td</span><span class="kwrd">&gt;&lt;</span><span class="html">b</span><span class="kwrd">&gt;</span>Username:<span class="kwrd">&lt;/</span><span class="html">b</span><span class="kwrd">&gt;&lt;/</span><span class="html">td</span><span class="kwrd">&gt;</span>
            <span class="kwrd">&lt;</span><span class="html">td</span><span class="kwrd">&gt;&lt;</span><span class="html">input</span> <span class="attr">name</span><span class="kwrd">="Username"</span> <span class="attr">value</span><span class="kwrd">=""</span><span class="kwrd">&gt;&lt;/</span><span class="html">input</span><span class="kwrd">&gt;&lt;/</span><span class="html">td</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;/</span><span class="html">tr</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">tr</span><span class="kwrd">&gt;</span>
            <span class="kwrd">&lt;</span><span class="html">td</span><span class="kwrd">&gt;&lt;</span><span class="html">b</span><span class="kwrd">&gt;</span>Password:<span class="kwrd">&lt;/</span><span class="html">b</span><span class="kwrd">&gt;&lt;/</span><span class="html">td</span><span class="kwrd">&gt;</span>
            <span class="kwrd">&lt;</span><span class="html">td</span><span class="kwrd">&gt;&lt;</span><span class="html">input</span> <span class="attr">name</span><span class="kwrd">="Password"</span> <span class="attr">value</span><span class="kwrd">=""</span><span class="kwrd">&gt;&lt;/</span><span class="html">input</span><span class="kwrd">&gt;&lt;/</span><span class="html">td</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;/</span><span class="html">tr</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">tr</span><span class="kwrd">&gt;</span>
            <span class="kwrd">&lt;</span><span class="html">td</span><span class="kwrd">&gt;&lt;</span><span class="html">b</span><span class="kwrd">&gt;</span>Input File:<span class="kwrd">&lt;/</span><span class="html">b</span><span class="kwrd">&gt;&lt;/</span><span class="html">td</span><span class="kwrd">&gt;</span>
            <span class="kwrd">&lt;</span><span class="html">td</span><span class="kwrd">&gt;&lt;</span><span class="html">input</span> <span class="attr">type</span><span class="kwrd">="file"</span> <span class="attr">name</span><span class="kwrd">="InputFile"</span><span class="kwrd">&gt;&lt;/</span><span class="html">input</span><span class="kwrd">&gt;</span> <span class="kwrd">&lt;/</span><span class="html">td</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;/</span><span class="html">tr</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">table</span><span class="kwrd">&gt;</span>
    
    <span class="kwrd">&lt;</span><span class="html">input</span> <span class="attr">type</span><span class="kwrd">="submit"</span> <span class="attr">value</span><span class="kwrd">="Submit"</span><span class="kwrd">&gt;&lt;/</span><span class="html">input</span><span class="kwrd">&gt;</span> 
    
<span class="kwrd">&lt;/</span><span class="html">html</span><span class="kwrd">&gt;</span>
</pre>
<p><!-- END demo.php --></p>
<p>If you look the PHP form&#8217;s action tag, you&#8217;ll see I used /demo.pdf as the action. Using the very nice <a href="http://learn.iis.net/page.aspx/460/using-url-rewrite-module/">IIS7 URL Rewrite Module</a>, I map all *.pdf URLs to my conversion Web Service. OK, this might be a little overkill, but this way the URLs look nice and all end in .pdf (which is appropriate).</p>
<p>The final piece of the puzzle is a small wrapper class I created to access the conversion Web Service from within my C# application:</p>
<p><!-- BEGIN ConvertClient --></p>
<pre class="csharpcode">
    <span class="kwrd">public</span> <span class="kwrd">class</span> ConvertClient
    {
        <span class="kwrd">public</span> ConvertClient(<span class="kwrd">string</span> convertHost, <span class="kwrd">string</span> username, <span class="kwrd">string</span> password)
        {
            _ConvertHost = convertHost;
            _Username    = username;
            _Password    = password;
        }

        <span class="kwrd">protected</span> <span class="kwrd">string</span> _ConvertHost;
        <span class="kwrd">public</span> <span class="kwrd">string</span> ConvertHost { get { <span class="kwrd">return</span> _ConvertHost; } set { _ConvertHost = <span class="kwrd">value</span>; } }

        <span class="kwrd">protected</span> <span class="kwrd">string</span> _Username;
        <span class="kwrd">public</span> <span class="kwrd">string</span> Username { get { <span class="kwrd">return</span> _Username; } set { _Username = <span class="kwrd">value</span>; } }

        <span class="kwrd">protected</span> <span class="kwrd">string</span> _Password;
        <span class="kwrd">public</span> <span class="kwrd">string</span> Password { get { <span class="kwrd">return</span> _Password; } set { _Password = <span class="kwrd">value</span>; } }

        <span class="kwrd">protected</span> <span class="kwrd">string</span> _Response;
        <span class="kwrd">public</span> <span class="kwrd">string</span> Response { get { <span class="kwrd">return</span> _Response; } set { _Response = <span class="kwrd">value</span>; } }

        <span class="kwrd">protected</span> <span class="kwrd">int</span> _MaxConvertAttempts = 2;
        <span class="kwrd">public</span> <span class="kwrd">int</span> MaxConvertAttempts { get { <span class="kwrd">return</span> _MaxConvertAttempts; } set { _MaxConvertAttempts = <span class="kwrd">value</span>; } }

        <span class="kwrd">protected</span> <span class="kwrd">string</span> _ResponseCode;
        <span class="kwrd">public</span> <span class="kwrd">string</span> ResponseCode { get { <span class="kwrd">return</span> _ResponseCode; } set { _ResponseCode = <span class="kwrd">value</span>; } }

        <span class="kwrd">protected</span> <span class="kwrd">static</span> <span class="kwrd">string</span> _szBoundary    = <span class="str">"SEPARATORSTRINGTEZTECHDOTCOM1"</span>;
        <span class="kwrd">protected</span> <span class="kwrd">static</span> <span class="kwrd">string</span> _szBoundary2   = <span class="str">"\r\n--SEPARATORSTRINGTEZTECHDOTCOM1\r\n"</span>;
        <span class="kwrd">protected</span> <span class="kwrd">static</span> <span class="kwrd">string</span> _szBoundary3   = <span class="str">"\r\n--SEPARATORSTRINGTEZTECHDOTCOM1--"</span>;
        <span class="kwrd">protected</span> <span class="kwrd">static</span> <span class="kwrd">string</span> _szFileSizeHdr = <span class="str">"Content-Disposition: form-data; name=\"MAX_FILE_SIZE\"\r\n\r\n"</span>;
        <span class="kwrd">protected</span> <span class="kwrd">static</span> <span class="kwrd">string</span> _szFileHdrFmt  = <span class="str">"Content-Disposition: form-data; name=\"InputFile\"; filename=\"{0}\"\r\nContent-Type: application/octet-stream\r\n\r\n"</span>;

        <span class="kwrd">public</span> <span class="kwrd">byte</span>[] ConvertToPdf(<span class="kwrd">byte</span>[] inputFileBytes, <span class="kwrd">string</span> inputFileName, <span class="kwrd">string</span> outputFileName)
        {
            <span class="kwrd">string</span> url = <span class="kwrd">string</span>.Format(<span class="str">"http://{0}/{1}?Username={2}&amp;Password={3}"</span>, ConvertHost, outputFileName, Username, Password);

            <span class="rem">// Calculate upload data size</span>

            <span class="kwrd">string</span> szFileSizeData = <span class="kwrd">string</span>.Format(<span class="str">"{0}"</span>, inputFileBytes.Length + 50000);
            <span class="kwrd">string</span> szFileHdr      = <span class="kwrd">string</span>.Format(_szFileHdrFmt, inputFileName);

            ASCIIEncoding ascii = <span class="kwrd">new</span> ASCIIEncoding(); <span class="rem">// At this time, file names must be ascii</span>
            List&lt;<span class="kwrd">byte</span>&gt; header = <span class="kwrd">new</span> List&lt;<span class="kwrd">byte</span>&gt;(); 
            List&lt;<span class="kwrd">byte</span>&gt; footer = <span class="kwrd">new</span> List&lt;<span class="kwrd">byte</span>&gt;(); 

            header.AddRange(ascii.GetBytes(_szBoundary2));      <span class="rem">// MAX_FILE_SIZE field</span>
            header.AddRange(ascii.GetBytes(_szFileSizeHdr));
            header.AddRange(ascii.GetBytes(szFileSizeData));
            header.AddRange(ascii.GetBytes(_szBoundary2));      <span class="rem">// userfile field</span>
            header.AddRange(ascii.GetBytes(szFileHdr));

            footer.AddRange(ascii.GetBytes(_szBoundary3));
            
            <span class="kwrd">int</span> cbContent = header.Count + inputFileBytes.Length + footer.Count;

            <span class="kwrd">int</span> attempts = 0;

            <span class="kwrd">while</span> (<span class="kwrd">true</span>)
            {
                <span class="kwrd">try</span>
                {
                    attempts++;

                    HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
                    webRequest.Method        = <span class="str">"POST"</span>;
                    webRequest.ContentType   = <span class="kwrd">string</span>.Format(<span class="str">"multipart/form-data; boundary={0}\r\n"</span>, _szBoundary);
                    webRequest.ContentLength = cbContent;

                    <span class="kwrd">using</span> (Stream request = webRequest.GetRequestStream())
                    {
                        request.Write(header.ToArray(), 0, header.Count);
                        request.Write(inputFileBytes, 0, inputFileBytes.Length);
                        request.Write(footer.ToArray(), 0, footer.Count);
                    }

                    <span class="kwrd">using</span> (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
                    {
                        <span class="kwrd">using</span> (BinaryReader reader = <span class="kwrd">new</span> BinaryReader(webResponse.GetResponseStream()))
                        {
                            <span class="kwrd">byte</span>[] pdfBytes = reader.ReadBytes((<span class="kwrd">int</span>)webResponse.ContentLength);
                            <span class="kwrd">return</span> pdfBytes;
                        }
                    }
                }
                <span class="kwrd">catch</span>
                {
                    <span class="kwrd">if</span> (attempts &gt;= MaxConvertAttempts)
                        <span class="kwrd">throw</span>;
                }
            }
        }
    }
</pre>
<p><!-- END ConvertClient --></p>
<p>I didn&#8217;t see an easy way to build a MIME document in .Net, so I&#8217;m building up the MIME document (used in the HTTP Post) from scratch.</p>
<p>To debug the Windows Service, as shown in the code above, I added code to log to the Windows Event Viewer. In this case, I started with working document conversion code, so I didn&#8217;t end up needing to run the service under a debugger. But, one of the nice things about services running as a dedicated process (unlike Apache modules, ISAPI modules and Control Panel applets) is that, with just a simple change (adding a Main function), you can run the service as a regular command line application and attach the Visual Studio debugger to the running process.</p>
<p>To troubleshoot the Web Service, my first step was to disable &#8220;friendly errors&#8221;. With IIS7, you have to do it on <a href="http://mvolo.com/blogs/serverside/archive/2007/07/26/Troubleshoot-IIS7-errors-like-a-pro.aspx">both the web browser client and in IIS7</a>. Debugging is just a matter of attaching the IIS7 process in Visual Studio (as usual for any web application).</p>
<p>All our production Windows servers use the 64 bit edition of Windows 2008 Server. Right now, I happen to do most of my development on a 32 bit edition of Windows Vista. Both platforms run IIS7 and usually, the 32 vs. 64 bit doesn&#8217;t cause any problems. However, the Windows version of OpenOffice only comes in a 32 bit version. This version runs fine on 64 bit Windows, but when programming OpenOffice via .Net, you need a 32 bit application, so you have to <a href="http://stackoverflow.com/questions/41449/i-get-a-an-attempt-was-made-to-load-a-program-with-an-incorrect-format-error-on-a">set the Target Platform in the Project Build Properties to X86</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.teztech.com/2009/06/28/web-service-for-document-conversion-an-odyssey/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New Year, New Projects Completed</title>
		<link>http://blogs.teztech.com/2009/03/26/new-year-new-projects-completed</link>
		<comments>http://blogs.teztech.com/2009/03/26/new-year-new-projects-completed#comments</comments>
		<pubDate>Fri, 27 Mar 2009 03:34:16 +0000</pubDate>
		<dc:creator><![CDATA[pj]]></dc:creator>
				<category><![CDATA[ListingsTech]]></category>
		<category><![CDATA[T3city]]></category>

		<guid isPermaLink="false">http://teztech.com/?p=27</guid>
		<description><![CDATA[Wow, this has been a busy few months. In addition to the usual flood of small projects, since November, we&#8217;ve published these brand new sites: http://www.lotterygold.com/ This was an interesting and very large project that recently went live. The application we created for this site is general purpose and can support many types of e-commerce. [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Wow, this has been a busy few months. In addition to the usual flood of small projects, since November, we&#8217;ve published these brand new sites:</p>
<p><a class="moz-txt-link-freetext" href="http://www.lotterygold.com/"><strong>http://www.lotterygold.com/</strong></a> This was an interesting and very large project that recently went live. The application we created for this site is general purpose and can support many types of e-commerce. The backend of this site is very comprehensive and highly automated. Due to its sensitive nature, the there are multiple layers of security and a dedicated audit trail facility.</p>
<p><a class="moz-txt-link-freetext" href="http://www.mountainhighoutfitters.com/"><strong>http://www.mountainhighoutfitters.com/</strong></a><strong> </strong>This site is based on our very comprehensive and sophisticated online store engine. Our client&#8217;s goal is to compete head on with the likes of rei.com (who probably have spent hundreds of thousands if not millions of dollars on their online store). We have a very full featured marketing capabilities, integrated product catalog management (with lots of JavaScript to make it friendly and easy to use), integrated order fulfillment and automated integration with in-house store inventory. Since Google is the source of so much traffic (both paid and non-paid), we support every service that Google offers: Google Base (a.k.a. Google Products and Froogle), Google Site Maps, Google Adwords, Google Checkout and Google Analytics. We have some interesting payment solutions for vendors that want to sell to non-traditional markets (overseas). All our web applications support our standard skin and content management system (see below), so just about any look and feel can be created without any programming or database changes. There is a lot of power and flexibility under the hood that is probably best demonstrated in a meeting.</p>
<p><a href="http://www.hudhomeschattanooga.com/"><strong>http://www.hudhomeschattanooga.com/</strong></a> This is a standard ListingsTech site to market HUD homes in the metro Chattanooga, TN area. One interesting thing about this project is that we allow visitors to search across subsets of two different listings databases. We needed to do this because the databases contain all HUD listings for Georgia and Tennessee, but the site is only for Chattanooga. Another interesting idea here is the general approach of keeping the site as simple as possible &#8211; we are trying to get visitors to the information or service they want in as few clicks as possible&#8230; Want to see listings for Walker County? Click the search term on the left. Need to get prequalified for a loan? Click the link on the top of the page and fill out the form. Need more information about a listing? Click the &#8220;Contact Us for More Info&#8221; link and type your question.  </p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.teztech.com/2009/03/26/new-year-new-projects-completed/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to get the best deal on a notebook computer (a.k.a. laptop computer)</title>
		<link>http://blogs.teztech.com/2008/07/07/how-to-get-the-best-deal-on-a-notebook-computer-aka-laptop-computer</link>
		<comments>http://blogs.teztech.com/2008/07/07/how-to-get-the-best-deal-on-a-notebook-computer-aka-laptop-computer#comments</comments>
		<pubDate>Mon, 07 Jul 2008 17:28:08 +0000</pubDate>
		<dc:creator><![CDATA[pj]]></dc:creator>
				<category><![CDATA[Networking]]></category>
		<category><![CDATA[T3city]]></category>

		<guid isPermaLink="false">http://teztech.com/?p=25</guid>
		<description><![CDATA[This is a question I get a lot. Notebook computers are extremely popular&#8230; everybody is tired of all the wires and space required by a traditional desktop computer. People are printing less and not everybody needs a big tower case that can hold the latest and greatest $500 video card! Kids want a computer they can [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>This is a question I get a lot. Notebook computers are extremely popular&#8230; everybody is tired of all the wires and space required by a traditional desktop computer. People are printing less and not everybody needs a big tower case that can hold the latest and greatest $500 video card! Kids want a computer they can easily take to college or class. They problem is that the typical budget notebook runs $700 &#8211; $800 (both online and in the stores), but everybody wants to pay $400 &#8211; $500.<span id="more-25"></span></p>
<h2>Getting a Deal </h2>
<p>FIrst, let&#8217;s look at how to get the great deal everybody wants: Retail stores know you want a $400 laptop, so they use this item as a loss leader. If you watch the newspapers around popular days for big sales (back to school tax holidays, July 4th, Black Friday, etc), you will often find impossible deals advertised. These really are great deals if you are willing and able to jump through the required hoops. Be aware that there are more people looking for the deal then there are systems available at the sweet price. In fact, the stores are counting on this&#8230; they sell 4 systems at the loss leader price and 100 systems at the &#8220;sale&#8221; price that they can make money at. </p>
<p>If you want the best deal, I highly recommend that you watch the newspaper advertisements. You&#8217;ll find prices you can&#8217;t even get online.  Also, check out this link: <a href="http://www.notebookreview.com/deals/">http://www.notebookreview.com/deals/.</a> There are probably other lists of laptop deals &#8211; I don&#8217;t buy them very often &#8211; this is just one I happen to know of.</p>
<p>Since it is easy, it is always worth checking out the deals available online. Two online stores I check a lot are <a href="http://newegg.com">NewEgg</a> and <a href="http://buy.com">Buy.com</a>. <a href="http://amazon.com">Amazon.com</a> also has good deals from time to time, but I hate their search interface.</p>
<p>Then, there are just the random deals you have to be on the lookout for. Here is an example: I wanted to buy my two older kids notebooks for Christmas to take to school. I did the usual initial searching around. I wasn&#8217;t willing to get in line for black Friday sales. One day, I just happened to pull up microcenter.com and do a search. I found an impossible deal &#8211; budget Lenovo 15&#8243; for $400. I printed the price and went to the store. The price on the display was like $700, but I asked. They guy said the $400 deal was for real and sold me two at that price. I am sure I could have sold them on ebay for $600! Crazy.</p>
<p>There are ultra budget systems available that normally cost around $400. A typical example is the <a href="http://en.wikipedia.org/wiki/ASUS_Eee_PC">Asus Eee PC</a>. Though they are interesting and competition is always good, I personally would not want one of these notebooks&#8230; the keyboards are bad and the screens are too small. Most people I know want a Windows OS. Windows XP was a solid notebook OS. Everybody knows how to use it. I am starting to wonder if <a href="http://ubuntu.com">Ubuntu </a>(a popular Linux distribution) is not a better choice than Windows Vista, though.</p>
<h2>Choosing a Model</h2>
<p>All the the name brands (Dell, Sony, NEC, HP, etc.) are going to have about the same reliability. Sony and Lenovo&#8217;s (formerly IBM) ThinkPad  are the premium laptops. If you are going to use the built-in keyboard a lot, consider the feel of the keyboard. I think the Lenovo&#8217;s keyboards are the best. I have a 13&#8243;, 4 pound Sony. I like the small form factor, but if I were to buy again, I&#8217;d look for a similar form factor in Lenovo because I really don&#8217;t like the Sony keyboard and I&#8217;ve now ended up using mine enough to where it has become annoying. The Lenovos also have a keyboard light&#8230; this is very useful and I wish my Sony had one.</p>
<p>I have a customer that bought 2 state of the art 13&#8243; 3 pond Sonys. They are similar to mine but have carbon fiber cases and <a href="http://en.wikipedia.org/wiki/Hybrid_drive">hybrid hard drives</a> (normal hard drive plus some flash). It turns out that the hybrid hard drives aren&#8217;t any faster or better for batteries than normal hard drives&#8230; also, these 2 notebooks have already been replaced twice each (one is in the shop for a 3rd time) for failed hard drives. The problem with the hard drives is probably just a coincidence, but, overall, I would not opt for the hybrid hard drive if I had a choice.</p>
<p>Your notebook will come with Vista. Technically, OEMs can&#8217;t sell Vista after July 1. Too bad because Vista is a poor match for the slower components (RAM, hard drives) used in notebooks. On some recent Vista notebooks I have setup for a client, I had to uninstall Norton Anti-Virus just to make them usable. With Vista, you&#8217;ll want at least 1GB RAM. A 7200 RPM hard drive would be good, too, but these are hard to find.</p>
<h2>Backups</h2>
<p>The new high capacity hard drives are the major weakness of all modern notebooks. Your notebook&#8217;s hard drive will fail! Unlike failures with desktop hard drives, the chances of a total hard drive failure (where only a backup recovery service can get the data off for a cost of $500 and a week wait) are very high. Don&#8217;t lose your family pictures! You definitely need a backup solution. I recommend something you can set and forget. The home version of <a href="http://mozy.com/">http://mozy.com/</a> is pretty good and the 2GB account is free &#8211; OK for My Documents (say for a computer to take back and forth to school), but not big enough for a large Outlook archive or a big collection of pictures. I am still searching for a really good and free or inexpensive set and forget backup solution.</p>
<h2>Antivirus</h2>
<p>I put <a href="http://free.avg.com/">AVG</a> on my kid&#8217;s notebooks. The free version is very popular and gets OK reviews, but there are a lot of complaints about the resources required by latest version (8.0). Also, I noticed that at least on one of the notebooks, it had not been running automatic updates&#8230; Really, this kind of software must be set and forget.</p>
<h2>Office Suite</h2>
<p>You can save some money with the free <a href="http://www.openoffice.org/">Open Office</a>. It really is a good program. If you configure it to save as .doc and .xls by default, most people will barely notice they aren&#8217;t using Microsoft Office. The only problem comes when somebody sends an Office 2007 docx or xlsx XML format file (the default &#8220;open&#8221; file format for Office 2007). Now that the competitors have mastered .doc and .xls, Microsoft had to change things up to keep customers coming back!</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.teztech.com/2008/07/07/how-to-get-the-best-deal-on-a-notebook-computer-aka-laptop-computer/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Switching from PayflowPro to PayPal Website Payments Pro</title>
		<link>http://blogs.teztech.com/2007/03/13/switching-from-payflowpro-to-paypal-website-payments-pro</link>
		<comments>http://blogs.teztech.com/2007/03/13/switching-from-payflowpro-to-paypal-website-payments-pro#comments</comments>
		<pubDate>Wed, 14 Mar 2007 02:32:41 +0000</pubDate>
		<dc:creator><![CDATA[pj]]></dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[T3city]]></category>

		<guid isPermaLink="false">http://teztech.com/2007/03/13/switching-from-payflowpro-to-paypal-website-payments-pro</guid>
		<description><![CDATA[Way back in 1996 I created an e-commerce web site for a small software company I owned. The system allowed customers to purchase and download software our web site. To make the system appealing and easy to use for buyers, we processed credit cards automatically. Back then, there were no Internet credit card processing gateways, but [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Way back in 1996 I created an e-commerce web site for a small software company I owned. The system allowed customers to purchase and download software our web site. To make the system appealing and easy to use for buyers, we processed credit cards automatically. Back then, there were no Internet credit card processing gateways, but I was able to purchase some rather expensive software that allowed my computer to emulate a credit card terminal. The software used the computer&#8217;s modem to call a modem bank at the credit card processor and complete the transaction. There was a way to automate the software via text files and command lines and that&#8217;s what I did. It was slow, but it worked.</p>
<p>Eventually, my credit card processor teamed up with one of the first companies to offer an Internet credit card processing gateway, Cybercash. I hopped on board as one of the first customers. <span id="more-18"></span>As with a lot of APIs created by hurried teams of inexperienced programmers, Cybercash was much more complex than was necessary to accomplish the simple task at hand. Credit card processing can be really simple: Pass the credit card processor a list of required fields and get back an Boolean success code and an error message.  HTTPS is a fine protocol for this type of stateless transaction that must occur over a secure channel. Input fields can be passed as a URL encoded query string. The error code and error message could be returned an HTTP response code or via a URL encoded fields in the response body. The modern, fancy name for this type of transaction protocol is <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">REST</a>. Under the hood of its overly complex API, Cybercash used the simple REST protocol I described earlier. Liked a lot of other Cybercash programmers, I eventually figured this out on my own and bypassed the complex and cumbersome API to use the simple REST protocol.</p>
<p>Time passed on and Verisign bought up all kinds of important technology related to e-commerce. They purchased Cybercash and started promoting their own gateway API, PayflowPro. Several times, we researched the fees and APIs offered by the various vendors. PayflowPro was the best and <a href="https://www.t3city.com/SupportFAQ.aspx?FAQID=10">the one we used and recommended</a>. The PayflowPro API was a tad bit easier to use than the official Cybercash API &#8211; easy enough that instead of bypassing the API for the REST protocol, I used the actual PayflowPro API function calls.</p>
<p>When the time came to automate the billing for T3city, I started out with PayflowPro. However when it came time to get a new merchant account, I took some time to review my options. On paper, PayPal Website Payments Pro looked pretty good &#8211; they have a nice and simple fee structure (unlike PayflowPro with all sorts of fees billed out at different times) and the fees are competitive if you can get your volume over $3,000/month (and not too bad if you can&#8217;t). The sign-up process was all online. I figured it couldn&#8217;t be too hard to change gateway APIs &#8211; I&#8217;d already used several others &#8211; so I made the switch.</p>
<p>Well, I was wrong about the difficulty level associated with switching from PayflowPro to PayPal. The PayPal API is much more complex. First, there is the fact that the API is <a href="http://en.wikipedia.org/wiki/SOAP">SOAP</a> based. In addition to the more complex SOAP protocol, the PayPal programming examples use another layer on top of the native SOAP API. Why they add this extra layer, I really don&#8217;t know &#8211; maybe it&#8217;s just a fact that every junior programmer feels like an extra layer or two will make things simpler. It doesn&#8217;t make the API any easier to use. In fact, I found the differences between the new layer and the documentation for the base SOAP protocol very confusing. In the end, I elected to ditch the PayPal examples and use PayPalSvc.wsdl and .Net&#8217;s SOAP support tools to generate my own SOAP client for the PayPal API. The resulting API is a little awkward is spots (mostly due to PalPals not so hot API design), but at least it matches the detailed and fairly comprehensive PayPal SOAP protocol documentation.</p>
<p>Once you get over the base complexity of the PayPal SOAP based API, then you have to deal with the stateful nature of PayPal. Credit card processing is normally a simple transaction, but the PayPal Website Payments Pro program requires that you offer your customers the option to pay via PayPal. And, what the heck, allowing payments by PayPal is not such a bad idea.  However, unlike a simple credit card transaction, payments with PayPal naturally flow over a series of pages, some on your site and some on PayPal&#8217;s site. Information such as billing and shipping addresses and invoice line items have to be exchanged in a delicate dance. Assuming you are willing to tackle the complexity of proper error handling, avoiding browser complaints about HTTPS redirects and giving the user the ability to cancel cleanly, getting PayPal transactions to flow smoothly turns out to be a fairly complex.</p>
<p>Is the extra complexity worth it? Consider these points:</p>
<ul>
<li>Both gateways are very reliable. </li>
<li>PayPal fee structure is simpler, clearly specified on their web site and may be less expensive &#8211; YMMV. Traditional store fronts may be able to get better rates from their current processors with a different gateway API.</li>
<li>PayPal charges the same fees for all types of credit cards. AMEX fees are usually higher, so this may save you some money, but, again, YMMV.</li>
<li>PayPal does not require any type of term or volume commitment</li>
<li>Accepting PayPal is nice &#8211; giving customers more ways to pay you is a good thing!</li>
<li>Implementing PayPal Website Payments Pro is a good deal harder than using PayflowPro. Depending on your web site/application, adding stateful credit card / PayPal transaction processing may require adding new database fields, new screens and other large scale programming changes.</li>
<li>Under .Net, PayPal Website Payments Pro does not require any native (non .Net) code. To use PayflowPro in .Net, I load and make native function calls into the native PayflowPro DLL.</li>
<li>PayPal Website Payments Pro requires full names for states (not the typical 2 letter codes) and proper ISO country codes for every transaction. If you don&#8217;t already have validation in place and tables to translate state codes into state names (users <em>will </em>use 2 letter state codes if you let them), this support will require additional programming work.</li>
<li>With PayPal Website Payments Pro, you have to perform an additional step to transfer money from your PayPal account into your bank account.  Funds from credit card purchases show up in your PayPal account immediately, but transfers to your bank account take multiple business days (similar to the delay you&#8217;ll have with a traditional merchant service provider and PayflowPro). In theory, you can use funds in your PayPal account immediately for purchases via PayPal, but you would need a careful strategy to ensure proper accounting.</li>
<li>To credit a customer via PayPal, you must create a new credit transaction that references a special code from the original sale transaction. Unlike PayflowPro, you cannot void a transaction and you cannot change a sale transaction to a credit transaction.</li>
<li>PayPal has different and likely much more strict fraud protection measures. Overall, I like this capability, but it did cause some pain during our switch when credit cards on file from long term customers no longer worked because of mismatched a CVV number, a mistyped expiration date, etc..</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blogs.teztech.com/2007/03/13/switching-from-payflowpro-to-paypal-website-payments-pro/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>&#8220;Green Address Bar&#8221; SSL Certificates</title>
		<link>http://blogs.teztech.com/2007/02/15/green-address-bar-ssl-certificates</link>
		<comments>http://blogs.teztech.com/2007/02/15/green-address-bar-ssl-certificates#comments</comments>
		<pubDate>Fri, 16 Feb 2007 00:02:04 +0000</pubDate>
		<dc:creator><![CDATA[pj]]></dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[Networking]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[T3city]]></category>

		<guid isPermaLink="false">http://teztech.com/2007/02/15/green-address-bar-ssl-certificates</guid>
		<description><![CDATA[I&#8217;ve written other places about SSL certificates. Once upon a time, you bought your SSL certificates from either Verisign or Thawte. Back then, all (both) SSL Certificate Authorities (CAs) did some real validation on the entity (business or person) that was applying for the SSL cert. To validate the entity, they did things like review [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve written other places about <a href="http://www.t3city.com/SupportFAQ.aspx?FAQID=9">SSL certificates</a>. Once upon a time, you bought your SSL certificates from either Verisign or Thawte. Back then, all (both) SSL Certificate Authorities (CAs) did some real validation on the entity (business or person) that was applying for the SSL cert. To validate the entity, they did things like review corporate records to make sure addresses matched, looked up phone numbers in public directories and matched drivers licenses to domain registrations.</p>
<p>I can understand why they wanted a bit of money for the work that was required for validation that first year, but overall, SSL certificates have long been overpriced for the value they provide. After that first validation, the next year&#8217;s renewal costs the CA practically nothing, but they used to give no renewal discounts at all and, even now, renewal discounts don&#8217;t exist and multi-year discounts are not as substantial as they could (should?) be.<span id="more-15"></span></p>
<p>Then there were (are) silly SSL cert upgrades that supposedly provided stronger encryption. Well, I suppose those upgrades actually could enhance encryption if you just happened to be running an old, obscure version of IE that was only available outside the US, only for a short time and has not been available since early 2000. Funny how even today, you&#8217;ll find that even the biggest CA charges extra for <a href="http://www.middleware.vt.edu/pubs/ssl.html" title="Even this outdated article suggests that SGC SSL certs are not useful">Server Gated Cryptography</a>, even though no browser modern enough to be secure needs or supports it.</p>
<p>If you want to spend even more on your SSL cert, CAs will happily add on various types of hyper-specific insurance policies and all manner of <a href="http://www.t3city.com/Default.aspx?ArticleID=20">&#8220;site seals&#8221; and  &#8220;trust logos&#8221;</a>.</p>
<p>The entire verification and trust thing is just silly. The percentage of Internet users that would recognize Verisign, Thawte, Comodo or any other CA is vanishingly small. Even if we were to assume your average Internet buyer were a sophisticated, educated, rational consumer, why would they trust some company they&#8217;ve never heard of to tell them how trustworthy amazon.com is? On top of all this, given the year after year rape attempts committed by big CAs with their over pricing of renewals, fake SGC upgrades and other kinds of fake &#8220;strong cryptography&#8221; upgrades, the only thing I personally trust CAs to do is to make as much money as they possibly can with any means at their disposal.</p>
<p>With the useless state of verification and trust, it&#8217;s no wonder that some smaller CAs eventually started verifying less and charging a lot less. Now days, you can buy an SSL certificate that certifies nothing other that you are using SSL. Fair enough &#8211; even that tidbit is more than most consumers are interested in knowing. Practically speaking, SSL is only a technology for the vendor. Vendors should use SSL properly because they care about the consumer enough to not transmit their personal information in the clear over the Internet.  Frankly, if my wife, my Mom or one of my kids finds something they want to buy, as long as the browser don&#8217;t completely refuse to accept the connection, they will be happy to click through all manner of browser warnings to put in a credit card number. Haven&#8217;t we all been trained to ignore these peskey warning messages by now? A few shoppers might be consoled by a a happy, friendly padlock icon, but how many users are fully aware that the pad-lock icon is supposed to be in the browser&#8217;s status bar. &#8220;What&#8217;s a status bar&#8221;, you ask?</p>
<p>Given all this, I&#8217;ve been using the least expensive SSL certs I can find. Here are a couple of different examples &#8211; can you tell what kind of validation was used?</p>
<ul>
<li><a href="https://www.searchenginecommando.com/order/">https://www.searchenginecommando.com/order/</a>  (cheap)</li>
<li><a href="https://www.t3city.com/">https://www.t3city.com/</a> (cheaper)</li>
<li><a href="https://www.embracegroup.com/index2.html">https://www.embracegroup.com/index2.html</a>  (cheapest)</li>
</ul>
<p>I suppose the SSL CAs all got together and decided something just had to be done before everybody started using self-signed SSL certificates. Enter now the &#8220;Green Address Bar&#8221; SSL Certificate. The real name is the &#8220;Extended Validation&#8221;  SSL Certificate, but my name would be better. At least with my name, there is a slight chance that consumers (of SSL certs) will notice.  If you have one of these super-duper certificates, IE&#8217;s address bar is supposed to turn green (as in the color of money, eh?). I think this is a Vista only feature, though.</p>
<p>The SSL vendors want $500 and more for these &#8220;EV&#8221; SSL certs. Personally, I think they are pricing themselves out of the market. Yes, a handful of sites like amazon.com will pay the extra $489 for the SSL cert that makes the browser&#8217;s address bar turn green (as in the color of envy?). I have to guess, though, that the vast majority of SSL certs are purchased for small e-commerce sites like searchenginecommando.com, t3city.com and embracegroup.com. These small operators will rightly assume that public will pay no attention to the fact that the address bar is not green. Personally, I doubt if many people really even look for the SSL lock icon anymore. If EV were just a $50 up-charge, then a lot of small shops might would go ahead and get it (at least for the first year until they find out it didn&#8217;t effect sales). Right now, since the new certs are so expensive, practically nobody will buy them and buyers will just forget all about the green address bar. If they do notice, they&#8217;ll probably just have a vague notion that something wrong with their computer (again). &#8220;Wasn&#8217;t Vista supposed to fix these kinds of problems?&#8221; they&#8217;ll wonder.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.teztech.com/2007/02/15/green-address-bar-ssl-certificates/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Linux vs. Windows for Web Hosting</title>
		<link>http://blogs.teztech.com/2007/02/09/linux-vs-windows-for-web-hosting</link>
		<comments>http://blogs.teztech.com/2007/02/09/linux-vs-windows-for-web-hosting#comments</comments>
		<pubDate>Fri, 09 Feb 2007 07:19:06 +0000</pubDate>
		<dc:creator><![CDATA[pj]]></dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[T3city]]></category>

		<guid isPermaLink="false">http://teztech.com/2007/02/09/linux-vs-windows-for-web-hosting</guid>
		<description><![CDATA[A lot of people think I&#8217;m an Linux/open source bigot. That&#8217;s not true at all. I do love Linux and open source. As a programmer, I dig the ability to &#8220;use the source, Luke&#8221;. Not only is looking at source code interesting on its own (at least for some of us), but every now and [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>A lot of people think I&#8217;m an Linux/open source bigot. That&#8217;s not true at all. I do love Linux and open source. As a programmer, I dig the ability to &#8220;use the source, Luke&#8221;. Not only is looking at source code interesting on its own (at least for some of us), but every now and then it really helps with debugging and troubleshooting. Linux Servers are simply better than Windows Servers for a lot of the <a href="http://www.t3city.com">hosting</a> I do, so I learned how to host on Linux. Back in the days of Windows NT, there was no comparison &#8211; our Linux web servers ran heavily loaded for<strong><em> years </em></strong>at a time while Windows NT systems with more than one web site needed regular reboots &#8211; really, I&#8217;m not making it up.<span id="more-14"></span></p>
<p>In modern times, Windows 2000 and Windows 2003 closed the gap for fast and reliable web hosting, but Linux still makes a better email server for ISP type email hosting. The Linux/UNIX security model is simpler than Windows while the Linux process model is slightly more featured. It turns out that these qualities make Linux a good fit for web and email hosting. You really don&#8217;t need complex ACL based permissions for web hosting. The simpler Linux security model works and because it&#8217;s simpler, it is easier to get right.  The Linux lightweight process model (including support for <em>fork</em> with copy on write) is a good match for virtual web hosting &#8211; think about all the perl CGI scripts out there. The lightweight process model is also handy for writing email servers. None of the nice email software I use for hosted email is even available for Windows. It&#8217;s not that it would be ultra-hard to port these packages to Windows. It&#8217;s just painful and really, why bother? DNS hosting is a wash. The only package I like is <a href="http://www.powerdns.com/">PowerDNS</a> and it runs on both Linux and Windows.</p>
<p><a href="http://www.php.net">PHP</a> runs fine on Windows under ISS, but really, why bother? I run Asp.Net on Windows under IIS. It is possible to run .Net applications under <a href="http://www.mono-project.com/">Mono</a>. But, from a practical standpoint, Mono still doesn&#8217;t fully support Asp.Net 2.0 (though it&#8217;s really close now) and Asp.Net 2.0 is so much better than .Net 1.1, I don&#8217;t bother with 1.1 for any of my <a href="http://www.listingstech.com/">own stuff</a>. Overall, running Asp.Net on Linux seems like a lot of struggling against the machine.</p>
<p>When it comes to developer tools, nothing comes close to Microsoft. I can program in vi, emacs or even notepad if I have to, but Microsoft programming tools are better. The IDEs are faster and more integrated. The debuggers are better. The compilers and linkers are faster. My biggest complaint with Linux programming tools is lack of performance. I need a fast compile/link/debug cycle. For anything bigger than a single file project, I can&#8217;t seem to get it on Linux. Last time I had a serious project on Linux, I took the time to try out lots of different IDEs. As I would have guessed, <a href="http://www.kdevelop.org/">Kdevelop </a>was the best &#8211; it&#8217;s beautiful and has tons of features, but I still found it slow and awkward for day-to-day use. I figured out how to use &#8220;<a href="http://www.gnu.org/software/automake/">automake</a> and friends&#8221;. Talk about weird (and slow). I do like <a href="http://subversion.tigris.org/">Subversion</a>. I&#8217;m already using it for all my cross-platform development projects and I&#8217;m thinking about converting everything else over. With Microsoft tools, debugging Asp.Net applications is just like debugging a GUI application. This alone justifies developing all my web application in Asp.Net and hosting them on Windows.</p>
<p>It&#8217;s been more than a couple of years since my last serious desktop GUI application. At that time, Windows and MFC were the obvious platform. If I had to run the application on Linux, I would have tried to get something going with <a href="http://www.winehq.com/site/winelib">Winelib</a>, but MFC support under Winelib has always looked like a PITA. For new development, I would consider using <a href="http://www.trolltech.com/products/qt/">Qt</a> or <a href="http://www.wxwidgets.org/">wxWigits</a>. My big complaint about both these libraries is the deliberate lack of support for exceptions &#8211; talk about stuck in the dark ages. I&#8217;ve done a little bit of WinForms programming. Overall, I think the library is pretty good (and with Mono, it could be cross-platform). My worry is the distribution requirements (though Windows 9X, ME and 2000 are finally starting to fade away) and the <a href="http://teztech.com/2006/10/24/lots-of-ram-for-net-programs">hefty resource requirements</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.teztech.com/2007/02/09/linux-vs-windows-for-web-hosting/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Primary Data Center Switch Upgraded to Gigabit Ethernet</title>
		<link>http://blogs.teztech.com/2007/01/31/primary-data-center-switch-upgraded-to-gigabit-ethernet</link>
		<comments>http://blogs.teztech.com/2007/01/31/primary-data-center-switch-upgraded-to-gigabit-ethernet#comments</comments>
		<pubDate>Wed, 31 Jan 2007 20:14:30 +0000</pubDate>
		<dc:creator><![CDATA[pj]]></dc:creator>
				<category><![CDATA[Networking]]></category>
		<category><![CDATA[T3city]]></category>

		<guid isPermaLink="false">http://teztech.com/2007/01/31/primary-data-center-switch-upgraded-to-gigabit-ethernet</guid>
		<description><![CDATA[We&#8217;ve been meaning to upgrade our switches to GigE for some time. Last week, I swapped out our trusty Cisco 2924 switch with a NetGear GigE Prosafe Smart Switch. So far, so good on the NetGear switch. The web UI is a little clunky, but overall, it&#8217;s better than most other switch configuration UI&#8217;s I&#8217;ve used in [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>We&#8217;ve been meaning to upgrade our switches to GigE for some time. Last week, I swapped out our trusty Cisco 2924 switch with a <a href="http://www.netgear.com/Products/Switches/SmartSwitches/GS748T.aspx">NetGear GigE Prosafe Smart Switch</a>. So far, so good on the NetGear switch.</p>
<p>The web UI is a little clunky, but overall, it&#8217;s better than most other switch configuration UI&#8217;s I&#8217;ve used in the past. I still prefer a script based configuration, but you don&#8217;t get that in these lower cost &#8220;web managed&#8221; switches.</p>
<p><span id="more-9"></span></p>
<p>The switch&#8217;s rules for VLANs are a bit weird. For example, I don&#8217;t like the &#8220;default VLAN&#8221; concept they have implemented. Also, you can&#8217;t mix tagged and untagged traffic on a single port (as you can with most hosts and many other switches). Really, VLANs are simple. A packet can be VLAN tagged or untagged. A switch port can be granted access to 1 or more VLANS. For each VLAN for which a switch port has been granted access, the port can either tag or not tag outgoing traffic. That&#8217;s it. I can see why the default configuration of a switch should be to grant very port untagged access to VLAN 1, but that doesn&#8217;t imply to me that there needs to be some kind of &#8220;default&#8221; VLAN for each port.</p>
<p>The switch&#8217;s management IP does not have to be on VLAN 1. This is a nice touch that I appreciate.</p>
<p>The statistics in the web GUI are pretty sparse. You can view basic interface counters for each port. It would be nice to get some idea of the bandwidth in use on each port. The 5 minute input and output rates on Cisco&#8217;s &#8220;show interfaces&#8221; output is a good example of what is useful.</p>
<p>SNMP support is also basic, but I had no problem configuring <a href="http://cacti.net/">Cacti</a> to create traffic graphs for each port. That is all I need.</p>
<p>Jumbo frame support is either on or off. Most switches let you set this per port. Setting it per VLAN would make the most sense to me. But, unless you could program the switch to automatically fragment packets for hosts that don&#8217;t support jumbo frames (and what switch does this?), a global switch is fine. Ultimately, you have to deal with the individual hosts on each VLAN &#8211; support for jumbo frames on the switch is just a simple yes or no (and can probably always be set to yes as long as the switch itself does not generate any jumbo packets).</p>
<p>The switch supports trunking. That is fairly common for switches that support VLANs. I haven&#8217;t tried out trunking. A GigE pipe is big enough for me right now.</p>
<p>You can have up to two ports configured to monitor (sniff) traffic on other ports. I haven&#8217;t tried this out yet, but I&#8217;m sure it will come in handy when one of our beloved unmentionable security agencies hits me with a court order for eavesdropping.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.teztech.com/2007/01/31/primary-data-center-switch-upgraded-to-gigabit-ethernet/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP guestbook for abbeyroadontheriver.com</title>
		<link>http://blogs.teztech.com/2006/11/28/php-guestbook-for-abbeyroadontherivercom</link>
		<comments>http://blogs.teztech.com/2006/11/28/php-guestbook-for-abbeyroadontherivercom#comments</comments>
		<pubDate>Tue, 28 Nov 2006 04:20:43 +0000</pubDate>
		<dc:creator><![CDATA[pj]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[T3city]]></category>

		<guid isPermaLink="false">http://teztech.com/2006/11/28/php-guestbook-for-abbeyroadontherivercom</guid>
		<description><![CDATA[When T3city took over the hosting for abbeyroadontheriver.com, they had a guestbook on their web site. Their old host used what appeared to be a custom guestbook written in Cold Fusion. We don&#8217;t support Cold Fusion and I figured I could find something better in PHP, anyway. I found and installed the Purple Yin Guestbook. [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>When <a href="http://www.t3city.com/">T3city</a> took over the hosting for <a href="http://www.abbeyroadontheriver.com/">abbeyroadontheriver.com</a>, they had a guestbook on their web site. Their old host used what appeared to be a custom guestbook written in Cold Fusion. We don&#8217;t support Cold Fusion and I figured I could find something better in PHP, anyway. I found and installed the <a href="http://purpleyin.com/">Purple Yin Guestbook</a>. The PYG script worked well for some time. At some point, though, their guestbook (and guestbooks all over the Internet) got hit by bots (autonomous programs) created by spammers to post in guestbooks. Because the posts were automated, there were many of them. Eventually, abbeyroadontheriver.com&#8217;s owner, Gary, called and we discussed the spam problem. I decided to upgrade to the latest version of PYG. This new version supported <a href="http://www.captcha.net/">captcha</a> images. Gary asked to only use one random digit for the captcha image. This stopped the spam right away. Unfortunately, there were a lot of spam entries to clean up, but Gary worked on this as time allowed.</p>
<p>A couple of weeks ago, Gary started having more problems with his guestbook. It was slow and, more importantly, it wasn&#8217;t taking new posts. After some digging around, I found out that it was slow because PYG stored all the entries in a simple text file. THis is OK (and maybe ideal) for a guestbook with a few posts. Gary&#8217;s guestbook is active and covers several years. Also, there were still a fair number of spam posts that were not visible (Gary&#8217;s guestbook is moderated), but still in the text file. Altogether, Gary has over 3000 posts in his guestbook. <span id="more-8"></span>The combination of simple text file storage with some inefficient coding in PYG and 3000+ posts was resulting in slow page generation. Gary allows HTML in posts. This is mostly so that this guests can post links to pictures, other concerts and videos (on <a href="http://youtube.com/">Youtube</a>, etc.). Allowing HTML can cause problems, but, because his guestbook is moderated, the problems should be correctable. Unfortunately, posts with invalid HTML tripped up the PYG administration interface. So, I started looking for a new guestbook script. PYG doesn&#8217;t have a version that supports MySQL. I wanted something that:</p>
<ul>
<li>Used PHP 4.x</li>
<li>Used MySQL</li>
<li>Used templates to create the Guestbook pages</li>
<li>Allowed the guestbook to be moderated</li>
</ul>
<p>Oddly enough, I couldn&#8217;t find anything that met these objectives. I searched <a href="http://www.google.com/">Google</a> and <a href="http://sf.net/">SourceForge</a>. I came across tons of Guestbook projects. Some required PHP 5. Others didn&#8217;t use templates. I found one that used PHP 4 and templates but didn&#8217;t support moderation. So, I ended up writing one from scratch. I&#8217;ve already got one PHP project on SourceForge, <a href="http://sourceforge.net/projects/phphitcounter/">phpHitCounter</a>. phpGuestbook is already taken, so I&#8217;m thinking phpMysqlGuestbook will be the name. Here are the highlights:</p>
<ul>
<li>Simple configuration (config.php) and installation (edit config.php and run .sql script to create database).</li>
<li>Excellent error messages and error handing for end users ((JavaScript and in page error reporting).</li>
<li>Extra feedback for end users via a special page that explains post moderation.</li>
<li>Fast post display for both end users and administrators</li>
<li>Emails sent to the moderator include a link to the post to be reviewed</li>
<li>Simplified administration</li>
<li>Simple template based customization of HTML output. Templates are valid HTML so they can be maintained in FrontPage, Dreamweaver, etc.</li>
<li>Option to allow HTML content in end user posts. Careful handling of user supplied HTML content in administration interface.</li>
<li>Comprehensive support for banned IPs and banned/moderated content</li>
</ul>
<p>This script is a nice companion to phpHitCounter.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.teztech.com/2006/11/28/php-guestbook-for-abbeyroadontherivercom/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
