<?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>Fernando Ipar &#187; Programming</title>
	<atom:link href="http://fernandoipar.com/category/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://fernandoipar.com</link>
	<description>I love mankind! Its people I can&#039;t stand!</description>
	<lastBuildDate>Tue, 06 Dec 2011 01:01:21 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=abc</generator>
		<item>
		<title>Piping data to multiple processes</title>
		<link>http://fernandoipar.com/2011/03/10/piping-data-to-multiple-processes/</link>
		<comments>http://fernandoipar.com/2011/03/10/piping-data-to-multiple-processes/#comments</comments>
		<pubDate>Thu, 10 Mar 2011 05:00:06 +0000</pubDate>
		<dc:creator>fernando</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://fernandoipar.com/?p=216</guid>
		<description><![CDATA[Here&#8217;s a simple shell script to stream data to multiple processes. It has many applications, but the reason I wrote it is to stream the same data to multiple netcat processes on remote machines. Here&#8217;s the code: #!/bin/bash usage() { cat &#60;&#38;2 usage : multi-fifo target0 [target1 [target2 [...]]] Where each targetN is a program [...]


Related posts:<ol><li><a href='http://fernandoipar.com/2009/03/09/using-the-enum-data-type-to-increase-performance/' rel='bookmark' title='Permanent Link: Using the ENUM data type to increase performance'>Using the ENUM data type to increase performance</a> <small>While going through the DATA TYPES section of the Certification...</small></li><li><a href='http://fernandoipar.com/2009/08/14/generating-data-with-dbmonster/' rel='bookmark' title='Permanent Link: Generating data with dbmonster'>Generating data with dbmonster</a> <small> In my last post I included some sample data...</small></li><li><a href='http://fernandoipar.com/2009/01/12/running-commands-from-the-shell-with-a-timeout-pt-2/' rel='bookmark' title='Permanent Link: Running commands from the shell with a timeout (pt 2)'>Running commands from the shell with a timeout (pt 2)</a> <small>Here&#8217;s an improved version of the safecmd script. This one...</small></li></ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a simple shell script to stream data to multiple processes. It has many applications, but the reason I wrote it is to stream the same data to multiple netcat processes on remote machines.</p>
<p>Here&#8217;s the code:</p>
<pre>
#!/bin/bash</code>

usage()
{
cat &lt;&amp;2

usage : multi-fifo target0 [target1 [target2 [...]]]

Where each targetN is a program you want to send the input multi-fifo receives

EOF

}

[ $# -eq 0 ] &amp;&amp; usage &amp;&amp; exit 1

i=0
pipeline="tee /dev/null"
while [ -n "$1" ]; do
target=$1
fifo=/tmp/multi-fifo-$$.$i
mkfifo $fifo
eval "$target &lt; $fifo" &amp;
pipeline="$pipeline | tee $fifo"
i=$((i+1))
shift
done

eval "cat | $pipeline"

j=0
while [ $j -lt $i ]; do
rm -f /tmp/multi-fifo-$$.$j
j=$((j+1))
done
</pre>
<p>Usage is pretty straightforward:</p>
<p><code><br />
tar cjvf - . | ./multi-fifo "nc host1 9999" "nc host2 9999" &gt;/dev/null<br />
</code></p>
<p>This way, the script will create a fifo for each netcat client, then send it&#8217;s stdin to a pipeline that writes to both fifos using tee. Useful for example if you want to stream a backup to multiple destination servers for cloning.</p>


<p>Related posts:<ol><li><a href='http://fernandoipar.com/2009/03/09/using-the-enum-data-type-to-increase-performance/' rel='bookmark' title='Permanent Link: Using the ENUM data type to increase performance'>Using the ENUM data type to increase performance</a> <small>While going through the DATA TYPES section of the Certification...</small></li><li><a href='http://fernandoipar.com/2009/08/14/generating-data-with-dbmonster/' rel='bookmark' title='Permanent Link: Generating data with dbmonster'>Generating data with dbmonster</a> <small> In my last post I included some sample data...</small></li><li><a href='http://fernandoipar.com/2009/01/12/running-commands-from-the-shell-with-a-timeout-pt-2/' rel='bookmark' title='Permanent Link: Running commands from the shell with a timeout (pt 2)'>Running commands from the shell with a timeout (pt 2)</a> <small>Here&#8217;s an improved version of the safecmd script. This one...</small></li></ol></p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://fernandoipar.com/2011/03/10/piping-data-to-multiple-processes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SOUNDEX(), triggers, and stored procedures</title>
		<link>http://fernandoipar.com/2009/04/29/soundex-triggers-and-stored-procedures/</link>
		<comments>http://fernandoipar.com/2009/04/29/soundex-triggers-and-stored-procedures/#comments</comments>
		<pubDate>Wed, 29 Apr 2009 23:14:51 +0000</pubDate>
		<dc:creator>fernando</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://fernandoipar.com/?p=166</guid>
		<description><![CDATA[MySQL provides a SOUNDEX() function, which returns the soundex of a given string. For details, refer to the manual, but to put it simply, it allows you to compare strings based on how they sound, hence letting you do proximity searches on your database. If you&#8217;re just querying for a word, it&#8217;s usage is pretty [...]


Related posts:<ol><li><a href='http://fernandoipar.com/2009/08/14/generating-data-with-dbmonster/' rel='bookmark' title='Permanent Link: Generating data with dbmonster'>Generating data with dbmonster</a> <small> In my last post I included some sample data...</small></li><li><a href='http://fernandoipar.com/2009/04/21/extending-procedure_analyse/' rel='bookmark' title='Permanent Link: Extending procedure_analyse'>Extending procedure_analyse</a> <small>My previous post explored a stored procedure that extended procedure_analyse...</small></li></ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>MySQL provides a SOUNDEX() function, which returns the soundex of a given string. For details, refer to the <a href="http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_soundex">manual</a>, but to put it simply, it allows you to compare strings based on how they sound, hence letting you do proximity searches on your database.</p>
<p>If you&#8217;re just querying for a word, it&#8217;s usage is pretty straightforward, and in fact, you can use the SOUNDS LIKE operator to build expressions such as this:</p>
<blockquote><p>SELECT <em>expr</em> FROM <em>table expr</em> WHERE <em>field0 </em>SOUNDS LIKE <em>&#8216;inputWord&#8217;</em></p></blockquote>
<p>However, if you&#8217;re storing multiple-word strings, things get a little more complicated, since they can&#8217;t be compared by their soundex. Rather, the soundex returned will be associated with the whole phrase. If at a later time, you want to search for a subpart of this phrase, there&#8217;s no way for you to do this.</p>
<p>Well, at least not directly, but by using an auxiliary table to store soundex strings, a couple of stored procedures, and a trigger, it can be done with little effort to programmers that use the database.</p>
<p>Let&#8217;s assume we have a very simple table called <em>soundex_text</em> with the following structure:</p>
<pre>create table if not exists soundex_text (
	id int unsigned not null auto_increment primary key,
	description text
) Engine = Innodb;</pre>
<p>The field we want to query by proximity is <em>description</em>, therefore we create the following auxiliary table to store soundex values:</p>
<pre>create table if not exists soundex_text_index (
	soundex_text_id int unsigned not null references soundex_text(id),
	soundex char(4)
) Engine = Innodb;</pre>
<p>We now create a stored procedure and a trigger to populate the auxiliary table automatically every time a row is inserted in the main table.</p>
<pre>-- adapted from example at http://forums.mysql.com/read.php?60,78776,242420#msg-242420
-- posted by jim smith: http://forums.mysql.com/profile.php?60,3154903
CREATE PROCEDURE update_soundex_text_index (sStringIn text,splitChar varchar(1), soundex_text_id int)
BEGIN
DECLARE comma INT DEFAULT 0;
DECLARE mylist TEXT DEFAULT sStringIn;
DECLARE temp TEXT DEFAULT '';
DECLARE strlen int DEFAULT LENGTH(sStringIn);
DECLARE insert_id int DEFAULT soundex_text_id;

/* find the first instance of the spliting character */
SET comma = LOCATE(splitChar,mylist);
/* Insert each split variable into the temp table */
WHILE strlen &gt; 0 DO
	IF comma = 0 THEN
		SET temp = TRIM(mylist);
		SET mylist = '';
		SET strlen = 0;
	END IF;
	IF comma != 0 THEN
		SET temp = TRIM(SUBSTRING(mylist,1,comma-1));
		SET mylist = TRIM(SUBSTRING(mylist FROM comma+1));
		SET strlen = LENGTH(mylist);
		-- Sample handling of special chars you might want removed from individual words
		-- before storing their soundex.
		SELECT REPLACE(temp,',','') INTO temp;
		SELECT REPLACE(temp,';','') INTO temp;
		SELECT REPLACE(temp,':','') INTO temp;
	END IF;
	IF temp != '' THEN
		insert into soundex_text_index (soundex_text_id,soundex) values (insert_id,substring(soundex(temp) from 1 for 4));
	END IF;
	SET comma = LOCATE(splitChar,mylist);
END WHILE;

END//

drop trigger if exists soundex_text_bi//
create trigger soundex_text_bi
before insert
on soundex_text
for each row
begin
	SET @id = last_insert_id();
	call update_soundex_text_index (NEW.description, ' ', @id);
end;//
delimiter ;</pre>
<p>Finally, a stored procedure to automatically query the table using the auxiliary table implicitly:</p>
<pre>delimiter //
create procedure query_soundex_text(sStringIn text, splitChar varchar(1))
BEGIN
DECLARE comma INT DEFAULT 0;
DECLARE mylist TEXT DEFAULT sStringIn;
DECLARE temp TEXT DEFAULT '';
DECLARE strlen int DEFAULT LENGTH(sStringIn); 

create temporary table results (id int unsigned, description text);

/* find the first instance of the spliting character */
SET comma = LOCATE(splitChar,mylist);
/* Insert each split variable into the temp table */
WHILE strlen &gt; 0 DO
	IF comma = 0 THEN
		SET temp = TRIM(mylist);
		SET mylist = '';
		SET strlen = 0;
	END IF;
	IF comma != 0 THEN
		SET temp = TRIM(SUBSTRING(mylist,1,comma-1));
		SET mylist = TRIM(SUBSTRING(mylist FROM comma+1));
		SET strlen = LENGTH(mylist);
		-- Sample handling of special chars you might want removed from individual words
		-- before storing their soundex.
		SELECT REPLACE(temp,',','') INTO temp;
		SELECT REPLACE(temp,';','') INTO temp;
		SELECT REPLACE(temp,':','') INTO temp;
	END IF;
	IF temp != '' THEN
		insert into results select st.id, st.description from soundex_text st, soundex_text_index sti where sti.soundex = substring(soundex(temp) from 1 for 4);
	END IF;
	SET comma = LOCATE(splitChar,mylist);
END WHILE;

select distinct * from results;
drop table results;

END//
delimiter ;</pre>
<p>Using this is pretty straightforward.<br />
Just insert some sample data into the table, and give it a shot!:</p>
<pre>mysql&gt; insert into soundex_text(description) values ('This is a sample text row');
Query OK, 1 row affected (0.00 sec)

mysql&gt; call query_soundex_text('semple',' ');
+------+---------------------------+
| id   | description               |
+------+---------------------------+
|    3 | This is a sample text row |
+------+---------------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql&gt; call query_soundex_text('THis is a samPLE taxt row',' ');
+------+---------------------------+
| id   | description               |
+------+---------------------------+
|    3 | This is a sample text row |
+------+---------------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql&gt; call query_soundex_text('rock',' ');
Empty set (0.01 sec)

Query OK, 0 rows affected (0.01 sec)</pre>
<p>To make it even easier, you could modify the querying stored procedure and always assume that the splitting character is a whitespace.</p>
<p>You can download a zipfile with a sql script with all this code for you to load into a MySQL database right <a title="Soundex search scripts" href="http://fernandoipar.com/soundex.sql.zip">here</a>.</p>
<p>Enjoy!</p>


<p>Related posts:<ol><li><a href='http://fernandoipar.com/2009/08/14/generating-data-with-dbmonster/' rel='bookmark' title='Permanent Link: Generating data with dbmonster'>Generating data with dbmonster</a> <small> In my last post I included some sample data...</small></li><li><a href='http://fernandoipar.com/2009/04/21/extending-procedure_analyse/' rel='bookmark' title='Permanent Link: Extending procedure_analyse'>Extending procedure_analyse</a> <small>My previous post explored a stored procedure that extended procedure_analyse...</small></li></ol></p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://fernandoipar.com/2009/04/29/soundex-triggers-and-stored-procedures/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Extending procedure_analyse</title>
		<link>http://fernandoipar.com/2009/04/21/extending-procedure_analyse/</link>
		<comments>http://fernandoipar.com/2009/04/21/extending-procedure_analyse/#comments</comments>
		<pubDate>Tue, 21 Apr 2009 16:06:26 +0000</pubDate>
		<dc:creator>fernando</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://fernandoipar.com/?p=163</guid>
		<description><![CDATA[My previous post explored a stored procedure that extended procedure_analyse with the intent of helping DBAs optimize table structure. Here&#8217;s an improved version. I&#8217;ve followed Arjen Lentz&#8216;s suggestion and added support for the max_elements and max_memory parameters. I also added a new Indexed column to the output, which is an ENUM(&#8216;No&#8217;,'Yes&#8217;,'Overindexed&#8217;). Yes and No are [...]


Related posts:<ol><li><a href='http://fernandoipar.com/2009/04/18/making-use-of-procedure-analyse/' rel='bookmark' title='Permanent Link: Making use of procedure analyse()'>Making use of procedure analyse()</a> <small>SELECT Field0[,Field1,Field2,...] FROM TABLE PROCEDURE ANALYSE() is a nice tool...</small></li></ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>My previous post explored a stored procedure that extended procedure_analyse with the intent of helping DBAs optimize table structure.</p>
<p>Here&#8217;s an improved version. I&#8217;ve followed <a title="Open Query" href="http://openquery.com/">Arjen Lentz</a>&#8216;s suggestion and added support for the max_elements and max_memory parameters.</p>
<p>I also added a new Indexed column to the output, which is an ENUM(&#8216;No&#8217;,'Yes&#8217;,'Overindexed&#8217;). Yes and No are self-explanatory, while Overindexed means the column is present as the left-most part of more than one index. This is useless, it just presents a performance penalty for MySQL (it needs to update more indexes) and if, for instance, you have columns A and B, and you have KEY(A) and KEY (A,B), mysql can use the second index to search for A alone too.</p>
<p>Here&#8217;s the updated version:</p>
<pre>
/*

extended procedure analyse
(C) 2009 Fernando Ipar
mail(at)fernandoipar.com

GPLv2

*/
drop procedure if exists extended_procedure_analyse;
delimiter //
create procedure extended_procedure_analyse(databaseName varchar(64), tableName varchar(64), max_elements int, max_memory int)
begin

	drop temporary table if exists procedure_analyse_output;
	drop temporary table if exists tmp_pao;

	create temporary table procedure_analyse_output
	(
	Field_name varchar(64),
	Min_value int,
	Max_value int,
	Min_length int,
	Max_length int,
	Empties_or_zeros int,
	Nulls int,
	Avg_value_or_avg_length float,
	Std float,
	Optimal_fieldtype text,
	Actual_fieldtype text,
	Indexed enum ('No','Yes','Overindexed') default 'No'
	);	

	set @table = concat(databaseName,'.',tableName);
	set @dbName = databaseName;
	set @tbName = tableName;
	set @maxEle = max_elements;
	set @maxMem = max_memory;

	set @qry = concat('insert into procedure_analyse_output (Field_name,Min_value,Max_value,Min_length,Max_length,Empties_or_zeros,Nulls,Avg_Value_or_avg_length,Std,Optimal_fieldtype) select * from ', @table,' procedure analyse(',@maxEle,',',@maxMem,')');
	prepare myStmt from @qry;
	execute myStmt;

	update procedure_analyse_output set Field_name = replace(Field_name,  CONCAT(databaseName,'.',tableName,'.'),'');

	prepare myStmt from 'update procedure_analyse_output pao, information_schema.columns c set pao.Actual_Fieldtype = c.column_type where table_schema = ? and table_name = ? and column_name = pao.Field_name';
	execute myStmt using @dbName,@tbName;

	set @qry = concat('select count(*) as `Total_number_of_rows` from ',@table);
	prepare myStmt from @qry;

	execute myStmt;

	set @qry = concat('update procedure_analyse_output pao set Indexed = "Yes\" where exists (select 1 from information_schema.statistics where table_schema = ? and table_name = ? and column_name = pao.Field_name)');
	prepare myStmt from @qry;
	execute myStmt using @dbName,@tbName;

	create temporary table tmp_pao as select * from procedure_analyse_output;
	prepare myStmt from 'update tmp_pao set Indexed = "Overindexed" where exists (select Field_name,count(*) from procedure_analyse_output pao inner join information_schema.statistics s on pao.Field_name = s.column_name where table_schema = ? and table_name = ? and seq_in_index = 1 and pao.Field_name = tmp_pao.Field_name group by Field_name having count(*) > 1)';
	execute myStmt  using @dbName,@tbName;

	select * from tmp_pao;

	drop temporary table procedure_analyse_output;
	drop temporary table tmp_pao; 

end;
//
delimiter ;
</pre>
<p>And here&#8217;s a sample output: </p>
<pre>
mysql> call extended_procedure_analyse('test','Account',4,100)\G
*************************** 1. row ***************************
Total_number_of_rows: 1
1 row in set (0.04 sec)

*************************** 1. row ***************************
             Field_name: InternalAID
              Min_value: 2147483647
              Max_value: 2147483647
             Min_length: 18
             Max_length: 18
       Empties_or_zeros: 0
                  Nulls: 0
Avg_value_or_avg_length: 1.65632e+17
                    Std: 0
      Optimal_fieldtype: BIGINT(18) UNSIGNED NOT NULL
       Actual_fieldtype: bigint(20)
                Indexed: Yes
*************************** 2. row ***************************
             Field_name: accountID
              Min_value: 12
              Max_value: 12
             Min_length: 2
             Max_length: 2
       Empties_or_zeros: 0
                  Nulls: 0
Avg_value_or_avg_length: 2
                    Std: NULL
      Optimal_fieldtype: ENUM('12') NOT NULL
       Actual_fieldtype: varchar(255)
                Indexed: Overindexed
*************************** 3. row ***************************
             Field_name: acctBalance
              Min_value: 2147483647
              Max_value: 2147483647
             Min_length: 11
             Max_length: 11
       Empties_or_zeros: 0
                  Nulls: 0
Avg_value_or_avg_length: 1.00051e+20
                    Std: 0
      Optimal_fieldtype: BIGINT(11) UNSIGNED NOT NULL
       Actual_fieldtype: double
                Indexed: Yes
*************************** 4. row ***************************
             Field_name: ownerID
              Min_value: 2147483647
              Max_value: 2147483647
             Min_length: 19
             Max_length: 19
       Empties_or_zeros: 0
                  Nulls: 0
Avg_value_or_avg_length: 6.57541e+18
                    Std: 0
      Optimal_fieldtype: BIGINT(19) UNSIGNED NOT NULL
       Actual_fieldtype: bigint(20)
                Indexed: No
4 rows in set (0.24 sec)

Query OK, 0 rows affected, 8 warnings (0.24 sec)
</pre>
<p>There&#8217;s a <a title="mydbsuggest at bitbucket" href="http://www.bitbucket.org/nandix/mydbsuggest/">hg repository</a> to handle the project. We&#8217;re working with <a title="fedesilva@bitbucket.org" href="http://www.bitbucket.org/fedesilva">@fedesilva</a> to create a standalone java app that will present this and more info in a friendly manner to sysadmins, and to handle the creation and destruction of the stored procedure automatically.</p>


<p>Related posts:<ol><li><a href='http://fernandoipar.com/2009/04/18/making-use-of-procedure-analyse/' rel='bookmark' title='Permanent Link: Making use of procedure analyse()'>Making use of procedure analyse()</a> <small>SELECT Field0[,Field1,Field2,...] FROM TABLE PROCEDURE ANALYSE() is a nice tool...</small></li></ol></p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://fernandoipar.com/2009/04/21/extending-procedure_analyse/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Coding Buddies</title>
		<link>http://fernandoipar.com/2009/03/04/coding-buddies/</link>
		<comments>http://fernandoipar.com/2009/03/04/coding-buddies/#comments</comments>
		<pubDate>Wed, 04 Mar 2009 19:50:32 +0000</pubDate>
		<dc:creator>fernando</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[rant]]></category>

		<guid isPermaLink="false">http://fernandoipar.com/?p=110</guid>
		<description><![CDATA[Coding Horror always has insightfull articles, and this one on code peer reviews is no exception. Why is it that writers, musicians and, well, any respected and professional artist or scientist gets his/her work reviewed before it&#8217;s published, but the same isn&#8217;t true in IT? My guess? Most programmers aren&#8217;t neither artists, nor scientists. They&#8217;re [...]


Related posts:<ol><li><a href='http://fernandoipar.com/2009/01/19/symbolics-lisp-machine/' rel='bookmark' title='Permanent Link: Symbolics Lisp Machine'>Symbolics Lisp Machine</a> <small>Wanna have your own Symbolics Lisp Machine? Here&#8217;s the info....</small></li></ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p><a title="Coding Horror" href="http://www.codinghorror.com/blog/">Coding Horror</a> always has insightfull articles, and this one on <a title="Who's your coding buddy?" href="http://www.codinghorror.com/blog/archives/001229.html">code peer reviews</a> is no exception.</p>
<p>Why is it that writers, musicians and, well, any respected and professional artist or scientist gets his/her work reviewed before it&#8217;s published, but the same isn&#8217;t true in IT?</p>
<p>My guess? Most programmers aren&#8217;t neither artists, nor scientists. They&#8217;re an anonymous resource in a badly oiled machine that&#8217;s always behind schedule.</p>
<p>Well, so long, Knuth!</p>


<p>Related posts:<ol><li><a href='http://fernandoipar.com/2009/01/19/symbolics-lisp-machine/' rel='bookmark' title='Permanent Link: Symbolics Lisp Machine'>Symbolics Lisp Machine</a> <small>Wanna have your own Symbolics Lisp Machine? Here&#8217;s the info....</small></li></ol></p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://fernandoipar.com/2009/03/04/coding-buddies/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Generating random salts from bash</title>
		<link>http://fernandoipar.com/2009/02/04/generating-random-salts-from-bash/</link>
		<comments>http://fernandoipar.com/2009/02/04/generating-random-salts-from-bash/#comments</comments>
		<pubDate>Wed, 04 Feb 2009 23:19:57 +0000</pubDate>
		<dc:creator>fernando</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[perl]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://fernandoipar.com/?p=86</guid>
		<description><![CDATA[From the &#8216;just because it can be done&#8217; column, here comes a handy shell script to generate random salts. So, without further ado,  here it goes: #!/bin/bash [ $# -eq 0 ] &#38;&#38; { echo "usage: salt &#60;length&#62;"&#62;&#38;2 exit } strings &#60;/dev/urandom &#124; while read line; do echo $line &#124; tr '\n\t ' $RANDOM:0:1 &#62;&#62; [...]


Related posts:<ol><li><a href='http://fernandoipar.com/2009/08/14/generating-data-with-dbmonster/' rel='bookmark' title='Permanent Link: Generating data with dbmonster'>Generating data with dbmonster</a> <small> In my last post I included some sample data...</small></li><li><a href='http://fernandoipar.com/2009/01/12/running-commands-from-the-shell-with-a-timeout-pt-2/' rel='bookmark' title='Permanent Link: Running commands from the shell with a timeout (pt 2)'>Running commands from the shell with a timeout (pt 2)</a> <small>Here&#8217;s an improved version of the safecmd script. This one...</small></li><li><a href='http://fernandoipar.com/2009/01/10/running-commands-from-the-shell-with-a-timeout/' rel='bookmark' title='Permanent Link: Running commands from the shell with a timeout'>Running commands from the shell with a timeout</a> <small>Sometimes, in a shell script, you need to run a...</small></li></ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p>From the &#8216;just because it can be done&#8217; column, here comes a handy shell script to generate random <a title="Cryptographic Salt (Wikipedia)" href="http://en.wikipedia.org/wiki/Salt_(cryptography)">salts</a>.</p>
<p>So, without further ado,  here it goes:</p>
<pre>#!/bin/bash 

[ $# -eq 0 ] &amp;&amp; {
        echo "usage: salt &lt;length&gt;"&gt;&amp;2
        exit
}
strings &lt;/dev/urandom | while read line; do
        echo $line | tr '\n\t ' $RANDOM:0:1 &gt;&gt; /tmp/.salt.$$
        salt=$(cat /tmp/.salt.$$)
        [ ${#salt} -ge $1 ] &amp;&amp; salt=${salt:0:$1} &amp;&amp; echo $salt &amp;&amp; break
done
rm -f /tmp/.salt.$$</pre>
<p>I had to use $1 and not a var, and echo the salt right from inside the while, because the &#8216;|&#8217; creates another shell, so I can&#8217;t pass variables to or from the while in this case.</p>
<p>If you want to keep things simple, you can go perl and just do</p>
<pre>
#!/usr/bin/perl
use Crypt::Salt;
my $length = shift;
print salt($length);
</pre>
<p>But if you ever find yourself in a server with no cpan, the first option might prove useful <img src='http://fernandoipar.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>


<p>Related posts:<ol><li><a href='http://fernandoipar.com/2009/08/14/generating-data-with-dbmonster/' rel='bookmark' title='Permanent Link: Generating data with dbmonster'>Generating data with dbmonster</a> <small> In my last post I included some sample data...</small></li><li><a href='http://fernandoipar.com/2009/01/12/running-commands-from-the-shell-with-a-timeout-pt-2/' rel='bookmark' title='Permanent Link: Running commands from the shell with a timeout (pt 2)'>Running commands from the shell with a timeout (pt 2)</a> <small>Here&#8217;s an improved version of the safecmd script. This one...</small></li><li><a href='http://fernandoipar.com/2009/01/10/running-commands-from-the-shell-with-a-timeout/' rel='bookmark' title='Permanent Link: Running commands from the shell with a timeout'>Running commands from the shell with a timeout</a> <small>Sometimes, in a shell script, you need to run a...</small></li></ol></p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://fernandoipar.com/2009/02/04/generating-random-salts-from-bash/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I love playing Monopoly</title>
		<link>http://fernandoipar.com/2009/02/02/i-love-playing-monopoly/</link>
		<comments>http://fernandoipar.com/2009/02/02/i-love-playing-monopoly/#comments</comments>
		<pubDate>Mon, 02 Feb 2009 02:09:18 +0000</pubDate>
		<dc:creator>fernando</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[ADSL]]></category>
		<category><![CDATA[Antel]]></category>
		<category><![CDATA[bandwidth]]></category>
		<category><![CDATA[Uruguay]]></category>

		<guid isPermaLink="false">http://fernandoipar.com/2009/02/02/i-love-playing-monopoly/</guid>
		<description><![CDATA[This is the latest speed test I run against Santiago de Chile, where a lonely database server is waiting for my queries. Well, it&#8217;s got a lot of waiting to do. This results are from a 2048 down /256 up Kb/s connection for which I pay U$S 52/monthly. Yeah, I feel your envy already. The [...]


No related posts.]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.speedtest.net/result/402451392.png">This is the latest speed test I run against Santiago de Chile</a>, where a lonely database server is waiting for my queries. Well, it&#8217;s got a lot of waiting to do.</p>
<p>This results are from a 2048 down /256 up Kb/s connection for which I pay U$S 52/monthly.<br />
Yeah, I feel your envy already.</p>
<p>The Administración Nacional de Telecomunicaciones of Uruguay runs my ISP. I could choose another one, but the link to the outside world would eventually be handled by the state.</p>
<p>I called tech support twice this week, and it seems this results are due to a problem with the international (I get real fast to anything in Uruguay or Argentina, I guess it&#8217;s my fault for getting customers outside of that comfort zone!) link. They don&#8217;t have an estimated date of repair, and they don&#8217;t need to, since, what else I&#8217;m I going to do? Probably take a plane and sit on a console in front of the damn database.</p>
<p>Uruguay: redefining the term &#8216;Sneaker Net&#8217;</p>


<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://fernandoipar.com/2009/02/02/i-love-playing-monopoly/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Erlybird 0.17.0 released</title>
		<link>http://fernandoipar.com/2009/02/02/erlybird-0170-released/</link>
		<comments>http://fernandoipar.com/2009/02/02/erlybird-0170-released/#comments</comments>
		<pubDate>Mon, 02 Feb 2009 02:02:02 +0000</pubDate>
		<dc:creator>fernando</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[netbeans]]></category>

		<guid isPermaLink="false">http://fernandoipar.com/?p=77</guid>
		<description><![CDATA[Yep, I&#8217;m really late for this. However, I didn&#8217;t want to let it pass. I checked up on erlybird a couple of times before, but it was only available as a source project, and you needed a particular netbeans version in order to build the module. I&#8217;m as geek as it gets, but I&#8217;m also [...]


No related posts.]]></description>
			<content:encoded><![CDATA[<p>Yep, I&#8217;m really late for this.</p>
<p>However, I didn&#8217;t want to let it pass. I checked up on erlybird a couple of times before, but it was only available as a source project, and you needed a particular netbeans version in order to build the module.</p>
<p>I&#8217;m as geek as it gets, but I&#8217;m also 30, married, and a parent. I would have done that 12 years ago, now ./configure &amp;&amp; make &amp;&amp; make install is as far as I take it unless I&#8217;m really into it.</p>
<p>So 0.17.0 (released last November) fixes all this, it&#8217;s a netbeans module, which you can install the usual way. It requires NetBeans 6.5, but that&#8217;s not an issue for me since I&#8217;ve been using that version for quite a while already.</p>
<p><a title="Erlybird 0.17.0" href="http://sourceforge.net/forum/forum.php?forum_id=891248" target="_blank">Here&#8217;s a link with more info. </a></p>
<p>Kudos to both admins for the great job they&#8217;ve done.</p>


<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://fernandoipar.com/2009/02/02/erlybird-0170-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Intrusion detection at the application level, for PHP</title>
		<link>http://fernandoipar.com/2009/01/19/intrusion-detection-at-the-application-level-for-php/</link>
		<comments>http://fernandoipar.com/2009/01/19/intrusion-detection-at-the-application-level-for-php/#comments</comments>
		<pubDate>Tue, 20 Jan 2009 01:19:54 +0000</pubDate>
		<dc:creator>fernando</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[lamp]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://fernandoipar.com/?p=52</guid>
		<description><![CDATA[Here&#8217;s phpids, an Intrusion Detection System for PHP. According to the site, it aims to counter XSS, SQL Injection, header injection, directory traversal, RFE/LFI, DoS and LDAP attacks, and unknown attack patterns,  through it&#8217;s Centrifuge component. Installation is simple. Just download it, copy the lib directory to a directory in your project structure, or add [...]


No related posts.]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s <a title="Intrusion Detection System for PHP" href="http://php-ids.org/" target="_self">phpids</a>, an Intrusion Detection System for PHP.</p>
<p>According to the site, it aims to counter XSS, SQL Injection, header injection, directory traversal, RFE/LFI, DoS and LDAP attacks, and unknown attack patterns,  through it&#8217;s Centrifuge component.</p>
<p>Installation is simple. Just download it, copy the lib directory to a directory in your project structure, or add it to your <code>include_path</code>.</p>
<p>I actually chose a mix of both ways, so it&#8217;s automatically included when I distribute my applications.</p>
<p>Here&#8217;s how to use it:</p>
<p><code><br />
ini_set('include_path',ini_get('include_path').PATH_SEPARATOR.PRIVATE_ROOT.DIRECTORY_SEPARATOR.'phpids'.DIRECTORY_SEPARATOR.'lib');<br />
</code><br />
Here we&#8217;re just modifying the include path in order to add phpids.<br />
PRIVATE_ROOT is a constant that I&#8217;ve defined in my app, which defines the root of the application. This is not accessible from the web server (following the recommendation of the <a href="http://phpsec.org/projects/guide/1.html#1.4.1">Dispatch</a> method, from the <a href="http://phpsec.org">PHP Security Consortium</a>. However, this is a particular case, in most situations, I&#8217;d recommend using a framework that already takes a similar pattern into account, like <a href="http://cakephp.org/">CakePHP</a>).<br />
phpids is where I&#8217;ve copied this IDS. The downloaded package has a similar root directory name, like phpids-x.y.n, depending on the version number.</p>
<p><code><br />
require_once 'IDS/Init.php';<br />
</code></p>
<p>Require the Init.php file</p>
<p>Then, whenever you need to access the request variables (in my case, this was just in one point in my application so I just had to modify one function), add something like this:</p>
<p><code><br />
$request = array(<br />
'REQUEST' =&gt; $_REQUEST,<br />
'GET' =&gt; $_GET,<br />
'POST' =&gt; $_POST,<br />
'COOKIE' =&gt; $_COOKIE<br />
);<br />
$init = IDS_Init::init(PRIVATE_ROOT. DIRECTORY_SEPARATOR .'phpids'.DIRECTORY_SEPARATOR.'lib/IDS/Config/Config.ini');</code></p>
<p>$ids = new IDS_Monitor($request, $init);<br />
$result = $ids-&gt;run();</p>
<p>if (!$result-&gt;isEmpty()) {<br />
trigger_error($result);<br />
}</p>
<p>If the $result object is not empty, the IDS detected an attack attempt and therefore you should stop processing the request.</p>
<p>And now the fun part.</p>
<p>In order to test this, I set up a very simple, very insecure test page.<br />
Here&#8217;s the php code:</p>
<pre>error_reporting(E_ALL);
ini_set('include_path',ini_get('include_path').':'.'../src/phpids/lib');
require 'IDS/Init.php';
function checkIds()
{
   $request = array(
     'REQUEST' =&gt; $_REQUEST,
     'GET' =&gt; $_GET,
     'POST' =&gt; $_POST,
     'COOKIE' =&gt; $_COOKIE
);

$init = IDS_Init::init('/home/fipar/workspace/at-intranet/src/phpids/lib/IDS/Config/Config.ini');
$ids = new IDS_Monitor($request,$init);
$result = $ids-&gt;run();
if (!$result-&gt;isEmpty()) {
     trigger_error($result);
}
}

if (isset($_REQUEST['sql'])) {
     checkIds();
     $sql = $_REQUEST['sql'];
     print 'Form says '.$sql.'
';
}</pre>
<p>The html page has just an input type text with the name &#8216;sql&#8217;, and a submit button.</p>
<p>I tried the following inputs:</p>
<ul>
<li>Hello, which goes by ok</li>
<li>&#8216; and 1, which generates errors for the REQUEST and POST variables, stating<br />
<blockquote><p>Detects classic SQL injection probings 1/2 | Tags: sqli, id, lfi | ID: 42</p></blockquote>
</li>
<li>&lt;a href=&#8221;http://www.google.com&#8221;&gt;www.google.com&lt;/a&gt;, which generates errors for the REQUEST and POST variables, stating<br />
<blockquote>
<ul>
<li>finds html breaking injections including whitespace attacks | Tags: xss, csrf | ID: 1</li>
<li>Detects JavaScript object properties and methods | Tags: xss, csrf, id, rfe | ID: 17</li>
<li>Detects basic SQL authentication bypass attempts 2/3 | Tags: sqli, id, lfi | ID: 45</li>
</ul>
</blockquote>
</li>
</ul>


<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://fernandoipar.com/2009/01/19/intrusion-detection-at-the-application-level-for-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symbolics Lisp Machine</title>
		<link>http://fernandoipar.com/2009/01/19/symbolics-lisp-machine/</link>
		<comments>http://fernandoipar.com/2009/01/19/symbolics-lisp-machine/#comments</comments>
		<pubDate>Mon, 19 Jan 2009 16:44:11 +0000</pubDate>
		<dc:creator>fernando</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Lisp]]></category>

		<guid isPermaLink="false">http://fernandoipar.com/?p=49</guid>
		<description><![CDATA[Wanna have your own Symbolics Lisp Machine? Here&#8217;s the info. I have enough room, I just live a few thousand miles too far, and have to deal with very picky Customs officials. No related posts.


No related posts.]]></description>
			<content:encoded><![CDATA[<p>Wanna have your own <a title="Symbolics" href="http://en.wikipedia.org/wiki/Symbolics" target="_self">Symbolics</a> Lisp Machine?</p>
<p><a title="How to get a Lisp Machine" href="http://xach.livejournal.com/209801.html" target="_self">Here&#8217;s the info</a>.</p>
<p>I have enough room, I just live a few thousand miles too far, and have to deal with very picky Customs officials.</p>


<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://fernandoipar.com/2009/01/19/symbolics-lisp-machine/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New release of MySQL Proxy GPL</title>
		<link>http://fernandoipar.com/2009/01/16/new-release-of-mysql-proxy-gpl/</link>
		<comments>http://fernandoipar.com/2009/01/16/new-release-of-mysql-proxy-gpl/#comments</comments>
		<pubDate>Fri, 16 Jan 2009 21:45:46 +0000</pubDate>
		<dc:creator>fernando</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Highbase]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Proxy]]></category>

		<guid isPermaLink="false">http://fernandoipar.com/?p=43</guid>
		<description><![CDATA[MySQL Proxy has a new release, just three days ago, and if that wasn&#8217;t good enough, it&#8217;s now hosted on Launchpad, so it&#8217;s repository is on bazaar, which is great, and is what I&#8217;ve been using for my new projects. MySQL Proxy sits between clients and servers and offers many possibilities, load balancing being the [...]


Related posts:<ol><li><a href='http://fernandoipar.com/2009/04/15/updated-mysql-proxy-benchmarking-script-for-proxy-07/' rel='bookmark' title='Permanent Link: Updated mysql-proxy benchmarking script (for proxy 0.7)'>Updated mysql-proxy benchmarking script (for proxy 0.7)</a> <small>My previous post contained a lua script for MySQL proxy...</small></li><li><a href='http://fernandoipar.com/2009/04/06/using-mysql-proxy-to-benchmark-query-performance/' rel='bookmark' title='Permanent Link: Using MySQL Proxy to benchmark query performance'>Using MySQL Proxy to benchmark query performance</a> <small>By transparently sitting between client and server on each request,...</small></li><li><a href='http://fernandoipar.com/2009/03/06/mysql-certification-self-study/' rel='bookmark' title='Permanent Link: MySQL Certification self study'>MySQL Certification self study</a> <small>I&#8217;m taking the MySQL Certification exams soon, and while I&#8217;d...</small></li></ol>

Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<p><a title="MySQL Proxy" href="http://dev.mysql.com/downloads/mysql-proxy/index.html" target="_self">MySQL Proxy</a> has a new release, just three days ago, and if that wasn&#8217;t good enough, it&#8217;s now hosted on <a title="MySQL Proxy at Launchpad" href="https://launchpad.net/mysql-proxy">Launchpad</a>, so it&#8217;s repository is on bazaar, which is great, and is what I&#8217;ve been using for my new projects.</p>
<p><a title="MySQL Proxy" href="http://dev.mysql.com/downloads/mysql-proxy/index.html">MySQL Proxy</a> sits between clients and servers and offers many possibilities, load balancing being the one that is of particular interest to me (and some <a title="Highbase" href="http://highbase.seriema-systems.com">Highbase</a> users who requested this feature).</p>
<p><a title="Proxy's new release" href="https://launchpad.net/mysql-proxy/+announcement/1798">Here</a>&#8216;s the official announcement.</p>


<p>Related posts:<ol><li><a href='http://fernandoipar.com/2009/04/15/updated-mysql-proxy-benchmarking-script-for-proxy-07/' rel='bookmark' title='Permanent Link: Updated mysql-proxy benchmarking script (for proxy 0.7)'>Updated mysql-proxy benchmarking script (for proxy 0.7)</a> <small>My previous post contained a lua script for MySQL proxy...</small></li><li><a href='http://fernandoipar.com/2009/04/06/using-mysql-proxy-to-benchmark-query-performance/' rel='bookmark' title='Permanent Link: Using MySQL Proxy to benchmark query performance'>Using MySQL Proxy to benchmark query performance</a> <small>By transparently sitting between client and server on each request,...</small></li><li><a href='http://fernandoipar.com/2009/03/06/mysql-certification-self-study/' rel='bookmark' title='Permanent Link: MySQL Certification self study'>MySQL Certification self study</a> <small>I&#8217;m taking the MySQL Certification exams soon, and while I&#8217;d...</small></li></ol></p>
<p>Related posts brought to you by <a href='http://mitcho.com/code/yarpp/'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://fernandoipar.com/2009/01/16/new-release-of-mysql-proxy-gpl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

