<?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>A Perfectly Normal Blog &#187; Software Development</title>
	<atom:link href="http://www.gefvert.org/blog/archives/category/software-development/feed" rel="self" type="application/rss+xml" />
	<link>http://www.gefvert.org/blog</link>
	<description>Just a scratchpad for thoughts, reflections, and stuff.</description>
	<lastBuildDate>Mon, 16 Jan 2012 03:51:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Storing Person-specific Sensitive Data in Databases</title>
		<link>http://www.gefvert.org/blog/archives/1002</link>
		<comments>http://www.gefvert.org/blog/archives/1002#comments</comments>
		<pubDate>Mon, 05 Dec 2011 18:24:22 +0000</pubDate>
		<dc:creator>Mats Gefvert</dc:creator>
				<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://www.gefvert.org/blog/?p=1002</guid>
		<description><![CDATA[How do you build a system that can ask people very sensitive questions, for instance about their work, etc; and ensure confidentiality of the answers on a database level, yet allow each person to answer only once (and if necessary &#8230; <a href="http://www.gefvert.org/blog/archives/1002">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>How do you build a system that can ask people very sensitive questions, for instance about their work, etc; and ensure confidentiality of the answers on a database level, yet allow each person to answer only once (and if necessary edit his answers)?</p>
<p>This is my proposed method.</p>
<ul>
<li>The system itself consists of a database, a set of PHP pages, and a configuration file.</li>
<li>The PHP files identify the user and give him a unique identifier <b>k<sub>u</sub></b>, say, the person&#8217;s name, SSN, or similar identity. This is only stored in the current session. Necessary referential constraints can be added to ensure the validity of the identifier, so the user specifies a real name &#8211; e.g. through a lookup in a user table.</li>
<li>The system configuration file contains a system key, <b>k<sub>s</sub></b>, which is a unique, random key, and which is kept secret.</li>
<li>The database has three tables.
<ul>
<li>Two tables make up the questions. One for each questionnaire, and one for each question connected to the questionnaire. Each questionnaire is given a unique, random key <b>k<sub>q</sub></b>, and each question has an auto-incrementing ID.</li>
<li>The third table contains the answers, which every user has specified. The unique key to each answer is given by the question ID, and a cryptographically secure hash <b>h</b> -> <b>H</b>(<b>k<sub>s</sub></b> + <b>k<sub>u</sub></b> + <b>k<sub>q</sub></b>)</b>.</li>
</ul>
</li>
</ul>
<p>By keeping <b>k<sub>s</sub></b> a secret, it is cryptologically impossible to find out the user identity of any given answer in the answers table. And by varying <b>k<sub>q</sub></b> for each questionnaire, it is also impossible to track users over several questionnaires. <b>h</b> will, however, be the same for each given questionnaire and user.</p>
<p>It is thereby possible for the system to post answers from a given user into the tables, and access previous answers; and it is also possible for a user to retrieve answers, filter them, and generate statistics, without ever having access to any identities for the given answers. Even if the system is compromised, it is impossible to learn the identities of any answers without using a brute-force (or table lookup) method.</p>
<p>Does this sound ok?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gefvert.org/blog/archives/1002/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL Function to Calculate Excel- (or Delphi)-style Dates</title>
		<link>http://www.gefvert.org/blog/archives/960</link>
		<comments>http://www.gefvert.org/blog/archives/960#comments</comments>
		<pubDate>Tue, 18 Oct 2011 18:00:18 +0000</pubDate>
		<dc:creator>Mats Gefvert</dc:creator>
				<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://www.gefvert.org/blog/?p=960</guid>
		<description><![CDATA[drop function if exists exceldate; delimiter // -- Function that returns an Excel-style or Delphi-style date value -- from a MySQL date. A date value of 0 represents 1899-12-30. create function exceldate(p_date date) returns int sql security invoker begin return &#8230; <a href="http://www.gefvert.org/blog/archives/960">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<pre>drop function if exists exceldate;

delimiter //

<em>-- Function that returns an Excel-style or Delphi-style date value
-- from a MySQL date. A date value of 0 represents 1899-12-30.</em>
create function exceldate(p_date date)
    returns int
    sql security invoker
begin
    return to_days(p_date) - 693959;
end //

delimiter ;

select '1899-12-31', exceldate('1899-12-31')     <em>-- should be 1</em>
union
select '2011-10-18', exceldate('2011-10-18');    <em>-- should be 40834</em></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.gefvert.org/blog/archives/960/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Luhn (mod 10) Check Digit Algorithm in MySQL</title>
		<link>http://www.gefvert.org/blog/archives/947</link>
		<comments>http://www.gefvert.org/blog/archives/947#comments</comments>
		<pubDate>Thu, 13 Oct 2011 13:19:19 +0000</pubDate>
		<dc:creator>Mats Gefvert</dc:creator>
				<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://www.gefvert.org/blog/?p=947</guid>
		<description><![CDATA[drop function if exists luhn; drop function if exists luhn_check; delimiter // -- Function that calculates a Luhn (mod 10) check digit from a numeric string. -- The behavior is undefined if the string contains anything else than digits. -- &#8230; <a href="http://www.gefvert.org/blog/archives/947">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<pre>drop function if exists luhn;
drop function if exists luhn_check;

delimiter //

<i>-- Function that calculates a Luhn (mod 10) check digit from a numeric string.
-- The behavior is undefined if the string contains anything else than digits.
-- Assumes that the string does not have a check digit added yet, so it starts
-- with a weight of 2 at the last digit.</i>
create function luhn(p_number varchar(31))
    returns char(1)
    sql security invoker
begin
    declare i, mysum, r, weight int;

    set weight = 2;
    set mysum = 0;
    set i = length(p_number);

    while i > 0 do
        set r = substring(p_number, i, 1) * weight;
        set mysum = mysum + if(r > 9, r - 9, r);
        set i = i - 1;
        set weight = 3 - weight;
    end while;

    return (10 - mysum % 10) % 10;
end //

<i>-- Check if a numeric string has a valid check digit. Does this by cutting off
-- the last digit, recalculating the Luhn check digit, and comparing the strings.</i>
create function luhn_check(p_number varchar(32))
    returns boolean
    sql security invoker
begin
    declare luhn_number varchar(32);

    set luhn_number = substring(p_number, 1, length(p_number) - 1);
    set luhn_number = concat(luhn_number, luhn(luhn_number));

    return luhn_number = p_number;
end //

delimiter ;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.gefvert.org/blog/archives/947/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>A Small Script to Compress Movies for Cellphones</title>
		<link>http://www.gefvert.org/blog/archives/931</link>
		<comments>http://www.gefvert.org/blog/archives/931#comments</comments>
		<pubDate>Fri, 04 Feb 2011 16:07:08 +0000</pubDate>
		<dc:creator>Mats Gefvert</dc:creator>
				<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://www.gefvert.org/blog/?p=931</guid>
		<description><![CDATA[I wrote this small script for Windows to compress movies (avi, mkv etc) down to cell phone format. The encoding isn&#8217;t great, but the average two-hour movie compresses down to just about ~100 MB, which is really nice. Works fine &#8230; <a href="http://www.gefvert.org/blog/archives/931">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I wrote this small script for Windows to compress movies (avi, mkv etc) down to cell phone format. The encoding isn&#8217;t great, but the average two-hour movie compresses down to just about ~100 MB, which is really nice. Works fine on Nokia N85. Edit to suit your needs. It relies on ffmpeg, which you can find Windows binary downloads for here and there. Google for it, kid, google for it!</p>
<p>Oh, it also requires cygwin, for the perl interpreter. (Or ActivePerl, I suppose.)</p>
<p>ff-m4v.cmd:</p>
<pre>@echo off
set CYGWIN=nodosfilewarning
for %%F in (%*) do (
    echo.
    echo ######## %%F #########
    echo.
    perl %~dpn0.pl %%F
)</pre>
<p>ff-m4v.pl:</p>
<pre>$in = shift;
$data = `ffmpeg -i '$in' 2>&#038;1`;

$out = $in;
$out =~ s/\.[A-Za-z0-9]+$/\.m4v/;

($x, $y) = $data =~ /Video:.*?(\d+)x(\d+)/i;
$dx = 320 / $x;
$dy = 240 / $y;
$d = $dx < $dy ? $dx : $dy;

$dim = int($d * $x) . 'x' . int($d * $y);

$opt = "ffmpeg -i '$in' -f mp4 -vcodec mpeg4 -b 80000 -r 12 -acodec aac -ar 16000 -ab 48000 -ac 1 -threads 2 -y -s $dim '$out'";
print "$opt\n";
system($opt);</pre>
<p>The parameters evaluate to mpeg4 encoding, 80 kbit/s bitrate for video, 12 frames per second; AAC encoding with 48 kbit/s bitrate, mono sound. It compresses the movie down to a maximum of 320x240 pixels, but preserves aspect ratio (effectively becoming 320x196, 320x160 or whatever). If you want to use 2-pass encoding, it's easy; just repeat the system($opt) call with "-pass 1" and "-pass 2" parameters.</p>
<p>Put both in the same folder, make sure ffmpeg.exe is in the system path, and run "ff-m4v *.avi".</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gefvert.org/blog/archives/931/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>CMD File to Run the Same Programs at Work Every Day</title>
		<link>http://www.gefvert.org/blog/archives/925</link>
		<comments>http://www.gefvert.org/blog/archives/925#comments</comments>
		<pubDate>Wed, 02 Feb 2011 13:30:44 +0000</pubDate>
		<dc:creator>Mats Gefvert</dc:creator>
				<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://www.gefvert.org/blog/?p=925</guid>
		<description><![CDATA[I usually sign on to work by starting at least four different programs: Microsoft Lync, Miranda, a SIP telephone, and a little break clock. I used to have a Python script for it, but I thought that installing ActivePython on &#8230; <a href="http://www.gefvert.org/blog/archives/925">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I usually sign on to work by starting at least four different programs: Microsoft Lync, Miranda, a SIP telephone, and a little break clock. I used to have a Python script for it, but I thought that installing ActivePython on a Windows machine just to start four programs is a bit of an overkill. So I wrote a CMD file instead. It&#8217;s really amazing what you can beat the old CMD interpreter into doing.</p>
<p>startToday.cmd:</p>
<pre>@echo off

tasklist /nh > __tasklist.txt

for /f "delims=" %%F in (startToday.files) do (
    findstr /b /i "%%~nxF" __tasklist.txt > nul
    if errorlevel 1 (
        echo starting %%F
        start "" "%%F"
    )
)

del /q /f __tasklist.txt</pre>
<p>startToday.files:</p>
<pre>C:\Program Files\CounterPath\X-Lite\x-lite.exe
C:\Program Files\Miranda IM\miranda32.exe
C:\Program Files\Microsoft Lync\communicator.exe
C:\Home\stuff\software projects\BreakTime\BreakTime.exe</pre>
<p>Voila!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gefvert.org/blog/archives/925/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Making Beautiful Lists</title>
		<link>http://www.gefvert.org/blog/archives/914</link>
		<comments>http://www.gefvert.org/blog/archives/914#comments</comments>
		<pubDate>Mon, 20 Dec 2010 22:22:08 +0000</pubDate>
		<dc:creator>Mats Gefvert</dc:creator>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[Lists]]></category>
		<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://www.gefvert.org/blog/?p=914</guid>
		<description><![CDATA[This is a nice way to make beautiful lists. Take any old list of unordered elements, for instance: Apples Bananas Blistering barnacles Gargoyles Oranges Pears Sunfruit Looks good? Sure. But sometimes, you want it horizontally. Let&#8217;s add the following style &#8230; <a href="http://www.gefvert.org/blog/archives/914">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This is a nice way to make beautiful lists. Take any old list of unordered elements, for instance:</p>
<ul>
<li>Apples</li>
<li>Bananas</li>
<li>Blistering barnacles</li>
<li>Gargoyles</li>
<li>Oranges</li>
<li>Pears</li>
<li>Sunfruit</li>
</ul>
<p>Looks good? Sure. But sometimes, you want it horizontally. Let&#8217;s add the following style sheet to it.</p>
<pre>    ul                     { list-style: none; padding: 0; margin: 0; }
    ul li                  { list-style: none; padding: 0; margin: 0; display: inline; }
    ul li:after            { content: '\B7'; padding: 0 0.2em 0 0.5em; }
    ul li:last-child:after { content: '' }
</pre>
<p>And what do we get? Something as beautiful as this:</p>
<ul class="bork">
<li>Apples</li>
<li>Bananas</li>
<li>Blistering barnacles</li>
<li>Gargoyles</li>
<li>Oranges</li>
<li>Pears</li>
<li>Sunfruit</li>
</ul>
<p>A nice, horizontal list; and the best thing about it, is that there are no little dots in the HTML code, no handling for first or last elements (no ul class=&#8221;last&#8221;), nothing. Just pure css. And, of course, each element can be styled, you can make links, or any old thing. Seems to work fine in Firefox and Chrome; IE8 doesn&#8217;t seem to get the last &#8220;ul li:last-child:after&#8221; element, but all you get is a little dot after the last element. Worse things could happen.</p>
<style>
    ul.bork                     { list-style: none; padding: 0; margin: 0; margin-left: 30px }
    ul.bork li                  { list-style: none; padding: 0; margin: 0; display: inline; }
    ul.bork li:after            { content: '\B7'; padding: 0 0.2em 0 0.5em; }
    ul.bork li:last-child:after { content: '' }
</style>
]]></content:encoded>
			<wfw:commentRss>http://www.gefvert.org/blog/archives/914/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Backup up MySQL Tables Using Only CMD.EXE and 7-zip</title>
		<link>http://www.gefvert.org/blog/archives/896</link>
		<comments>http://www.gefvert.org/blog/archives/896#comments</comments>
		<pubDate>Tue, 07 Dec 2010 21:42:29 +0000</pubDate>
		<dc:creator>Mats Gefvert</dc:creator>
				<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://www.gefvert.org/blog/?p=896</guid>
		<description><![CDATA[A small batch file I wrote today, to back up MySQL databases, table by table. So many times have I needed to restore only a specific table, and yet it&#8217;s so difficult to dig out the correct table from the &#8230; <a href="http://www.gefvert.org/blog/archives/896">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A small batch file I wrote today, to back up MySQL databases, table by table.</p>
<p>So many times have I needed to restore only a specific table, and yet it&#8217;s so difficult to dig out the correct table from the whole database backup file (or even worse, server backup file).</p>
<p>This little file will store the whole database/server in individual files, and if you run it on a daily basis, will keep history in &#8220;backup.n&#8221; directories.</p>
<pre>@echo off

<span class="comment">rem Enable delayed expansion - otherwise the backup.n folder renaming won't work</span>
setlocal enabledelayedexpansion

<span class="comment">rem Change to the script's home folder</span>
%~d0
cd %~p0

<span class="comment">rem Rotate previous backup folders</span>
if exist backup.9 rd /s /q backup.9
for /l %%i in (8 -1 1) do (
    set /a j=%%i + 1
    if exist backup.%%i move backup.%%i backup.!j! > nul
)
if exist backup move backup backup.1 > nul

md backup

<span class="comment">rem Change these to reflect your MySQL connection parameters</span>
set OPT=-ubackup -pbackup -hlocalhost

<span class="comment">rem List all the databases and process them</span>
mysql %OPT% -e"show databases" --skip-column-names -B | findstr /v "information_schema" > _db.txt
for /f %%d in (_db.txt) do call :backupdb %%d

<span class="comment">rem Clean up, clean up, everybody wants to clean up</span>
del /f /q _dbt.txt
del /f /q _db.txt

dir backup

goto :eof

:backupdb
    <span class="comment">rem List the tables in the current database</span>
    echo %1
    mysql %OPT% -e"show tables" --skip-column-names -B %1 > _dbt.txt
    md backup\work

    <span class="comment">rem Dump each table into an SQL file</span>
    echo  - dumping data
    for /f %%t in (_dbt.txt) do mysqldump --opt %OPT% -rbackup\work\%%t.sql %1 %%t

    <span class="comment">rem Compress them with 7-zip into a single zip file</span>
    echo  - compressing
    cd backup\work
    ..\..\7z -y a ..\%1.zip * > nul

    <span class="comment">rem Clean up</span>
    cd ..
    rd /s /q work
    cd ..
    echo.

    goto :eof
</pre>
<p>Download 7-zip, extract 7z.exe and 7z.dll and put in the same folder as the &#8220;backup.cmd&#8221; file above, and you should be good to go. Change the -u and -p parameters in the &#8220;set OPT&#8221; statement to reflect the login settings for your database server.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gefvert.org/blog/archives/896/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Persistence</title>
		<link>http://www.gefvert.org/blog/archives/731</link>
		<comments>http://www.gefvert.org/blog/archives/731#comments</comments>
		<pubDate>Sun, 11 Oct 2009 09:19:03 +0000</pubDate>
		<dc:creator>Mats Gefvert</dc:creator>
				<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://www.matsgefvert.se/blog/?p=731</guid>
		<description><![CDATA[/** * NF_Persistence * * Agent Smith: "Why, Mr. Anderson, why? Why do you persist?" * Neo: "Because I choose to." * * PHP Version 5 * * @category NiftyFramework * @package NiftyFramework * @subpackage Database * @author Mats Gefvert &#8230; <a href="http://www.gefvert.org/blog/archives/731">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<pre>/**
 *  NF_Persistence
 *
 *  Agent Smith: "Why, Mr. Anderson, why? Why do you persist?"
 *  Neo:         "Because I choose to."
 *
 *  PHP Version 5
 *
 *  @category   NiftyFramework
 *  @package    NiftyFramework
 *  @subpackage Database
 *  @author     Mats Gefvert
<public @matsgefvert.se>
 *  @license    http://www.sun.com/cddl/ Common Development and Distribution License
 */

class NF_PersistenceRelationMap
{
    ....</public></pre>
<p>I make myself laugh sometimes. Is that a good sign? :)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gefvert.org/blog/archives/731/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Speeding Up Delphi&#8217;s TStringList.IndexOf</title>
		<link>http://www.gefvert.org/blog/archives/651</link>
		<comments>http://www.gefvert.org/blog/archives/651#comments</comments>
		<pubDate>Mon, 01 Jun 2009 13:33:52 +0000</pubDate>
		<dc:creator>Mats Gefvert</dc:creator>
				<category><![CDATA[Music]]></category>
		<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://www.matsgefvert.se/blog/archives/651</guid>
		<description><![CDATA[Delphi&#8217;s TStringList is one of the objects I love the most. If it&#8217;s sorted (StringList.Sorted := true) then you can use it to parse huge chunks of data quickly. For instance, looping through an enormous amount of IP addresses and &#8230; <a href="http://www.gefvert.org/blog/archives/651">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Delphi&#8217;s TStringList is one of the objects I love the most. If it&#8217;s sorted (StringList.Sorted := true) then you can use it to parse huge chunks of data quickly.</p>
<p>For instance, looping through an enormous amount of IP addresses and keeping count of how many times they appeared, is easily done using the following code (not compiled or checked for syntax errors):</p>
<blockquote>
<pre>ls := TStringList.Create;
ls.Sorted := true;
for ip in ipAddresses do begin
  n := ls.IndexOf(ip);
  if n = -1 then
    ls.AddObject(ip, TObject(1))
  else
    ls.Objects[n] := TObject(Integer(ls.Objects[n]) + 1);
end;</pre>
</blockquote>
<p>It&#8217;s very efficient. Since TStringList.IndexOf always does a binary search, it operates in log2(n) time, and using Objects as integers allows us to keep track of count without messing with the string data.</p>
<p>But there are things we can do to speed it up. For instance, TStringList.IndexOf relies on TStringList.Find, which itself uses AnsiCompareStr, which is a slow Windows call, taking locale and its mother into consideration. Overriding this with our own method should be worthwhile. (The code below is adapted straight from the Classes unit.)</p>
<blockquote>
<pre>type
  TStringListEx = class(TStringList)
  public
    function Find(const S: string; var Index: Integer): Boolean; override;
  end;

function TStringListEx.Find(const S: string; var Index: Integer): Boolean;
var
  L, H, I, C: Integer;
begin
  Result := False;
  L := 0;
  H := Count - 1;
  while L &lt;= H do
  begin
    I := (L + H) shr 1;
    C := CompareStr(Get(I), S);
    if C &lt; 0 then L := I + 1 else
    begin
      H := I - 1;
      if C = 0 then
      begin
        Result := True;
        if Duplicates &lt;&gt; dupAccept then L := I;
      end;
    end;
  end;
  Index := L;
end;</pre>
</blockquote>
<p>We&#8217;ve replaced AnsiCompareStr with Delphi&#8217;s own CompareStr, which is a highly optimized FastCode routine. There are some drawbacks &#8211; things will always be sorted in byte order and no case-sensitivity is done. But we don&#8217;t care about this &#8211; it can always be done afterwards; right now, speed is the main importance.</p>
<p>And it turns out that using the above code, in pure examples, can slash execution time with up to about 80%. Dramatic savings, indeed. In my own example, where I analyze ftp log data, I managed to cut execution time on 122 MB of data down from 7 seconds down to 3.1 seconds.</p>
<p>Best of all, since TStringList.Find is declared virtual, we don&#8217;t need to change any types anywhere, just do a <tt>TStringListEx.Create</tt> instead of a <tt>TStringList.Create</tt> and you&#8217;re good to go.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gefvert.org/blog/archives/651/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Computer Speed and Memory Access</title>
		<link>http://www.gefvert.org/blog/archives/631</link>
		<comments>http://www.gefvert.org/blog/archives/631#comments</comments>
		<pubDate>Mon, 04 May 2009 09:15:20 +0000</pubDate>
		<dc:creator>Mats Gefvert</dc:creator>
				<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://www.matsgefvert.se/blog/archives/631</guid>
		<description><![CDATA[I&#8217;ve found a new great blog, Gustavo Duarte&#8217;s blog, where he talks about hardware, operating system kernerls, and other fun items. I liked his comparison of how fast different types of memory is. The first thing that jumps out is &#8230; <a href="http://www.gefvert.org/blog/archives/631">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve found a new great blog, <a href="http://duartes.org/gustavo/blog/">Gustavo Duarte&#8217;s blog</a>, where he talks about hardware, operating system kernerls, and other fun items.</p>
<p>I liked his <a title="Gustavo Duarte: What Your Computer Does While You Wait" href="http://duartes.org/gustavo/blog/post/what-your-computer-does-while-you-wait">comparison of how fast different types of memory</a> is.</p>
<blockquote>
<p>The first thing that jumps out is how absurdly fast our processors are. Most simple instructions on the Core 2 take one clock cycle to execute, hence a third of a nanosecond at 3.0Ghz. For reference, light only travels ~4 inches (10 cm) in the time taken by a clock cycle&#8230;</p>
<p>Normally when the CPU needs to touch the contents of a memory region they must either be in the L1/L2 caches already or be brought in from the main system memory &#8230; To put this into perspective, reading from L1 cache is like grabbing a piece of paper from your desk (3 seconds), L2 cache is picking up a book from a nearby shelf (14 seconds), and main system memory is taking a 4-minute walk down the hall to buy a Twix bar&#8230;</p>
<p>[...] Even main memory is blazing fast compared to hard drives. Keeping with the office analogy, waiting for a hard drive seek is like leaving the building to roam the earth for <strong>one year and three months</strong>. This is why so many workloads are dominated by disk I/O and why database performance can drive off a cliff once the in-memory buffers are exhausted &#8230;</p>
</blockquote>
<p>Subscribed. :)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gefvert.org/blog/archives/631/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

