<?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>Matthew Steven Kelly</title>
	<atom:link href="http://www.matthewstevenkelly.com/blog/feed" rel="self" type="application/rss+xml" />
	<link>http://www.matthewstevenkelly.com/blog</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Thu, 25 Feb 2010 04:29:35 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Massachusetts Data Breach Protection Law</title>
		<link>http://www.matthewstevenkelly.com/blog/kb/massachusetts-data-breach-protection-law.html</link>
		<comments>http://www.matthewstevenkelly.com/blog/kb/massachusetts-data-breach-protection-law.html#comments</comments>
		<pubDate>Thu, 25 Feb 2010 03:02:04 +0000</pubDate>
		<dc:creator>Matthew Steven Kelly</dc:creator>
				<category><![CDATA[The Knowledgebase]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://www.matthewstevenkelly.com/blog/?p=705</guid>
		<description><![CDATA[Massachusetts is enacting a data protection law in response to a significant rise in electronic data breaches. The law affects any company that stores personal information of a Massachusetts resident. The four page law can be read here: http://www.mass.gov/Eoca/docs/idtheft/201CMR1700reg.pdf
Companies will be required to develop, implement and maintain a comprehensive information security program that is written and contains [...]]]></description>
			<content:encoded><![CDATA[<p>Massachusetts is enacting a data protection law in response to a significant rise in electronic data breaches. The law affects any company that stores personal information of a Massachusetts resident. The four page law can be read here: <a href="http://www.mass.gov/Eoca/docs/idtheft/201CMR1700reg.pdf">http://www.mass.gov/Eoca/docs/idtheft/201CMR1700reg.pdf</a></p>
<p>Companies will be required to develop, implement and maintain a comprehensive information security program that is written and contains administrative, technical and physical safeguards appropriate to safeguard the data.</p>
<p>Every comprehensive information security program shall include:</p>
<h2>(1) Administrative Safeguards:</h2>
<ol>
<li>Designating one or more employees to maintain the comprehensive information security program</li>
<li>Taking reasonable steps to select and retain third-party service providers that are capable of maintaining appropriate security measures to protect such personal information consistent with these regulations and any applicable federal regulations</li>
<li>Reviewing the scope of the security measures at least annually or whenever there is a material change in business practices that may reasonably implicate the security or integrity of records containing personal information</li>
<li>Developing security policies for employees relating to the storage, access and transportation of records containing personal information outside of business premises</li>
<li>Providing ongoing employee training that educates the employees on the proper use of the computer security system and the importance of personal information security.</li>
<li>Documenting responsive actions taken in connection with any incident involving a breach of security, and mandatory post-incident review of events and actions taken, if any, to make changes in business practices relating to protection of personal information.</li>
</ol>
<h2>(2) Technical Safeguards:</h2>
<ol>
<li>Preventing terminated employees from accessing records containing personal information</li>
<li>Providing means for detecting and preventing security system failures by regular monitoring to ensure that the comprehensive information security program is operating in a manner reasonably calculated to prevent unauthorized access to or unauthorized use of personal information; and upgrading information safeguards as necessary to limit risks</li>
<li>Implementing secure user authentication protocols including:
<ol>
<li>(a) control of user IDs and other identifiers;</li>
<li>(b) a reasonably secure method of assigning and selecting passwords, or use of unique identifier technologies, such as biometrics or token devices;</li>
<li>(c) control of data security passwords to ensure that such passwords are kept in a location and/or format that does not compromise the security of the data they protect;</li>
<li>(d) restricting access to active users and active user accounts only; and</li>
<li>(e) blocking access to user identification after multiple unsuccessful attempts to gain access or the limitation placed on access for the particular system;</li>
</ol>
</li>
<li>Implementing secure access control measures that:
<ol>
<li>(a) restrict access to records and files containing personal information to those who need such information to perform their job duties; and</li>
<li>(b) assign unique identifications plus passwords, which are not vendor supplied default passwords, to each person with computer access, that are reasonably designed to maintain the integrity of the security of the access controls;</li>
</ol>
</li>
<li>Encryption of all:
<ol>
<li>(a) Transmitted records and files containing personal information that will travel across public networks, and encryption of all data containing personal information to be transmitted wirelessly.</li>
<li>(b) Personal information stored on laptops or other portable devices;</li>
</ol>
</li>
<li>On any system that is connected to the Internet  and contains files with personal information on them
<ol>
<li>(a) Keeping reasonably up-to-date firewall protection and operating system security patches, reasonably designed to maintain the integrity of the personal information</li>
<li>(b) Keeping reasonably up-to-date versions of system security agent software which must include malware protection and reasonably up-to-date patches and virus definitions, or a version of such software that can still be supported with up-to-date patches and virus definitions, and is set to receive the most current security updates on a regular basis.</li>
</ol>
</li>
</ol>
<h2><strong><span style="font-weight: normal; font-size: 13px;"> </span>(3) Physical Safeguards</strong></h2>
<div id="_mcePaste">
<ol>
<li>Providing reasonable restrictions upon physical access to records containing personal information,and storage of such records and data in locked facilities, storage areas or containers.</li>
</ol>
</div>
<p><strong>Definitions used in the law:</strong></p>
<p><strong> </strong></p>
<ul>
<li><strong>Breach of security</strong><span style="font-weight: normal;">, the unauthorized acquisition or unauthorized use of unencrypted data or, encrypted electronic data and the confidential process or key that is capable of compromising the security, confidentiality, or integrity of personal information, maintained by a person or agency that creates a substantial risk of identity theft or fraud against a resident of the commonwealth. A good faith but unauthorized acquisition of personal information by a person or agency, or employee or agent thereof, for the lawful purposes of such person or agency, is not a breach of security unless the personal information is used in an unauthorized manner or subject to further unauthorized disclosure.</span></li>
<li><span style="font-weight: normal;"><strong>Electronic</strong>, relating to technology having electrical, digital, magnetic, wireless, optical, electromagnetic or similar capabilities.</span></li>
<li><span style="font-weight: normal;"><strong>Encrypted</strong>, the transformation of data into a form in which meaning cannot be assigned without the use of a confidential process or key.</span></li>
<li><span style="font-weight: normal;"><strong>Owns or licenses</strong>, receives, stores, maintains, processes, or otherwise has access to personal information in connection with the provision of goods or services or in connection with employment.</span></li>
<li><span style="font-weight: normal;"><strong>Person</strong>, a natural person, corporation, association, partnership or other legal entity, other than an agency, executive office, department, board, commission, bureau, division or authority of the Commonwealth, or any of its branches, or any political subdivision thereof.</span></li>
<li><span style="font-weight: normal;"><strong>Personal information</strong><span style="font-weight: normal;">, a Massachusetts resident&#8217;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&#8217;s license number or state-issued identification card number; or (c) financial account number, or credit or debit card number, with or without any required security code, access code, personal identification number or password, that would permit access to a resident’s financial account; provided, however, that “Personal information” shall not include information that is lawfully obtained from publicly available information, or from federal, state or local government records lawfully made available to the general public.</span></span></li>
<li><span style="font-weight: normal;"><strong>Record or Records</strong><span style="font-weight: normal;">, any material upon which written, drawn, spoken, visual, or electromagnetic information or images are recorded or preserved, regardless of physical form or characteristics.</span></span></li>
<li><span style="font-weight: normal;"><strong>Service provider</strong><span style="font-weight: normal;">, any person that receives, stores, maintains, processes, or otherwise is permitted access to personal information through its provision of services directly to a person that is subject to this regulation.</span></span></li>
</ul>
<p><strong>Compliance Deadline:</strong></p>
<h2><span style="font-weight: normal;"><strong> </strong></span></h2>
<ul>
<li><strong><span style="font-weight: normal;">Every person who owns or licenses personal information about a resident of the Commonwealth shall be in full compliance with 201 CMR 17.00 on or before March 1, 2010.</span></strong></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.matthewstevenkelly.com/blog/kb/massachusetts-data-breach-protection-law.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Security+ Certification</title>
		<link>http://www.matthewstevenkelly.com/blog/career/security-certification.html</link>
		<comments>http://www.matthewstevenkelly.com/blog/career/security-certification.html#comments</comments>
		<pubDate>Tue, 23 Feb 2010 04:40:08 +0000</pubDate>
		<dc:creator>Matthew Steven Kelly</dc:creator>
				<category><![CDATA[My Career]]></category>

		<guid isPermaLink="false">http://www.matthewstevenkelly.com/blog/?p=699</guid>
		<description><![CDATA[On Friday I took and passed the CompTIA Security+ certification (2008 edition &#8211; SYO-201)
To view the certification verification visit: https://www.certmetrics.com/comptia/public/verification.aspx?code=2DZJZFGD2K4E22C2
For more information on this certification visit: http://www.comptia.org/certifications/listed/security.aspx

]]></description>
			<content:encoded><![CDATA[<p>On Friday I took and passed the CompTIA Security+ certification (2008 edition &#8211; SYO-201)</p>
<p>To view the certification verification visit: <a href="https://www.certmetrics.com/comptia/public/verification.aspx?code=2DZJZFGD2K4E22C2">https://www.certmetrics.com/comptia/public/verification.aspx?code=2DZJZFGD2K4E22C2</a></p>
<p>For more information on this certification visit: <a href="http://www.comptia.org/certifications/listed/security.aspx">http://www.comptia.org/certifications/listed/security.aspx</a></p>
<p><a href="https://www.certmetrics.com/comptia/public/verification.aspx?code=2DZJZFGD2K4E22C2"><img class="alignnone size-full wp-image-700" title="Security+_Certified" src="http://www.matthewstevenkelly.com/blog/wp-content/uploads/2010/02/Security+_Certified.jpg" alt="" width="383" height="158" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.matthewstevenkelly.com/blog/career/security-certification.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Check your privacy settings</title>
		<link>http://www.matthewstevenkelly.com/blog/random/check-your-privacy-settings.html</link>
		<comments>http://www.matthewstevenkelly.com/blog/random/check-your-privacy-settings.html#comments</comments>
		<pubDate>Sat, 16 Jan 2010 23:57:08 +0000</pubDate>
		<dc:creator>Matthew Steven Kelly</dc:creator>
				<category><![CDATA[Random]]></category>

		<guid isPermaLink="false">http://www.matthewstevenkelly.com/blog/?p=689</guid>
		<description><![CDATA[Think you should only check your privacy settings for sites like Facebook? Most other sites provide privacy settings as well. Those settings are most likely defaulting to sharing your information, so it is best to check and then update them appropriately.
Wells Fargo defaults &#8220;Allow sharing of my information among Wells Fargo Companies?&#8221; to &#8220;Yes&#8221; for [...]]]></description>
			<content:encoded><![CDATA[<p>Think you should only check your privacy settings for sites like <a href="http://www.matthewstevenkelly.com/blog/technology-and-me/what-goes-online-stays-online.html">Facebook</a>? Most other sites provide privacy settings as well. Those settings are most likely defaulting to sharing your information, so it is best to check and then update them appropriately.</p>
<p>Wells Fargo defaults &#8220;Allow sharing of my information among Wells Fargo Companies?&#8221; to &#8220;Yes&#8221; for example:</p>
<p><img class="alignnone size-full wp-image-690" title="wells_fargo" src="http://www.matthewstevenkelly.com/blog/wp-content/uploads/2010/01/wells_fargo.jpg" alt="" width="429" height="380" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.matthewstevenkelly.com/blog/random/check-your-privacy-settings.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Yahoo Hot Jobs</title>
		<link>http://www.matthewstevenkelly.com/blog/kb/yahoo-hot-jobs.html</link>
		<comments>http://www.matthewstevenkelly.com/blog/kb/yahoo-hot-jobs.html#comments</comments>
		<pubDate>Sun, 27 Dec 2009 17:51:03 +0000</pubDate>
		<dc:creator>Matthew Steven Kelly</dc:creator>
				<category><![CDATA[The Knowledgebase]]></category>

		<guid isPermaLink="false">http://www.matthewstevenkelly.com/blog/?p=682</guid>
		<description><![CDATA[Yahoo had an interesting article about what is &#8220;in&#8221; and what is &#8220;out&#8221; when creating a professional resume. To quote the article &#8220;Fashion changes, and resume styles change, too. If you have solid skills and work experience but your resume isn&#8217;t getting any bites, you might need a resume makeover.&#8221;
http://hotjobs.yahoo.com/career-articles-the_new_resume_rules_what_s_in_and_what_s_out-1056
To summarize the article:

Include a &#8220;Professional [...]]]></description>
			<content:encoded><![CDATA[<p>Yahoo had an interesting article about what is &#8220;in&#8221; and what is &#8220;out&#8221; when creating a professional resume. To quote the article &#8220;Fashion changes, and resume styles change, too. If you have solid skills and work experience but your resume isn&#8217;t getting any bites, you might need a resume makeover.&#8221;</p>
<p><a href="http://hotjobs.yahoo.com/career-articles-the_new_resume_rules_what_s_in_and_what_s_out-1056">http://hotjobs.yahoo.com/career-articles-the_new_resume_rules_what_s_in_and_what_s_out-1056</a></p>
<p>To summarize the article:</p>
<ol>
<li>Include a &#8220;Professional Summary&#8221; on the top of the resume instead of an &#8220;Objective&#8221;</li>
<li>Make it easy on the eyes</li>
<li>Customize the resume for the job</li>
<li>One-page resumes are a myth</li>
<li>Quantify your accomplishments</li>
<li>Include website links to previous employers and possibly a brief description of them</li>
<li>Include LinkedIn or other social networking site links at the top of the resume</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.matthewstevenkelly.com/blog/kb/yahoo-hot-jobs.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP Best Practices</title>
		<link>http://www.matthewstevenkelly.com/blog/kb/php-best-practices.html</link>
		<comments>http://www.matthewstevenkelly.com/blog/kb/php-best-practices.html#comments</comments>
		<pubDate>Sat, 26 Dec 2009 23:46:25 +0000</pubDate>
		<dc:creator>Matthew Steven Kelly</dc:creator>
				<category><![CDATA[The Knowledgebase]]></category>

		<guid isPermaLink="false">http://www.matthewstevenkelly.com/blog/?p=676</guid>
		<description><![CDATA[This was a very informative article: http://www.odi.ch/prog/design/php/guide.php

Best practices
This guide will give you solutions to common PHP design problems. It also provides a sketch of an application layout that I developed during the implementation of some projects.
php.ini quirks
Some settings in the php.ini control how PHP interpretes your scripts. This can lead to unexpected behaviour when moving your [...]]]></description>
			<content:encoded><![CDATA[<p>This was a very informative article: <a href="http://www.odi.ch/prog/design/php/guide.php">http://www.odi.ch/prog/design/php/guide.php</a></p>
<div style="display: none;">
<p>Best practices</p>
<p>This guide will give you solutions to common PHP design problems. It also provides a sketch of an application layout that I developed during the implementation of some projects.<br />
php.ini quirks<br />
Some settings in the php.ini control how PHP interpretes your scripts. This can lead to unexpected behaviour when moving your application from development to the productive environment. The following measures reduce dependency of your code on php.ini settings.</p>
<p>short_open_tag<br />
Always use the long PHP tags:<br />
Do not use the echo shortcut</p>
<p>asp_tags<br />
Do not use ASP like tags:</p>
<p>gpc_magic_quotes<br />
I recommend that you include code in a global include file which is run before any $_GET or $_POST parameter or $_COOKIE is read. That code should check if the gpc_magic_quotes option is enabled and run all $_GET, $_POST and $_COOKIE values through the stripslashes function.</p>
<p>register_globals<br />
Never rely on this option beeing set. Always access all GET, POST and COOKIE values through the &#8217;superglobal&#8217; $_GET, $_POST and $_COOKIE variables. For convenience declare $PHP_SELF = $_SERVER['PHP_SELF']; in your global include file after the gpc_magic_quotes quirk.</p>
<p>File uploads:<br />
The maximum size of an uploaded file is determined by the following parameters:<br />
file_uploads must be 1 (default)<br />
memory_limit must be slightly larger than the post_max_size and upload_max_filesize<br />
post_max_size must be large enough<br />
upload_max_filesize must be large enough<br />
Have one single configuration file<br />
You should define all configuration parameters of your application in a single (include) file. This way you can easily exchange this file to reflect settings for your local development site, a test site and the customer&#8217;s production environment. Common configuration parameters are:<br />
database connection parameters<br />
email addresses<br />
options<br />
debug and logging output switches<br />
application constants<br />
Keep an eye on the namespace<br />
As PHP does not have a namespace facility like Java packages, you must be very careful when choosing names for your classes and functions.<br />
Avoid functions outside classes whenever possible and feasible. Classes provide some extra namespace for the methods and variables that live inside them.<br />
If you declare global functions use a prefix. Some examples are dao_factory(), db_getConnection(), text_parseDate() etc.<br />
Use a database abstraction layer<br />
In PHP there are no database-independent functions for database access apart from ODBC (which nobody uses on Linux). You should not use the PHP database functions directly because this makes it expensive when the database product changes. Your customer may move from MySQL to Oracle one day or you will need an XML database maybe. You never know. Moreover an abstraction layer can ease development as the PHP database functions are not very userfriendly.<br />
Use Value Objects (VO)<br />
VOs are actually a J2EE pattern. It can easily be implemented in PHP. A value object corresponds directly to a C struct. It&#8217;s a class that contains only member variables and no methods other than convenience methods (usually none). A VO corresponds to a business object. A VO typically corresponds directly to a database table. Naming the VO member variables equal to the database fields is a good idea. Do not forget the ID column.<br />
class Person {<br />
var $id, $first_name, $last_name, $email;<br />
}<br />
Use Data Access Objects (DAO)<br />
DAO is actually a J2EE pattern. It can easily be implemented in PHP and helps greatly in separating database access from the rest of your code. The DAOs form a thin layer. The DAO layer can be &#8217;stacked&#8217; which helps for instance if you want to add DB caching later when tuning your application. You should have one DAO class for every VO class. Naming conventions are a good practice.<br />
class PersonDAO {<br />
var $conn;</p>
<p>function PersonDAO(&amp;$conn) {<br />
$this-&gt;conn =&amp; $conn;<br />
}</p>
<p>function save(&amp;$vo) {<br />
if ($v-&gt;id == 0) {<br />
$this-&gt;insert($vo);<br />
} else {<br />
$this-&gt;update($vo);<br />
}<br />
}</p>
<p>function get($id) {<br />
#execute select statement<br />
#create new vo and call getFromResult<br />
#return vo<br />
}</p>
<p>function delete(&amp;$vo) {<br />
#execute delete statement<br />
#set id on vo to 0<br />
}</p>
<p>#&#8211; private functions</p>
<p>function getFromResult(&amp;vo, $result) {<br />
#fill vo from the database result set<br />
}</p>
<p>function update(&amp;$vo) {<br />
#execute update statement here<br />
}</p>
<p>function insert(&amp;$vo) {<br />
#generate id (from Oracle sequence or automatically)<br />
#insert record into db<br />
#set id on vo<br />
}<br />
}<br />
A DAO typically implements the following methods:<br />
save: inserts or updates a record<br />
get: fetches a record<br />
delete: removes a record<br />
The DAO may define additional methods as required by your application&#8217;s needs. The should only perform actions that require the database (maybe only for performance reasons) and can not be implemented in a different mannor. Examples: isUsed(), getTop($n), find($criteria).</p>
<p>The DAO should only implement basic select / insert / update operations on one table. It must not contain the business logic. For example the PersonDAO should not contain code to send email to a person. For n-to-n relationships create a separate DAO (and even a VO if the relationships has additional properties) for the relation table.</p>
<p>Write a factory function that returns the proper DAO given the class name of a VO.Caching is a good idea here.<br />
function dao_getDAO($vo_class) {<br />
$conn = db_conn(&#8216;default&#8217;); #get a connection from the pool<br />
switch ($vo_class) {<br />
case &#8220;person&#8221;: return new PersonDAO($conn);<br />
case &#8220;newsletter&#8221;: return new NewsletterDAO($conn);<br />
&#8230;<br />
}<br />
}</p>
<p>Generate code<br />
99% of the code for your VOs and DAOs can be generated automatically from your database schema when you use some naming conventions for your tables and columns. Having a generator script ready saves you time when you are likely to change the database schema during development. I successfully used a perl script to generate my VOs and DAOs for a project. Unfortunately I am not allowed to post it here.<br />
Business logic<br />
Business logic directly reflects the use cases. The business logic deals with VOs, modifies them according to the business requirements and uses DAOs to access the persistence layer. The business logic classes should provide means to retrieve information about errors that occurred.<br />
class NewsletterLogic {<br />
function NewsletterLogic() {<br />
}</p>
<p>function subscribePerson(&amp;$person) {<br />
&#8230;<br />
}</p>
<p>function unsubscribePerson(&amp;$person) {<br />
&#8230;<br />
}</p>
<p>function sendNewsletter(&amp;$newsletter) {<br />
&#8230;<br />
}<br />
}</p>
<p>Page logic (Controller)<br />
When a page is called, the page controller is run before any output is made. The controller&#8217;s job is to transform the HTTP request into business objects, then call the approriate logic and prepare the objects used to display the response.<br />
The page logic performs the following steps:</p>
<p>1. The cmd request parameter is evaluated.<br />
2. Based on the action other request parameters are evaluated.<br />
3. Value Objects (or a form object for more complex tasks) are created from the parameters.<br />
4. The objects are validated and the result is stored in an error array.<br />
5. The business logic is called with the Value Objects.<br />
6. Return status (error codes) from the business logic is evaluated.<br />
7. A redirect to another page is executed if necessary.<br />
8. All data needed to display the page is collected and made available to the page as variables of the controller. Do not use global variables.</p>
<p>Note: it is a good idea to have a utility function that returns a parameter that is sent via GET or POST respectivly and provide a default value if the parameter is missing. The page logic is the only non-HTML include file in the actual page! The page logic file must include all other include files used by the logic (see base.inc.php below). Use the require_once PHP command to include non-HTML files.<br />
class PageController {<br />
var $person; #$person is used by the HTML page<br />
var $errs;</p>
<p>function PageController() {<br />
$action = Form::getParameter(&#8216;cmd&#8217;);<br />
$this-&gt;person = new Person();<br />
$this-&gt;errs = array();</p>
<p>if ($action == &#8217;save&#8217;) {<br />
$this-&gt;parseForm();<br />
if (!this-&gt;validate()) return;</p>
<p>NewsletterLogic::subscribe($this-&gt;person);</p>
<p>header(&#8216;Location: confirmation.php&#8217;);<br />
exit;<br />
}<br />
}</p>
<p>function parseForm() {<br />
$this-&gt;person-&gt;name = Form::getParameter(&#8216;name&#8217;);<br />
$this-&gt;person-&gt;birthdate = Util::parseDate(Form::getParameter(&#8216;birthdate&#8217;);<br />
&#8230;<br />
}</p>
<p>function validate() {<br />
if ($this-&gt;person-&gt;name == &#8221;) $this-&gt;errs['name'] = FORM_MISSING;<br />
#FORM_MISSING is a constant<br />
&#8230;<br />
return (sizeof($this-&gt;errs) == 0);<br />
}<br />
}<br />
Presentation Layer<br />
The top level page will contain the actual HTML code. You may include HTML parts that you reuse across pages like the navigation etc. The page expects the page logic to prepare all business objects that it needs. It&#8217;s a good idea to document the business objects needed at the top of the page.<br />
The page accesses properties of those business objects and formats them into HTML.</p>
<form action="&lt;?php echo htmlspecialchars($PHP_SELF) ?&gt;" method="POST">
<input name="cmd" type="hidden" value="save" />
<input name="name" type="text" />
value=&#8221;name); ?&gt;&#8221;&gt;<br />
<button>Subscribe</button><br />
</form>
<p>Localization<br />
Localization is a problem. You must choose among<br />
a) duplicating pages<br />
b) removing all hardcoded strings from your HTML.</p>
<p>As I work in a design company I usually take approach a). Approach b) is not feasible as it makes the HTML very hard to read and nearly impossible to edit in a visual web editor like Dreamweaver. Dynamic content is hard enough to edit with Dreamweaver. Removing also all strings, makes the page look quite empty&#8230;</p>
<p>So finish the project in one language first. The copy the HTML pages that need translation. Use a naming convention like index_fr.php to designate the French version of the index page. Always use the ISO two letter language codes. Do not invent your own language codes.</p>
<p>To keep track of the language the user selected you must choose among<br />
a) storing the language setting in a session variable or cookie<br />
b) reading the preferred language (locale) from the HTTP headers the browser sends you<br />
c) appending the language to the URL of every link in your application</p>
<p>While a) seems a lot more easier than c) it may be subject to session timeout. Option b) should only be implemented as an extension to a) or c).<br />
Strings in a database must be localized too!<br />
Making your application location independent<br />
PHP has problems in some situations when include files are nested and reside in different folders and it is unclear at which directory level the file will be included. One can solve this by using absolute path names or using $_SERVER['DOCUMENT_ROOT'] as a starting point. However this makes your code location dependent &#8211; it will not run anymore if you move it down your directory structure one level. Of cource we do not like that.<br />
I have found a convenient solution to this problem. The toplevel page (the one that is called by the browser) needs to know the relative path to the application root directory. Unfortunately there is no such function in PHP and the webapp context concept is completely absent in PHP. So we can not automatically determine the application root reliably in all situations (It is *really* impossible. Don&#8217;t even try. It&#8217;s not worth the effort.)<br />
Let&#8217;s define a global variable called $ROOT in an include file in every directory that contains toplevel pages. The include file (call it root.inc.php) must be included by the page logic before any other include files. Now you can use the $ROOT variable to reference include files with their exact path!</p>
<p>Sample:<br />
We have toplevel pages in /admin/pages/. The $ROOT variable must therefore be set to $ROOT = &#8216;../..&#8217;;. The page logic included by pages in that folder would reference their include files like require_once(&#8220;$ROOT/lib/base.inc.php&#8221;);.</p>
<p>In my suggested folder outline (see below) we don&#8217;t even need that, since all toplevel pages reside in the webapp root directory anyway. So the webapp root directory is always the current directory.<br />
Folder outline<br />
I suggest you make one file per class and follow a naming convention. Make sure that all your include files end with .php to avoid disclosure of your code to malicious users, which is a major security problem. I suggest the following folder structure:<br />
/	 Webapp root directory. Contains the pages that are actually called by the browser.<br />
/lib/	 Contains base.inc.php and config.inc.php<br />
/lib/common/	 Contains libraries and tools reusable for other projects, like your database abstraction classes.<br />
/lib/model/	 Contains the Value Object classes<br />
/lib/dao/	 Contains the DAO classes and the DAO factory<br />
/lib/logic/	 Contains the business logic classes<br />
/parts/	 Contains partial HTML that is included by pages<br />
/control/	 Contains the page logic. For larger applications you may want additional sub-directories for the individual parts (e.g. /admin/, /pub/) of your application to make the root directory a little lighter. Each of them would have their own control sub-directory.</p>
<p>Provide a base.inc.php file that includes (require_once) in the right order:<br />
frequently used stuff (database layer) from /lib/common<br />
the config include file<br />
all classes from /lib/model<br />
all classes from /lib/dao</p>
<p>Of course you will have additional directories for your images, uploaded files, &#8230; etc.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.matthewstevenkelly.com/blog/kb/php-best-practices.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Access QuickBooks from a Windows Service (such as Apache)</title>
		<link>http://www.matthewstevenkelly.com/blog/technology/access-quickbooks-from-a-windows-service-such-as-apache.html</link>
		<comments>http://www.matthewstevenkelly.com/blog/technology/access-quickbooks-from-a-windows-service-such-as-apache.html#comments</comments>
		<pubDate>Wed, 16 Dec 2009 04:29:09 +0000</pubDate>
		<dc:creator>Matthew Steven Kelly</dc:creator>
				<category><![CDATA[Technology and Me]]></category>

		<guid isPermaLink="false">http://www.matthewstevenkelly.com/blog/?p=667</guid>
		<description><![CDATA[Quickbooks Desktop Integration
I was trying to get a Apache/PHP application to interface with Quickbooks using QBXML through the Quickbooks SDK and kept receiving the following error:

&#8220;Could not start Quickbooks&#8221;

When looking at the SDK log file (Located at C:\Documents and Settings\All Users\Application Data\Intuit\QuickBooks\qbsdklog.txt), I kept seeing the following error when attempting access the file:
20091215.215811 I 3416 [...]]]></description>
			<content:encoded><![CDATA[<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; padding: 0px;"><strong><span style="text-decoration: underline;">Quickbooks Desktop Integration</span></strong></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; padding: 0px;">I was trying to get a Apache/PHP application to interface with Quickbooks using QBXML through the Quickbooks SDK and kept receiving the following error:</p>
<ul>
<li>&#8220;Could not start Quickbooks&#8221;</li>
</ul>
<p>When looking at the SDK log file (Located at <span style="color: #0000ff;">C:\Documents and Settings\All Users\Application Data\Intuit\QuickBooks\qbsdklog.txt</span>), I kept seeing the following error when attempting access the file:</p>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">20091215.215811<span style="white-space: pre;"> </span>I<span style="white-space: pre;"> </span>3416<span style="white-space: pre;"> </span>RequestProcessor<span style="white-space: pre;"> </span>========= Started Connection =========</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">20091215.215811<span style="white-space: pre;"> </span>I<span style="white-space: pre;"> </span>3416<span style="white-space: pre;"> </span>RequestProcessor<span style="white-space: pre;"> </span>Request Processor, QBXMLRP2 v7.0</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">20091215.215811<span style="white-space: pre;"> </span>I<span style="white-space: pre;"> </span>3416<span style="white-space: pre;"> </span>RequestProcessor<span style="white-space: pre;"> </span>Connection opened by app named &#8216;php QB via C#&#8217;</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">20091215.215812<span style="white-space: pre;"> </span>E<span style="white-space: pre;"> </span>3416<span style="white-space: pre;"> </span>RequestProcessor<span style="white-space: pre;"> </span>QuickBooks is not running and the data file name is not provided. Cannot continue.</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">20091215.215812<span style="white-space: pre;"> </span>E<span style="white-space: pre;"> </span>3416<span style="white-space: pre;"> </span>RequestProcessor<span style="white-space: pre;"> </span>Could not create instance of QuickBooks. hr = 80040416</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">20091215.215812<span style="white-space: pre;"> </span>I<span style="white-space: pre;"> </span>3416<span style="white-space: pre;"> </span>RequestProcessor<span style="white-space: pre;"> </span>Connection closed by app named &#8216;php QB via C#&#8217;</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">20091215.215812<span style="white-space: pre;"> </span>I<span style="white-space: pre;"> </span>3416<span style="white-space: pre;"> </span>RequestProcessor<span style="white-space: pre;"> </span>========== Ended Connection ==========</div>
<pre>========= Started Connection =========
Request Processor, QBXMLRP2 v7.0
Connection opened by app named 'php QB via Apache'
An internal error occured while looking for a running instance of
QuickBooks. Cannot continue. hr = 800401f3
Could not create instance of QuickBooks. hr = 8004041c
Connection closed by app named 'php QB via Apache'
========== Ended Connection ==========</pre>
<p>If I ran my integration application through command prompt (via a .bat file) instead of Apache it worked perfectly. But Apache would not sync. I was running the Apache service as an Administrator which is I though all I needed to do. I was wrong.</p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; padding: 0px;">Apparently accessing QuickBooks from a Windows service requires special COM permissions, because there are in-process/out-of-process Windows COM issues. We basically need to do three things: configure the COM permissions for QBXMLRP2e (installed with the Quickbooks SDK), configure Apache to run as a Windows user and configure Quickbooks to allow the application to connect.</p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; padding: 0px;"><strong>COM Permissions configuration:</strong></p>
<ol>
<li>Make sure the Quickbooks SDK is installed.</li>
<li>Run command prompt and type: &#8220;C:\Program Files\Intuit\IDN\QBSDK7.0\tools\access\QBXMLRP2e\qbXMLRP2e.exe&#8221; /RegServerThis adds qbXMLRP2e to the DCOM settings list.</li>
<li>Run &#8220;Component Services&#8221; from &#8220;Control Panel &gt; Administrator Tools&#8221;</li>
<li>Then from &#8220;Console Root &gt; Computers &gt; My Computers &gt; DCOM Config&#8221; right click on &#8220;qbXMLRP2e&#8221; and select Properties</li>
</ol>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 60px; ">“Authentication level” should be set to <strong>Default</strong></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 60px; "><strong><span style="font-weight: normal; ">Go in Security “Launch and activation” select “Customize” and press Edit. Add the Windows user the service runs as and assign all calling rights. “Access” select “Customize” and press Edit. Add the Windows user the service runs as and assign all. “Configuration” select “Customize” and press Edit. Add the Windows user the service runs as and assign all.</span></strong></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 60px; "><strong><span style="font-weight: normal; ">Go in “Identity” tab and select &#8220;The interactive user&#8221;</span></strong></p>
<p><strong> </strong></p>
<p><strong>Click Apply.</strong></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px;"><strong>Apache/Quickbooks configuration:</strong></p>
<ol>
<li>Make sure Apache is running as the user configured as the DCOM Windows user. Right click on the Apache Monitor and select Open Services. Change the &#8220;Log On As&#8221; user for the Apache service.</li>
<li>Open Quickbooks and set it to multi-user mode. Be sure to clear out any applications in &#8220;Preference | Application Settings&#8221; first to make sure the permission settings get set correctly.</li>
<li>Run a GUI version of your application accessing quickbooks. For example running your program through command line instead of Apache.</li>
<li>Follow the prompts in Quickbooks to allow the application access.</li>
<li>Run the integration through Apache and it should work now!</li>
</ol>
<p>This took forever to figure out and hopefully it helps someone googling the error codes I was receiving.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.matthewstevenkelly.com/blog/technology/access-quickbooks-from-a-windows-service-such-as-apache.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Chase website missing a feature</title>
		<link>http://www.matthewstevenkelly.com/blog/random/chase-website-missing-a-feature.html</link>
		<comments>http://www.matthewstevenkelly.com/blog/random/chase-website-missing-a-feature.html#comments</comments>
		<pubDate>Mon, 07 Dec 2009 01:16:12 +0000</pubDate>
		<dc:creator>Matthew Steven Kelly</dc:creator>
				<category><![CDATA[Random]]></category>

		<guid isPermaLink="false">http://www.matthewstevenkelly.com/blog/?p=665</guid>
		<description><![CDATA[I paid off my car in October. My Chase auto loan account is closed. It says &#8220;account closed&#8221; when I try to login at chase.com. However, during the first week of December, my bank account was charged a regular car payment. Apparently unless you cancel the auto pay feature on their website they keep charging [...]]]></description>
			<content:encoded><![CDATA[<p>I paid off my car in October. My Chase auto loan account is closed. It says &#8220;account closed&#8221; when I try to login at chase.com. However, during the first week of December, my bank account was charged a regular car payment. Apparently unless you cancel the auto pay feature on their website they keep charging you against your closed account. And then when you call them and ask them about it, they say the only thing you can do is send them a letter because since the account is closed, they have no way of refunding the money. Chase really needs to have a &#8220;feature&#8221; where they don&#8217;t continue auto pay on a closed account that has a $0 balance&#8230;.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.matthewstevenkelly.com/blog/random/chase-website-missing-a-feature.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Real People = Real Results!</title>
		<link>http://www.matthewstevenkelly.com/blog/community/real-people-real-results.html</link>
		<comments>http://www.matthewstevenkelly.com/blog/community/real-people-real-results.html#comments</comments>
		<pubDate>Sun, 22 Nov 2009 23:08:02 +0000</pubDate>
		<dc:creator>Matthew Steven Kelly</dc:creator>
				<category><![CDATA[Community Building]]></category>

		<guid isPermaLink="false">http://www.matthewstevenkelly.com/blog/?p=662</guid>
		<description><![CDATA[On December 19th, Kenneth Wade A., is holding a &#8220;Citizens for Change&#8221; meeting at 215 East 3rd Street, Dayton Ohio (Dayton Metro Library) 10am-12pm. Help us put Dayton back on track!
http://www.ourdayton.com/










Matthew Steven Kelly is a fan of










Kenneth Wade A.





Create your Fan Badge


]]></description>
			<content:encoded><![CDATA[<p>On December 19th, Kenneth Wade A., is holding a &#8220;Citizens for Change&#8221; meeting at 215 East 3rd Street, Dayton Ohio (Dayton Metro Library) 10am-12pm. Help us put Dayton back on track!</p>
<p><a href="http://www.ourdayton.com/">http://www.ourdayton.com/</a></p>
<p><!-- Facebook Fan Badge START --></p>
<div style="width: 100%;">
<div style="background: #3B5998;padding: 5px;"><img src="http://www.facebook.com/images/fb_logo_small.png" alt="Facebook" /><img src="http://badge.facebook.com/badge/101021373743.21903674.1412973001.png" alt="" width="0" height="0" /></div>
<div style="background: #EDEFF4;display: block;border-right: 1px solid #D8DFEA;border-bottom: 1px solid #D8DFEA;border-left: 1px solid #D8DFEA;margin: 0px;padding: 0px 0px 5px 0px;">
<div style="background: #EDEFF4;display: block;padding: 5px;">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top"><img src="http://www.facebook.com/images/icons/fbpage.gif" alt="" /></td>
<td valign="top">
<p style="color: #808080;font-family: verdana;font-size: 11px;margin: 0px 0px 0px 0px;padding: 0px 8px 0px 8px;"><a style="color: #3B5998;font-family: verdana;font-size: 11px;font-weight: normal;margin: 0px;padding: 0px 0px 0px 0px;text-decoration: none;" title="Matthew Steven Kelly" href="http://www.facebook.com/matthewstevenkelly" target="_TOP">Matthew Steven Kelly</a> is a fan of</p>
</td>
</tr>
</tbody>
</table>
</div>
<div style="background: #FFFFFF;clear: both;display: block;margin: 0px;overflow: hidden;padding: 5px;">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="middle"><a style="border: 0px;color: #3B5998;font-family: verdana;font-size: 12px;font-weight: bold;margin: 0px;padding: 0px;text-decoration: none;" title="Kenneth Wade A." href="http://www.facebook.com/pages/Kenneth-Wade-A/101021373743" target="_TOP"><img style="border: 0px;margin: 0px;padding: 0px;" src="http://www.facebook.com/profile/pic.php?oid=AAAAAQAQxCgOtuIgLT28HlHsqbZEngAAAAwR_eDXh5efMNrfGo-a_WU6&amp;size=square" alt="Kenneth Wade A." /></a></td>
<td style="padding: 0px 8px 0px 8px;" valign="middle"><a style="border: 0px;color: #3B5998;font-family: verdana;font-size: 12px;font-weight: bold;margin: 0px;padding: 0px;text-decoration: none;" title="Kenneth Wade A." href="http://www.facebook.com/pages/Kenneth-Wade-A/101021373743" target="_TOP">Kenneth Wade A.</a></td>
</tr>
</tbody>
</table>
</div>
</div>
<div style="display: block;float: right;margin: 0px;padding: 4px 0px 0px 0px;"><a style="color: #3B5998;font-family: verdana;font-size: 11px;font-weight: none;margin: 0px;padding: 0px;text-decoration: none;" title="Create your Fan Badge" href="http://www.facebook.com/facebook-widgets/fanbadges.php" target="_TOP">Create your Fan Badge</a></div>
</div>
<p><!-- Facebook Fan Badge END --></p>
]]></content:encoded>
			<wfw:commentRss>http://www.matthewstevenkelly.com/blog/community/real-people-real-results.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Community Supported Agriculture</title>
		<link>http://www.matthewstevenkelly.com/blog/health/community-supported-agriculture.html</link>
		<comments>http://www.matthewstevenkelly.com/blog/health/community-supported-agriculture.html#comments</comments>
		<pubDate>Wed, 18 Nov 2009 06:21:47 +0000</pubDate>
		<dc:creator>Matthew Steven Kelly</dc:creator>
				<category><![CDATA[Healthy Living]]></category>

		<guid isPermaLink="false">http://www.matthewstevenkelly.com/blog/?p=660</guid>
		<description><![CDATA[Ohio needs to get a handle on its obesity epidemic: http://www.daytondailynews.com/news/dayton-news/half-of-ohios-adults-may-be-obese-by-2018half-of-ohios-adults-may-be-obese-by-2018-405474.html. Obesity, as they mention in the article, is defined by the federal Centers for Disease Control and Prevention as anyone with a body mass index of 30 or higher. You can calculate your BMI with an online BMI calculator: http://www.nhlbisupport.com/bmi/
One great way to fight obesity [...]]]></description>
			<content:encoded><![CDATA[<p>Ohio needs to get a handle on its obesity epidemic: <a href="http://www.daytondailynews.com/news/dayton-news/half-of-ohios-adults-may-be-obese-by-2018half-of-ohios-adults-may-be-obese-by-2018-405474.html">http://www.daytondailynews.com/news/dayton-news/half-of-ohios-adults-may-be-obese-by-2018half-of-ohios-adults-may-be-obese-by-2018-405474.html</a>. Obesity, as they mention in the article, is defined by the federal Centers for Disease Control and Prevention as anyone with a body mass index of 30 or higher. You can calculate your BMI with an online BMI calculator: <a href="http://www.nhlbisupport.com/bmi/">http://www.nhlbisupport.com/bmi/</a></p>
<p>One great way to fight obesity in Ohio is to promote community supported agriculture (CSA&#8217;s) such as Blue Bird Hills: <a href="http://www.bluebirdhills.com/CSA%20Introduction.html">http://www.bluebirdhills.com/CSA%20Introduction.html</a>. For 5 months out of the year a large box of vegetables is picked up at convenient locations throughout the Dayton area. As much as I like fresh vegetables, I would never buy this much from a store each week, and best of all &#8211; it&#8217;s all organic. It keeps your fridge well stocked, and scrambling for ways to incorporate fresh food into every meal so you finish it all off before the next box arrives.</p>
<p>This was my first year belonging to a CSA, and I have never eaten healthier. I will definitely be joining next year as well.</p>
<p>There are other CSA&#8217;s in the area such as &#8220;The Happy Box&#8221; from Fulton Farms, <a href="http://www.fultonfarmsorganic.com/">http://www.fultonfarmsorganic.com/</a> which delivers the box right to your door. There are many offerings in our area: <a href="http://miamivalleygrown.ning.com/page/2613934:Page:581">http://miamivalleygrown.ning.com/page/2613934:Page:581</a> and if enough Ohioans start joining CSA&#8217;s maybe instead of the obesity rate climbing from 34% to 50.9% it will actually decrease!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.matthewstevenkelly.com/blog/health/community-supported-agriculture.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows 7 Starter Edition</title>
		<link>http://www.matthewstevenkelly.com/blog/technology/windows-7-starter-edition.html</link>
		<comments>http://www.matthewstevenkelly.com/blog/technology/windows-7-starter-edition.html#comments</comments>
		<pubDate>Wed, 11 Nov 2009 14:19:33 +0000</pubDate>
		<dc:creator>Matthew Steven Kelly</dc:creator>
				<category><![CDATA[Technology and Me]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[netbook]]></category>
		<category><![CDATA[Windows 7]]></category>

		<guid isPermaLink="false">http://www.matthewstevenkelly.com/blog/?p=638</guid>
		<description><![CDATA[Recently purchased a netbook with Windows 7 on it a few weeks ago. I didn&#8217;t realize until I started using it the massive limitations of Windows 7 Starter Edition. This article articulates it pretty well: http://www.eweek.com/c/a/Windows/Microsofts-Windows-7-Could-Disappoint-Netbook-Users-Says-Survey-368762/
Even worse, when the netbook was first loading, they misspelled initializing as &#8220;Initailizing&#8230;&#8221;. My blackberry doesn&#8217;t take very good shots [...]]]></description>
			<content:encoded><![CDATA[<p>Recently purchased a netbook with Windows 7 on it a few weeks ago. I didn&#8217;t realize until I started using it the massive limitations of Windows 7 <strong>Starter </strong>Edition. This article articulates it pretty well: <a href="http://www.eweek.com/c/a/Windows/Microsofts-Windows-7-Could-Disappoint-Netbook-Users-Says-Survey-368762/">http://www.eweek.com/c/a/Windows/Microsofts-Windows-7-Could-Disappoint-Netbook-Users-Says-Survey-368762/</a></p>
<p>Even worse, when the netbook was first loading, they misspelled initializing as &#8220;Initailizing&#8230;&#8221;. My blackberry doesn&#8217;t take very good shots of LCD netbook screens, but here is the picture:</p>
<div id="attachment_640" class="wp-caption alignnone" style="width: 310px"><img class="size-medium wp-image-640" title="windows_7_initailizing" src="http://www.matthewstevenkelly.com/blog/wp-content/uploads/2009/11/windows_7_initailizing-300x225.jpg" alt="Windows 7 misspells initializing" width="300" height="225" /><p class="wp-caption-text">Windows 7 misspells initializing as &quot;Initailizing&quot;</p></div>
<p>A coworker of mine is always talking about how great Ubutnu is: <a href="http://www.ubuntu.com/">http://www.ubuntu.com/</a>, and I do have an extra laptop to try it out on. So that seems like a nice weekend project.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.matthewstevenkelly.com/blog/technology/windows-7-starter-edition.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
