<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
<title type="text">milmazz</title>
<generator uri="https://github.com/mojombo/jekyll">Jekyll</generator>
<link rel="self" type="application/atom+xml" href="http://milmazz.uno/atom.xml" />
<link rel="alternate" type="text/html" href="http://milmazz.uno" />
<updated>2015-04-08T22:18:52-05:00</updated>
<id>http://milmazz.uno/</id>
<author>
  <name>Milton Mazzarri</name>
  <uri>http://milmazz.uno/</uri>
  <email>me@milmazz.uno</email>
</author>


<entry>
  <title type="html"><![CDATA[How to document your Javascript code]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2014/08/27/how-to-document-your-javascript-code/"/>
  <id>http://milmazz.uno/article/2014/08/27/how-to-document-your-javascript-code</id>
  <published>2014-08-27T12:00:00-05:00</published>
  <updated>2014-08-27T12:00:00-05:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p&gt;Someone that knows something about Java probably knows about &lt;a href=&quot;http://en.wikipedia.org/wiki/Javadoc&quot;&gt;JavaDoc&lt;/a&gt;. If you know something about Python you probably document your code following the rules defined for &lt;a href=&quot;http://sphinx-doc.org&quot;&gt;Sphinx&lt;/a&gt; (Sphinx uses &lt;a href=&quot;http://docutils.sf.net/rst.html&quot;&gt;reStructuredText&lt;/a&gt; as its markup language). Or in C, you follow the rules defined for &lt;a href=&quot;http://www.stack.nl/~dimitri/doxygen/&quot;&gt;Doxygen&lt;/a&gt; (Doxygen also supports other programming languages such as Objective-C, Java, C#, PHP, etc.). But, what happens when we are coding in JavaScript? How can we document our source code?&lt;/p&gt;

&lt;p&gt;As a developer that interacts with other members of a team, the need to document all your intentions must become a habit. If you follow some basic rules and stick to them you can gain benefits like the automatic generation of documentation in formats like HTML, PDF, and so on. &lt;/p&gt;

&lt;p&gt;I must confess that I’m relatively new to JavaScript, but one of the first things that I implement is the source code documentation. I’ve been using &lt;a href=&quot;http://usejsdoc.org/&quot;&gt;JSDoc&lt;/a&gt; for documenting all my JavaScript code, it’s easy, and you only need to follow a short set of rules.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/**&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt; * @file Working with Tags&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt; * @author Milton Mazzarri &amp;lt;me@milmazz.uno&amp;gt;&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt; * @version 0.1&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt; */&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Tag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
  &lt;span class=&quot;cm&quot;&gt;/**&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;   * The Tag definition.&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;   *&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;   * @param {String} id - The ID of the Tag.&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;   * @param {String} description - Concise description of the tag.&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;   * @param {Number} min - Minimum value accepted for trends.&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;   * @param {Number} max - Maximum value accepted for trends.&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;   * @param {Object} plc - The ID of the {@link PLC} object where this tag belongs.&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;   */&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Tag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;plc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;description&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;trend_min&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;trend_max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;plc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;plc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/**&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;     * Get the current value of the tag.&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;     *&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;     * @see [Example]{@link http://example.com}&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;     * @returns {Number} The current value of the tag.&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;     */&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;}());&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the previous example, I have documented the index of the file, showing the
author and version, you can also include other things such as a copyright and license note. I have also documented the &lt;em&gt;class definition&lt;/em&gt; including parameters and methods specifying the name, and type with a concise description.&lt;/p&gt;

&lt;p&gt;After you process your source code with &lt;a href=&quot;http://usejsdoc.org/&quot;&gt;JSDoc&lt;/a&gt; the result looks like the following:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://milmazz.uno/images/2014-08-27-how-to-document-your-javascript-code/jsdoc3.png&quot; alt=&quot;usejsdoc&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the previous image you see the documentation in HTML format, also you see a table that displays the parameters with appropriate links to your source code, and finally, JSDoc implements a very nice style to your document.&lt;/p&gt;

&lt;p&gt;If you need further details I recommend you check out the &lt;a href=&quot;http://usejsdoc.org/index.html&quot;&gt;JSDoc
documentation&lt;/a&gt;.&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2014/08/27/how-to-document-your-javascript-code/&quot;&gt;How to document your Javascript code&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on August 27, 2014.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Grunt: The Javascript Task Manager]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2014/06/28/grunt-javascript-task-manager/"/>
  <id>http://milmazz.uno/article/2014/06/28/grunt-javascript-task-manager</id>
  <published>2014-06-28T16:00:00-05:00</published>
  <updated>2014-06-28T16:00:00-05:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p class=&quot;pull-right&quot;&gt;&lt;img src=&quot;http://milmazz.uno/images/grunt/grunt-logo.png&quot; alt=&quot;Grunt&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When you play the Web Developer role, sometimes you may have to endure some
repetitive tasks like minification, unit testing, compilation, linting,
beautify or unpack Javascript code and so on. To solve this problems, and in
the meantime, try to keep your mental health in a good shape, you desperately
need to find a way to automate this tasks. &lt;a href=&quot;http://gruntjs.com&quot;&gt;Grunt&lt;/a&gt; offers you an easy way to
accomplish this kind of automation.&lt;/p&gt;

&lt;!-- break --&gt;

&lt;p&gt;In this article I’ll try to explain how to automate some tasks with Grunt, but
I recommend that you should take some time to read Grunt’s documentation and
enjoy the experience by yourself.&lt;/p&gt;

&lt;p&gt;So, in the following sections I’ll try to show you how to accomplish this
tasks:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Concatenate and create a minified version of your CSS, JavaScript and HTML
files.&lt;/li&gt;
  &lt;li&gt;Automatic generation of the documentation for JavaScript with JSDoc.&lt;/li&gt;
  &lt;li&gt;Linting your JavaScript code.&lt;/li&gt;
  &lt;li&gt;Reformat and reindent (prettify) your JavaScript code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can install &lt;a href=&quot;http://gruntjs.com&quot;&gt;Grunt&lt;/a&gt; via &lt;a href=&quot;https://www.npmjs.org&quot;&gt;npm&lt;/a&gt; (Node Package Manager), so, to
install Grunt you need to install &lt;a href=&quot;http://nodejs.org&quot;&gt;Node.js&lt;/a&gt; first.&lt;/p&gt;

&lt;p&gt;Now that you have &lt;a href=&quot;http://nodejs.org&quot;&gt;Node.js&lt;/a&gt; and &lt;code&gt;npm&lt;/code&gt; installed is a good time to install
&lt;em&gt;globally&lt;/em&gt; the Grunt CLI (Command Line Interface) package.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo npm install -g grunt-cli&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once &lt;code&gt;grunt-cli&lt;/code&gt; is installed you need to go to the root directory of your
project and create a &lt;code&gt;package.json&lt;/code&gt; file, to accomplish this you can do the
following:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;example_project
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm init&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The previous command will ask you a series of questions in order to create the
&lt;code&gt;package.json&lt;/code&gt; file, &lt;code&gt;package.json&lt;/code&gt; basically store metadata for projects
published as &lt;code&gt;npm&lt;/code&gt; modules. It’s important to remember to add this file to your
source code versioning tool to ease the installation process of the development
dependencies among your partners via &lt;code&gt;npm install&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;At this point we can install Grunt and their respective plugins in the
existing &lt;code&gt;package.json&lt;/code&gt; with:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm install grunt --save-dev&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And the plugins that you need can be installed as follows:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm install &amp;lt;grunt-plugin-name&amp;gt; --save-dev&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Please note that the &lt;code&gt;--save-dev&lt;/code&gt; parameter will change your &lt;code&gt;devDependencies&lt;/code&gt;
section in your &lt;code&gt;package.json&lt;/code&gt;. So, be sure to commit the updated &lt;code&gt;package.json&lt;/code&gt;
file with your project whenever you consider appropriate.&lt;/p&gt;

&lt;h2 id=&quot;code-documentation&quot;&gt;Code documentation&lt;/h2&gt;

&lt;p&gt;If you document your code following the syntax rules defined on &lt;a href=&quot;http://usejsdoc.org&quot;&gt;JSDoc&lt;/a&gt; 3,
e.g.:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/**&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;  * A callback function returning array defining where the ticks&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;  * are laid out on the axis.&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;  *&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;  * @function tickPositioner&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;  * @see {@link http://api.highcharts.com/highstock#yAxis.tickPositioner}&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;  * @param {String} xOrY - Is it X or Y Axis?&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;  * @param {Number} min - Minimum value&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;  * @param {Number} max - Maximum value&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;  * @returns {Array} - Where the ticks are laid out on the axis.&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;  */&lt;/span&gt;
 &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tickPositioner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;xOrY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// do something&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tickPositions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you need more information about &lt;a href=&quot;http://usejsdoc.org&quot;&gt;JSDoc&lt;/a&gt;, read their documentation, it’s
easy to catch up.&lt;/p&gt;

&lt;p&gt;The next step to automate the generation of the code documentation is to install
first the &lt;a href=&quot;https://github.com/krampstudio/grunt-jsdoc&quot;&gt;grunt-jsdoc&lt;/a&gt; plugin as follows:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm install grunt-jsdoc --save-dev&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once &lt;code&gt;grunt-jsdoc&lt;/code&gt; is installed you must create your &lt;code&gt;Gruntfile.js&lt;/code&gt; in the
root directory of your project and then add the &lt;code&gt;jsdoc&lt;/code&gt; entry to the options
of the &lt;code&gt;initConfig&lt;/code&gt; method.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Project configuration.&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;initConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;pkg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readJSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;package.json&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;jsdoc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;dist&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;src/*.js&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;test/*.js&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; 
              &lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;doc&amp;#39;&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, you need to load the plugin after the &lt;code&gt;initConfig&lt;/code&gt; method in the
&lt;code&gt;Gruntfile.js&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Load the plugin that provides the &amp;#39;jsdoc&amp;#39; task.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loadNpmtasks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;grunt-jsdoc&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The resulting &lt;code&gt;Gruntfile.js&lt;/code&gt; until now is:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Project configuration.&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;initConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;pkg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readJSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;package.json&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;jsdoc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;dist&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;src/*.js&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;test/*.js&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; 
              &lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;doc&amp;#39;&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Load the plugin that provides the &amp;#39;jsdoc&amp;#39; task.&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loadNpmtasks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;grunt-jsdoc&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To generate the documentation, you need to call the &lt;code&gt;jsdoc&lt;/code&gt; task as follows:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt jsdoc&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Immediately you can see, inside the &lt;code&gt;doc&lt;/code&gt; directory, the available documentation
in HTML format with some beautiful styles by default.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://milmazz.uno/images/grunt/jsdoc.png&quot; alt=&quot;JSDoc&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;linting-your-javascript-code&quot;&gt;Linting your JavaScript code&lt;/h2&gt;

&lt;p&gt;In order to find suspicious, non-portable or potential problems in JavaScript
code or simply to enforce your team’s coding convention, whatever may be the
reason, I recommend that you should include a static code analysis tool in
your toolset.&lt;/p&gt;

&lt;p&gt;The first step is to define your set of rules. I prefer to specify the set of
rules in an independent file called &lt;code&gt;.jshintrc&lt;/code&gt; located at the root directory of
the project, let’s see an example:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// file: .jshintrc&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;globals&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;Highcharts&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// This is only necessary if you use Highcharts&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;module&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Gruntfile.js&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;bitwise&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;browser&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;camelcase&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;curly&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;eqeqeq&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;forin&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;freeze&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;immed&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;indent&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;jquery&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;latedef&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;newcap&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;noempty&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;nonew&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;quotmark&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;trailing&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;undef&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;unused&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you need more details about the checks that offer every rule mentioned above,
please, read the page that contains a list of
&lt;a href=&quot;http://www.jshint.com/docs/options/&quot;&gt;all options supported by JSHint&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To install the &lt;a href=&quot;https://github.com/gruntjs/grunt-contrib-jshint&quot;&gt;grunt-contrib-jshint&lt;/a&gt; plugin, , please do as follows:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm install grunt-contrib-jshint --save-dev&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, proceed to add the &lt;code&gt;jshint&lt;/code&gt; entry to the options of the &lt;code&gt;initConfig&lt;/code&gt;
method in the &lt;code&gt;Gruntfile.js&lt;/code&gt; as follows:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;jshint&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;jshintrc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;.jshintrc&amp;#39;&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
 &lt;span class=&quot;nx&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Gruntfile.js&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;src/*.js&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;test/*.js&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, as it’s done in the previous section, you need to load the plugin after
the &lt;code&gt;initConfig&lt;/code&gt; method in the &lt;code&gt;Grunfile.js&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Load the plugin that provides the &amp;#39;jshint&amp;#39; task.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loadNpmTasks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;grunt-contrib-jshint&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To validate your JavaScript code against the previous set of rules you need to
call the &lt;code&gt;jshint&lt;/code&gt; task:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt jshint&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that if you need more information or explanations about the errors that you
may receive after the previous command I suggest that you should visit
&lt;a href=&quot;http://jslinterrors.com&quot;&gt;JSLint Error Explanations&lt;/a&gt; site.&lt;/p&gt;

&lt;h2 id=&quot;code-style&quot;&gt;Code Style&lt;/h2&gt;

&lt;p&gt;As I mentioned in the previous section, I suggest that you should maintain an
independent file where you define the set of rules about your coding styles:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// file: .jsbeautifyrc&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;indent_size&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;indent_char&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;indent_level&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;indent_with_tabs&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;preserve_newlines&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;max_preserve_newlines&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;jslint_happy&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;brace_style&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;collapse&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;keep_array_indentation&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;keep_function_indentation&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;space_before_conditional&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;break_chained_methods&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;eval_code&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;unescape_strings&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;wrap_line_length&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, proceed to add the &lt;code&gt;jsbeautifier&lt;/code&gt; entry to the options of the &lt;code&gt;initConfig&lt;/code&gt;
method in the &lt;code&gt;Gruntfile.js&lt;/code&gt; as follows:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;jsbeautifier&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;modify&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;index.js&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;.jsbeautifyrc&amp;#39;&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;verify&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;index.js&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;VERIFY_ONLY&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;.jsbeautifyrc&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The next step it to load the plugin after the &lt;code&gt;initConfig&lt;/code&gt; method:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Load the plugin that provides the &amp;#39;jsbeautifier&amp;#39; task.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loadNpmTasks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;grunt-jsbeautifier&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To adjust your JS files according to the previous set of rules you need to call
the &lt;code&gt;jsbeautifier&lt;/code&gt; task:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt jsbeautifier:modify&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id=&quot;concat-and-minified-css-html-js&quot;&gt;Concat and minified CSS, HTML, JS&lt;/h2&gt;

&lt;p&gt;To reduce the size of your CSS, HTML and JS files do as follows:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm install grunt-contrib-uglify --save-dev
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm install grunt-contrib-htmlmin --save-dev
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm install grunt-contrib-cssmin --save-dev&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, add the &lt;code&gt;htmlmin&lt;/code&gt;, &lt;code&gt;cssmin&lt;/code&gt; and &lt;code&gt;uglify&lt;/code&gt; entries to the options
of the &lt;code&gt;initConfig&lt;/code&gt; method in the &lt;code&gt;Gruntfile.js&lt;/code&gt; as follows:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;htmlmin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;dist&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;removeComments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;collapseWhitespace&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;&amp;#39;dist/index.html&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;src/index.html&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// &amp;#39;destination&amp;#39;: &amp;#39;source&amp;#39;&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;&amp;#39;dist/contact.html&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;src/contact.html&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;cssmin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;add_banner&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;banner&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/* My minified css file */&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;&amp;#39;path/to/output.css&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;path/to/**/*.css&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;uglify&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;banner&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/* &amp;lt;%= grunt.template.today(&amp;quot;yyyy-mm-dd&amp;quot;) %&amp;gt; */\n&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;separator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;compress&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
 &lt;span class=&quot;nx&quot;&gt;chart&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;src/js/*.js&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;dist/js/example.min.js&amp;#39;&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The next step it to load the plugins after the &lt;code&gt;initConfig&lt;/code&gt; method:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Load the plugin that provides the &amp;#39;uglify&amp;#39; task.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loadNpmTasks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;grunt-contrib-uglify&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Load the plugin that provides the &amp;#39;htmlmin&amp;#39; task.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loadNpmTasks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;grunt-contrib-htmlmin&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Load the plugin that provides the &amp;#39;cssmin&amp;#39; task.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loadNpmTasks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;grunt-contrib-cssmin&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To adjust your files according to the previous set of rules you need to call
the &lt;code&gt;htmlmin&lt;/code&gt;, &lt;code&gt;cssmin&lt;/code&gt; or &lt;code&gt;uglify&lt;/code&gt; tasks:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt htmlmin
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt cssmin
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt uglify&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After loading all of your Grunt tasks you can create some aliases.&lt;/p&gt;

&lt;p&gt;If you want to create an alias that runs the three previous tasks in one step do
as follows:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Wrapper around htmlmin, cssmin and uglify tasks.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerTask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;minified&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&amp;#39;htmlmin&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&amp;#39;cssmin&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&amp;#39;uglify&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So, to execute the three tasks in one step you can do the following:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;grunt minified&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The previous command is a wrapper around the &lt;code&gt;htmlmin&lt;/code&gt;, &lt;code&gt;cssmin&lt;/code&gt; and &lt;code&gt;uglify&lt;/code&gt;
tasks defined before.&lt;/p&gt;

&lt;p&gt;Wrapping all together we get the following [Grunfile.js][]&lt;/p&gt;

&lt;h2 id=&quot;other-plugins&quot;&gt;Other plugins&lt;/h2&gt;

&lt;p&gt;Grunt offers you a very large amount of &lt;a href=&quot;http://gruntjs.com/plugins&quot;&gt;plugins&lt;/a&gt;, they have a dedicated
section to list them!&lt;/p&gt;

&lt;p&gt;I recommend that you should take some time to check out the following
&lt;em&gt;plugins&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.npmjs.org/package/grunt-newer&quot;&gt;grunt-newer&lt;/a&gt; lets you configure Grunt tasks to run with newer files
only.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.npmjs.org/package/grunt-contrib-watch&quot;&gt;grunt-contrib-watch&lt;/a&gt; lets you run predefined tasks whenever file patterns
are added, changed or deleted.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.npmjs.org/package/grunt-contrib-imagemin&quot;&gt;grunt-contrib-imagemin&lt;/a&gt; let you minify images.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Certainly, Grunt do a great job when we talk about task automation, also,
automating this repetitive tasks is fun and reduce the errors associated with
tasks that in the past we used to run manually over and over again. That been
said, I definitely recommend that you should try Grunt, you will get in exchange
an improvement in your development workflow, also with it you can forget to
endure repetitive tasks that we hate to do, as a result you will get more
free time to focus on getting things done.&lt;/p&gt;

&lt;p&gt;Last but not least, another option for Grunt is &lt;a href=&quot;http://gulpjs.com&quot;&gt;Gulp&lt;/a&gt;, I recently read about
it, if you look at their documentation you notice that their syntax is more
clean than Grunt, also is very concise and allows chaining calls, following the
concept of streams that pipes offer in *nix like systems, so, I’ll give it a try
in my next project.&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2014/06/28/grunt-javascript-task-manager/&quot;&gt;Grunt: The Javascript Task Manager&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on June 28, 2014.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[The DRY principle]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2014/06/24/the-dry-principle/"/>
  <id>http://milmazz.uno/article/2014/06/24/the-dry-principle</id>
  <published>2014-06-24T19:00:00-05:00</published>
  <updated>2014-06-24T19:00:00-05:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p&gt;The &lt;a href=&quot;http://en.wikipedia.org/wiki/DRY_principle&quot;&gt;DRY&lt;/a&gt; (&lt;em&gt;Don’t Repeat Yourself&lt;/em&gt;) principle it basically consist in the
following:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That said, it’s almost clear that the DRY principle is against the code
duplication, something that in the long-term affect the maintenance phase, it
doesn’t facilitate the improvement or code refactoring and, in some
cases, it can generate some contradictions, among other problems.&lt;/p&gt;

&lt;p&gt;Recently I have inherited a project, and one of the things that I noticed in
some part of the source code are the following:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/milmazz/ed5d4aab90ea70deda9c.js?file=original.js&quot;&gt; &lt;/script&gt;

&lt;p&gt;After a glance, you can save some bytes and apply the &lt;em&gt;facade&lt;/em&gt; and &lt;em&gt;module&lt;/em&gt;
pattern without breaking the API compatibility in this way:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/milmazz/ed5d4aab90ea70deda9c.js?file=first_iteration.js&quot;&gt; &lt;/script&gt;

&lt;p&gt;But, if you have read the &lt;a href=&quot;http://jquery.com&quot;&gt;jQuery&lt;/a&gt; documentation it’s obvious that the
previous code portions are against the DRY principle, basically, this functions
expose some shorthands for the &lt;code&gt;$.ajax&lt;/code&gt; method from the jQuery library. That
said, it’s important to clarify that &lt;a href=&quot;http://jquery.com&quot;&gt;jQuery&lt;/a&gt;, from version 1.0, offers some
shorthands, they are: &lt;code&gt;$.get()&lt;/code&gt;, &lt;code&gt;$.getJSON()&lt;/code&gt;, &lt;code&gt;$.post()&lt;/code&gt;, among others.&lt;/p&gt;

&lt;p&gt;So, in this particular case, I prefer to break the backward compatibility and
delete the previous code portions. After that, I changed the code that used the
previous functions and from this point I only used the shorthand that jQuery
offers, some examples may clarify this thought:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/milmazz/ed5d4aab90ea70deda9c.js?file=final.js&quot;&gt; &lt;/script&gt;

&lt;p&gt;Another advantage of using the shorthand methods that jQuery provides is that
you can work with Deferreds, one last thing that we must take in consideration
is that &lt;code&gt;jqXHR.success()&lt;/code&gt; and &lt;code&gt;jqXHR.error()&lt;/code&gt; callback methods are deprecated
as of jQuery 1.8.&lt;/p&gt;

&lt;p&gt;Anyway, I wanted to share my experience in this case. Also, remark that we need
to take care of some principles at the moment we develop software and avoid to
reinvent the wheel or do &lt;em&gt;overengineering&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Last but not least, one way to read &lt;em&gt;offline&lt;/em&gt; documentation that I tend to use is
&lt;a href=&quot;http://kapeli.com/dash&quot;&gt;Dash&lt;/a&gt; or &lt;a href=&quot;http://zealdocs.org&quot;&gt;Zeal&lt;/a&gt;, I can reach a bunch of documentation without the need of an
Internet connection, give it a try!&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2014/06/24/the-dry-principle/&quot;&gt;The DRY principle&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on June 24, 2014.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[libturpial needs your help]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2014/03/10/libturpial-needs-your-help/"/>
  <id>http://milmazz.uno/article/2014/03/10/libturpial-needs-your-help</id>
  <published>2014-03-10T15:00:00-06:00</published>
  <updated>2014-03-10T15:00:00-06:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p&gt;Do you want to begin to contribute into &lt;a href=&quot;https://github.com/satanas/libturpial&quot;&gt;libturpial&lt;/a&gt; codebase but you don’t
know where to start?, that’s ok, it also happens to me sometimes, but today, the
reality is that we need your help to fix some errors reported by our style
checker (&lt;a href=&quot;https://pypi.python.org/pypi/flake8‎&quot;&gt;flake8&lt;/a&gt;), this errors are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;E126&lt;/code&gt;: continuation line over-indented for hanging indent&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;E128&lt;/code&gt;: continuation line under-indented for visual indent&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;E231&lt;/code&gt;: missing whitespace after &lt;code&gt;:&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;E251&lt;/code&gt;: unexpected spaces around keyword / parameter equals&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;E261&lt;/code&gt;: at least two spaces before inline comment&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;E301&lt;/code&gt;: expected 1 blank line&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;E302&lt;/code&gt;: expected 2 blank lines&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;E303&lt;/code&gt;: too many blank lines&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;E501&lt;/code&gt;: line too long&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;E711&lt;/code&gt;: comparison to &lt;code&gt;None&lt;/code&gt; should be &lt;code&gt;if cond is not None:&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;E712&lt;/code&gt;: comparison to &lt;code&gt;False&lt;/code&gt; should be &lt;code&gt;if cond is False:&lt;/code&gt; or &lt;code&gt;if not cond:&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;F401&lt;/code&gt;: imported but unused&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;F403&lt;/code&gt;: unable to detect undefined names&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;F821&lt;/code&gt;: undefined name&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;F841&lt;/code&gt;: local variable is assigned to but never used&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;F999&lt;/code&gt;: syntax error in doctest&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;W291&lt;/code&gt;: trailing whitespace&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;W391&lt;/code&gt;: blank line at end of file&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;W601&lt;/code&gt;: &lt;code&gt;.has_key()&lt;/code&gt; is deprecated, use &lt;code&gt;in&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, some errors are really easy to fix but are too many for us, so
please, we desperately need your help, help us!&lt;/p&gt;

&lt;p&gt;The following is how we expect the community can contribute code into
&lt;code&gt;libturpial&lt;/code&gt; via &lt;a href=&quot;https://help.github.com/articles/using-pull-requests&quot;&gt;Pull Requests&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;1) If you don’t have a &lt;a href=&quot;https://github.com&quot;&gt;Github&lt;/a&gt; account, please create one first.&lt;/p&gt;

&lt;p&gt;2) Fork our project&lt;/p&gt;

&lt;p&gt;3) Install &lt;a href=&quot;http://git-scm.com/download&quot;&gt;Git&lt;/a&gt;, after that you should setup your name and email:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git config --global user.name &lt;span class=&quot;s2&quot;&gt;&amp;quot;Your Name, not your Github nickname&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git config --global user.email &lt;span class=&quot;s2&quot;&gt;&amp;quot;you@example.com&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;4) Set your local repository&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git clone https://github.com/your_github_nickname/libturpial.git&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;5) Set &lt;code&gt;satanas/libturpial&lt;/code&gt; as your &lt;code&gt;upstream&lt;/code&gt; remote, this basically tells Git
that your are referencing libturpial’s repository as your main source.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git remote add upstream https://github.com/satanas/libturpial.git&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;5.1) Update your local copy&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git fetch upstream&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;6) Verify that no one else has been working on the same bug, you can check that
in our &lt;a href=&quot;https://github.com/satanas/libturpial/issues&quot;&gt;issues&lt;/a&gt; list, in this list you can also check
&lt;a href=&quot;https://help.github.com/articles/using-pull-requests&quot;&gt;Pull Requests&lt;/a&gt; pending for the &lt;a href=&quot;http://en.wikipedia.org/wiki/Benevolent_Dictator_for_Life‎&quot;&gt;BDFL&lt;/a&gt; approval.&lt;/p&gt;

&lt;p&gt;7) Working on a bug&lt;/p&gt;

&lt;p&gt;7.1) In the first place, install &lt;a href=&quot;https://pypi.python.org/pypi/tox‎&quot;&gt;tox&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;pip install tox&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;7.2) Then, create a branch that identifies the bug that you will begin to work
on:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git checkout -b E231 upstream/development&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this example we are working on the bugs of the type: &lt;strong&gt;E231&lt;/strong&gt; (as indicated
by our style checker, &lt;code&gt;flake8&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;7.3) Make some local changes and commit, repeat.&lt;/p&gt;

&lt;p&gt;7.3.1) Delete the error code that you will begin to work from the &lt;code&gt;ignore&lt;/code&gt; list
located at the &lt;code&gt;flake8&lt;/code&gt; section in the &lt;code&gt;tox.ini&lt;/code&gt; file (located at the root of
the project)&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Original list:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ignore&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;E126,E128,E231,E251,E261,E301&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# After we decide to work in the E231 error:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ignore&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;E126,E128,E251,E261,E301&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;7.3.2) Execute &lt;code&gt;tox -e py27&lt;/code&gt; to check the current errors.&lt;/p&gt;

&lt;p&gt;7.3.3) Fix, fix, fix…&lt;/p&gt;

&lt;p&gt;7.3.4) Commit your changes&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git commit -m &lt;span class=&quot;s2&quot;&gt;&amp;quot;Fixed errors &amp;#39;E231&amp;#39; according to flake8.&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;7.4) In the case that you fixed all errors of the same type, please delete the
corresponding line in the &lt;code&gt;tox.ini&lt;/code&gt; file (located at the root of the project)&lt;/p&gt;

&lt;p&gt;7.4.1) Don’t forget to commit that.&lt;/p&gt;

&lt;p&gt;8) Publish your work&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git push origin E231&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Please, adjust the name &lt;code&gt;E231&lt;/code&gt; to something more appropiate in your case.&lt;/p&gt;

&lt;p&gt;9) Create a Pull Request and don’t hesitate to bug the main maintainer until
your changes get merged and published. Last but not least, don’t forget to add
yourself as an author in the AUTHORS file, located at the root of the project.&lt;/p&gt;

&lt;p&gt;10) Enjoy your work! :-)&lt;/p&gt;

&lt;p&gt;If you want to help us more than you did already you can check our &lt;a href=&quot;https://github.com/satanas/libturpial/issues&quot;&gt;issues&lt;/a&gt;
list, also, you can check out the &lt;a href=&quot;https://github.com/satanas/Turpial&quot;&gt;Turpial&lt;/a&gt; project, our light, fast and
beautiful microblogging client written in Python, currently supports
&lt;a href=&quot;https://twitter.com&quot;&gt;Twitter&lt;/a&gt;, and &lt;a href=&quot;https://identi.ca&quot;&gt;identi.ca&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can find more details on our &lt;a href=&quot;http://libturpial.readthedocs.org/en/latest/&quot;&gt;guide&lt;/a&gt;, also, in case
of doubt don’t hesitate to reach us.&lt;/p&gt;

&lt;h2 id=&quot;about-libturpial&quot;&gt;About libturpial&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;libturpial&lt;/em&gt; is a Python library that handles multiple microblogging protocols.
It  implements a lot of features and aims to support all the features for each
protocol. At the moment it supports &lt;a href=&quot;https://twitter.com&quot;&gt;Twitter&lt;/a&gt; and &lt;a href=&quot;https://identi.ca&quot;&gt;Identi.ca&lt;/a&gt; and is the
backend  used for &lt;em&gt;Turpial&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;about-turpial&quot;&gt;About Turpial&lt;/h2&gt;

&lt;p&gt;Turpial is an alternative client for microblogging with multiple interfaces. At
the moment it supports Twitter and Identi.ca and works with Gtk and Qt
interfaces.&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2014/03/10/libturpial-needs-your-help/&quot;&gt;libturpial needs your help&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on March 10, 2014.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[jQuery best practices]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2014/02/24/jquery-best-practices/"/>
  <id>http://milmazz.uno/article/2014/02/24/jquery-best-practices</id>
  <published>2014-02-24T18:20:00-06:00</published>
  <updated>2014-02-24T18:20:00-06:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p&gt;After some time working with C programming language in a *NIX like operating
system, recently I came back again to Web Programming, mostly working with HTML,
CSS and JavaScript in the client-side and other technologies in the backend
area.&lt;/p&gt;

&lt;p&gt;The current project I’ve been working on, heavily relies on &lt;a href=&quot;http://jquery.com/&quot;&gt;jQuery&lt;/a&gt; and
&lt;a href=&quot;http://www.highcharts.com/&quot;&gt;Highcharts/Highstock&lt;/a&gt; libraries, I must confess that at the
beginning of the project my skills in the client-side were more than rusted, so,
I began reading a lot of articles about new techniques and good practices to
catch up very quickly, in the meantime, I start taking some notes about “best
practices”&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; that promotes a better use of jQuery&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;, I hope you find this
information useful, if you have more tips or any doubt please leave your
comments at the end of this article.&lt;/p&gt;

&lt;p&gt;The first recommendation is to use the last version of jQuery, the reason is
that in new releases you will find new features, and also a good amount of bugs
and performance problems are fixed.&lt;/p&gt;

&lt;!---
jquery 1.4.2 vs 1.6.2 vs 1.10.1
http://jsperf.com/dh-jquery-1-4-vs-1-6/50
--&gt;

&lt;p&gt;One of the benefits to work with jQuery is that it lets you find elements inside
of the DOM using a syntax similar to the CSS selectors&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. But, please, take
into account the following considerations.&lt;/p&gt;

&lt;p&gt;Modern browser support &lt;code&gt;getElementsByClassName&lt;/code&gt;, &lt;code&gt;querySelector&lt;/code&gt; and
&lt;code&gt;querySelectorAll&lt;/code&gt; directives. However, old browser versions only offer support
for &lt;code&gt;getElementById&lt;/code&gt; and &lt;code&gt;getElementByTagName&lt;/code&gt; directives. So, if you are only
targeting recent version of browsers, you might not need anything more than what
the browser offers.&lt;/p&gt;

&lt;p&gt;One of the first tips that you need to know is this: Have preference over IDs
whenever it’s possible, even in old browser versions the search based on the ID
of an element is fast because the jQuery selector internally is converted to the
native &lt;code&gt;getElementById&lt;/code&gt; directive.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#myelement&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Good&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Avoid the tag prefix when you search for an &lt;code&gt;id&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;div#myelement&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Bad&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The example above creates an inefficient query because in the first place we
traverse all the &lt;code&gt;div&lt;/code&gt; tags in the document, after that we look up the
&lt;code&gt;myelement&lt;/code&gt; &lt;code&gt;id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the same way, it’s redundant to nest multiple IDs in a jQuery selector:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#content #myelement&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Bad&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case always use the most specific &lt;code&gt;id&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#myelement&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Remember, keep it simple&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Also, if you want to select multiple elements, this implies that you need to
traverse all the DOM, which can generate a hit in your query performance, so,
you can avoid this negative impact descending from the most near ID element, for
example, imagine that you need to capture all the &lt;code&gt;input&lt;/code&gt; elements inside of a
form which &lt;code&gt;id&lt;/code&gt; is &lt;code&gt;#myform&lt;/code&gt; (yes, I know, this ID name sucks, remember, it’s
just for example purposes)&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#myform input&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Good&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#myform&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;input&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Better&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id=&quot;avoid-the-selection-of-elements-only-by-class&quot;&gt;Avoid the selection of elements only by class&lt;/h2&gt;

&lt;p&gt;Avoid to select an element only by its class, the major hit in performance
occurs when your browser doesn’t support the native call
&lt;code&gt;getElementByClassName&lt;/code&gt;, in old versions (like IE 6/7/8 and Mozilla Firefox 2)
jQuery needs to examine each element in the page to determine where is the class
that we are looking for.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;.myclass&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Bad&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;One workaround that you can use is to prefix the search with the tag element
associated with the class “myclass”.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;div.myclass&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Good&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#container&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;.myclass&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Better&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But if you are targeting only modern browsers, you better try
&lt;code&gt;getElementsByClassName()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;See: &lt;a href=&quot;http://jsperf.com/jquery-class-vs-tag-qualfied-class-selector/25&quot;&gt;jQuery class vs. tag qualified class selector&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;cache&quot;&gt;Cache&lt;/h2&gt;

&lt;p&gt;Whenever you need to use multiple times the object returned by a jQuery
selector, please store that object in a variable, avoid the following practice:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#intro&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;css&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;color&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;blue&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#intro&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;css&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;font-size&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;1.2em&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#intro&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Hello World!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case you are making three queries to get the same object!, you can
improve the example above as follows:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$intro&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#intro&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$intro&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;css&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;color&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;blue&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$intro&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;css&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;font-size&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;1.2em&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$intro&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Hello World!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the example above we store the object (cache) returned by the jQuery
selector, after that we apply multiple methods over the same object.&lt;/p&gt;

&lt;p&gt;Please note that the name of the local variable has the ‘$’ prefix, that’s not
really necessary, but some JavaScript developers have adopted this convention
that facilitates them to remember that local variable stores the results of a
jQuery selector. If you prefer you can avoid this “convention”. The important
thing here is that if you need to apply more than one method over the same
object you must store this object in a local variable first.&lt;/p&gt;

&lt;p&gt;Another advantage of storing objects in cache memory is that you can make sub-
queries, just look at the following example:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;ul&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;groceries&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;meat&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Chicken&lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;meat&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Turkey breasts&lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;oil&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Olive oil&lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;oil&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Canola oil&lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And now we apply some queries over the unordered list:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$groceries&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#groceries&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After that we make some sub-queries:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$meat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$groceries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;li.meat&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;$oil&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$groceries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;li.oil&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The principal benefit of store jQuery objects in memory is that the subsequent
queries don’t need to traverse again the DOM.&lt;/p&gt;

&lt;p&gt;See: &lt;a href=&quot;http://jsperf.com/ns-jq-cached&quot;&gt;jQuery Cached Set&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;method-chaining&quot;&gt;Method chaining&lt;/h2&gt;

&lt;p&gt;Look at the following example:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$intro&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#intro&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$intro&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;css&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;color&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;blue&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$intro&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;css&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;font-size&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;1.2em&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$intro&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Hello World!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Most of the jQuery methods returns an object, that &lt;em&gt;feature&lt;/em&gt; facilitate the
method chaining over the same element:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$intro&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#intro&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$intro&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;css&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;color&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;blue&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;css&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;font-size&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;1.2em&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Hello World!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;See: &lt;a href=&quot;http://jsperf.com/jquery-chaining/32&quot;&gt;jQuery chaining&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;group-the-set-of-parameters-over-the-same-method&quot;&gt;Group the set of parameters over the same method&lt;/h2&gt;

&lt;p&gt;You can rearrange the previous example as this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$intro&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;css&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;color&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;blue&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;font-size&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;1.2em&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Hello World!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This way you can reduce the number of times that you need to call the same
methods over the same objects. This technique create a unique literal object
that combines the set of parameters that we’ll use to pass information to the
method.&lt;/p&gt;

&lt;h2 id=&quot;minimize-the-use-of-append-insertbefore-and-insertafter&quot;&gt;Minimize the use of .append(), .insertBefore() and .insertAfter()&lt;/h2&gt;

&lt;p&gt;If you want to use the &lt;code&gt;.append()&lt;/code&gt; method, try to avoid its use inside a loop,
in the first place you can try to generate HTML strings in memory, after your
cycle ends you can append your new string to the content instead of apply the
&lt;code&gt;.append()&lt;/code&gt; method inside your cycle.&lt;/p&gt;

&lt;p&gt;Considering the following HTML structure:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;ul&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;demo&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Content added via JS --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Please, avoid the following pattern:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$demo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#demo&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;elements&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;one&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;two&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;three&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;li/&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$demo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;One approach can be this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$demo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#demo&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;elements&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;one&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;two&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;three&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;li&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;$demo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Also, you can replace the &lt;code&gt;.append()&lt;/code&gt; method with &lt;code&gt;.replaceWith()&lt;/code&gt; in some cases:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$demo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#demo&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;elements&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;one&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;two&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;three&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;ul id=\&amp;quot;demo\&amp;quot;&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;li&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;$demo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;replaceWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id=&quot;event-delegation&quot;&gt;Event delegation&lt;/h2&gt;

&lt;p&gt;Take this HTML structure as an example:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;home&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Home&lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;about&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;About&lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;contact&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Contact&lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;One way to manage the navigation buttons are this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#home&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// do something&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#about&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// do something&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;#contact&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// do something&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is really terrible because you bound an event to multiple DOM elements.&lt;/p&gt;

&lt;p&gt;You can mitigate the example above as this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$nav&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;nav&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;$nav&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;click&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;#home&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// do something&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;$nav&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;click&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;#about&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// do something&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;$nav&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;click&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;#contact&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// do something&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the example above we use event delegation, this means that we need to bind to
a single element and intercept events as they bubble up the DOM tree.&lt;/p&gt;

&lt;p&gt;If the previous methods do the same at the &lt;code&gt;click&lt;/code&gt; event you can rearrange the
example above as this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$nav&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;nav&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;$nav&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;click&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;li&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// do something&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Remember, the idea behind event delegation is to bind to a single root element
and then wait an intercept events as they &lt;em&gt;bubble up&lt;/em&gt; the DOM tree.&lt;/p&gt;

&lt;h2 id=&quot;pseudo-selectors&quot;&gt;Pseudo selectors&lt;/h2&gt;

&lt;p&gt;One the of the slowest jQuery selectors are &lt;em&gt;pseudo&lt;/em&gt; and &lt;em&gt;attribute&lt;/em&gt; selectors,
so, use this selectors with precaution.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;:visible, :hidden&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;[attribute=value]&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The performance hit is greater in this cases because jQuery can’t take advantage
of a native call. In modern browsers &lt;code&gt;querySelector()&lt;/code&gt; and &lt;code&gt;querySelectorAll()&lt;/code&gt;
can help us.&lt;/p&gt;

&lt;p&gt;See: &lt;a href=&quot;http://jsperf.com/id-vs-class-vs-tag-selectors/2&quot;&gt;id vs. class vs. tag vs. pseudo vs. attribute selectors&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;each-or-fneach-loops&quot;&gt;$.each() or $fn.each() loops&lt;/h2&gt;

&lt;p&gt;Whenever you can, try to use a plain &lt;code&gt;for&lt;/code&gt; (in some modern browsers &lt;code&gt;forEach&lt;/code&gt; is
even faster than &lt;code&gt;for&lt;/code&gt;) over the jQuery &lt;code&gt;$.each()&lt;/code&gt; function. Also, you can gain
some benefits if you cache in memory the length of your container:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Good&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// do something&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Better&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// do something&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;See: &lt;a href=&quot;http://jsperf.com/jquery-each-vs-for-loop/11&quot;&gt;Nesteds: JQuery each vs native JS for loop&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.sitepoint.com/efficient-jquery-selectors/&quot;&gt;Efficient jQuery Selectors&lt;/a&gt; by Craig Buckler.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.artzstudio.com/2009/04/jquery-performance-rules/&quot;&gt;jQuery Performance rules&lt;/a&gt; by ArtzStudio.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://blog.sathomas.me/post/jquery-best-practices&quot;&gt;jQuery best practices&lt;/a&gt; by Stephen A. Thomas.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://gregfranko.com/jquery-best-practices/&quot;&gt;jQuery best practices&lt;/a&gt; by Greg Franko.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.slideshare.net/AddyOsmani/jquery-proven-performance-tips-tricks&quot;&gt;jQuery proven performance tips &amp;amp; tricks&lt;/a&gt; by Addy Osmani.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.quirksmode.org/dom/w3c_core.html&quot;&gt;DOM Core&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;Please take this “best practices” with a grain of salt, do your research and see if this recommendations applies in your web clients, in my case, I need to provide support for some older browsers (IE 7/8/9 mostly). &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot;&gt;
      &lt;p&gt;As a side note, besides jQuery nowadays are used by a large percentage of sites, according to W3Techs, &lt;a href=&quot;http://w3techs.com/blog/entry/jquery_now_runs_on_every_second_website&quot;&gt;jQuery now runs on every second website&lt;/a&gt; (2012). However, currently exists a trend that states that you need to avoid jQuery when it’s possible, so, whenever it’s possible try to use native JavaScript, one example of this trend is &lt;a href=&quot;http://youmightnotneedjquery.com/&quot;&gt;You Might Not Need jQuery&lt;/a&gt; website. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot;&gt;
      &lt;p&gt;You might find useful some other alternatives as &lt;a href=&quot;https://github.com/ded/qwery&quot;&gt;qwery&lt;/a&gt; and &lt;a href=&quot;http://sizzlejs.com/&quot;&gt;Sizzle&lt;/a&gt;. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;

  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2014/02/24/jquery-best-practices/&quot;&gt;jQuery best practices&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on February 24, 2014.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[MongoDB University: M101P]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2014/02/17/mongodb-university-m101p/"/>
  <id>http://milmazz.uno/article/2014/02/17/mongodb-university-m101p</id>
  <published>2014-02-17T02:00:00-06:00</published>
  <updated>2014-02-17T02:00:00-06:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p&gt;A finales del año pasado finalice satisfactoriamente el curso en línea &lt;em&gt;M101P: MongoDB for Python Developers&lt;/em&gt; de &lt;a href=&quot;https://education.mongodb.com/&quot;&gt;MongoDB University&lt;/a&gt; (otrora conocido como &lt;em&gt;10gen Education&lt;/em&gt;). Sin embargo, no me había tomado el tiempo para compartirles la experiencia, sino hasta ahora.&lt;/p&gt;

&lt;p&gt;Cualquier persona sin práctica en el área puede tomar este curso, pues es un abreboca al mundo detrás de MongoDB y explora un buen número de temas relacionados a esta base de datos &lt;a href=&quot;http://en.wikipedia.org/wiki/NoSQL&quot;&gt;NoSQL&lt;/a&gt;. Aunque está orientado a desarrolladores en Python lo exigido por el curso es mínimo en este lenguaje, incluso dentro de los temas está contemplado una introducción a este lenguaje. Sin embargo, para aquellos que decidan explorar otros lenguajes de programación, &lt;a href=&quot;https://education.mongodb.com/&quot;&gt;MongoDB University&lt;/a&gt; ofrece alternativas para programadores en &lt;a href=&quot;https://education.mongodb.com/courses/10gen/M101J/2013_October/about&quot;&gt;Java&lt;/a&gt;, &lt;a href=&quot;https://education.mongodb.com/courses/10gen/M101JS/2013_October/about&quot;&gt;Node.js&lt;/a&gt; y también para &lt;a href=&quot;https://education.mongodb.com/courses/10gen/M102/2013_September/about&quot;&gt;DBAs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;La duración del curso es de 7 semanas, en base al conocimiento previo que se maneje de las tecnologías puede necesitar de unas 4 a 6 horas semanales de dedicación. La estructura del curso permite ver inicialmente varios videos introductorios que hacen referencia a un tópico en particular, luego podrá reforzar lo visto con una serie de &lt;em&gt;quizzes&lt;/em&gt;, en este punto siempre es recomendable contrastar lo visto con la &lt;a href=&quot;http://docs.mongodb.org/manual/&quot;&gt;documentación oficial en línea&lt;/a&gt; y no dejar de responder todas las tareas de cada semana pues tienen un peso total del 50%, el plazo de respuesta es más que aceptable, se da una semana de plazo para responder. En la última semana será el examen final, el cual consta de 10 preguntas, con ello se obtiene el otro 50%.&lt;/p&gt;

&lt;p&gt;En mi caso aprovechaba el tiempo al ser trasladado hacia/desde el trabajo y veía &lt;em&gt;fuera de línea&lt;/em&gt; los videos ofrecidos por &lt;a href=&quot;https://education.mongodb.com/&quot;&gt;MongoDB University&lt;/a&gt;. Luego, al retornar a casa en las noches o los fines de semana respondía los &lt;em&gt;quizzes&lt;/em&gt; y las asignaciones, de ese modo me fue posible lograr aprobar sin problemas el curso, además, al final recibes un certificado de aprobación, aunque lo más importante para mi fue aprender algunas cuestiones que aún desconocía de MongoDB, las semanas podrían resumirse como siguen:&lt;/p&gt;

&lt;p&gt;En la primera semana se ve una introducción a MongoDB, se compara en cierta medida con el esquema relacional y se plasma un bosquejo del desarrollo de aplicaciones con MongoDB. También se explora el &lt;em&gt;shell&lt;/em&gt; y se introduce la notación JSON, a partir de acá se crean &lt;em&gt;arrays&lt;/em&gt;, documentos y subdocumentos, entre otros detalles de la &lt;a href=&quot;http://www.json.org/&quot;&gt;especificación&lt;/a&gt;. También se comienza a preparar el ambiente de trabajo futuro, es decir, se explica como instalar MongoDB en diversas plataformas, así como &lt;a href=&quot;http://python.org&quot;&gt;Python&lt;/a&gt;, &lt;a href=&quot;http://bottlepy.org&quot;&gt;Bottle&lt;/a&gt; (&lt;em&gt;microframework&lt;/em&gt; para desarrollo &lt;em&gt;Web&lt;/em&gt; en Python) y &lt;a href=&quot;http://api.mongodb.org/python/current/&quot;&gt;pymongo&lt;/a&gt;, éste último ofrece un conjunto de herramientas para interactuar con MongoDB desde Python. Ya para finalizar las sesiones de la semana, se da una introducción al lenguaje de programación Python y manejo básico del &lt;em&gt;framework&lt;/em&gt; Bottle.&lt;/p&gt;

&lt;p&gt;La segunda semana se tiene mayor interacción con el &lt;em&gt;shell&lt;/em&gt; de MongoDB, se inicia el proceso de &lt;a href=&quot;http://docs.mongodb.org/manual/crud/&quot;&gt;CRUD&lt;/a&gt;, se podrán ejecutar consultas por medio de &lt;code&gt;find&lt;/code&gt;, &lt;code&gt;findOne&lt;/code&gt;. Se comienza el uso de &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/query-comparison/&quot;&gt;operadores de comparación&lt;/a&gt; de campos como &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/gt/&quot;&gt;$gt&lt;/a&gt; y &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/lt/&quot;&gt;$lt&lt;/a&gt;, &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/query-logical/&quot;&gt;operadores lógicos&lt;/a&gt; como &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/or/&quot;&gt;$or&lt;/a&gt;, &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/and/&quot;&gt;$and&lt;/a&gt;, uso de operadores &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/exists/&quot;&gt;$exists&lt;/a&gt;, &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/type/&quot;&gt;$type&lt;/a&gt;, conteo de consultas sobre colecciones con el método &lt;a href=&quot;http://docs.mongodb.org/manual/reference/method/db.collection.count/&quot;&gt;count()&lt;/a&gt;, uso de expresiones regulares (compatibles a las usadas en Perl) a través del operador &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/regex/&quot;&gt;$regex&lt;/a&gt;&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, consultas sobre elementos dentro de &lt;em&gt;arrays&lt;/em&gt; con los operadores &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/in/&quot;&gt;$in&lt;/a&gt; y &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/all/&quot;&gt;$all&lt;/a&gt;, actualizaciones de &lt;em&gt;arrays&lt;/em&gt; a través de &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/push/&quot;&gt;$push&lt;/a&gt;, &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/pop/&quot;&gt;$pop&lt;/a&gt;, &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/pull/&quot;&gt;$pull&lt;/a&gt;, &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/pullAll/&quot;&gt;$pullAll&lt;/a&gt; y &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/addToSet/&quot;&gt;$addToSet&lt;/a&gt;. Además, uso de operadores de actualización &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/set/&quot;&gt;$set&lt;/a&gt; y &lt;a href=&quot;http://docs.mongodb.org/manual/reference/operator/unset/&quot;&gt;$unset&lt;/a&gt; para establecer o eliminar campos de un documento respectivamente. &lt;a href=&quot;http://docs.mongodb.org/manual/reference/method/db.collection.update/&quot;&gt;Actualización de documentos&lt;/a&gt; existentes y la posibilidad de utilizar opciones como &lt;code&gt;upsert&lt;/code&gt; (operación que permite hacer una actualización si el documento en cuestión existe, de lo contrario, se realiza una inserción automática) o &lt;code&gt;multi&lt;/code&gt; (actualización múltiple). Ya para finalizar la segunda semana se deja de lado un poco el &lt;em&gt;shell&lt;/em&gt; y se comienza el mismo proceso de interacción descrito previamente pero en esta ocasión desde &lt;em&gt;pymongo&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;La tercera semana nos podemos encontrar con temas enfocados al área de &lt;a href=&quot;http://docs.mongodb.org/manual/core/data-modeling-introduction/&quot;&gt;modelado de datos&lt;/a&gt;, pues MongoDB ofrece un esquema flexible, incluso cada documento puede manejar un esquema dinámico. Por lo tanto, resulta conveniente estudiar las posibilidades existentes en el &lt;a href=&quot;http://docs.mongodb.org/manual/applications/data-models/&quot;&gt;modelaje de datos&lt;/a&gt; y que la escogencia de un esquema particular apunte a cubrir los requerimientos de la aplicación, explotación de las características propias del motor de base de datos y los mecanismos comunes de obtención de dichos datos. En el transcurso de la tercera semana, se contrasta como ejemplo el modelado de datos relacional de las tablas que pueden estar asociadas a un &lt;em&gt;blog&lt;/em&gt; y como cambia dicho modelado desde la visión no relacional, también se cubren temas como las &lt;a href=&quot;http://docs.mongodb.org/manual/tutorial/model-embedded-one-to-one-relationships-between-documents/&quot;&gt;relaciones uno a uno&lt;/a&gt;, &lt;a href=&quot;http://docs.mongodb.org/manual/tutorial/model-referenced-one-to-many-relationships-between-documents/&quot;&gt;uno a muchos con referencias a otros documentos&lt;/a&gt;, &lt;a href=&quot;http://docs.mongodb.org/manual/tutorial/model-embedded-one-to-many-relationships-between-documents/&quot;&gt;uno a muchos con documentos embebidos&lt;/a&gt;, en qué casos puede ser beneficioso embeber datos. Finalmente se explora &lt;a href=&quot;http://docs.mongodb.org/manual/core/gridfs/&quot;&gt;GridFS&lt;/a&gt; para el manejo de &lt;em&gt;blobs&lt;/em&gt;, ficheros que normalmente superen el límite de tamaño de cada documento (16MB).&lt;/p&gt;

&lt;p&gt;El tema principal de la cuarta semana es el rendimiento, lo cual puede estar influenciado por muchos factores, desde el sistema de gestión de ficheros, hasta la memoria, CPU, tipos de discos, entre otros. Sin embargo, en esta semana se concentrarán en explorar los algoritmos que dependiendo de la situación puede ejecutar rápidamente o no las consultas. Por lo tanto, es necesario explorar conceptos básicos como índices, su creación y descubrimiento, índices con múltiples claves hasta temas como la detección de posible cuellos de botella al no utilizar índices o mala utilización de los mismos. Al finalizar se comienza a explorar los &lt;a href=&quot;[http://docs.mongodb.org/manual/core/sharding-introduction/]&quot;&gt;shardings&lt;/a&gt;, básicamente es una técnica que permite dividir largas colecciones de datos en múltiples servidores.&lt;/p&gt;

&lt;p&gt;La quinta semana se explora una de las funcionalidades mas atractivas de MongoDB: &lt;a href=&quot;http://docs.mongodb.org/manual/aggregation/&quot;&gt;Aggregation framework&lt;/a&gt;. Para los que vienen del mundo SQL puede parecerles una respuesta a la agrupación de resultados por grupos, en donde se pueden obtener sumas (&lt;code&gt;$sum&lt;/code&gt;), conteos (&lt;code&gt;$count&lt;/code&gt;), promedios (&lt;code&gt;$avg&lt;/code&gt;) y otras funciones sobre un conjunto de colecciones agrupadas por ciertos valores particulares.&lt;/p&gt;

&lt;p&gt;La sexta semana se cubren interesantes temas como la replicación y &lt;em&gt;sharding&lt;/em&gt;. La última semana se tiene acceso a 2 casos de estudio, en particular, la primera entrevista es con Jon Hoffman (&lt;a href=&quot;https://twitter.com/Hoffrocket&quot;&gt;@Hoffrocket&lt;/a&gt;) de Foursquare y la segunda con Ryan Bubinski (&lt;a href=&quot;https://twitter.com/ryanbubinski&quot;&gt;@ryanbubinski&lt;/a&gt;) de Codecademy.&lt;/p&gt;

&lt;p&gt;Después de las entrevistas viene el examen final, el cual cubre el 50% del curso. ¡Éxitos! y recuerde siempre reforzar lo visto en el curso con la documentación oficial, también existen recursos adicionales&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; en la red que podrían servirles.&lt;/p&gt;

&lt;p&gt;Ya para finalizar quisiera decirles que se animen a intentar unirse al curso que se ofrece de MongoDB, vale la pena intentarlo y verán que son semanas bien aprovechadas.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;Resalto que de llegar a necesitar hacer uso de expresiones regulares a través del operador &lt;code&gt;$regex&lt;/code&gt;, tenga en cuenta que solo podrá hacer uso eficiente del índice cuando la expresión regular incluye el ancla de inicio de cadena: ^ (acento cincunflejo) y sea &lt;em&gt;case-sensitive&lt;/em&gt;. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot;&gt;
      &lt;p&gt;Puede encontrar material de apoyo introductorio en el libro &lt;a href=&quot;https://github.com/karlseguin/the-little-mongodb-book&quot;&gt;The Little MongoDB Book&lt;/a&gt; de Karl Seguin, también existen guías y presentaciones adicionales que pueden ayudarle a comprender aún más MongoDB, por ejemplo, &lt;a href=&quot;http://www.slideshare.net/vkarpov15/mongodb-queries-and-aggregation-framework-with-nba-game-data&quot;&gt;esta presentación sobre distintas consultas y uso del &lt;em&gt;aggregation framework&lt;/em&gt; para explorar datos de resultados la NBA&lt;/a&gt;.  &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;

  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2014/02/17/mongodb-university-m101p/&quot;&gt;MongoDB University: M101P&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on February 17, 2014.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Elixir: Primeras impresiones]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2013/09/23/erlang-primeras-impresiones/"/>
  <id>http://milmazz.uno/article/2013/09/23/erlang-primeras-impresiones</id>
  <updated>2014-02-07T00:00:00-00:00</updated>
  <published>2013-09-23T17:22:20-05:00</published>
  
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;h3 id=&quot;elixir-primeras-impresiones&quot;&gt;Elixir: Primeras impresiones&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;NOTA: Este artículo originalmente lo escribí para &lt;a href=&quot;http://lacaraoscura.com/post/59947279510/elixir-primeras-impresiones&quot;&gt;La Cara Oscura del Software&lt;/a&gt;, un &lt;em&gt;blog&lt;/em&gt; colectivo dedicado a desarrollo de software.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://media.tumblr.com/67428e8bd65cf2747d8a1b19f67bb3b6/tumblr_inline_msfr2tm7tU1qz4rgp.png&quot; alt=&quot;&quot; /&gt; Durante el segundo &lt;em&gt;hangout&lt;/em&gt; de &lt;a href=&quot;http://www.twitter.com/Rubyve&quot;&gt;@rubyVE&lt;/a&gt; escuché a &lt;a href=&quot;http://www.twitter.com/edgar&quot;&gt;@edgar&lt;/a&gt; comentar sobre &lt;a href=&quot;http://www.elixir-lang.org&quot;&gt;Elixir&lt;/a&gt; y en verdad me llamó la atención lo que indicaba, siempre me inquieta conocer al menos un poco sobre otros lenguajes de programación, siempre terminas aprendiendo algo, una buena lección es seguro, sobre todo por aquello de la filosofía del programador pragmático y la necesidad de invertir regularmente en tu &lt;a href=&quot;http://pragmatictips.com/8&quot;&gt;portafolio de conocimientos&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ahora bien, después de leer un artículo de &lt;a href=&quot;http://joearms.github.io/2013/05/31/a-week-with-elixir.html&quot;&gt;Joe Armstrong&lt;/a&gt;, padre de &lt;a href=&quot;http://www.erlang.org/&quot;&gt;Erlang&lt;/a&gt;, en donde afirmaba que tras una semana de haber usado Elixir estaba &lt;strong&gt;completamente entusiasmado&lt;/strong&gt; por lo visto. Con esto era claro que se estaba presentando para mi una gran oportunidad para retomar la programación funcional con &lt;a href=&quot;http://www.elixir-lang.org&quot;&gt;Elixir&lt;/a&gt;, inicié con &lt;a href=&quot;http://www.haskell.org&quot;&gt;Haskell&lt;/a&gt; en la Universidad en la materia de &lt;em&gt;Compiladores&lt;/em&gt; y la verdad es que no lo he vuelto a tocar. &lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.twitter.com/josevalim&quot;&gt;José Valim&lt;/a&gt; es un brasileño, parte del equipo &lt;a href=&quot;http://rubyonrails.org/core&quot;&gt;core committer&lt;/a&gt; de Rails. Después de sufrir &lt;a href=&quot;http://en.wikipedia.org/wiki/Repetitive_strain_injury&quot;&gt;RSI&lt;/a&gt;, en su afán por encontrar qué hacer en su reposo se puso a leer el libro: &lt;a href=&quot;http://pragprog.com/book/btlang/seven-languages-in-seven-weeks&quot;&gt;Seven Languages in Seven Weeks: A Pragmatic Guide to Learning Programming Languages&lt;/a&gt; y allí conoció &lt;a href=&quot;http://www.erlang.org/&quot;&gt;Erlang&lt;/a&gt; y su EVM (&lt;em&gt;Erlang Virtual Machine&lt;/em&gt;), cierto tiempo después creo este nuevo lenguaje llamado Elixir, en donde uno de sus mayores activos es la EVM, tanto es así que de hecho no existe un costo de conversión al invocar Erlang desde Elixir y viceversa. Todo esto es seguramente es la respuesta de Valim a las limitantes físicas actuales en los procesadores o lo que se conoce también como: “&lt;a href=&quot;http://www.gotw.ca/publications/concurrency-ddj.htm&quot;&gt;se nos acabó el almuerzo gratis&lt;/a&gt;”, sobre todo ahora con recientes anuncios de &lt;a href=&quot;http://www.parallella.org/&quot;&gt;Parallella&lt;/a&gt; y de Intel con los procesadores &lt;a href=&quot;http://www.drdobbs.com/parallel/intels-50-core-xeon-phi-the-new-era-of-i/240105810&quot;&gt;Xeon Phi&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A pesar de la horrible sintaxis de Erlang, o al menos después de leer a Damien Katz, autor original de &lt;a href=&quot;http://couchdb.apache.org/&quot;&gt;CouchDB&lt;/a&gt; en &lt;a href=&quot;http://damienkatz.net/2008/03/what_sucks_abou.html&quot;&gt;What Sucks About Erlang&lt;/a&gt; y a Tony Arcieri, autor de &lt;a href=&quot;http://reia-lang.org/&quot;&gt;Reia&lt;/a&gt; (otro lenguaje basado en BEAM), en su artículo &lt;a href=&quot;http://www.unlimitednovelty.com/2011/07/trouble-with-erlang-or-erlang-is-ghetto.html&quot;&gt;The Trouble with Erlang (or Erlang is a ghetto)&lt;/a&gt; es fácil concluir que la sintaxis no es la más amenas de todas. Sin embargo, las inmensas habilidades que brinda Erlang para establecer sistemas concurrentes (distribuidos, tolerantes a fallas y &lt;em&gt;code swapping&lt;/em&gt;) ha permitido llegar a mantener hasta &lt;a href=&quot;http://blog.whatsapp.com/index.php/2012/01/1-million-is-so-2011/&quot;&gt;2 millones de conexiones TCP en un solo nodo&lt;/a&gt;. Es por ello que compañías como &lt;a href=&quot;http://www.whatsapp.com/&quot;&gt;Whatsapp&lt;/a&gt;, &lt;a href=&quot;http://www.facebook.com/&quot;&gt;Facebook&lt;/a&gt;, &lt;a href=&quot;http://www.amazon.com/&quot;&gt;Amazon&lt;/a&gt;, &lt;a href=&quot;http://www.ericsson.com/‎&quot;&gt;Ericsson&lt;/a&gt;, &lt;a href=&quot;http://www.motorola.com/‎&quot;&gt;Motorola&lt;/a&gt;, &lt;a href=&quot;http://basho.com/erlang-at-basho-five-years-later/&quot;&gt;Basho&lt;/a&gt; (&lt;a href=&quot;http://basho.com/riak/&quot;&gt;Riak&lt;/a&gt;) y &lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt; por mencionar algunas están usando Erlang para desarrollar sus sistemas.&lt;/p&gt;

&lt;p&gt;Rápidamente quisiera compartirles mi felicidad por haber iniciado a explorar este lenguaje. Para iniciar tu proyecto tienes un magnífico utilitario llamado &lt;a href=&quot;http://elixir-lang.org/getting_started/mix/1.html&quot;&gt;mix&lt;/a&gt; (inspirado en &lt;a href=&quot;https://github.com/technomancy/leiningen&quot;&gt;Leiningen&lt;/a&gt; de Clojure). Mix también permite manejar las tareas más comunes como administración de dependencias de tu proyecto, compilación, ejecución de pruebas, despliegue (pronto), entre otras. Incluso puedes programar nuevas tareas, simplemente asombroso, en fin, vamos a jugar:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ mix help
mix                 # Run the default task (current: mix run)
mix archive         # Archive this project into a .ez file
mix clean           # Clean generated application files
mix cmd             # Executes the given command
mix compile         # Compile source files
mix deps            # List dependencies and their status
mix deps.clean      # Remove the given dependencies&#39; files
mix deps.compile    # Compile dependencies
mix deps.get        # Get all out of date dependencies
mix deps.unlock     # Unlock the given dependencies
mix deps.update     # Update the given dependencies
mix do              # Executes the tasks separated by comma
mix escriptize      # Generates an escript for the project
mix help            # Print help information for tasks
mix local           # List local tasks
mix local.install   # Install a task or an archive locally
mix local.rebar     # Install rebar locally
mix local.uninstall # Uninstall local tasks or archives
mix new             # Creates a new Elixir project
mix run             # Run the given file or expression
mix test            # Run a project&#39;s tests
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Procedamos con la creación de un nuevo proyecto:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ mix new demo
* creating README.md
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/demo.ex
* creating test
* creating test/test_helper.exs
* creating test/demo_test.exs

Your mix project was created with success.
You can use mix to compile it, test it, and more:

    cd demo
    mix compile
    mix test

Run `mix help` for more information.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;La estructura del proyecto creado por &lt;code&gt;mix&lt;/code&gt; es como sigue:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ cd demo
$ tree
.
|-- README.md
|-- lib
|   `-- demo.ex
|-- mix.exs
`-- test
    |-- demo_test.exs
    `-- test_helper.exs

2 directories, 5 files
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;En &lt;code&gt;mix.exs&lt;/code&gt; encontramos la configuración del proyecto así como sus dependencias en caso de aplicar, en &lt;code&gt;lib/demo.ex&lt;/code&gt; ubicamos la definición del módulo que nos ayudará a estructurar posteriormente nuestro código, en &lt;code&gt;test/test_demo.exs&lt;/code&gt; encontramos un esqueleto base para los casos de pruebas asociadas al modulo. Finalmente en &lt;code&gt;test/test_helper.exs&lt;/code&gt; radica inicialmente el arranque del &lt;em&gt;framework&lt;/em&gt; &lt;a href=&quot;http://elixir-lang.org/getting_started/ex_unit/1.html&quot;&gt;ExUnit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Creemos un par de pruebas sencillas primero:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ vim test/demo_test.exs
defmodule DemoTest do
  use ExUnit.Case

  test &quot;factorial base case&quot; do
    assert Demo.factorial(0) == 1
  end

  test &quot;factorial general case&quot; do
    assert Demo.factorial(10) == 3628800
  end

  test &quot;map factorial&quot; do
    assert Demo.map([6, 8, 10], fn(n) -&amp;gt; Demo.factorial(n) end) == [720, 40320, 3628800]
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Evidentemente al hacer “mix test” todas las pruebas fallaran, vamos a comenzar a subsanar eso:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ vim lib/demo.ex
defmodule Demo do

def factorial(0) do
    1
end

def factorial(n) when n &amp;gt; 0 do
    n * factorial(n - 1)
end

end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;En el par de bloques de código mostrado previamente se cubren los dos casos posibles del factorial.&lt;/p&gt;

&lt;p&gt;Volvamos a correr las pruebas:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ mix test       
..

  1) test map factorial (DemoTest)
     ** (UndefinedFunctionError) undefined function: Demo.map/2
     stacktrace:
       Demo.map([6, 8, 10], #Function&amp;lt;0.60019678 in DemoTest.test map factorial/1&amp;gt;)
       test/demo_test.exs:13: DemoTest.&quot;test map factorial&quot;/1



Finished in 0.04 seconds (0.04s on load, 0.00s on tests)
3 tests, 1 failures
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;De las 3 pruebas programadas hemos superado dos, nada mal, continuemos, volvamos a editar nuestro módulo:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ vim lib/demo.ex
defmodule Demo do
    def factorial(0) do
        1
    end

    def factorial(n) when n &amp;gt; 0 do
        n * factorial(n - 1)
    end

    def map([], _func) do
        []
    end

    def map([head|tail], func) do
        [func.(head) | map(tail, func)]
    end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;En esta última versión se ha agregado la función &lt;code&gt;map&lt;/code&gt;, básicamente esta función recibe una colección de datos y una función que se aplicará sobre cada uno de los elementos de la colección, para nuestros efectos prácticos la función que será pasada a &lt;code&gt;map&lt;/code&gt; será el factorial.&lt;/p&gt;

&lt;p&gt;Como nota adicional, los bloques de código vistos en el ejemplo anterior prefiero expresarlos de manera sucinta así, cuestión que también es posible en Elixir:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ vim lib/demo.ex
defmodule Demo do
    @moduledoc &quot;&quot;&quot;
    Demo module documentation, Python *docstrings* inspired.
    &quot;&quot;&quot;
    def factorial(0), do: 1

    def factorial(n) when n &amp;gt; 0, do: n * factorial(n - 1)

    def map([], _func), do: []

    def map([head|tail], func), do: [func.(head) | map(tail, func)]
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Acá se pueden apreciar conceptos como &lt;em&gt;pattern matching&lt;/em&gt;, &lt;em&gt;guard clauses&lt;/em&gt;, manejo de listas y &lt;em&gt;docstrings&lt;/em&gt; (inspirado en Python). Atención, los &lt;em&gt;docstrings&lt;/em&gt; soportan &lt;a href=&quot;http://daringfireball.net/projects/markdown/&quot;&gt;MarkDown&lt;/a&gt;, junto a &lt;a href=&quot;https://github.com/elixir-lang/ex_doc&quot;&gt;ExDoc&lt;/a&gt; es posible producir sitios estáticos que extraen los &lt;em&gt;docstrings&lt;/em&gt; a partir del código fuente.&lt;/p&gt;

&lt;p&gt;Comprobemos los casos desde la consola interactiva &lt;code&gt;iex&lt;/code&gt; antes de pasar de nuevo al caso automatizado:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ iex lib/demo.ex
Erlang R16B01 (erts-5.10.2) [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Interactive Elixir (0.10.2-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)&amp;gt; import Demo
nil
iex(2)&amp;gt; h(Demo)
# Demo

Demo module documentation, Python *docstrings* inspired.

iex(3)&amp;gt; Demo.factorial(10)
3628800
iex(4)&amp;gt; Demo.map([6, 8, 10], Demo.factorial(&amp;amp;1))
[720, 40320, 3628800]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Lo previo es una &lt;em&gt;consola interactiva&lt;/em&gt;, vimos la documentación e hicimos unas pruebas manuales.&lt;/p&gt;

&lt;p&gt;Seguro notaron que al final del ejemplo previo, al hacer el &lt;code&gt;map&lt;/code&gt; he cambiado la forma en la que invoco a la función anónima la cual originalmente fue definida en las pruebas como &lt;code&gt;fn(n) -&amp;gt; Demo.factorial(n) end&lt;/code&gt;, solamente he recurrido a un modo que permite Elixir y otros lenguajes funcionales para expresar este tipo de funciones de manera concisa, se le conoce como &lt;em&gt;Partials&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Ahora corramos las pruebas automatizadas de nuevo:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ mix test
Compiled lib/demo.ex
Generated demo.app
...

Finished in 0.04 seconds (0.04s on load, 0.00s on tests)
3 tests, 0 failures
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Con eso hemos pasado los casos de pruebas.&lt;/p&gt;

&lt;p&gt;En este caso particular, prefiero que las pruebas sean autocontenidas en el módulo, además, no recurrimos a &lt;em&gt;fixtures&lt;/em&gt; ni nada por el estilo, así que vamos a cambiar el código para que soporte &lt;em&gt;doctest&lt;/em&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ vim lib/demo.ex
defmodule Demo do
    @moduledoc &quot;&quot;&quot;
    Demo module documentation, Python *docstrings* inspired.
    &quot;&quot;&quot;

    @doc &quot;&quot;&quot;
    Some examples

    iex&amp;gt; Demo.factorial(0)
    1

    iex&amp;gt; Demo.factorial(10)
    3628800

    iex&amp;gt; Demo.map([6, 8, 10], Demo.factorial(&amp;amp;1))
    [720, 40320, 3628800]
    &quot;&quot;&quot;
    def factorial(0), do: 1

    def factorial(n) when n &amp;gt; 0, do: n * factorial(n - 1)

    def map([], _func), do: []

    def map([head|tail], func), do: [func.(head) | map(tail, func)]
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Dado lo anterior ya no es necesario tener las pruebas aparte, por lo que reduzco:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ vim test/demo_test.exs
defmodule DemoTest do
  use ExUnit.Case
  doctest Demo
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Comprobamos la equivalencia:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ mix test              
...

Finished in 0.06 seconds (0.06s on load, 0.00s on tests)
3 tests, 0 failures
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Simplemente hermoso, cabe resaltar que lo mencionado es solo rascar un poco la superficie de Elixir :-)&lt;/p&gt;

&lt;p&gt;Ah, por cierto, ya para finalizar, José Valim está apuntando el desarrollo de Elixir y &lt;a href=&quot;https://github.com/elixir-lang/dynamo&quot;&gt;Dynamo&lt;/a&gt; (framework) a la Web, lo ha dejado claro, por eso he visto que algunos programadores Rails están “echándole un ojo” a Elixir, al menos eso es lo que concluyo de los &lt;a href=&quot;https://github.com/elixir-lang/elixir/issues/1663&quot;&gt;elixir-issues&lt;/a&gt; en Github, el reciente screencast de &lt;a href=&quot;https://peepcode.com/products/elixir&quot;&gt;Peepcode&lt;/a&gt; (vale la pena comprarlo) y los libros que se avecinan de &lt;a href=&quot;http://pragprog.com/book/elixir/programming-elixir&quot;&gt;Dave Thomas&lt;/a&gt; y &lt;a href=&quot;http://shop.oreilly.com/product/0636920030584.do&quot;&gt;Simon St. Laurent&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Quizá en una nueva oportunidad hablemos de Macros, pase de mensajes entre procesos, Protocolos (inspirados en &lt;a href=&quot;http://clojure.org/protocols&quot;&gt;Clojure protocols&lt;/a&gt;), Reducers (inspirados también en &lt;a href=&quot;http://clojure.com/blog/2012/05/08/reducers-a-library-and-model-for-collection-processing.html&quot;&gt;Clojure Reducers&lt;/a&gt;), HashDict, el hermoso y *nix like operador pipeline (&lt;code&gt;|&amp;gt;&lt;/code&gt;), mejorar nuestra implementación de la función &lt;code&gt;map&lt;/code&gt; para que haga los cálculos de manera concurrente, entre otros.&lt;/p&gt;

&lt;p&gt;Espero hayan disfrutado la lectura, que este artículo sirva de abreboca y les anime a probar Elixir.&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2013/09/23/erlang-primeras-impresiones/&quot;&gt;Elixir: Primeras impresiones&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on September 23, 2013.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Python: ¿Cómo puedo comenzar a programar?]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2012/11/12/python-como-puedo-comenzar/"/>
  <id>http://milmazz.uno/article/2012/11/12/python-como-puedo-comenzar</id>
  <published>2012-11-12T02:30:07-06:00</published>
  <updated>2012-11-12T02:30:07-06:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p&gt;Hay mucha documentación sobre
el lenguaje de programación Python, tal vez eso haya quedado claro en el
&lt;a href=&quot;/archivos/2012/11/09/python-el-comienzo&quot; title=&quot;Python: El Comienzo&quot;&gt;artículo anterior&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Sin embargo, se puede iniciar revisando el &lt;a href=&quot;http://docs.python.org/3/tutorial/&quot;&gt;tutorial oficial de Python&lt;/a&gt;. El libro &lt;a href=&quot;http://learnpythonthehardway.org/&quot; title=&quot;Learn Python The Hard Way&quot;&gt;Learn Python the Hard Way&lt;/a&gt;
(LPTHW) de &lt;a href=&quot;http://zedshaw.com/&quot; title=&quot;Zed Shaw&quot;&gt;Zed Shaw&lt;/a&gt; está muy bueno
para comenzar, tiene una buena cantidad de ejercicios.
&lt;a href=&quot;http://learnpythonthehardway.org/&quot; title=&quot;Learn Python The Hard Way&quot;&gt;LPTHW&lt;/a&gt;
no es el único libro de fácil o libre acceso, también podrá disponer de
los siguientes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://getpython3.com/diveintopython3/&quot;&gt;Dive Into Python 3&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.greenteapress.com/thinkpython/thinkCSpy/thinkCSpy.pdf&quot;&gt;How to think like a computer scientist&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.swaroopch.com/notes/Python/&quot;&gt;A Bite Of Python&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.greenteapress.com/thinkpython/thinkpython.pdf&quot;&gt;Think Python&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google también ofrece muy buen material a través de &lt;a href=&quot;http://code.google.com/edu/languages/google-python-class/&quot;&gt;Google Python Class&lt;/a&gt;, no
olvide revisarlo. Otros recursos muy interesantes son los del &lt;em&gt;MIT Open
Courseware&lt;/em&gt; &lt;a href=&quot;http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-189-a-gentle-introduction-to-programming-using-python-january-iap-2008/&quot;&gt;A Gentle Introduction to Programming Using Python&lt;/a&gt; y &lt;a href=&quot;http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html&quot;&gt;Code Like a Pythonista: Idiomatic Python&lt;/a&gt;.
Lamentablemente libros en español recuerdo pocos, el último que llegue a
revisar fue &lt;a href=&quot;http://mundogeek.net/tutorial-python/&quot;&gt;Python para todos&lt;/a&gt;,
también alcance a revisar un libro de la &lt;a href=&quot;http://www.uji.es/&quot;&gt;Universidad de Jaume&lt;/a&gt;, muestran una grata &lt;a href=&quot;http://www.uji.es/bin/publ/edicions/ippython.pdf&quot;&gt;introducción a la programación con Python&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Considero que la mejor manera de engancharte con un lenguaje es trabajar
en un proyecto personal o practicando, si no se te ocurre nada por el
momento, puedes comenzar vía &lt;a href=&quot;http://www.learnstreet.com/lang/python/&quot;&gt;Learn Street&lt;/a&gt;, &lt;a href=&quot;http://www.codecademy.com/&quot;&gt;Code Academy&lt;/a&gt;, &lt;a href=&quot;http://www.pythonchallenge.com/&quot;&gt;Python Challenge&lt;/a&gt;, &lt;a href=&quot;http://projecteuler.net/&quot;&gt;Project Euler&lt;/a&gt;. Si quieres ver la ejecución paso a
paso de tus programas en Python no dejes de revisar &lt;a href=&quot;http://www.pythontutor.com/&quot;&gt;Python Tutor&lt;/a&gt;.
El gran dilema: ¿Python 2 o 3? Si tienes un objetivo con Python y la
versión 3 puede cubrirlo perfecto, pero ten claras las reglas del juego
antes de escoger la versión &lt;code&gt;2.x&lt;/code&gt; o &lt;code&gt;3.x&lt;/code&gt;, &lt;a href=&quot;http://wiki.python.org/moin/Python2orPython3&quot;&gt;este artículo&lt;/a&gt; te puede aclarar
el panorama.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2012/11/12/python-como-puedo-comenzar/&quot;&gt;Python: ¿Cómo puedo comenzar a programar?&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on November 12, 2012.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Python: El comienzo]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2012/11/09/python-el-comienzo/"/>
  <id>http://milmazz.uno/article/2012/11/09/python-el-comienzo</id>
  <updated>2014-02-07T00:00:00-00:00</updated>
  <published>2012-11-09T16:22:20-06:00</published>
  
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;h3 id=&quot;qu-es-python&quot;&gt;¿Qué es Python?&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Lenguaje de programación orientado a objetos, interactivo e
interpretado.&lt;/li&gt;
  &lt;li&gt;Estructuras de datos alto nivel, dinámicamente tipado.&lt;/li&gt;
  &lt;li&gt;Aumenta la productividad de desarrollo en comparación con otros
lenguajes estáticamente tipados.&lt;/li&gt;
  &lt;li&gt;Multiplataforma:
    &lt;ul&gt;
      &lt;li&gt;El interprete &lt;strong&gt;CPython&lt;/strong&gt; puede ejecutarse nativamente en
muchas plataformas (esto incluye Windows, OS X, GNU/Linux, entre
&lt;a href=&quot;http://www.python.org/download/other/&quot;&gt;otras&lt;/a&gt;).&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://www.jython.org/&quot;&gt;Jython&lt;/a&gt; corre dentro de la &lt;em&gt;Java
Virtual Machine&lt;/em&gt;.&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://ironpython.codeplex.com/&quot;&gt;IronPython&lt;/a&gt; está orientado a
plataformas &lt;strong&gt;.NET&lt;/strong&gt; y &lt;strong&gt;Mono&lt;/strong&gt;.&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://pypy.org/&quot;&gt;PyPy&lt;/a&gt; es una implementación enfocada en el
&lt;a href=&quot;http://speed.pypy.org/&quot;&gt;rendimiento&lt;/a&gt; con un compilador &lt;em&gt;Just In
Time&lt;/em&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://www.stackless.com/&quot;&gt;Stackless&lt;/a&gt; es una rama de CPython
con soporte a &lt;em&gt;microthreads&lt;/em&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;http://www.python.org&quot;&gt;Python&lt;/a&gt; es un lenguaje dinámicamente tipado,
esto quiere decir que el tipo de cada variable se conoce en tiempo de ejecución, a su vez,
&lt;a href=&quot;http://www.python.org&quot;&gt;Python&lt;/a&gt; es un lenguaje fuertemente tipado, lo anterior implica que si usted posee una
variable de tipo entero no puede tratarla como una cadena de texto a menos que
usted realice la conversión de manera explícita previamente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CPython&lt;/strong&gt; es la primera implementación del lenguaje
&lt;a href=&quot;http://www.python.org&quot;&gt;Python&lt;/a&gt;, también es la de mayor uso a nivel mundial, dicha implementación esta escrita en el
lenguaje de programación &lt;strong&gt;C&lt;/strong&gt;. Esta es la implementación que todos conocemos al
referirnos al lenguaje de programación &lt;a href=&quot;http://www.python.org&quot;&gt;Python&lt;/a&gt;,
pero en aquellos escenarios en donde es necesario distinguirla de otras implementaciones alternativas
se le conoce como &lt;strong&gt;CPython&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;por-qu-usar-python&quot;&gt;¿Por qué usar Python?&lt;/h3&gt;

&lt;p&gt;En uno de los primeros libros que leí sobre Python, &lt;a href=&quot;http://rmi.net/~lutz/&quot;&gt;Mark
Lutz&lt;/a&gt; resumía estos puntos de la siguiente
manera:&lt;/p&gt;

&lt;h4 id=&quot;calidad-del-software&quot;&gt;Calidad del software&lt;/h4&gt;

&lt;p&gt;Para muchos, Python se enfoca en la legibilidad, coherencia, y la calidad del software en general. Al ofrecer un diseño legible, el proceso de mantenimiento se hace más fácil y rápido.&lt;/p&gt;

&lt;h4 id=&quot;incremento-en-la-productividad-del-desarrollo&quot;&gt;Incremento en la productividad del desarrollo&lt;/h4&gt;

&lt;p&gt;El código en Python regularmente es de 1/3 a 1/5 el tamaño de un código equivalente escrito en C++ o Java. Esto quiere decir que el desarrollador tendrá menos que escribir, menos que depurar, y menos que mantener después de todo. Además, los programas en Python pueden ejecutarse inmediatamente, sin tener que recurrir a los largos y tediosos pasos de compilación y enlazado.&lt;/p&gt;

&lt;h4 id=&quot;portabilidad&quot;&gt;Portabilidad&lt;/h4&gt;

&lt;p&gt;La mayoría de los programas en Python se pueden ejecutar indistintamente en la mayoría de las plataformas. Por otra parte, &lt;a href=&quot;http://www.python.org&quot;&gt;Python&lt;/a&gt; le ofrece múltiples opciones para desarrollar interfaces gráficas de usuario portables, entre ellas contamos con: TkInter, wxPython, PyGTK, PyQT, WxWidgets. Además, cuenta con módulos de accesos a base de datos, sistemas Web, entre otros.&lt;/p&gt;

&lt;h4 id=&quot;integracin-de-componentes&quot;&gt;Integración de componentes&lt;/h4&gt;

&lt;p&gt;Los scripts en Python fácilmente pueden comunicarse con otras partes de una aplicación, usando una variedad de mecanismos para la integración. Actualmente, Python puede invocar librerías en C y C++, puede ser llamado desde programas en C y C++, puede integrarse con componentes en Java, puede comunicarse sobre Corba y .NET, puede interactuar en la red con interfaces como SOAP, protocolo estándar que define cómo dos objetos en diferentes procesos puede comunicarse por medio del intercambio de datos en XML, REST y XML-RPC.&lt;/p&gt;

&lt;h4 id=&quot;diversin&quot;&gt;Diversión&lt;/h4&gt;

&lt;p&gt;Ya que Python es tan fácil de usar y le brinda un gran conjunto de herramientas, puede hacer el acto de programar una tarea muy placentera.&lt;/p&gt;

&lt;h3 id=&quot;qu-es-el-zen-de-python&quot;&gt;¿Qué es el Zen de Python?&lt;/h3&gt;

&lt;p&gt;A través de &lt;em&gt;Zen de Python&lt;/em&gt; puede conocer los principios del diseño y la
filosofía detrás del lenguaje de programación Python. También resulta
útil para comprender y utilizar el lenguaje.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;lineno&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;  &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;this&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;2&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;The&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Zen&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Python&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;por&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Tim&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Peters&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Obtendrá por respuesta algo como:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Hermoso es mejor que Feo.
Explícito es mejor que Implícito.
Simple es mejor que Complejo.
Complejo es mejor que Complicado.
Lineal es mejor que Cruzado.
Escaso es mejor que Denso.
Poder leer el código, cuenta.
Los Casos Especiales no son tan especiales como para romper reglas.
Lo Práctico le gana a Lo Puro.
Los Errores no deben pasar desapercibidos.
A menos de que Explícitamente se silencien.
En la ambigüedad, rehusa el Adivinar.
Sólo debería haber una, y preferiblemente Una, manera
obvia de hacer las cosas.
Aunque esa manera no se obvia al principio, a menos que seas (Dutch).
Ahora es mejor que Nunca.
A pesar de que Nunca es mejor que Ahora Mismo.
Si la implementación es difícil de explicar, es probable
que sea una mala idea.
Si la implementación es fácil de explicar, es probable
que sea una buena idea.
Namespaces son una Gran idea — Hagamos mas de esas.
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;qu-tipos-de-aplicaciones-puedo-desarrollar-en-python&quot;&gt;¿Qué tipos de aplicaciones puedo desarrollar en Python?&lt;/h3&gt;

&lt;p&gt;Python es un lenguaje multipropósito, basta darle una revisión al
&lt;a href=&quot;http://pypi.python.org/pypi&quot;&gt;Python Package Index&lt;/a&gt; para ver una muestra
de las aplicaciones desarrolladas con este hermoso lenguaje.&lt;/p&gt;

&lt;p&gt;Sin embargo, podemos ubicar el dominio de las aplicaciones en Python en:&lt;/p&gt;

&lt;h4 id=&quot;herramientas-y-utilidades-para-la-administracin-de-sistemas&quot;&gt;Herramientas y utilidades para la administración de sistemas&lt;/h4&gt;

&lt;p&gt;Python provee interfaces para servicios de Sistemas Operativos, desde un programa escrito en Python podemos buscar ficheros y árboles de directorios, cargar otros programas, realizar procesamiento paralelo, entre otras cosas muy interesantes.&lt;/p&gt;

&lt;h4 id=&quot;gui-interfaz-grfica-de-usuario&quot;&gt;GUI (Interfaz gráfica de usuario)&lt;/h4&gt;

&lt;p&gt;Python viene con una interfaz estándar orientada por objetos llamada &lt;a href=&quot;http://wiki.python.org/moin/TkInter&quot;&gt;TkInter&lt;/a&gt;, la cual permite a los programas escritos en Python implementar GUIs con una interfaz nativa del Sistema Operativo. Además, pueden encontrarse implementaciones más atractivas como: &lt;a href=&quot;http://www.wxpython.org/&quot;&gt;wxWidgets&lt;/a&gt;, &lt;a href=&quot;http://www.pygtk.org/&quot;&gt;GTK+&lt;/a&gt;, Qt (&lt;a href=&quot;http://www.riverbankcomputing.co.uk/software/pyqt/intro&quot;&gt;pyqt&lt;/a&gt; o &lt;a href=&quot;http://www.pyside.org/&quot;&gt;pyside&lt;/a&gt;), entre otras.&lt;/p&gt;

&lt;h4 id=&quot;internet&quot;&gt;Internet&lt;/h4&gt;

&lt;p&gt;Python viene con módulos estándar para Internet que permiten a los programas realizar una gran variedad de tareas en redes, tanto en el modo servidor como cliente. Los &lt;em&gt;scripts&lt;/em&gt; en Python pueden comunicarse sobre sockets; transferir ficheros vía FTP; procesar ficheros XML, JSON, también permite establecer comunicaciones sobre XML-RPC, SOAP, telnet, [hermosas APIs para la interacción con &lt;a href=&quot;http://docs.python-requests.org/en/latest/&quot; title=&quot;Requests: HTTP for Humans&quot;&gt;HTTP&lt;/a&gt; y &lt;a href=&quot;http://docs.python.org/2/library/internet&quot;&gt;más&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En el ámbito Web se pueden encontrar variadas opciones, desde &lt;a href=&quot;http://wiki.python.org/moin/CgiScripts&quot;&gt;CGI básicos&lt;/a&gt;, pasando por &lt;a href=&quot;http://www.plone.org/&quot;&gt;avanzados manejadores de contenido&lt;/a&gt; hasta &lt;em&gt;frameworks&lt;/em&gt; de desarrollo como &lt;a href=&quot;http://www.djangoproject.com/&quot;&gt;Django&lt;/a&gt;, &lt;a href=&quot;http://flask.pocoo.org/&quot;&gt;Flask&lt;/a&gt; y &lt;em&gt;microframeworks&lt;/em&gt; como &lt;a href=&quot;http://bottlepy.org/&quot;&gt;Bottle&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&quot;bases-de-datos&quot;&gt;Bases de Datos&lt;/h4&gt;

&lt;p&gt;Python ofrece módulos para interactuar con la mayoría de las bases
de datos relacionales, existen interfaces en Python: PostgreSQL,
MySQL, Sybase, Oracle, Informix, ODBC, y más. También ofrece un &lt;a href=&quot;http://www.python.org/dev/peps/pep-0249/&quot;&gt;API
estándar para la interacción con Bases de
Datos&lt;/a&gt;. Es claro entonces
poder observar &lt;a href=&quot;http://wiki.python.org/moin/HigherLevelDatabaseProgramming&quot;&gt;proyectos que brindan una interacción de alto nivel con bases de datos&lt;/a&gt;
como los ORM &lt;a href=&quot;http://www.sqlalchemy.org/&quot;&gt;SQLAlchemy&lt;/a&gt; o
&lt;a href=&quot;http://web2py.com/books/default/chapter/29/06&quot;&gt;DAL&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;También hay cabida para el mundo NoSQL en Python, donde hay soporte
para: Cassandra, Riak, MongoDB, CouchDB y Redis por mencionar solo
algunas.&lt;/p&gt;

&lt;h4 id=&quot;juegos-imgenes-ai-xml&quot;&gt;Juegos, Imágenes, AI, XML&lt;/h4&gt;

&lt;p&gt;Se pueden realizar fácilmente gráficos y programación de juegos en
Python con la librería &lt;a href=&quot;http://pygame.org/&quot;&gt;pygame&lt;/a&gt;,
&lt;a href=&quot;http://www.alobbs.com/pykyra&quot;&gt;PyKyra&lt;/a&gt;,
&lt;a href=&quot;http://www.pyglet.org/&quot;&gt;pyglet&lt;/a&gt;, &lt;a href=&quot;http://cocos2d.org/&quot;&gt;cocos2d&lt;/a&gt; y
&lt;a href=&quot;http://wiki.python.org/moin/PythonGames&quot;&gt;más&lt;/a&gt;, incluso puedes
participar en el concurso &lt;a href=&quot;http://www.pyweek.org/&quot;&gt;PyWeek&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;También se puede incluir en el largo listado el procesamiento de
imágenes con el paquete PIL y otros. Programación de Inteligencia
Artificial con simuladores de redes neuronales y Sistemas Expertos,
análisis de ficheros XML con el paquete de bibliotecas xml. Python
soporta a traves de extensiones Programación numérica avanzada,
NumPy/SciPy vuelve a Python en una sofisticada herramienta de fácil
uso para la &lt;a href=&quot;http://wiki.python.org/moin/NumericAndScientific&quot;&gt;programación numérica y
científica&lt;/a&gt;. De
manera adicional, Python puede soportar animaciones,&lt;a href=&quot;http://matplotlib.org/&quot;&gt;visualización 2D&lt;/a&gt; y
&lt;a href=&quot;http://www.vrplumber.com/py3d.py&quot;&gt;3D&lt;/a&gt;, &lt;a href=&quot;http://www.onlamp.com/pub/a/python/2002/10/17/biopython.html&quot;&gt;Biología
Molecular&lt;/a&gt;,
cálculo estadístico (RPy) y más.&lt;/p&gt;

&lt;h3 id=&quot;quienes-usan-python&quot;&gt;¿Quienes usan Python?&lt;/h3&gt;

&lt;p&gt;La lista incluye a grandes en el mundo de tecnología, un excelente
resumen se puede encontrar en el listado de &lt;a href=&quot;http://python.org/about/success&quot;&gt;casos de
éxito&lt;/a&gt; y
&lt;a href=&quot;http://python.org/about/quotes&quot;&gt;citas&lt;/a&gt; del portal oficial de Python.&lt;/p&gt;

&lt;h1 id=&quot;cmo-puedo-mantenerme-al-da&quot;&gt;¿Cómo puedo mantenerme al día?&lt;/h1&gt;

&lt;p&gt;Son muchas las fuentes de información sobre Python, algunas interesantes
son las siguientes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.python.org&quot;&gt;Sitio oficial de Python&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://mail.python.org&quot;&gt;Lista de discusión de Python&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://planet.python.org/&quot;&gt;Planet Python&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.python.org/doc/faq&quot;&gt;Preguntas de uso frecuente acerca de
Python&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.python.org/doc/tut&quot;&gt;Tutorial oficial de Python&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Newsletters: &lt;a href=&quot;http://pycoders.com/&quot;&gt;Pycoder’s Weekly&lt;/a&gt;, &lt;a href=&quot;http://www.pythonweekly.com/&quot;&gt;Python
Weekly&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En el siguiente artículo de esta serie espero poder listar algunos
recursos que pueden ser de ayuda a los principiantes en este fabuloso
mundo de la programación con Python.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2012/11/09/python-el-comienzo/&quot;&gt;Python: El comienzo&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on November 09, 2012.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Fortaleciendo nuestras contraseñas]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2011/12/30/fortaleciendo-nuestras-contrasenas/"/>
  <id>http://milmazz.uno/article/2011/12/30/fortaleciendo-nuestras-contrasenas</id>
  <published>2011-12-30T20:53:55-06:00</published>
  <updated>2011-12-30T20:53:55-06:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p&gt;Si una de las promesas que tiene para este cierre de año es fortalecer las contraseñas en sus equipos personales, cambiarlas mensualmente y no repetir la misma contraseña en al menos doce cambios. En este artículo se le explicará como hacerlo sin tener que invertir una uva en ello, todo esto gracias al paquete &lt;code&gt;libpam-cracklib&lt;/code&gt; en Debian, el procedimiento mostrado debe aplicarse a otras distribuciones derivadas de Debian.&lt;/p&gt;

&lt;p&gt;Pareciese lógico que algunas de las mejores prácticas para el fortalecimiento de las contraseñas son las siguientes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Cambiar las contraseñas periódicamente.&lt;/li&gt;
  &lt;li&gt;Establecer una longitud mínima en las contraseñas.&lt;/li&gt;
  &lt;li&gt;Establecer &lt;strong&gt;buenas&lt;/strong&gt; reglas para las nuevas contraseñas, es decir, mezcla entre letras mayúsculas, minúsculas, dígitos y caracteres alfanuméricos.&lt;/li&gt;
  &lt;li&gt;Mantener un histórico de las contraseñas usadas previamente, de ese modo, alentamos a los usuarios establecer nuevas contraseñas.&lt;/li&gt;
  &lt;li&gt;Indicarle a los usuarios que es &lt;strong&gt;inaudito&lt;/strong&gt; que se anoten las contraseñas en un &lt;em&gt;post-it&lt;/em&gt; y se dejen pegadas en los monitores o incluso en las gavetas de sus archivadores.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El primer paso es instalar el paquete &lt;code&gt;libpam-cracklib&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# apt-get install libpam-cracklib
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A partir de la versión 1.0.1-6 de PAM se recomienda manejar la configuración vía &lt;code&gt;pam-auth-update&lt;/code&gt;. Por lo tanto, por favor tome un momento y lea la sección 8 del manual del comando &lt;code&gt;pam-auth-update&lt;/code&gt; para aclarar su uso y ventajas.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ man 8 pam-auth-update
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ahora establezca una configuración similar a la siguiente, vamos primero con la exigencia en la fortaleza de las contraseñas, para ello edite o cree el fichero &lt;code&gt;/usr/share/pam-configs/cracklib&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Name: Cracklib password strength checking
Default: yes
Priority: 1024
Conflicts: unix-zany
Password-Type: Primary
Password:
	requisite	pam_cracklib.so retry=3 minlen=8 difok=3
Password-Initial:
	requisite	pam_cracklib.so retry=3 minlen=8 difok=3
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;NOTA:&lt;/strong&gt; Le recomiendo leer la sección 8 del manual de &lt;code&gt;pam_cracklib&lt;/code&gt; para encontrar un mayor numero de opciones de configuración. Esto es solo un ejemplo.&lt;/p&gt;

&lt;p&gt;En versiones previas el modulo &lt;code&gt;pam_cracklib&lt;/code&gt; hacia uso del fichero &lt;code&gt;/etc/security/opasswd&lt;/code&gt; para conocer si la propuesta de cambio de contraseña no había sido utilizada previamente. Dicha funcionalidad ahora corresponde al nuevo modulo &lt;code&gt;pam_pwhistory&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Definamos el funcionamiento de &lt;code&gt;pam_pwhistory&lt;/code&gt; a través del fichero &lt;code&gt;/usr/share/pam-configs/history&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Name: PAM module to remember last passwords
Default: yes
Priority: 1023
Password-Type: Primary
Password:
	requisite	pam_pwhistory.so use_authtok enforce_for_root remember=12 retry=3
Password-Initial:
	requisite	pam_pwhistory.so use_authtok enforce_for_root remember=12 retry=3
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;NOTA:&lt;/strong&gt; Para mayor detalle de las opciones puede revisar la sección 8 del manual de &lt;code&gt;pam_pwhistory&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Seguidamente proceda a actualizar la configuración de PAM vía &lt;code&gt;pam-auth-update&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/2011-12-31-fortaleciendo-nuestras-contrasenas/pantallazo-300x132.png&quot; alt=&quot;pam-auth-update&quot; title=&quot;pam-auth-update&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Una vez cubierta la fortaleza de las contraseñas nuevas y de evitar la reutilización de las ultimas 12, de acuerdo al ejemplo mostrado, resta cubrir la definición de los periodos de cambio de las contraseñas.&lt;/p&gt;

&lt;p&gt;Para futuros usuarios debemos ajustar ciertos valores en el fichero &lt;code&gt;/etc/login.defs&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#
# Password aging controls:
#
#       PASS_MAX_DAYS   Maximum number of days a password may be used.
#       PASS_MIN_DAYS   Minimum number of days allowed between password changes.
#       PASS_WARN_AGE   Number of days warning given before a password expires.
#
PASS_MAX_DAYS   30
PASS_MIN_DAYS   0
PASS_WARN_AGE   5
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Las reglas previas no aplicaran para los usuarios existentes, pero para este tipo de usuarios podremos hacer uso del comando &lt;code&gt;chage&lt;/code&gt; de la siguiente manera:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# chage -m 0 -M 30 -W 5 ${user}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Donde el valor de &lt;code&gt;${user}&lt;/code&gt; debe ser reemplazo por el &lt;em&gt;username&lt;/em&gt;.&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2011/12/30/fortaleciendo-nuestras-contrasenas/&quot;&gt;Fortaleciendo nuestras contraseñas&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on December 30, 2011.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[apt-get detrás de proxy con autenticación NTLM]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2011/12/29/apt-get-detras-de-proxy-con-autenticacion-ntlm/"/>
  <id>http://milmazz.uno/article/2011/12/29/apt-get-detras-de-proxy-con-autenticacion-ntlm</id>
  <published>2011-12-29T11:16:59-06:00</published>
  <updated>2011-12-29T11:16:59-06:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p&gt;Por motivos que no vienen al caso discutir en este artículo tuve que instalar Debian GNU/Linux detrás de un &lt;em&gt;proxy&lt;/em&gt; que aún utiliza NTLM como medio de autenticación, aunque NTLM ya no es recomendado por Microsoft desde hace años en pro de usar &lt;a href=&quot;http://web.mit.edu/kerberos/&quot;&gt;Kerberos&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Una vez instalada la distribución quería utilizar &lt;code&gt;apt-get&lt;/code&gt; para actualizarla e instalar nuevos paquetes, el resultado fue que &lt;code&gt;apt-get&lt;/code&gt; no funciona de manera transparente detrás de un &lt;em&gt;proxy&lt;/em&gt; con autenticación NTLM. La solución fue colocar un &lt;em&gt;proxy interno&lt;/em&gt; que esté atento a peticiones en un puerto particular en el &lt;em&gt;host&lt;/em&gt;, el &lt;em&gt;proxy interno&lt;/em&gt; se encargará de proveer de manera correcta las credenciales al &lt;em&gt;proxy externo&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;La solución descrita previamente resulta sencilla al utilizar &lt;code&gt;cntlm&lt;/code&gt;. En principio será necesario instalarlo vía &lt;code&gt;dpkg&lt;/code&gt;, posteriormente deberá editar los campos apropiados en el fichero &lt;code&gt;/etc/cntlm.conf&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Username&lt;/li&gt;
  &lt;li&gt;Domain&lt;/li&gt;
  &lt;li&gt;Password&lt;/li&gt;
  &lt;li&gt;Proxy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seguidamente reinicie el servicio:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# /etc/init.d/cntlm restart
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ahora solo resta configurar &lt;code&gt;apt-get&lt;/code&gt; para que utilice nuestro &lt;em&gt;proxy interno&lt;/em&gt;, para ello edite el fichero &lt;em&gt;/etc/apt.conf.d/02proxy&lt;/em&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Acquire::http::Proxy &quot;http://127.0.0.1:3128&quot;;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;NOTA:&lt;/strong&gt; Se asume que el puerto de escucha de &lt;code&gt;cntlm&lt;/code&gt; es el &lt;em&gt;3128&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Ahora puede hacer uso correcto de &lt;code&gt;apt-get&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# apt-get update
# apt-get upgrade
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;NOTA FINAL:&lt;/strong&gt; Es evidente que cualquier comando o herramienta que necesite autenticarse contra el &lt;em&gt;proxy externo&lt;/em&gt; deberá configurarlo para que utilice el &lt;em&gt;proxy interno&lt;/em&gt;, lo explicado en este artículo no solo aplica para el comando &lt;code&gt;apt-get&lt;/code&gt;.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2011/12/29/apt-get-detras-de-proxy-con-autenticacion-ntlm/&quot;&gt;apt-get detrás de proxy con autenticación NTLM&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on December 29, 2011.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Enviando correos con Perl]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2011/09/21/enviando-correos-con-perl/"/>
  <id>http://milmazz.uno/article/2011/09/21/enviando-correos-con-perl</id>
  <published>2011-09-21T12:28:02-05:00</published>
  <updated>2011-09-21T12:28:02-05:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p&gt;Regularmente los administradores de sistemas requieren notificar, vía correo electrónico, a sus usuarios de ciertos cambios o nuevos servicios disponibles. La experiencia me ha indicado que el usuario aprecia más un correo personalizado que uno general. Sin embargo, lograr lo primero de manera manual es bastante tedioso e ineficaz. Por lo tanto, es lógico pensar en la posibilidad de automatizar el proceso de envío de correos electrónicos personalizados, en este artículo, explicaré una de las tantas maneras de lograrlo haciendo uso del lenguaje de programación &lt;a href=&quot;http://www.perl.org/&quot;&gt;Perl&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En &lt;a href=&quot;http://www.cpan.org/&quot;&gt;CPAN&lt;/a&gt; podrá encontrar muchas alternativas, recuerde el principio &lt;a href=&quot;http://en.wikipedia.org/wiki/There_is_more_than_one_way_to_do_it&quot;&gt;TIMTOWTDI&lt;/a&gt;. Sin embargo, la opción que más me atrajo fue &lt;code&gt;MIME::Lite:TT&lt;/code&gt;, básicamente este módulo en Perl es un &lt;em&gt;wrapper&lt;/em&gt; de &lt;code&gt;MIME::Lite&lt;/code&gt; que le permite el uso de plantillas, vía &lt;code&gt;Template::Toolkit&lt;/code&gt;, para el cuerpo del mensaje del correo electrónico. También puede encontrar &lt;code&gt;MIME::Lite::TT::HTML&lt;/code&gt; que le permitirá enviar correos tanto en texto sin formato (&lt;code&gt;MIME::Lite::TT&lt;/code&gt;) como en formato HTML. Sin embargo, estoy en contra de enviar correos en formato HTML, lo dejo a su criterio.&lt;/p&gt;

&lt;p&gt;Una de las ventajas de utilizar &lt;code&gt;Template::Toolkit&lt;/code&gt; para el cuerpo del mensaje es separar en &lt;em&gt;capas&lt;/em&gt; nuestra &lt;em&gt;script&lt;/em&gt;, si se observa desde una versión muy simplificada del patrón &lt;a href=&quot;http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller&quot;&gt;MVC&lt;/a&gt;, el control de la lógica de programación reside en el &lt;em&gt;script&lt;/em&gt; en Perl, la plantilla basada en &lt;em&gt;Template Toolkit&lt;/em&gt; ofrecería la vista de los datos, de modo tal que podríamos garantizar que la presentación está separada de los datos, los cuales pueden encontrarse desde una base de datos o un simple fichero CSV. Otra ventaja evidente es el posible reuso de componentes posteriormente.&lt;/p&gt;

&lt;p&gt;Un primer ejemplo del uso de &lt;code&gt;MIME::Lite:TT&lt;/code&gt; puede ser el siguiente:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-perl&quot; data-lang=&quot;perl&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/perl&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;warnings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;MIME::Lite::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INCLUDE_PATH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;/home/jdoe/example&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Milton&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Mazzarri&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;milmazz&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;sysadmin&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$msg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;MIME::Lite::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;From&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;jdoe@example.com&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;To&lt;/span&gt;          &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;milmazz@example.com&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Charset&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;utf8&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;TimeZone&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;America/Caracas&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Subject&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Example&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Template&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;example.txt.tt&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;TmplOptions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;TmplParams&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Y el cuerpo del correo electrónico, lo que en realidad es una plantilla basada en &lt;code&gt;Template::Toolkit&lt;/code&gt;, vendría definido en el fichero &lt;code&gt;example.txt.tt&lt;/code&gt; de la siguiente manera:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-perl&quot; data-lang=&quot;perl&quot;&gt;&lt;span class=&quot;n&quot;&gt;Hola&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;last_name&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;first_name&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;].&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;Tu&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nombre&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;de&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;usuario&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;es&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;].&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;Un&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;saludo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;feliz&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;í&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;Su&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;querido&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BOFH&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;de&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;siempre&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;En el &lt;em&gt;script&lt;/em&gt; en Perl mostrado previamente podemos percatarnos que los datos del destinario se encuentran inmersos en la lógica. Por lo tanto, el siguiente paso sería desacoplar esta parte de la siguiente manera:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-perl&quot; data-lang=&quot;perl&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/perl&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;warnings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;MIME::Lite::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Class::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CSV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INCLUDE_PATH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;/home/jdoe/example&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Lectura del fichero CSV&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$csv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Class::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CSV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;example.csv&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;qw/last_name first_name username email/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;csv_xs_options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$csv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nv&quot;&gt;$params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$msg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;MIME::Lite::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;From&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;jdoe@example.com&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;To&lt;/span&gt;          &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Charset&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;utf8&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;TimeZone&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;America/Caracas&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Subject&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Example&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Template&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;example.txt.tt&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;TmplOptions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;TmplParams&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;nv&quot;&gt;$msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ahora los datos de los destinarios los extraemos de un fichero en formato CSV, en este ejemplo, el fichero en formato CSV lo hemos denominado &lt;code&gt;example.csv&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Cabe aclarar que &lt;code&gt;$msg-&amp;gt;send()&lt;/code&gt; realiza el envío por medio de &lt;code&gt;Net::SMTP&lt;/code&gt; y podrá usar las opciones que se describen en dicho módulo. Sin embargo, si necesita establecer una conexión SSL con el servidor SMTP es oportuno recurrir a &lt;code&gt;Net::SMTP::SSL&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-perl&quot; data-lang=&quot;perl&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/perl&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;warnings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;MIME::Lite::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Net::SMTP::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SSL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Class::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CSV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;jdoe@example.com&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;mail.example.com&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;jdoe&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$pass&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;example&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INCLUDE_PATH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;/home/jdoe/example&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Lectura del fichero CSV&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$csv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Class::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CSV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;example.csv&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;qw/last_name first_name username email/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;csv_xs_options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$csv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nv&quot;&gt;$params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$msg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;MIME::Lite::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;From&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;To&lt;/span&gt;          &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Charset&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;utf8&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;TimeZone&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;America/Caracas&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Subject&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Example&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Template&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;example.txt.tt&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;TmplOptions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;TmplParams&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$smtp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Net::SMTP::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SSL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;465&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;die&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;No pude conectarme&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$smtp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$pass&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;die&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;No pude autenticarme:&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$smtp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$smtp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;                 &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;die&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Error:&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$smtp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$smtp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;        &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;die&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Error:&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$smtp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$smtp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;                      &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;die&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Error:&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$smtp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$smtp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datasend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;as_string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;die&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Error:&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$smtp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$smtp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dataend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;                   &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;die&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Error:&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$smtp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$smtp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;quit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;                      &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;die&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Error:&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$smtp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note en este último ejemplo que la representación en cadena de caracteres del cuerpo del correo electrónico viene dado por &lt;code&gt;$msg-&amp;gt;as_string&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Para finalizar, es importante mencionar que también podrá adjuntar ficheros de cualquier tipo a sus correos electrónicos, solo debe prestar especial atención en el tipo MIME de los ficheros que adjunta, es decir, si enviará un fichero adjunto PDF debe utilizar el tipo &lt;code&gt;application/pdf&lt;/code&gt;, si envía una imagen en el formato GIF, debe usar el tipo &lt;code&gt;image/gif&lt;/code&gt;. El método a seguir para adjuntar uno o más ficheros lo dejo para su investigación ;)&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2011/09/21/enviando-correos-con-perl/&quot;&gt;Enviando correos con Perl&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on September 21, 2011.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Construyendo de manera efectiva y rápida imágenes ISO de Debian con jigdo]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2010/12/02/construyendo-de-manera-efectiva-y-rapida-imagenes-iso-de-debian-con-jigdo/"/>
  <id>http://milmazz.uno/article/2010/12/02/construyendo-de-manera-efectiva-y-rapida-imagenes-iso-de-debian-con-jigdo</id>
  <published>2010-12-02T08:04:39-06:00</published>
  <updated>2010-12-02T08:04:39-06:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p&gt;Si usted desea el conjunto de CD o DVD para instalar Debian, tiene muchas posibilidades, desde la &lt;a href=&quot;http://www.debian.org/CD/vendors/&quot;&gt;compra&lt;/a&gt; de los mismos, muchos de los vendedores contribuyen con Debian. También puede realizar descargas vía &lt;a href=&quot;http://www.debian.org/CD/http-ftp/&quot;&gt;HTTP/FTP&lt;/a&gt;, vía &lt;a href=&quot;http://www.debian.org/CD/torrent-cd/&quot;&gt;torrent&lt;/a&gt; o &lt;a href=&quot;http://www.debian.org/CD/mirroring/rsync-mirrors&quot;&gt;rsync&lt;/a&gt;. Pero en este artículo se discutirá sobre un método para construir las imágenes ISO de Debian de manera eficiente, sobretodo si cuenta con un repositorio local de paquetes, dicho método se conoce de manera abreviada como &lt;a href=&quot;http://atterer.org/jigdo/&quot;&gt;jigdo&lt;/a&gt; o &lt;em&gt;Jigsaw Download&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Las ventajas que ofrece &lt;a href=&quot;http://www.debian.org/CD/jigdo-cd/&quot;&gt;jigdo&lt;/a&gt; están bien claras en el portal de Debian, cito:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;¿Por qué jigdo es mejor que una descarga directa?&lt;/p&gt;

  &lt;p&gt;¡Porque es más rápido! Por varias razones, hay muchas menos réplicas para imágenes de CDs que para el archivo «normal» de Debian. Consecuentemente, si descarga desde una réplica de imágenes de CD, esa réplica no sólo estará más lejos de su ubicación, además estará sobrecargada, especialmente justo después de una publicación.&lt;/p&gt;

  &lt;p&gt;Además, algunos tipos de imágenes no están disponibles para descarga completa como .iso porque no hay suficiente espacio en nuestros servidores para alojarlas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Considero que la pregunta pertinente ahora es: &lt;em&gt;¿Cómo descargo la imagen con jigdo?&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;En primer lugar, instalamos el paquete &lt;code&gt;jigdo-file&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# aptitude install jigdo-file
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Mi objetivo era generar los 2 primeros CD para Debian Lenny, para la fecha de publicación de este artículo la versión más reciente es la &lt;a href=&quot;http://www.debian.org/News/2010/20101127&quot;&gt;5.0.7&lt;/a&gt;. La lista de imágenes oficiales para &lt;em&gt;jigdo&lt;/em&gt; las puede encontrar &lt;a href=&quot;http://www.debian.org/CD/jigdo-cd/#which&quot;&gt;acá&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;milmazz@manaslu /tmp $ cat files
http://cdimage.debian.org/debian-cd/5.0.7/i386/jigdo-cd/debian-507-i386-CD-1.jigdo
http://cdimage.debian.org/debian-cd/5.0.7/i386/jigdo-cd/debian-507-i386-CD-1.template
http://cdimage.debian.org/debian-cd/5.0.7/i386/jigdo-cd/debian-507-i386-CD-2.jigdo
http://cdimage.debian.org/debian-cd/5.0.7/i386/jigdo-cd/debian-507-i386-CD-2.template
milmazz@manaslu /tmp $ wget -c -i files
--2010-12-02 12:39:52--  http://cdimage.debian.org/debian-cd/5.0.7/i386/jigdo-cd/debian-507-i386-CD-1.jigdo
Resolving cdimage.debian.org... 130.239.18.163, 130.239.18.173, 2001:6b0:e:2018::173, ...
Connecting to cdimage.debian.org|130.239.18.163|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 31737 (31K) [text/plain]
Saving to: `debian-507-i386-CD-1.jigdo&#39;

100%[===================================================================================================================&amp;gt;] 31.737      44,7K/s   in 0,7s

...

FINISHED --2010-12-02 12:50:15--
Downloaded: 4 files, 27M in 10m 21s (44,7 KB/s)
milmazz@manaslu /tmp $ ls
debian-507-i386-CD-1.jigdo  debian-507-i386-CD-1.template  debian-507-i386-CD-2.jigdo  debian-507-i386-CD-2.template files
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Una vez descargados los ficheros necesarios, es hora de ejecutar el comando &lt;code&gt;jigdo-lite&lt;/code&gt;, siga las instrucciones del asistente.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;milmazz@manaslu ~ $ jigdo-lite debian-507-i386-CD-2.jigdo

Jigsaw Download &quot;lite&quot;
Copyright (C) 2001-2005  |  jigdo@
Richard Atterer          |  atterer.net
Loading settings from `/home/milmazz/.jigdo-lite&#39;

-----------------------------------------------------------------
Images offered by `debian-507-i386-CD-2.jigdo&#39;:
1: &#39;Debian GNU/Linux 5.0.7 &quot;Lenny&quot; - Official i386 CD Binary-2 20101127-16:55 (20101127)&#39; (debian-507-i386-CD-2.iso)

Further information about `debian-507-i386-CD-2.iso&#39;:
Generated on Sat, 27 Nov 2010 17:02:14 +0000

-----------------------------------------------------------------
If you already have a previous version of the CD you are
downloading, jigdo can re-use files on the old CD that are also
present in the new image, and you do not need to download them
again. Mount the old CD ROM and enter the path it is mounted under
(e.g. `/mnt/cdrom&#39;).
Alternatively, just press enter if you want to start downloading
the remaining files.
Files to scan:
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;El comando despliega información acerca de la imagen ISO que generará, en este caso particular, &lt;code&gt;debian-507-i386-CD-2.iso&lt;/code&gt;. Además, &lt;code&gt;jigdo-lite&lt;/code&gt; puede reutilizar ficheros que se encuentren en CD viejos y así no tener que descargarlos de nuevo. Sin embargo, este no era mi caso así que presione la tecla ENTER.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;-----------------------------------------------------------------
The jigdo file refers to files stored on Debian mirrors. Please
choose a Debian mirror as follows: Either enter a complete URL
pointing to a mirror (in the form
`ftp://ftp.debian.org/debian/&#39;), or enter any regular expression
for searching through the list of mirrors: Try a two-letter
country code such as `de&#39;, or a country name like `United
States&#39;, or a server name like `sunsite&#39;.
Debian mirror [http://debian.example.com/debian/]:
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;En esta fase &lt;code&gt;jigdo-lite&lt;/code&gt; solicita la dirección &lt;strong&gt;URL completa&lt;/strong&gt; de un repositorio, aproveche la oportunidad de utilizar su repositorio local si es que cuenta con uno. Luego de presionar la tecla ENTER es tiempo de relajarse y esperar que &lt;code&gt;jigdo&lt;/code&gt; descargue todos y cada uno de los ficheros que componen la imagen ISO.&lt;/p&gt;

&lt;p&gt;Luego de descargar los paquetes y realizar las operaciones necesarias para la construcción de la imagen ISO &lt;code&gt;jigdo&lt;/code&gt; le informará los resultados.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;FINISHED --2010-12-01 14:43:50--
Downloaded: 6 files, 2,5M in 1,8s (1,39 MB/s)
Found 6 of the 6 files required by the template
Successfully created `debian-507-i386-CD-2.iso&#39;

-----------------------------------------------------------------
Finished!
The fact that you got this far is a strong indication that `debian-507-i386-CD-2.iso&#39;
was generated correctly. I will perform an additional, final check,
which you can interrupt safely with Ctrl-C if you do not want to wait.

OK: Checksums match, image is good!
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ahora bien, haciendo uso de un repositorio local, es bueno preguntarse en cuanto tiempo aproximadamente puedes construir tu imagen ISO, en mi caso el tiempo de construcción de &lt;code&gt;debian-507-i386-CD-2.iso&lt;/code&gt; fue de:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;milmazz@manaslu ~ $ time jigdo-lite debian-507-i386-CD-2.jigdo

...

real	8m35.704s
user	0m13.101s
sys	0m16.569s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nada mal, ¿no les parece?.&lt;/p&gt;

&lt;p&gt;Ahora bien, haciendo uso de un repositorio local, es bueno preguntarse en cuanto tiempo aproximadamente puedes construir tu imagen ISO, en mi caso el tiempo de construcción de &lt;code&gt;debian-507-i386-CD-2.iso&lt;/code&gt; fue de:&lt;/p&gt;

&lt;h2 id=&quot;referencias&quot;&gt;Referencias&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://atterer.org/jigdo&quot;&gt;jigdo - Jigsaw Download&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.debian.org/CD/jigdo-cd/&quot;&gt;Descargar imágenes de CD de Debian con jigdo&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://atterer.org/jigdo/debian-jigdo-mini-howto&quot;&gt;Debian Jigdo mini-HOWTO&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2010/12/02/construyendo-de-manera-efectiva-y-rapida-imagenes-iso-de-debian-con-jigdo/&quot;&gt;Construyendo de manera efectiva y rápida imágenes ISO de Debian con jigdo&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on December 02, 2010.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Generar reporte en formato CSV de tickets en Trac desde Perl]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2010/11/17/generar-reporte-en-formato-csv-de-tickets-en-trac-desde-perl/"/>
  <id>http://milmazz.uno/article/2010/11/17/generar-reporte-en-formato-csv-de-tickets-en-trac-desde-perl</id>
  <published>2010-11-17T11:12:06-06:00</published>
  <updated>2010-11-17T11:12:06-06:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p&gt;El día de hoy recibí una llamada telefónica de un compañero de labores en donde me solicitaba con cierta preocupación un “pequeño” reporte del estado de un listado de &lt;em&gt;tickets&lt;/em&gt; que recién me había enviado vía correo electrónico puesto que no contaba con conexión a la &lt;em&gt;intranet&lt;/em&gt;, al analizar un par de &lt;em&gt;tickets&lt;/em&gt; me dije que no iba a ser fácil realizar la consulta desde el asistente que brinda el mismo &lt;a href=&quot;http://trac.edgewall.com&quot;&gt;Trac&lt;/a&gt;. Así que inmediatamente puse las manos sobre un pequeño &lt;em&gt;script&lt;/em&gt; en Perl que hiciera el &lt;em&gt;trabajo sucio&lt;/em&gt; por mí.&lt;/p&gt;

&lt;p&gt;Es de hacer notar que total de tickets a revisar era el siguiente:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ wc -l tickets
126 tickets
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Tomando en cuenta el resultado previo, era &lt;strong&gt;inaceptable&lt;/strong&gt; hacer dicha labor de manera manual. Por lo tanto, confirmaba que realizar un &lt;em&gt;script&lt;/em&gt; era la vía correcta y a la final iba a ser más divertido.&lt;/p&gt;

&lt;p&gt;Tomando en cuenta que el formato de entrada era el siguiente:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#3460
#3493
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;El formato de la salida que esperaba era similar a la siguiente:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;3460,&quot;No expira la sesión...&quot;,closed,user
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Básicamente el formato implica el &lt;em&gt;id&lt;/em&gt;, &lt;em&gt;sumario&lt;/em&gt;, &lt;em&gt;estado&lt;/em&gt; y &lt;em&gt;responsable&lt;/em&gt; asociado al &lt;strong&gt;ticket&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://search.cpan.org/~jesse/Net-Trac-0.15/lib/Net/Trac.pm&quot;&gt;Net::Trac&lt;/a&gt; le ofrece una manera sencilla de interactuar con una instancia remota de Trac, desde el manejo de credenciales, consultas, revisión de &lt;em&gt;tickets&lt;/em&gt;, entre otros. A la vez, se hace uso del módulo &lt;a href=&quot;http://search.cpan.org/~djr/Class-CSV-1.03/CSV.pm&quot;&gt;Class::CSV&lt;/a&gt; el cual le ofrece análisis y escritura de documentos en formato CSV.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-perl&quot; data-lang=&quot;perl&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/perl &lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;warnings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Net::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Trac&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Class::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CSV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Estableciendo la conexion a la instancia remota de Trac&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$trac&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Net::Trac::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Connection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;http://trac.example.com/project&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;password&amp;#39;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Construccion del objecto CSV y definicion de opciones&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$csv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Class::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CSV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;qw/ticket sumario estado responsable/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;line_separator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;\r\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;csv_xs_options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Manejo de caracteres non-ASCII&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Nos aseguramos que el inicio de sesion haya sido exitoso&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$trac&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ensure_logged_in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ticket&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Net::Trac::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ticket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;connection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$trac&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Consultamos cada uno de los tickets indicados en el fichero de entrada&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;chomp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;m/^#\d+$/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;s/^#(\d+)$/$1/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$ticket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;nv&quot;&gt;$csv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;ticket&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ticket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;sumario&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ticket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;estado&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ticket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;responsable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ticket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;owner&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;[INFO] La linea no cumple el formato requerido: $line\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$csv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;No se pudieron asegurar las credenciales&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La manera de ejecutar el &lt;code&gt;script&lt;/code&gt; es la siguiente:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ perl trac_query.pl tickets
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;En donde &lt;code&gt;trac_query.pl&lt;/code&gt; es el nombre del &lt;em&gt;script&lt;/em&gt; y &lt;code&gt;tickets&lt;/code&gt; es el fichero de entrada.&lt;/p&gt;

&lt;p&gt;Debo aclarar que el &lt;em&gt;script&lt;/em&gt; carece de comentarios, &lt;em&gt;mea culpa&lt;/em&gt;. Además, el manejo de opciones vía linea de comandos es &lt;em&gt;inexistente&lt;/em&gt;, si desea mejorarlo puede hacer uso de &lt;a href=&quot;http://perldoc.perl.org/Getopt/Long.html&quot;&gt;Getopt::Long&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cualquier comentario, sugerencia o corrección es bienvenida.&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2010/11/17/generar-reporte-en-formato-csv-de-tickets-en-trac-desde-perl/&quot;&gt;Generar reporte en formato CSV de tickets en Trac desde Perl&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on November 17, 2010.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Instalando dependencias no-libres de JAVA en ambientes pbuilder]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2010/11/15/instalando-dependencias-no-libres-de-java-en-ambientes-pbuilder/"/>
  <id>http://milmazz.uno/article/2010/11/15/instalando-dependencias-no-libres-de-java-en-ambientes-pbuilder</id>
  <published>2010-11-15T11:14:37-06:00</published>
  <updated>2010-11-15T11:14:37-06:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p&gt;El día de hoy asumí la construcción de unos paquetes internos compatibles con &lt;a href=&quot;http://www.debian.org&quot;&gt;Debian&lt;/a&gt; 5.0 (a.k.a. Lenny) que anteriormente eran responsabilidad de ex-compañeros de labores. El paquete en cuestión posee una dependencia &lt;strong&gt;no-libre&lt;/strong&gt;, &lt;code&gt;sun-java6-jre&lt;/code&gt;. En este artículo se describirá como lograr adecuar su configuración de &lt;code&gt;pbuilder&lt;/code&gt; para la correcta construcción del paquete.&lt;/p&gt;

&lt;p&gt;Asumiendo que tiene un configuración similar a la siguiente:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ cat /etc/pbuilderrc
MIRRORSITE=http://example.com/debian
DEBEMAIL=&quot;Maintainer Name &amp;lt;mail@example.com&amp;gt;&quot;
DISTRIBUTION=lenny
DEBOOTSTRAP=&quot;cdebootstrap&quot;
COMPONENTS=&quot;main contrib non-free&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Para mayor información sobre estas opciones sírvase leer:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ man 5 pbuilderrc
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Mientras intenta compilar su paquete en el ambiente proporcionado por &lt;code&gt;pbuilder&lt;/code&gt; el proceso fallará ya que no se mostró la ventana para aceptar la licencia de JAVA. Podrá observar en el registro de la construcción del build un mensaje similar al siguiente:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Unpacking sun-java6-jre (from .../sun-java6-jre_6-20-0lenny1_all.deb) ...

sun-dlj-v1-1 license could not be presented
try &#39;dpkg-reconfigure debconf&#39; to select a frontend other than noninteractive

dpkg: error processing /var/cache/apt/archives/sun-java6-jre_6-20-0lenny1_all.deb (--unpack):
subprocess pre-installation script returned error exit status 2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Para evitar esto altere la configuración del fichero &lt;code&gt;pbuilderrc&lt;/code&gt; de la siguiente manera:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ cat /etc/pbuilderrc
MIRRORSITE=http://example.com/debian
DEBEMAIL=&quot;Maintainer Name &amp;lt;mail@example.com&amp;gt;&quot;
DISTRIBUTION=lenny
DEBOOTSTRAP=&quot;cdebootstrap&quot;
COMPONENTS=&quot;main contrib non-free&quot;
export DEBIAN_FRONTEND=&quot;readline&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Una vez alterada la configuración podrá interactuar con las opciones que le ofrece &lt;code&gt;debconf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ahora bien, si usted constantemente tiene que construir paquetes con dependencias &lt;strong&gt;no-libres&lt;/strong&gt; como las de JAVA, es probable que le interese lo que se menciona a continuación.&lt;/p&gt;

&lt;p&gt;Si lee detenidamente la página del manual de &lt;code&gt;pbuilder&lt;/code&gt; en su sección 8 podrá encontrar lo siguiente:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ man 8 pbuilder
...
--save-after-login
--save-after-exec
Save the chroot image after exiting from the chroot instead of deleting changes.  Effective for login and execute session.
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Por lo tanto, usaremos esta funcionalidad que ofrece &lt;code&gt;pbuilder&lt;/code&gt; para insertar valores por omisión en la base de datos de &lt;code&gt;debconf&lt;/code&gt; para que no se nos pregunte si deseamos aceptar la licencia de JAVA:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# pbuilder login --save-after-login
I: Building the build Environment
I: extracting base tarball [/var/cache/pbuilder/base.tgz]
I: creating local configuration
I: copying local configuration
I: mounting /proc filesystem
I: mounting /dev/pts filesystem
I: Mounting /var/cache/pbuilder/ccache
I: policy-rc.d already exists
I: Obtaining the cached apt archive contents
I: entering the shell
File extracted to: /var/cache/pbuilder/build//27657

pbuilder:/# cat &amp;gt; java-license &amp;lt;&amp;lt; EOF
&amp;gt; sun-java6-bin shared/accepted-sun-dlj-v1-1 boolean true
&amp;gt; sun-java6-jdk shared/accepted-sun-dlj-v1-1 boolean true
&amp;gt; sun-java6-jre shared/accepted-sun-dlj-v1-1 boolean true
&amp;gt; EOF
pbuilder:/# debconf-set-selections &amp;lt; java-license
pbuilder:/# exit
logout
I: Copying back the cached apt archive contents
I: Saving the results, modifications to this session will persist
I: unmounting /var/cache/pbuilder/ccache filesystem
I: unmounting dev/pts filesystem
I: unmounting proc filesystem
I: creating base tarball [/var/cache/pbuilder/base.tgz]
I: cleaning the build env
I: removing directory /var/cache/pbuilder/build//27657 and its subdirectories
&lt;/code&gt;&lt;/pre&gt;


  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2010/11/15/instalando-dependencias-no-libres-de-java-en-ambientes-pbuilder/&quot;&gt;Instalando dependencias no-libres de JAVA en ambientes pbuilder&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on November 15, 2010.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Presentaciones]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2010/11/12/presentaciones/"/>
  <id>http://milmazz.uno/article/2010/11/12/presentaciones</id>
  <published>2010-11-12T21:38:53-06:00</published>
  <updated>2010-11-12T21:38:53-06:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p&gt;Desde hace algunos meses he decidido recopilar y organizar algunas de las presentaciones que he dado hasta ahora en eventos de &lt;em&gt;Software Libre&lt;/em&gt;, Universidades y empresas privadas.&lt;/p&gt;

&lt;p&gt;El software que regularmente utilizo para realizar mis presentaciones es &lt;a href=&quot;http://latex-beamer.sourceforge.net/&quot;&gt;Beamer&lt;/a&gt;, una clase &lt;a href=&quot;http://www.latex-project.org/&quot;&gt;LaTeX&lt;/a&gt; que facilita enormente la producción de presentaciones de alta calidad, este software trabaja de la mano con &lt;code&gt;pdflatex&lt;/code&gt;, también con &lt;code&gt;dvips&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;La lista de presentaciones que he recopilado hasta la fecha son las siguientes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.slideshare.net/milmazz/pylint&quot;&gt;Análisis estático del código fuente en Python&lt;/a&gt;: Describe el concepto del análisis estático del código, se indica los pasos a seguir para la detección de errores mediante la herramienta &lt;em&gt;Pylint&lt;/em&gt;, se exponen sus funcionalidades, reportes y se muestran ejemplos para corregir los errores encontrados por la herramienta.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.slideshare.net/milmazz/desarrollo-colectivo-en-turpial&quot;&gt;Desarrollo colectivo en Turpial&lt;/a&gt;: Describe la visión del cliente para Twitter Turpial, sus funcionalidades actuales, el uso de herramientas como &lt;em&gt;Transifex&lt;/em&gt;, &lt;em&gt;PyBabel&lt;/em&gt;, &lt;em&gt;Distutils&lt;/em&gt;, &lt;em&gt;Sphinx&lt;/em&gt;, dichas herramientas facilitan y mejoran la calidad del software que se desarrolla.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.slideshare.net/milmazz/canaima-gnulinux&quot;&gt;Canaima GNU/Linux&lt;/a&gt;: Una introducción, se describe la historia, definición del proyecto Canaima, principales características, procesos para colaborar, enlaces de interés, entre otros.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.slideshare.net/milmazz/proyecto-maestro-virtual-novela-grfica-creada-con-el-motor-renpy&quot;&gt;Novela gráfica creada con el motor Ren’Py&lt;/a&gt;: Relata la experiencia del desarrollo de una novela gráfica para niños de 5to. grado de educación, de acuerdo a currículo impartido en las escuelas venezolanas.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.slideshare.net/milmazz/trac-3717222&quot;&gt;Trac&lt;/a&gt;: Herramientas libres para el apoyo en el proceso de desarrollo de software, se discute las características y funcionalidades que ofrece el software. Además del proceso de personalización por medio de complementos o plugins.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;GnuPG, GNU Privacy Guard&lt;/em&gt;: Importancia del cifrado de la información, diferencias entre llaves simétricas y asimétricas, criptografía, fiestas de firmado de llaves, beneficios. Instalación y suo práctico de GnuPG.&lt;/li&gt;
  &lt;li&gt;Uso de &lt;code&gt;dbconfig-common&lt;/code&gt;: Presentación que es parte de la serie mejores prácticas para el empaquetamiento de aplicaciones en Debian, se describe el uso de la herramienta y su respectiva integración con el asistente debhelper&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Conociendo el framework web Django&lt;/em&gt;: Introducción, historia, características, primeros pasos, instalación y demostración de desarrollo de una aplicación sencilla bajo este excelente framework basado en el lenguaje de Programación Python&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Las fuentes en LaTeX de las presentaciones, así como su licencia de uso y proceso de conversión al formato PDF se describe en el proyecto &lt;a href=&quot;https://github.com/milmazz/Presentations&quot;&gt;Presentations&lt;/a&gt; que he creado en &lt;a href=&quot;http://www.github.com/&quot;&gt;github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Agradezco enormemente cualquier comentario que pueda hacer respecto a los temas presentados puesto que en el próximo mes trataré de actualizar el contenido, así como incluir nuevas presentaciones. ¿Desearía poder conocer más sobre un tema en particular?, ¿cuál sería ese tema?.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota final&lt;/strong&gt;: Si encuentra algún &lt;strong&gt;error&lt;/strong&gt; por favor notificarlo vía &lt;a href=&quot;https://github.com/milmazz/Presentations/issues&quot;&gt;issues&lt;/a&gt; del proyecto &lt;a href=&quot;https://github.com/milmazz/Presentations&quot;&gt;Presentations&lt;/a&gt;.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2010/11/12/presentaciones/&quot;&gt;Presentaciones&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on November 12, 2010.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Mejoras en el comportamiento a la hora de eliminar un ForeignKey]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2010/11/09/mejoras-en-el-comportamiento-a-la-hora-de-eliminar-un-foreignkey/"/>
  <id>http://milmazz.uno/article/2010/11/09/mejoras-en-el-comportamiento-a-la-hora-de-eliminar-un-foreignkey</id>
  <published>2010-11-09T13:51:35-06:00</published>
  <updated>2010-11-09T13:51:35-06:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p&gt;&lt;img src=&quot;/images/2010-11-09-mejoras-en-el-comportamiento-a-la-hora-de-eliminar-un-foreignkey/djangove.png&quot; alt=&quot;Logo de Django &quot; /&gt; Cuando un objeto referenciado por una clave foránea (&lt;code&gt;ForeignKey&lt;/code&gt;) es eliminado, &lt;a href=&quot;http://www.djangoproject.com&quot;&gt;Django&lt;/a&gt; por omisión emula el comportamiento de la sentencia SQL &lt;code&gt;ON DELETE CASCADE&lt;/code&gt; y también se elimina el objeto que contiene el &lt;em&gt;ForeignKey&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A partir de la versión 1.3 de Django el comportamiento descrito en el párrafo anterior puede ser sobreescrito al especificar el argumento &lt;code&gt;on_delete&lt;/code&gt;. Por ejemplo, si usted permite que una clave foránea pueda ser &lt;em&gt;nula&lt;/em&gt; y usted desea que sea establecida a &lt;code&gt;NULL&lt;/code&gt; cuando un objeto referenciado sea eliminado:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ForeignKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blank&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;on_delete&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SET_NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Los posibles valores para el argumento &lt;code&gt;on_delete&lt;/code&gt; pueden encontrarse en django.db.models:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;CASCADE: Eliminación en cascada, el comportamiento por omisión.&lt;/li&gt;
  &lt;li&gt;PROTECT: Prevee la eliminación del objeto referenciado al lanzar una excepción del tipo: &lt;code&gt;django.db-IntegrityError&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;SET_NULL: Establece la clave foránea a &lt;code&gt;NULL&lt;/code&gt;, esto solo es posible si el argumento &lt;code&gt;null&lt;/code&gt; es &lt;code&gt;True&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;SET_DEFAULT: Establece la clave foránea a su valor por omisión, tenga en cuenta que un valor por omisión debe ser establecido.&lt;/li&gt;
  &lt;li&gt;SET(): Establece el valor del &lt;code&gt;ForeignKey&lt;/code&gt; indicado en &lt;code&gt;SET()&lt;/code&gt;, si una función es invocada, el resultado de dicha función será el valor establecido.&lt;/li&gt;
  &lt;li&gt;DO_NOTHING: No tomar acciones. Si el gestor de base de datos requiere integridad referencial, esto causará una excepción del tipo &lt;code&gt;IntegrityError&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A continuación un par de ejemplos de esta nueva funcionalidad:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c&quot;&gt;# models.py&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;nickname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__unicode__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nickname&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ForeignKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blank&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;on_delete&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SET_NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__unicode__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Nuestra sesión interactiva con el API sería similar a la siguiente:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ python manage.py shell
&lt;/code&gt;&lt;/pre&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ondelete.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Creamos el autor&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nickname&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;milmazz&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Guardamos el objeto en la base de datos al usar de manera explícita el método save()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Obtenemos el autor en base a su id&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;milmazz&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Creamos par de artículos&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;article1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Article 1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;article1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;article2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Article 2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;article2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;article&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; by &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Article&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;milmazz&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Article&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;milmazz&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Eliminamos el autor&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;article&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; by &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Article&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Article&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Un segundo ejemplo, ahora haciendo uso del valor &lt;code&gt;SET()&lt;/code&gt; en el argumento &lt;code&gt;on_delete&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c&quot;&gt;# models.py&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.contrib.auth.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_superuser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ForeignKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;on_delete&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_superuser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__unicode__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Nuestra sesión interactiva con el API sería similar a la siguiente:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ python manage.py shell
&lt;/code&gt;&lt;/pre&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ondelete.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.contrib.auth.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;milmazz&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Creamos un nuevo usuario&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;milton&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Guardamos el objeto en la base de datos, &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# de manera explícita al invocar el método save()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Vista de los usuarios registrados en la base de datos&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;milmazz&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;milton&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Creamos par de artículos&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;article1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Article 1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;article1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;article2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Article 2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;article2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;article&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; by &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Article&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;milton&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Article&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;milton&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Eliminamos el usuario &amp;#39;milton&amp;#39;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;article&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; by &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Article&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;milmazz&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Article&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;milmazz&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2010/11/09/mejoras-en-el-comportamiento-a-la-hora-de-eliminar-un-foreignkey/&quot;&gt;Mejoras en el comportamiento a la hora de eliminar un ForeignKey&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on November 09, 2010.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Subversion: Notificaciones vía correo electrónico]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2010/04/24/subversion-notificaciones-via-correo-electronico/"/>
  <id>http://milmazz.uno/article/2010/04/24/subversion-notificaciones-via-correo-electronico</id>
  <published>2010-04-24T02:00:17-05:00</published>
  <updated>2010-04-24T02:00:17-05:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p&gt;Al darse un proceso de desarrollo colectivo es recomendable mantener una o varias listas de notificación acerca de los cambios hechos (&lt;em&gt;commits&lt;/em&gt;) en el repositorio de código fuente. Para este tipo de actividades es muy útil emplear &lt;a href=&quot;http://search.cpan.org/dist/SVN-Notify/&quot;&gt;&lt;code&gt;SVN::Notify&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SVN::Notify&lt;/code&gt; le ofrece un número considerable de opciones, a continuación resumo algunas de ellas:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Obtiene información relevante acerca de los cambios ocurridos en el repositorio &lt;em&gt;Subversion&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Realiza análisis sobre la información recolectada y brinda la posibilidad de reconocer distintos formatos vía filtros (Ej. Textile, Markdown, Trac).&lt;/li&gt;
  &lt;li&gt;Puede obtener la salida tanto en texto sin formato como en XHTML.&lt;/li&gt;
  &lt;li&gt;Le brinda la posibilidad de construir correos electrónicos en base a la salida obtenida.&lt;/li&gt;
  &lt;li&gt;Permite el envío de correo, ya sea por el comando &lt;code&gt;sendmail&lt;/code&gt; o SMTP.&lt;/li&gt;
  &lt;li&gt;Es posible indicar el método de autenticación ante el servidor SMTP.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para instalar el &lt;code&gt;SVN::Notify&lt;/code&gt; en sistemas &lt;a href=&quot;http://www.debian.org/&quot;&gt;Debian&lt;/a&gt; o derivados proceda de la siguiente manera:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# aptitude install libsvn-notify-perl&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Una vez instalado &lt;code&gt;SVN::Notify&lt;/code&gt;, es hora de definir su comportamiento. Aunque es posible hacerlo vía comando &lt;code&gt;svnnotify&lt;/code&gt; y empotrarlo en un &lt;em&gt;script&lt;/em&gt; escrito en &lt;em&gt;Bash&lt;/em&gt; he preferido hacerlo en &lt;a href=&quot;http://www.perl.org/&quot;&gt;Perl&lt;/a&gt;, es más natural y legible hacerlo de este modo.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-perl&quot; data-lang=&quot;perl&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/perl -w&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;SVN::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Notify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ARGV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$rev&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ARGV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%params&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;repos_path&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;revision&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$rev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;handler&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;HTML::ColorDiff&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;trac_url&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;http://trac.example.com/project&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;filters&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;Trac&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;with_diff&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;diff_switches&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;--no-diff-added --no-diff-deleted&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;subject_cx&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;strip_cx_regex&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;^trunk/&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;^branches/&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;^tags/&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;footer&lt;/span&gt;          &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Administrado por: BOFH &amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;max_sub_length&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;72&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;max_diff_length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt;            &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;noreply@example.com&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;subject_prefix&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;[project]&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;smtp&lt;/span&gt;            &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;smtp.example.com&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;smtp_user&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;example&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;smtp_pass&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;example&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$developers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;dev@example.com&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$admins&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;admins@example.com&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_regex_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$developers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;^trunk|^branches&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$admins&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;^tags|^trunk&amp;#39;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$notifier&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;SVN::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Notify&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$notifier&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prepare&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$notifier&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Si seguimos con el ejemplo indicado en el artículo anterior, &lt;a href=&quot;/archivos/2010/04/23/instalacion-basica-de-trac-y-subversion&quot;&gt;Instalación básica de Trac y Subversion&lt;/a&gt;, este &lt;em&gt;hook&lt;/em&gt; lo vamos a colocar en &lt;code&gt;/srv/svn/project/hooks/post-commit&lt;/code&gt;, dicho fichero deberá tener permisos de ejecución para el Servidor Web Apache.&lt;/p&gt;

&lt;p&gt;Con este sencillo &lt;em&gt;script&lt;/em&gt; en Perl se ha logrado lo siguiente:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;La salida se generará en XHTML.&lt;/li&gt;
  &lt;li&gt;Las diferencias de código serán resaltadas o coloreadas, esto es posible por el &lt;em&gt;handler&lt;/em&gt; &lt;code&gt;SVN::Notify::ColorDiff&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;El sistema de notificación está integrado a la sintaxis de enlaces de Trac. Por lo tanto, los &lt;em&gt;commits&lt;/em&gt; que posean este tipo de enlaces serán interpretados correctamente. Ej. &lt;code&gt;#123 changeset:234 r234&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/2010-04-24-subversion-notificaciones-via-correo-electronico/Pantallazo-271x300.png&quot; alt=&quot;Muestra del coloreado que ofrece SVN::Notify&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Aunque el código es sucinto y claro, trataré de resumir cada uno de los parámetros utilizados.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;repos_path&lt;/code&gt;: Define la ruta al repositorio &lt;em&gt;Subversion&lt;/em&gt;, la cual es obtenida a partir del primer argumento que pasa &lt;em&gt;Subversion&lt;/em&gt; al ejecutar el &lt;em&gt;hook&lt;/em&gt; &lt;code&gt;post-commit&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;revision&lt;/code&gt;: El número de la revisión del &lt;em&gt;commit&lt;/em&gt; actual. El número de la revisión se obtiene a partir del segundo argumento que pasa &lt;em&gt;Subversion&lt;/em&gt; al ejecutar el &lt;em&gt;hook&lt;/em&gt; &lt;code&gt;post-commit&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;handler&lt;/code&gt;: Especifica una subclase de &lt;code&gt;SVN::Notify&lt;/code&gt; que será utilizada para el manejo de las notificaciones. En el ejemplo se hace uso de &lt;code&gt;HTML::ColorDiff&lt;/code&gt;, el cual permite colorear o resaltar la sintaxis del comando &lt;code&gt;svnlook diff&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;trac_url&lt;/code&gt;: Este parámetro será usado para generar enlaces al Trac para los números de revisiones y similares en el mensaje de notificación.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;filters&lt;/code&gt;: Especifica la carga de más módulos que terminan de difinir la salida de la notificación. En el ejemplo, se hace uso del filtro &lt;code&gt;Trac&lt;/code&gt;, filtro que convierte el &lt;em&gt;log&lt;/em&gt; del &lt;em&gt;commit&lt;/em&gt; que cumple con el formato de Trac a HTML.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;with_diff&lt;/code&gt;: Valor lógico que especifica si será o no incluida la salida del comando &lt;code&gt;svnlook diff&lt;/code&gt; en la notificación vía correo electrónico.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;diff_switches&lt;/code&gt;: Permite el pase de opciones al comando &lt;code&gt;svnlook diff&lt;/code&gt;, en particular recomiendo utilizar &lt;code&gt;--no-diff-deleted&lt;/code&gt; y &lt;code&gt;--no-diff-added&lt;/code&gt; para evitar ver las diferencias para los archivos borrados y añadidos respectivamente.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;subject_cx&lt;/code&gt;: Valor lógico que indica si incluir o nó el contexto del &lt;em&gt;commit&lt;/em&gt; en la línea de asunto del correo electrónico de notificación.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;strip_cx_regex&lt;/code&gt;: Acá se indican las expresiones regulares que serán utilizadas para eliminar información del contexto de la línea de asunto del correo electrónico de notificación.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;footer&lt;/code&gt;: Agrega la cadena definida al final del cuerpo del correo electrónico de notificación&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;max_sub_length&lt;/code&gt;: Indica la longitud máxima de la línea de asunto del correo electrónico de notificación.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;max_diff_length&lt;/code&gt;: Máxima longitud del &lt;code&gt;diff&lt;/code&gt; (esté adjunto o en el cuerpo de la notificación).&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;from&lt;/code&gt;: Define la dirección de correo que será usada en la línea &lt;code&gt;From&lt;/code&gt;. Si no se especifica será utilizado el nombre de usuario definido en el &lt;em&gt;commit&lt;/em&gt;, esta información se obtiene vía el comando &lt;code&gt;svnlook&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;subject_prefix&lt;/code&gt;: Define una cadena de texto que será el prefijo de la línea correspondiente al asunto del correo electrónico de notificación.  &lt;/li&gt;
  &lt;li&gt;&lt;code&gt;smtp&lt;/code&gt;: Indica la dirección para el servidor SMTP que el cual se enviarán las notificaciones de correo electrónico. Si no se utiliza este parámetro, &lt;code&gt;SVN::Notify&lt;/code&gt; utilizará el comando &lt;code&gt;sendmail&lt;/code&gt; para el envío del mensaje.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;smtp_user&lt;/code&gt;: El nombre de usuario para la autenticación SMTP.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;smtp_pass&lt;/code&gt;: Contraseña para la autenticación SMTP&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;to_regex_map&lt;/code&gt;: Este parámetro contiene un &lt;em&gt;hash&lt;/em&gt; que mantiene referencias de direcciones de correo electrónico contra expresiones regulares. La idea es enviar las notificaciones si y solo si el nombre de uno o más directorios son afectados por un &lt;em&gt;commit&lt;/em&gt; y dicha ruta coincide con las expresiones regulares definidas. Este parámetro resulta muy útil en proyectos de desarrollo de software grandes y donde es posible disponer de varias listas de correo para informar a los desarrolladores interesados en secciones específicas.
Para mayor detalle de las opciones mencionadas previamente vea &lt;a href=&quot;http://search.cpan.org/dist/SVN-Notify/&quot;&gt;&lt;code&gt;SVN::Notify&lt;/code&gt;&lt;/a&gt;, acá también encontrará más opciones de configuración.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;observacin&quot;&gt;Observación&lt;/h2&gt;

&lt;p&gt;Hasta ahora he encontrado que el coloreado o resaltado de la sintaxis no funciona en algunos sistemas &lt;a href=&quot;http://es.wikipedia.org/wiki/Webmail&quot;&gt;Webmail&lt;/a&gt;, como por ejemplo &lt;a href=&quot;http://www.gmail.com&quot;&gt;Gmail&lt;/a&gt;, &lt;a href=&quot;http://squirrelmail.org/&quot;&gt;SquirrelMail&lt;/a&gt;. Sin embargo, en otros sistemas &lt;em&gt;Webmail&lt;/em&gt; como &lt;a href=&quot;http://roundcube.net/&quot;&gt;RoundCube&lt;/a&gt; si funciona. Este comportamiento se presenta porque en sistemas como &lt;em&gt;Gmail&lt;/em&gt; las hojas de estilos en cascada (CSS) &lt;a href=&quot;http://www.w3schools.com/css/css_howto.asp&quot;&gt;internas&lt;/a&gt; no son aplicadas en la interfaz. Es por ello que en estos casos es necesario recurrir a la definición de &lt;a href=&quot;http://www.w3schools.com/css/css_howto.asp&quot;&gt;estilos en línea&lt;/a&gt;.&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2010/04/24/subversion-notificaciones-via-correo-electronico/&quot;&gt;Subversion: Notificaciones vía correo electrónico&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on April 24, 2010.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Instalación básica de Trac y Subversion]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2010/04/22/instalacion-basica-de-trac-y-subversion/"/>
  <id>http://milmazz.uno/article/2010/04/22/instalacion-basica-de-trac-y-subversion</id>
  <published>2010-04-22T21:14:51-05:00</published>
  <updated>2010-04-22T21:14:51-05:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p&gt;En este artículo se pretenderá mostrarle el proceso de instalación de un ambiente de desarrollo que le permitirá hacerle seguimiento a su &lt;em&gt;proyecto personal&lt;/em&gt;, de igual manera se le indicará el modo en el cual puede comenzar a utilizar un &lt;em&gt;sistema de control de versiones&lt;/em&gt;. Todas las indicaciones mostradas en este documento han sido probadas en la distribución Debian GNU/Linux 5.0 (nombre código &lt;em&gt;Lenny&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;La herramienta de seguimiento o manejo del proyecto que se procederá a instalar es &lt;a href=&quot;http://trac.edgewall.com&quot;&gt;Trac&lt;/a&gt;, el sistema de control de versiones que se presentará será &lt;a href=&quot;http://subversion.tigris.org&quot;&gt;Subversion&lt;/a&gt;. Todo lo anterior se presentará vía &lt;em&gt;Web&lt;/em&gt; haciendo uso del servidor &lt;a href=&quot;http://httpd.apache.org&quot;&gt;Apache&lt;/a&gt;, de manera adicional se utilizará el servidor de bases de datos &lt;a href=&quot;http://www.postgresql.org&quot;&gt;PostgreSQL&lt;/a&gt; como &lt;em&gt;backend&lt;/em&gt; de Trac.&lt;/p&gt;

&lt;h2 id=&quot;dependencias&quot;&gt;Dependencias&lt;/h2&gt;

&lt;p&gt;En primer lugar proceda a instalar las siguientes dependencias.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# aptitude install apache2 \
libapache2-mod-python \
postgresql \
subversion \
python-psycopg2 \
libapache2-svn \
python-subversion \
trac
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;La versión de Trac que se encuentra en los archivos de Debian &lt;em&gt;Lenny&lt;/em&gt; es estable (&lt;strong&gt;0.11.1&lt;/strong&gt;). Sin embargo, si usted compara esta versión con lo publicado en el sitio oficial de Trac, podrá encontrar que existen nuevas versiones estables de mantenimiento que contienen correcciones a errores de programación y algunas nuevas funcionalidades de bajo impacto, para el momento de la redacción de este artículo se encuentra la versión &lt;a href=&quot;http://ftp.edgewall.com/pub/trac/Trac-0.11.7.tar.gz&quot;&gt;0.11.7&lt;/a&gt;. Es recomendable que utilice el paquete &lt;code&gt;trac&lt;/code&gt; desde el archivo &lt;a href=&quot;http://backports.org&quot;&gt;backports&lt;/a&gt; de Debian.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# aptitude -t lenny-backports install trac
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Si desea usar el paquete proveniente del archivo &lt;a href=&quot;http://backports.org&quot;&gt;backports&lt;/a&gt; le recomiendo leer las &lt;a href=&quot;http://backports.org/dokuwiki/doku.php?id=instructions&quot;&gt;instrucciones&lt;/a&gt; de uso de este repositorio de paquetes.&lt;/p&gt;

&lt;p&gt;Con el fin de mantener este artículo lo más sencillo y conciso posible se describirá la versión que viene por defecto con la distribución utilizada en este caso.&lt;/p&gt;

&lt;h3 id=&quot;versin-de-desarrollo-de-trac&quot;&gt;Versión de desarrollo de Trac&lt;/h3&gt;

&lt;p&gt;Si desea conocer algunas características interesantes que se han agregado a Trac en las nuevas versiones, o si su interés particular es
examinar las bondades que le ofrece Trac en su versión de desarrollo puede hacer uso del comando &lt;code&gt;pip&lt;/code&gt;, si no tiene instalado &lt;a href=&quot;http://pip.openplans.org/&quot;&gt;pip&lt;/a&gt; proceda como sigue:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# aptitude install python-setuptools
# easy_install pip
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Proceda a instalar la versión de desarrollo de Trac.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# pip install https://svn.edgewall.org/repos/trac/trunk
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;creacin-de-usuario-y-base-de-datos&quot;&gt;Creación de usuario y base de datos&lt;/h2&gt;

&lt;p&gt;Antes de proceder con la instalación de Trac se debe establecer el usuario y la base de datos que se utilizará para trabajar.&lt;/p&gt;

&lt;p&gt;En el siguiente ejemplo el usuario de la base de datos PostgreSQL que utilizará Trac será &lt;code&gt;trac_user&lt;/code&gt;, su contraseña será &lt;code&gt;trac_passwd&lt;/code&gt;. El uso de la contraseña lo del usuario &lt;code&gt;trac_user&lt;/code&gt; lo veremos más tarde al proceder a configurar el ambiente de Trac.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# su postgres
$ createuser \
--no-superuser \
--no-createdb \
--no-createrole \
--pwprompt \
--encrypted trac_user
Enter password for new role:
Enter it again:
CREATE ROLE
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nótese que se &lt;strong&gt;debe&lt;/strong&gt; utilizar el usuario &lt;code&gt;postgres&lt;/code&gt; (u otro usuario con los privilegios necesarios) del sistema para proceder a crear los usuarios.&lt;/p&gt;

&lt;p&gt;Ahora procedemos a crear la base de datos &lt;code&gt;trac_dev&lt;/code&gt;, cuyo dueño será el usuario &lt;code&gt;trac_user&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ createdb --encoding UTF8 --owner trac_user trac_dev
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;ambiente-de-trac&quot;&gt;Ambiente de Trac&lt;/h2&gt;

&lt;p&gt;Creamos el directorio &lt;code&gt;/srv/www&lt;/code&gt; que será utilizado para prestar servicios &lt;em&gt;Web&lt;/em&gt;, para mayor referencia acerca de esta elección se le recomienda leer el documento &lt;a href=&quot;http://www.pathname.com/fhs/pub/fhs-2.3.html&quot;&gt;Filesystem Hierarchy Standard&lt;/a&gt; en su versión 2.3.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sudo mkdir -p /srv/www
$ cd /srv/www
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Generamos el ambiente de Trac. Básicamente se deben contestar ciertas preguntas como:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Nombre del proyecto.&lt;/li&gt;
  &lt;li&gt;Enlace con la base de datos que se utilizará.&lt;/li&gt;
  &lt;li&gt;Sistema de control de versiones a utilizar (por defecto será SVN).&lt;/li&gt;
  &lt;li&gt;Ubicación absoluta del repositorio a utilizar.&lt;/li&gt;
  &lt;li&gt;Ubicación de las plantillas de Trac.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En el siguiente ejemplo se omitirán los comentarios brindados por el comando &lt;code&gt;trac-admin&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# trac-admin project initenv
Creating a new Trac environment at /srv/www/project

...

Project Name [My Project]&amp;gt; Demo

...

Database connection string [sqlite:db/trac.db]&amp;gt; 
postgres://trac_user:trac_passwd@localhost:5432/trac_dev

...

Repository type [svn]&amp;gt;

...

Path to repository [/path/to/repos]&amp;gt; /srv/svn/project

...

Templates directory [/usr/share/trac/templates]&amp;gt;

Creating and Initializing Project
 Installing default wiki pages

...

---------------------------------------------------------
Project environment for &#39;Demo&#39; created.

You may now configure the environment by editing the file:

  /srv/www/project/conf/trac.ini

...

Congratulations!
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Se ha culminado la instalación del ambiente de Trac, ahora procederemos a crear el ambiente de subversion.&lt;/p&gt;

&lt;h2 id=&quot;subversion-sistema-control-de-versiones&quot;&gt;Subversion: Sistema Control de Versiones&lt;/h2&gt;

&lt;p&gt;La puesta a punto del sistema de control de versiones es bastante sencilla, se resume en los siguientes pasos.&lt;/p&gt;

&lt;p&gt;Creación del espacio para prestar el servicio SVN, de igual manera se seguirá los lineamientos planteados en el FHS v2.3 mencionado previamente.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# mkdir -p /srv/svn
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Seguidamente crearemos el proyecto &lt;em&gt;subversion&lt;/em&gt; &lt;code&gt;project&lt;/code&gt; y haremos un importe inicial con la estructura básica de un proyecto de desarrollo de software.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ cd /srv/svn
# svnadmin create project
$ mkdir -p /tmp/project/{trunk,tags,branches}
$ tree /tmp/project/
/tmp/project/
├── branches
├── tags
└── trunk
# svn import /tmp/project/ \
file:///srv/svn/project/ \
-m &#39;Importe inicial&#39;

Adding         /tmp/project/trunk
Adding         /tmp/project/branches
Adding         /tmp/project/tags

Committed revision 1.
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;apache-servidor-web&quot;&gt;Apache: Servidor Web&lt;/h2&gt;

&lt;p&gt;Es hora de configurar los &lt;em&gt;sitios virtuales&lt;/em&gt; que utilizaremos tanto para Trac como para subversion.&lt;/p&gt;

&lt;p&gt;A continuación se presenta la configuración &lt;em&gt;básica&lt;/em&gt; de Trac.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# cat &amp;gt; /etc/apache2/sites-available/trac.example.com &amp;lt;&amp;lt;EOF
&amp;gt; &amp;lt;VirtualHost *&amp;gt;
&amp;gt; ServerAdmin webmaster@localhost
&amp;gt; ServerName trac.example.com
&amp;gt; CustomLog /var/log/apache2/trac.example.com/access.log combined
&amp;gt; ServerSignature Off
&amp;gt; ErrorLog /var/log/apache2/trac.example.com/error.log
&amp;gt; LogLevel warn
&amp;gt; DocumentRoot /srv/www/project
&amp;gt; &amp;lt;Location /&amp;gt;
&amp;gt; SetHandler mod_python
&amp;gt; PythonInterpreter main_interpreter
&amp;gt; PythonHandler trac.web.modpython_frontend
&amp;gt; PythonOption TracEnv /srv/www/project
&amp;gt; PythonOption TracUriRoot /
&amp;gt; &amp;lt;/Location&amp;gt;
&amp;gt; &amp;lt;/VirtualHost&amp;gt;
&amp;gt; EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ahora veamos la configuración &lt;em&gt;básica&lt;/em&gt; de nuestro proyecto subversion.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# cat &amp;gt; /etc/apache2/sites-available/svn.example.com &amp;lt;&amp;lt;EOF
&amp;gt; &amp;lt;VirtualHost *&amp;gt;
&amp;gt; ServerAdmin webmaster@localhost
&amp;gt; ServerName svn.example.com
&amp;gt; CustomLog /var/log/apache2/svn.example.com/access.log combined
&amp;gt; ServerSignature Off
&amp;gt; ErrorLog /var/log/apache2/svn.example.com/error.log
&amp;gt; LogLevel warn
&amp;gt; DocumentRoot /srv/svn/project
&amp;gt; &amp;lt;Location /&amp;gt;
&amp;gt; DAV svn
&amp;gt; SVNPath /srv/svn/project
&amp;gt; &amp;lt;/Location&amp;gt;
&amp;gt; &amp;lt;/VirtualHost&amp;gt;
&amp;gt; EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;De acuerdo a la configuración mostrada es necesario crear los directorios &lt;code&gt;/var/log/apache2/svn.example.com&lt;/code&gt; y &lt;code&gt;/var/log/apache2/trac.example.com&lt;/code&gt; para mantener por separado el registro de accesos y errores de los &lt;em&gt;sitios virtuales&lt;/em&gt; recién creados. De
lo contrario no podremos iniciar el servidor &lt;em&gt;Web&lt;/em&gt; Apache.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# mkdir /var/log/apache2/{svn,trac}.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Activamos el módulo &lt;code&gt;DAV&lt;/code&gt; necesario para cumplir con la configuración mostrada para el &lt;em&gt;sitio virtual&lt;/em&gt; &lt;code&gt;svn.example.com&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# a2enmod dav
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Activamos los sitios virtuales recién creados.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# a2ensite trac.example.com
# a2ensite svn.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Como la puesta en marcha y configuración de un servidor DNS escapa a los fines de este artículo, simplemente definiremos los &lt;em&gt;hosts&lt;/em&gt; en la tabla estática que se encuentra definida en el archivo &lt;code&gt;/etc/hosts&lt;/code&gt; de la siguiente manera.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# cat &amp;gt;&amp;gt; /etc/hosts &amp;lt;&amp;lt;EOF
&amp;gt; 127.0.0.1 trac.example.com trac
&amp;gt; 127.0.0.1 svn.example.com svn
&amp;gt; EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finalmente debemos forzar la recarga de la configuración del servidor &lt;em&gt;Web&lt;/em&gt; Apache, esto con el fin de cargar el módulo &lt;code&gt;DAV&lt;/code&gt; y los sitios virtuales definidos, es decir, &lt;code&gt;trac.example.com&lt;/code&gt; y &lt;code&gt;svn.example.com&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# /etc/init.d/apache2 force-reload
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;¡Felicitaciones!&lt;/strong&gt;, ya puede ir a su navegador favorito y colocar cualquiera de los sitios virtuales que acaba de definir.&lt;/p&gt;

&lt;h2 id=&quot;recomendaciones&quot;&gt;Recomendaciones&lt;/h2&gt;

&lt;p&gt;Una vez que haya llegado a este sección deberá comenzar a modificar adecuadamente los permisos para el usuario y grupo &lt;code&gt;www-data&lt;/code&gt; (Servidor Web Apache) para que escriba en las ubicaciones que sea necesario tanto en Trac como en subversion.&lt;/p&gt;

&lt;p&gt;La configuración de Trac podrá encontrarla en &lt;code&gt;/srv/www/project/conf/trac.ini&lt;/code&gt;, para mayor detalle acerca de la configuración de este fichero se le recomienda leer el documento &lt;a href=&quot;http://trac.edgewall.org/wiki/TracIni&quot;&gt;TracIni&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Si en su proyecto prevé que participarán otras personas, es recomendable establecer notificaciones de &lt;em&gt;tickets&lt;/em&gt; y cambios en el
repositorio &lt;em&gt;subversion&lt;/em&gt;, para esto último deberá revisar el &lt;em&gt;hook&lt;/em&gt; &lt;code&gt;post-commit&lt;/code&gt; y la documentación del paquete &lt;a href=&quot;/article/2010/04/24/subversion-notificaciones-via-correo-electronico/&quot;&gt;libsvn-notify-perl&lt;/a&gt; que le ofrece una extraordinaria cantidad de opciones.&lt;/p&gt;

&lt;p&gt;Conozca el entorno de Trac y Subversion. Si desea agregar nuevas funciones a su instalación le recomiendo visitar el sitio &lt;a href=&quot;http://trac-hacks.org/&quot;&gt;Trac Hacks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Espero poder mostrarles en próximos artículos algunas configuraciones más avanzadas en Trac, incluyendo la instalación, configuración y uso de &lt;em&gt;plugins&lt;/em&gt;.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2010/04/22/instalacion-basica-de-trac-y-subversion/&quot;&gt;Instalación básica de Trac y Subversion&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on April 22, 2010.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Sistema de manejo y seguimiento de proyectos: Trac]]></title>
  <link rel="alternate" type="text/html" href="http://milmazz.uno/article/2010/03/15/sistema-de-manejo-y-seguimiento-de-proyectos-trac/"/>
  <id>http://milmazz.uno/article/2010/03/15/sistema-de-manejo-y-seguimiento-de-proyectos-trac</id>
  <published>2010-03-15T19:24:43-06:00</published>
  <updated>2010-03-15T19:24:43-06:00</updated>
  <author>
    <name>Milton Mazzarri</name>
    <uri>http://milmazz.uno</uri>
    <email>me@milmazz.uno</email>
  </author>
  <content type="html">&lt;p&gt;&lt;a href=&quot;http://trac.edgewall.org&quot;&gt;Trac&lt;/a&gt; es un sistema multiplataforma desarrollado y mantenido por &lt;a href=&quot;http://edgewall.org&quot;&gt;Edgewall Software&lt;/a&gt;, el cual está orientado al seguimiento y manejo de proyectos de desarrollo de &lt;em&gt;software&lt;/em&gt; haciendo uso de un enfoque minimalista basado en la &lt;em&gt;Web&lt;/em&gt;, su misión es ayudar a los desarrolladores a escribir software de excelente calidad mientras busca no interferir con el proceso y políticas de desarrollo. Incluye un sistema &lt;em&gt;wiki&lt;/em&gt; que es adecuado para el manejo de la base de conocimiento del proyecto, fácil integración con sistemas de control de versiones ((Por defecto Trac se integra con &lt;em&gt;subversion&lt;/em&gt;)). Además incluye una interfaz para el seguimiento de tareas, mejoras y reporte de errores por medio de un completo y totalmente personalizable sistema de &lt;em&gt;tickets&lt;/em&gt;, todo esto con el fin de ofrecer una interfaz integrada y consistente para acceder a toda información referente al proyecto de desarrollo de software. Además, todas estas capacidades son extensibles por medio de &lt;em&gt;plugins&lt;/em&gt; o complementos desarrollados específicamente para Trac.&lt;/p&gt;

&lt;h2 id=&quot;breve-historia-de-trac&quot;&gt;Breve historia de Trac&lt;/h2&gt;

&lt;p&gt;El origen de Trac no es una idea original, algunos de sus objetivos se basan en los diversos sistemas de manejo y seguimiento de errores que existen en la actualidad, particularmente del sistema &lt;a href=&quot;http://cvstrac.org/&quot;&gt;CVSTrac&lt;/a&gt; y sus autores.&lt;/p&gt;

&lt;p&gt;Trac comenzó como la &lt;a href=&quot;http://trac.edgewall.org/wiki/TracHistory&quot;&gt;reimplementación&lt;/a&gt; del sistema CVSTrac en el lenguaje de programación &lt;a href=&quot;http://www.python.org&quot;&gt;Python&lt;/a&gt; y como ejercicio de entretenimiento, además de utilizar la base de datos embebida &lt;a href=&quot;http://www.sqlite.org&quot;&gt;SQLite&lt;/a&gt; ((Hoy día también se le da soporte a &lt;a href=&quot;http://www.postgresql.org&quot;&gt;PostgreSQL&lt;/a&gt;, mayor detalle en &lt;a href=&quot;http://trac.edgewall.org/wiki/DatabaseBackend&quot;&gt;Database Backend&lt;/a&gt;)). En un corto lapso de tiempo, el alcance de estos esfuerzos iniciales crecieron en gran medida, se establecieron metas y en el presente Trac presenta un curso de desarrollo propio.&lt;/p&gt;

&lt;p&gt;Los desarrolladores de &lt;em&gt;Edgewall Software&lt;/em&gt; esperan que Trac sea una plataforma viable para explorar y expandir el cómo y qué puede hacerse con sistemas de manejo de proyectos de desarrollo de software basados en sistemas wiki.&lt;/p&gt;

&lt;h2 id=&quot;caractersticas-de-trac&quot;&gt;Características de Trac&lt;/h2&gt;

&lt;p&gt;A continuación se presenta una descripción breve de las distintas características de Trac.&lt;/p&gt;

&lt;h3 id=&quot;herramienta-de-cdigo-abierto-para-el-manejo-de-proyectos&quot;&gt;Herramienta de código abierto para el manejo de proyectos&lt;/h3&gt;

&lt;p&gt;Trac es una herramienta ligera para el manejo de proyectos basada en la &lt;em&gt;Web&lt;/em&gt;, desarrollada en el lenguaje de programación Python. Está enfocada en el manejo de proyectos de desarrollo de software, aunque es lo suficientemente flexible para usarla en muchos tipos de proyectos. Al ser una herramienta de &lt;a href=&quot;http://trac.edgewall.org/wiki/TracLicense&quot;&gt;código abierto&lt;/a&gt;, si Trac no llena completamente sus necesidades, puede aplicar los cambios necesarios usted mismo, escribir complementos o &lt;em&gt;plugins&lt;/em&gt;, o contratar a alguien calificado que lo haga por usted.&lt;/p&gt;

&lt;h2 id=&quot;sistema-de-tickets&quot;&gt;Sistema de tickets&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/images/2010-03-16-sistema-de-manejo-y-seguimiento-de-proyectos-trac/tickets-300x193.png&quot; alt=&quot;Tickets activos para el hito 0.12 de Trac, ordenados por última fecha de modificación&quot; /&gt;&lt;/p&gt;

&lt;p&gt;El sistema de &lt;em&gt;tickets&lt;/em&gt; le permite hacer seguimiento del progreso en la resolución de problemas de programación particulares, requerimientos de nuevas características, problemas e ideas, cada una de ellas en su propio &lt;em&gt;ticket&lt;/em&gt;, los cuales son enumerados de manera ascendente. Puede resolver o reconciliar aquellos &lt;em&gt;tickets&lt;/em&gt; que buscan un mismo objetivo o donde más de una persona reporta el mismo requerimiento. Permite hacer búsquedas o filtrar &lt;em&gt;tickets&lt;/em&gt; por severidad, componente del proyecto, versión, responsable de atender el &lt;em&gt;ticket&lt;/em&gt;, entre otros.&lt;/p&gt;

&lt;p&gt;Para mejorar el seguimiento de los &lt;em&gt;tickets&lt;/em&gt; Trac ofrece la posibilidad de activar notificaciones vía correo electrónico, de este modo se mantiene informado a los desarrolladores de los avances en la resolución de las actividades planificadas.&lt;/p&gt;

&lt;h2 id=&quot;vista-de-progreso&quot;&gt;Vista de progreso&lt;/h2&gt;

&lt;p&gt;Existen varias maneras convenientes de estar al día con los acontecimientos y cambios que ocurren dentro de un proyecto. Puede establecer hitos y ver un mapa del progreso (así como los logros históricos) de manera resumida. Además, puede visualizar desde una interfaz centralizada los cambios ocurridos cronológicamente en el wiki, hitos, tickets y repositorios de código fuente, comenzando con los eventos más recientes, toda esta información es accesible vía &lt;em&gt;Web&lt;/em&gt; o de manera alternativa Trac le ofrece la posibilidad de exportar esta información a otros formatos como el RSS, permitiendo que los usuarios puedan observar esos cambios fuera de la interfaz centralizada de Trac, así como la notificación por correo electrónico.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/2010-03-16-sistema-de-manejo-y-seguimiento-de-proyectos-trac/milestone-300x221.png&quot; alt=&quot;vista de progreso del proyecto&quot; title=&quot;Vista del avance del proyecto para un hito particular&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;vista-del-repositorio-en-lnea&quot;&gt;Vista del repositorio en línea&lt;/h2&gt;

&lt;p&gt;Una de las características de mayor uso en Trac es el navegador o visor del repositorio en línea, se le ofrece una interfaz bastante amigable para el sistema de control de versiones que esté usando ((Por defecto Trac se integra con &lt;em&gt;subversion&lt;/em&gt;, la integración con otros sistemas es posible gracias a &lt;em&gt;plugins&lt;/em&gt; o complementos.)). Este visualizador en línea le ofrece una manera clara y elegante de observar el código fuente resaltado, así como también la comparación de ficheros, apreciando fácilmente las diferencias entre ellos.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/2010-03-16-sistema-de-manejo-y-seguimiento-de-proyectos-trac/code-275x300.png&quot; alt=&quot;Visor de código fuente en Trac&quot; title=&quot;Cambios entre revisiones en trunk/setup.py&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;manejo-de-usuarios&quot;&gt;Manejo de usuarios&lt;/h2&gt;

&lt;p&gt;Trac ofrece un sistema de permisología para controlar cuales usuarios pueden acceder o no a determinadas secciones del sistema de manejo y seguimiento del proyecto, esto se logra a través de la interfaz administrativa. Además, esta interfaz es posible integrarla con la definición de permisos de lectura y escritura de los usuarios en el sistema de control de versiones, de ese modo se logra una
administración centralizada de usuarios.&lt;/p&gt;

&lt;h2 id=&quot;wiki&quot;&gt;Wiki&lt;/h2&gt;

&lt;p&gt;El sistema wiki es ideal para mantener la base de conocimientos del proyecto, la cual puede ser usada por los desarrolladores o como medio para ofrecerles recursos a los usuarios. Tal como funcionan otros sistemas wiki, puede permitirse la edición compartida. La sintaxis del sistema wiki es bastante sencilla, si esto no es suficiente, es posible integrar en Trac un editor WYSIWYG (lo que se ve es lo que se obtiene, por sus siglas en inglés) que facilita la edición de los documentos.&lt;/p&gt;

&lt;h2 id=&quot;caractersticas-adicionales&quot;&gt;Características adicionales&lt;/h2&gt;

&lt;p&gt;Al ser Trac un sistema modular puede ampliarse su funcionalidad por medio de complementos o &lt;em&gt;plugins&lt;/em&gt;, desde sistemas anti-spam hasta diagramas de Gantt o sistemas de seguimiento de tiempo.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;http://milmazz.uno/article/2010/03/15/sistema-de-manejo-y-seguimiento-de-proyectos-trac/&quot;&gt;Sistema de manejo y seguimiento de proyectos: Trac&lt;/a&gt; was originally published by Milton Mazzarri at &lt;a href=&quot;http://milmazz.uno&quot;&gt;milmazz&lt;/a&gt; on March 15, 2010.&lt;/p&gt;</content>
</entry>

</feed>
