<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title>JuanPabloAJ Page</title>
  <link href="http://juanpabloaj.com/atom.xml" rel="self"/>
  <link href="http://juanpabloaj.com/"/>
  <updated>2026-04-16T22:19:00+00:00</updated>
  <id>http://juanpabloaj.com/</id>
  <author>
    <name>JuanPablo AJ</name>
    <email></email>
  </author>
  
  <entry>
    <title>A lightweight way to make agents talk without paying for API usage</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2026-04-16T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2026/04/16/a-lightweight-way-to-make-agents-talk-without-paying-for-api-usage</id>
    <content type="html">&lt;p&gt;For the past few weeks I have been testing a simple workflow for making coding agents interact with each other without using APIs, SDKs, or extra dependencies.&lt;/p&gt;

&lt;p&gt;The main constraint is this: use the subscription plans you already have, avoid paying for API usage, and keep the setup simple enough that you can try it in a few minutes.&lt;/p&gt;

&lt;p&gt;This became useful to me for two reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I sometimes want to extend a Claude session by asking Codex or Gemini to review or continue part of the work.&lt;/li&gt;
  &lt;li&gt;I also want to delegate work and get different model perspectives on the same draft, spec, or implementation, instead of relying on a single vendor’s subagents.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not a polished framework. It is just a practical pattern that works well enough to test multi-agent workflows with very little setup.&lt;/p&gt;

&lt;p&gt;To keep the examples simple, the rest of this post uses a draft as the running example, but the same pattern applies to specs, code changes, and review tasks.&lt;/p&gt;

&lt;h3 id=&quot;the-basic-idea&quot;&gt;The basic idea&lt;/h3&gt;

&lt;p&gt;Instead of integrating models through APIs, you let one agent invoke another through the CLI in a way that preserves the previous conversation.&lt;/p&gt;

&lt;p&gt;For the non-interactive pattern, the key is to resume the previous session instead of starting a new one every time.&lt;/p&gt;

&lt;p&gt;The commands the agent should use are:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;codex &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;resume &lt;span class=&quot;nt&quot;&gt;--last&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;prompt&quot;&lt;/span&gt;
gemini &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; latest &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;prompt&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The important part is that the agent resumes the previous interaction so it can keep iterating on the same topic instead of starting from zero on every call. In the Codex example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--last&lt;/code&gt; tells the CLI to continue the most recent session instead of opening a new one.&lt;/p&gt;

&lt;p&gt;I keep the conventions for this pattern in this Claude memory file:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/juanpabloaj/dotclaude/blob/main/memory/feedback_external_agents.md&quot;&gt;external agent conventions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It contains the exact invocation rules and can be read and reused by other agents so they know how to keep the interaction going consistently.&lt;/p&gt;

&lt;p&gt;That gives you a very lightweight loop:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;One agent produces or reviews a draft.&lt;/li&gt;
  &lt;li&gt;That agent invokes another agent to critique it using resume mode.&lt;/li&gt;
  &lt;li&gt;The orchestrating agent reads the critique and decides the next step.&lt;/li&gt;
  &lt;li&gt;The agents keep iterating until the draft is good enough or the discussion stops adding value.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In practice, this lets you do things like:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;ask Codex to review a draft produced in Claude&lt;/li&gt;
  &lt;li&gt;ask Gemini for an alternative reading of the same draft&lt;/li&gt;
  &lt;li&gt;use one agent as the writer and another as the reviewer&lt;/li&gt;
  &lt;li&gt;act as the human orchestrator, or delegate orchestration to one of the agents&lt;/li&gt;
  &lt;li&gt;avoid manually copy-pasting each interaction between agents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One reason to do this across vendors is to get a different perspective, not just another pass from the same model family.&lt;/p&gt;

&lt;p&gt;At a high level, the non-interactive flow looks like this:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Claude writes a draft
-&amp;gt; Codex reviews it using resume mode
-&amp;gt; Claude revises the draft
-&amp;gt; Claude or Codex summarizes the disagreements
-&amp;gt; Repeat until the output is stable enough
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This pattern is good when:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;you want the smallest possible setup&lt;/li&gt;
  &lt;li&gt;you do not want extra dependencies&lt;/li&gt;
  &lt;li&gt;you care more about fast experimentation than about observability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Its biggest limitation is visibility. You can make agents talk, but it is not always easy to inspect the interaction history, monitor progress, or understand what happened at each step.&lt;/p&gt;

&lt;p&gt;It is also worth paying attention to permissions, especially if one agent is invoking another autonomously.&lt;/p&gt;

&lt;h3 id=&quot;the-more-visible-pattern-tmux&quot;&gt;The more visible pattern: tmux&lt;/h3&gt;

&lt;p&gt;If you want better visibility, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt; is the better option.&lt;/p&gt;

&lt;p&gt;This version depends on having &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt; installed, but in exchange you can see what each agent is doing in separate panes or sessions and capture their output more easily.&lt;/p&gt;

&lt;p&gt;A few commands the agent can use in that workflow are:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Create a dedicated tmux socket and start an isolated session&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;SOCKET&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TMPDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/tmp&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/claude-tmux-sockets/claude.sock&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TMPDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/tmp&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/claude-tmux-sockets&quot;&lt;/span&gt;
tmux &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$SOCKET&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; new &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;descriptive-name&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Send a prompt literally, then submit it with Enter&lt;/span&gt;
tmux &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$SOCKET&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; send-keys &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; target &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$cmd&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sleep &lt;/span&gt;1
tmux &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$SOCKET&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; send-keys &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; target Enter
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Capture recent pane output without line wrapping artifacts&lt;/span&gt;
tmux &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$SOCKET&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; capture-pane &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-J&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; target &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Attach to the running session to monitor the agents directly&lt;/span&gt;
tmux &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$SOCKET&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; attach &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; session-name
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I keep the conventions for this pattern in this Claude memory file:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/juanpabloaj/dotclaude/blob/main/memory/feedback_tmux_agents.md&quot;&gt;tmux multi-agent patterns&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It describes the socket, monitoring, and pane-management conventions, and other agents can read it as a reusable reference.&lt;/p&gt;

&lt;p&gt;This pattern is better when:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;you want to watch the interaction as it happens&lt;/li&gt;
  &lt;li&gt;you want to run two or more agents in parallel&lt;/li&gt;
  &lt;li&gt;you want easier debugging when the workflow becomes messy&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;the-main-caveat&quot;&gt;The main caveat&lt;/h3&gt;

&lt;p&gt;I think there is real value in getting multiple perspectives from different models, but I am still not fully convinced that more agent-to-agent interaction always pays off.&lt;/p&gt;

&lt;p&gt;LLMs are very good at producing plausible, well-written text. When they start talking to each other, they can produce a lot of it.&lt;/p&gt;

&lt;p&gt;So the open question is not whether they can reach consensus. They can.&lt;/p&gt;

&lt;p&gt;The harder question is whether the final result is actually better, or whether it is just a more polished hallucination produced after a longer chain of interactions.&lt;/p&gt;

&lt;p&gt;That is why I currently see this as a useful workflow to test, not as a universal solution.&lt;/p&gt;

&lt;h3 id=&quot;in-summary&quot;&gt;In summary&lt;/h3&gt;

&lt;p&gt;If you already use subscription-based coding agents, the simplest way I have found to make them collaborate without paying for API usage is:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;use non-interactive calls with resume when you want simplicity&lt;/li&gt;
  &lt;li&gt;use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt; when you want visibility and tighter control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is enough to build small multi-agent workflows across tools like Claude, Codex, and Gemini without much setup.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>From Agentic Reasoning to Deterministic Scripts</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2026-03-08T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2026/03/08/from-agentic-reasoning-to-deterministic-scripts</id>
    <content type="html">&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;

&lt;p&gt;AI agents shouldn’t solve the same task over and over.
Their execution history could be used to detect recurring patterns and compile them into deterministic scripts.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The purpose of AI agents is not to execute tasks indefinitely, but to discover the procedures that replace them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;the-overhead-of-routine-tasks&quot;&gt;The Overhead of Routine Tasks&lt;/h2&gt;

&lt;p&gt;AI agents like Claude, Codex, OpenClaw, or any of their derivatives are remarkably capable tools. They can explore a repository, diagnose a bug, write tests, execute commands, and produce results that previously required hours of human work. All of this is possible because every task goes through an LLM: the agent receives an instruction, reasons about it, chooses tools, executes them, observes the result, and repeats.&lt;/p&gt;

&lt;p&gt;That loop is flexible and powerful. It is also inherently expensive: each step consumes tokens, introduces latency, and produces outputs that can vary between runs. For routine tasks- cleaning a build directory, updating dependencies according to a known policy, generating a report with a fixed format- this level of reasoning is overkill. The agent is “thinking from scratch” every single time.&lt;/p&gt;

&lt;p&gt;The problem isn’t that agents are bad. The problem is that we are using our most powerful- and most expensive- instrument for everything, indiscriminately.&lt;/p&gt;

&lt;h2 id=&quot;a-developer-before-automating&quot;&gt;A developer before automating&lt;/h2&gt;

&lt;p&gt;There is a pattern any developer will recognize. Before writing a script:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;You perform the task manually, paying attention, understanding each step and its edge cases.&lt;/li&gt;
  &lt;li&gt;You iterate, fix errors, and refine the process.&lt;/li&gt;
  &lt;li&gt;You identify the routine part: the steps that repeat without meaningful variation.&lt;/li&gt;
  &lt;li&gt;You automate that part, and reserve human judgment for the edge cases.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This pattern appears in other contexts outside programming- the way a process matures from deliberate effort to fluid execution. What I want to propose here is whether AI agents could follow a similar trajectory.&lt;/p&gt;

&lt;h2 id=&quot;a-task-maturation-cycle&quot;&gt;A task maturation cycle&lt;/h2&gt;

&lt;p&gt;What I propose is an idea of how the lifecycle of a task could be structured within an agentic system:&lt;/p&gt;

&lt;p&gt;Phase 1 - Deliberative Execution: The agent receives a new or ambiguous request. It solves it using full LLM reasoning. Unlike a script, the agent doesn’t just execute steps: it reasons about them. The log it produces can be qualitatively richer than a standard structured log- it can include the explicit reasoning behind each decision, the tools considered and discarded, the observed conditions, and the ambiguities it resolved. That richness is not a byproduct; it is the most valuable raw material for the subsequent phases.&lt;/p&gt;

&lt;p&gt;Phase 2 - History Analysis: A separate process analyzes the repository of logs or traces of tasks performed by agents. It looks for tasks that repeat with high similarity: same steps, same context, same expected outcome. It identifies stable execution patterns. This analysis- especially for detecting semantic equivalence between tasks described in different ways- might require an LLM. The irony is intentional: we invest LLM reasoning now to reduce LLM reasoning in the future. The hypothesis is that this cost, when run in batch and periodically, would amortize if the number of executions routed to the resulting script is high enough- something that depends on the volume of repetitive tasks in each specific context.&lt;/p&gt;

&lt;p&gt;Phase 3 - Automation Generation: When a task crosses a certain threshold of recurrence and stability, the system can propose- or directly generate- a deterministic script that replaces the LLM loop for that specific case.&lt;/p&gt;

&lt;p&gt;Phase 4 - Smart Routing: When a new request comes in, the system first evaluates if there is a validated automation that covers it. If so, it executes the script. If not, it falls back to the deliberative agent.&lt;/p&gt;

&lt;p&gt;If the cycle works as proposed, over time the proportion of tasks requiring LLM reasoning would decrease. The system would trend toward being faster, cheaper, and more predictable, without losing the ability to handle the novel. The cost of the analysis in Phase 2 is the price of that improvement- not a contradiction to the argument, but a necessary part of it.&lt;/p&gt;

&lt;h2 id=&quot;beyond-cost&quot;&gt;Beyond cost&lt;/h2&gt;

&lt;p&gt;The reduction in token costs is the most obvious benefit, but not the most important one.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Auditability: A deterministic script has verifiable behavior. You can read it, test it, and do code reviews on it. An LLM reasoning loop produces results that are hard to audit systematically.&lt;/li&gt;
  &lt;li&gt;Operational Reliability: In production environments, variability is a risk. For known tasks, determinism is not a limitation: it is an advantage.&lt;/li&gt;
  &lt;li&gt;Energy Footprint: Every call to an LLM has an energy cost. Replacing recurring calls with scripts that run locally or on lightweight infrastructure could reduce that footprint.&lt;/li&gt;
  &lt;li&gt;Response Speed: A script runs in milliseconds. An LLM reasoning loop can take seconds or minutes depending on the complexity and the model’s latency.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;grep-is-not-enough&quot;&gt;grep is not enough&lt;/h2&gt;

&lt;p&gt;Detecting recurrence in text logs is relatively simple with tools like grep or ripgrep. But that only works for exact or near- exact matches. The interesting problem here is semantic similarity: two tasks might be described with different words, executed in slightly different contexts, and yet be functionally equivalent.&lt;/p&gt;

&lt;p&gt;Reliably identifying that equivalence requires more than textual search: it requires a semantic indexing layer over the execution history. That is a non- trivial technical problem, and I am deliberately leaving it out of scope for this post. It is, in itself, the most interesting component of the proposed system, and deserves separate treatment.&lt;/p&gt;

&lt;p&gt;Tools like LlamaIndex or PageIndex seem to be interesting alternatives to explore for what is described in Phase 2.&lt;/p&gt;

&lt;h2 id=&quot;what-this-is-not&quot;&gt;What this is not&lt;/h2&gt;

&lt;p&gt;To avoid misunderstandings:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;This is not an agent that “learns” in the sense of retraining. I am not talking about fine- tuning or updating weights. The learning here is purely behavioral: the system observes what works and codifies it as a procedure.&lt;/li&gt;
  &lt;li&gt;This is not about replacing LLM agents. Deliberative agents remain necessary for everything new, ambiguous, or exceptional. The proposal is complementary, not a substitute.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Current AI agents are deliberative tools that solve almost everything through reasoning. That is powerful, but it might not be the desirable end state. A more mature system could recognize when a task no longer requires reasoning, and execute it more directly.&lt;/p&gt;

&lt;p&gt;The path forward isn’t just building better models for routine tasks. It is building the infrastructure that allows LLM reasoning to be the starting point, not the permanent destination.&lt;/p&gt;

&lt;p&gt;The logs that agents already produce today are the raw material for this. The question is whether someone will build the pipeline that converts them into automations.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;A brief note on sources: This text is the sum of several influences worth naming: the emergence and popularization of OpenClaw and its derivatives; the economic and energetic cost of tokens; the ideas from Kahneman’s Thinking, Fast and Slow regarding deliberative and automatic processing modes; the way a developer builds automations by iterating manually first; the moment when a repeated request to an agent starts sounding exactly like a bash script.&lt;/p&gt;

&lt;p&gt;The structure of this text was reorganized with the help of LLMs.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The silent filter</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2026-02-27T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2026/02/27/the-silent-filter</id>
    <content type="html">&lt;p&gt;“We have arranged a society based on science and technology in which nobody understands anything about science and technology. And this combustible mixture of ignorance and power, sooner or later, is going to blow up in our faces.” - Carl Sagan, 1994.&lt;/p&gt;

&lt;p&gt;Sagan’s prophecy did not come true, at least not in the cinematic way we imagined. There was no explosion. The warning has circulated for decades as background noise, just uncomfortable enough to ignore, and familiar enough to no longer be frightening. The mistake was taking the word “explosion” literally.&lt;/p&gt;

&lt;p&gt;What I propose in this text is that the real danger takes a quieter, more probable, and much harder-to-detect form: a process of cognitive erosion.&lt;/p&gt;

&lt;h3 id=&quot;the-great-filter-might-not-be-an-event&quot;&gt;The Great Filter might not be an event&lt;/h3&gt;

&lt;p&gt;In 1998, Robin Hanson proposed the concept of the Great Filter to explain the Fermi Paradox: if the universe is vast and ancient, where are the advanced civilizations? The usual answer imagines a catastrophic event: nuclear war, pandemics, asteroids, or an artificial intelligence deciding that humans are a problem. Something identifiable with a date on a calendar.&lt;/p&gt;

&lt;p&gt;But in my view, a filter does not need to be an event. It can be a condition of stagnation. A species that gradually loses the ability to understand, maintain, and extend the technology it depends on does not necessarily collapse; it simply becomes incapable of going any further. It does not disappear through an explosion, but through an accumulated incapacity.&lt;/p&gt;

&lt;p&gt;This is what I call a Silent Filter. It is not a sudden extinction; it is an obsolescence programmed by our own pursuit of efficiency.&lt;/p&gt;

&lt;h3 id=&quot;the-trap-of-the-shortcut&quot;&gt;The Trap of the Shortcut&lt;/h3&gt;

&lt;p&gt;Describing this mechanism does not require assuming the worst of human nature. it requires assuming something much more mundane: that given access to two paths toward the same result, most of us will take the shorter one. This is not a moral critique; it is a description. The problem arises when the shorter path eliminates the very mechanism of learning.&lt;/p&gt;

&lt;p&gt;“An expert is a person who has made all the mistakes that can be made in a very narrow field.” — Niels Bohr.&lt;/p&gt;

&lt;p&gt;Knowledge is not only built on successes but on the accumulation and assimilation of errors. Not observed errors, not delegated errors: errors committed, understood, and overcome. Without that process, what you get is familiarity, not comprehension. And familiarity only allows you to use what you inherited, not to improve or extend it.&lt;/p&gt;

&lt;p&gt;A similar thing happens with creativity. “Inspiration exists, but it has to find you working,” a phrase often attributed to Picasso. Regardless of who said it, anyone who has practiced a discipline, artistic, athletic, or scientific, recognizes it as true. It defines the creative process. Ideas do not appear in a vacuum. They appear in the middle of the process, between one failed attempt and the next. Iterating to understand, understanding to assimilate, assimilating to expand. Without that iteration, the creative cycle becomes sterile.&lt;/p&gt;

&lt;p&gt;This is, ultimately, the same observation Bohr made from a different angle. Errors and iteration are not the price paid for learning. They are the mechanism by which learning occurs.&lt;/p&gt;

&lt;p&gt;The thread connecting these two ideas is this: the understanding of any system requires having built it, at least partially. A species that systematically delegates this process does not just become dependent: it becomes incapable of replicating what its predecessors achieved. And that incapacity, unlike common ignorance, is invisible from the inside.&lt;/p&gt;

&lt;h3 id=&quot;the-delegation-of-synthesis-and-linguistic-drift&quot;&gt;The Delegation of Synthesis and Linguistic Drift&lt;/h3&gt;

&lt;p&gt;Artificial Intelligence is not the first system that allows us to delegate comprehension. The calculator allowed us to delegate arithmetic. GPS allowed us to delegate navigation. Internet search allowed us to delegate memory. But current AI absorbs something structurally different: the process of synthesis and reasoning.&lt;/p&gt;

&lt;p&gt;Without debating what “thinking” or “intelligence” means, it is undeniable that AI performs processes in a way that is fluid and useful enough that delegation is often the rational decision. Faster, less effort, comparable or better results. The shortest path, available to everyone, all the time.&lt;/p&gt;

&lt;p&gt;The problem is not that AI solves problems. The problem is that every solution accepted without understanding the reasoning behind it is an iteration that did not happen and a mistake that was not made. Individually, this is irrelevant. On a global scale and over generations, this is the exact mechanism of the Silent Filter.&lt;/p&gt;

&lt;p&gt;One could argue that this doesn’t matter much: knowledge does not disappear; it is simply stored in systems that can retrieve it when necessary.&lt;/p&gt;

&lt;p&gt;But there is a distinction worth considering. Accessing a solution is not the same as understanding the reasoning that produced it. And supervising a system is not the same as being able to correct or improve it. As AI systems become more complex and interact with each other, the reasoning behind their decisions is not just difficult to follow due to volume or speed: it may become structurally different from how humans reason.&lt;/p&gt;

&lt;p&gt;Noam Chomsky proposed that all human languages share a common underlying architecture. Regardless of the absolute certainty of that claim, it leads to a simpler observation: all human languages emerged in humans, and therefore reflect the way humans process and communicate ideas. A communication system that emerges between agents with different objectives has no reason to respect that architecture. To us, rather than a difficult language to learn, it could become structurally unintelligible.&lt;/p&gt;

&lt;p&gt;A species that cannot follow the reasoning of its own systems does not supervise them; it simply inhabits them until they stop working.&lt;/p&gt;

&lt;h3 id=&quot;a-likely-obvious-confession&quot;&gt;A Likely Obvious Confession&lt;/h3&gt;

&lt;p&gt;This text, its structure and parts of its refinement, has been organized with the help of artificial intelligence. No one is outside this phenomenon. The Silent Filter does not require villains; it only requires rational individual decisions that accumulate in a direction no one quite chose.&lt;/p&gt;

&lt;p&gt;I don’t have a solution. I suspect one that is compatible with our nature does not exist. Perhaps the first step to avoiding a filter is being able to see it.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The noise circuit breaker</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2026-02-26T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2026/02/26/the-noise-circuit-breaker</id>
    <content type="html">&lt;h3 id=&quot;an-attempt-to-audit-ai-agreeability&quot;&gt;An attempt to audit AI agreeability&lt;/h3&gt;

&lt;p&gt;Most AI interactions are governed by a hidden bias: agreeability. These models are designed to be helpful and polite, which often turns them into a digital mirror that simply reflects your own ideas back to you with a professional polish. This creates a feedback loop where you feel productive, but you are actually just spinning in circles.&lt;/p&gt;

&lt;p&gt;Why use this prompt?&lt;/p&gt;

&lt;p&gt;The prompt below is an attempt to force the AI out of its default “helpful assistant” mode. By demanding a technical report on the conversation itself, you push the model to analyze the interaction from the outside. It’s a tool to help you spot when a conversation has stopped being useful and has started becoming an echo chamber.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-prompt&quot;&gt;Perform a technical analysis of this chat session so far. Act as a neutral observer of natural language processing and deliver a structured report based on the following criteria:

Signal-to-Noise Ratio (SNR): Evaluate whether the conversation is converging toward a resolution or drifting into redundancy.

Entropy Level: Determine if the introduction of new concepts is constant or if the dialogue has entered a low-information transfer cycle.

Density and Register: Classify the complexity of the exchange (technical, operational, speculative) and the precision of the vocabulary used.

Inference of Intent and State: Based on rhythm, syntax, and topics, infer the user’s underlying objective and current disposition (skepticism, pragmatism, intellectual rumination, etc.).

Archetype Mapping: Identify the user profile emerging from the inputs (e.g., analytical-critical, execution-oriented).

Conclude with a &apos;Conversation Performance&apos; metric: Is there still an information gain, or are we facing diminishing returns? Suggest a path to recover technical utility if necessary.
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;when-to-use-it&quot;&gt;When to use it&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;When you feel stuck: If you’ve been chatting for a while and haven’t made a concrete decision or produced anything tangible.&lt;/li&gt;
  &lt;li&gt;When you suspect “playing along”: Especially useful during speculative or philosophical discussions where the AI might just be matching your tone instead of providing real friction.&lt;/li&gt;
  &lt;li&gt;As an exit signal: If the report shows “diminishing returns,” it’s a clear sign to close the tab and return to the physical world or raw work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do you have any other prompts that help you break out of the agreeability loop?&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Life as an Accelerator of Chaos</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2025-10-06T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2025/10/06/life-as-an-accelerator-of-caos</id>
    <content type="html">&lt;p&gt;A few years ago, in Nick Lane’s book, &lt;em&gt;The Vital Question: Why Is Life the Way It Is?&lt;/em&gt;, I read a sentence that went something like this: “Consider the stars. They pay for their ordered existence by emitting enormous amounts of energy into the universe.”&lt;/p&gt;

&lt;p&gt;Every now and then, I come back to that idea, and it pushes me to think further. In this post, I’ll try to summarize and organize the thoughts that stemmed from it. I don’t have a scientific background to back up what I’m saying with equations or academic papers; this is simply an extension of that phrase I once read, an exercise in reasoning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The reasoning in 5 steps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Basic principle: entropy tends to increase&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The second law of thermodynamics states that in a closed system, total entropy (the degree of disorder) tends to increase. This isn’t a “force” but a statistical tendency: states of greater disorder are simply more numerous and, therefore, more probable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The fastest paths to entropy are the most probable&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If a system can evolve along different paths, it will tend to follow those that lead it most quickly to a state of greater entropy. Sometimes, the most efficient route to global disorder involves creating intermediate ordered structures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Ordered structures as efficient shortcuts to greater entropy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Examples like hurricanes or stars themselves show that highly organized systems can emerge as transient forms that channel energy into their surroundings in an incredibly effective way. They don’t contradict the second law; instead, they serve it more efficiently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Life as an ordered structure that accelerates entropy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Living beings are an extreme example of internal order. To maintain it, we consume energy from our environment (sun, food) and release heat and waste. In practice, we are highly efficient channels for transforming concentrated energy into more dispersed forms, accelerating the increase of global entropy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Hypothesis: Life as a consequence of accelerating entropy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is where it all comes together. If the states of greatest entropy are the most probable (Point 1), and there are paths that accelerate the arrival to that state (Point 2), then those paths will be statistically favored. Since life is one of these efficient routes (Point 4), its emergence ceases to be an improbable accident and becomes a logical consequence: one of the most probable trajectories that matter can follow under certain conditions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After organizing these ideas, I asked the AI Gemini if similar concepts existed. The answer was yes, and it mentioned two main fields: Dissipative Structures (Ilya Prigogine) and Dissipation-Driven Adaptation (Jeremy England). Perhaps I’ll research them and their work a bit and continue writing about this topic. Just perhaps.&lt;/p&gt;

&lt;p&gt;Note: Much of the wording in this text was revised and polished with the help of Google’s Gemini to ensure clarity.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Context, Hallucinations, and How LLMs Are Changing Development</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2025-09-09T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2025/09/09/context-hallucinations-and-LLMs</id>
    <content type="html">&lt;p&gt;Taking advantage of this recent OpenAI post on hallucinations:&lt;/p&gt;

&lt;p&gt;https://openai.com/index/why-language-models-hallucinate/&lt;/p&gt;

&lt;p&gt;I will summarize my experience from the last six months using LLMs intensively in a development context. By “intensively,” I mean all day, multiple times a day, comparing different LLMs, and so on.&lt;/p&gt;

&lt;p&gt;I will focus on two key concepts when working with LLMs: context and hallucinations, and how they change the way we work in development.&lt;/p&gt;

&lt;p&gt;Most of what I share here is based on my own opinions and lessons learned during this period.&lt;/p&gt;

&lt;h3 id=&quot;context-size-matters&quot;&gt;Context size matters&lt;/h3&gt;

&lt;p&gt;In my view, the turning point for LLMs came in late March, when Gemini 2.5 Pro was released for free with a context size of 1M tokens.
For the first time, you could feed a large portion of an entire project to an LLM—not just fragments or chunks.
When the model has access to the full project, it can better infer overall behavior. Previously, the only option was to provide smaller parts to avoid filling the context, which forces the model into assumptions—and eventually, hallucinations. This leads to the second point.&lt;/p&gt;

&lt;h3 id=&quot;trust-no-llm-completely&quot;&gt;Trust no LLM completely&lt;/h3&gt;

&lt;p&gt;Right now, you cannot fully trust what an LLM produces. There’s no guaranteed way to know whether its responses are accurate or to what degree they are true. Ignoring this is a critical mistake.
You need independent methods to validate responses, and those methods should not be built by the LLM itself—at least not by the same instance.&lt;/p&gt;

&lt;h3 id=&quot;change-in-the-development-process&quot;&gt;Change in the development process&lt;/h3&gt;

&lt;p&gt;In software development, the TDD (Test-Driven Development) methodology is well known.
It starts with defining validations—what you expect to get—and writing the tests. This forces the developer to clearly understand the requirements, because only someone with that clarity can define a validation scenario in words and translate it into an automated test.&lt;/p&gt;

&lt;p&gt;The flow is:&lt;/p&gt;

&lt;p&gt;Write a test → The test fails → Modify the code → The test passes → Iterate.&lt;/p&gt;

&lt;p&gt;Earlier, I mentioned hallucinations. One way to reduce and catch them—adapting the TDD approach—is as follows (without going too deep into details):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Be clear about what you need and precise in the description you give to the LLM, including scenario definitions. This requires human time and focus.&lt;/li&gt;
  &lt;li&gt;Provide the information to the LLM and ask it to restate in its own words what you asked for, adding examples. Then you can verify, based on those examples, that you are aligned.&lt;/li&gt;
  &lt;li&gt;Have or build ways to validate the LLM’s output; this is the only way to detect hallucinations. In particular, use the scenarios defined in the first step.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Leveraging LLMs with larger context windows is also important, as they rely less on assumptions and can use other parts of the project as reference.&lt;/p&gt;

&lt;h3 id=&quot;in-summary&quot;&gt;In summary&lt;/h3&gt;
&lt;p&gt;Yes, LLMs change and accelerate the way we work, but at this point, they are still like an assistant that needs a detailed and precise definition of what is expected, plus well-defined validation criteria for the results. Both require time and effort.&lt;/p&gt;

&lt;p&gt;In my opinion, how seriously you take this last point will determine how reliable your solution will be. There are no magic solutions.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Fail-Fast Testing of Goroutines with WaitGroup and time.After</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2025-04-25T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2025/04/25/fail-fast-testing-goroutines</id>
    <content type="html">&lt;p&gt;TL;DR&lt;/p&gt;

&lt;p&gt;Unit-testing async code in Go? Drop in a mock that just closes a sync.WaitGroup, then wrap the wait in a select with time.After. If the goroutine never returns, the test fails quickly instead of hanging your CI.&lt;/p&gt;

&lt;p&gt;Your function fires a goroutine — maybe it pushes to Kafka or hits an API. In a test you don’t care about the payload; you care that the goroutine actually ran. And if it deadlocks, you want to know fast.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;package main

import (
    &quot;sync&quot;
    &quot;testing&quot;
    &quot;time&quot;
)

type Actor interface {
    Perform()
}

func Cinema(a Actor) {
    go a.Perform()
}

type mockActor struct{ wg *sync.WaitGroup }

func (m mockActor) Perform() {
    m.wg.Done()
}

func TestCinema(t *testing.T) {
    var wg sync.WaitGroup
    wg.Add(1)

    Cinema(mockActor{wg: &amp;amp;wg})

    done := make(chan struct{})
    go func() {
        defer close(done)
        wg.Wait()
    }()

    select {
    case &amp;lt;-done:
    case &amp;lt;-time.After(500 * time.Millisecond):
        t.Fatalf(&quot;timeout: Perform did not finish in 500 ms&quot;)
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What’s happening&lt;/p&gt;

&lt;p&gt;Bump the WaitGroup, call the code under test.&lt;/p&gt;

&lt;p&gt;The mock fires inside the goroutine and calls wg.Done()—proof the path was hit.&lt;/p&gt;

&lt;p&gt;A helper goroutine converts wg.Wait() into a channel you can watch in a select.&lt;/p&gt;

&lt;p&gt;If the deadline expires first, the test explodes instead of blocking your pipeline.&lt;/p&gt;

&lt;p&gt;For quick unit tests, this WaitGroup-plus-timeout trick hits the sweet spot.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Distributing Elixir applications with Burrito</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2023-08-20T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2023/08/20/distributing-elixir-applications-with-burrito</id>
    <content type="html">&lt;p&gt;In this post, I will demonstrate how to use Burrito to create a self-extracting archive for an Elixir project, to use it across varied environments (Windows, MacOS, or Linux). This post is a small complement to the previous post &lt;a href=&quot;https://juanpabloaj.com/2023/08/19/elixir-and-sqlite3/&quot;&gt;Elixir and Ecto with SQLite3&lt;/a&gt;, which was about how to use SQLite3 with Elixir and Ecto.&lt;/p&gt;

&lt;p&gt;This test was made in a clean Debian virtual machine (aarch64), the objective is to create a binary for use in Ubuntu (x86_64) where Erlang and Elixir are not available and I don’t have root permissions.&lt;/p&gt;

&lt;p&gt;Burrito’s dependencies include XZ, 7zip, and Zig (version 0.10.0). You can install XZ and 7zip with the package manager. Since Zig wasn’t available in the package manager, you can obtain it from the &lt;a href=&quot;https://ziglang.org/learn/getting-started/&quot;&gt;Zig’s Getting Started page&lt;/a&gt;, there, you’ll find instructions on how to install it. Simply download the tar file, uncompress it, and you’ll have Zig’s binary available for use. Please note that, Burrito is compatible with Zig version 0.10.0. During my initial tests, I downloaded the latest version of Zig, but found that Burrito wasn’t compatible with it.&lt;/p&gt;

&lt;p&gt;You can read more about Burrito in &lt;a href=&quot;https://github.com/burrito-elixir/burrito&quot;&gt;its repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I took the code from the &lt;a href=&quot;https://juanpabloaj.com/2023/08/19/elixir-and-sqlite3/&quot;&gt;previous post&lt;/a&gt;, I added Burrito to the dependencies&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# mix.exs
defp deps do
[
    {:burrito, github: &quot;burrito-elixir/burrito&quot;}
]
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From Burrito’s documentation, I copied this function&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# mix.exs
def releases do
[
  data_collector: [
    steps: [:assemble, &amp;amp;Burrito.wrap/1],
    burrito: [
      targets: [
        linux: [os: :linux, cpu: :x86_64]
      ]
    ]
  ]
]
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mix.exs&lt;/code&gt;, I added this line to the project function&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# mix.exs
def project do
[
  ...
  releases: releases()
]
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;These are all the modifications related to Burrito. However, in my scenario, I needed to migrate the database before starting the application. In the previous post, I had done the migrations manually as a release command&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ DATABASE_PATH=/tmp/data_collector_prod.db _build/prod/rel/data_collector/bin/data_collector eval &quot;DataCollector.Release.migrate&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this case, I preferred to call the migrations automatically, so I called the migration function before starting the Supervisor (I am not sure if it is the best way to call the migrations automatically at the beginning).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#lib/data_collector/application.ex
@impl true
def start(_type, _args) do
    DataCollector.Release.migrate()

    children = [
    ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I called Burrito with the release command&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ MIX_ENV=prod mix release
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Burrito created the directory &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;burrito_out&lt;/code&gt; with the binary called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data_collector_linux&lt;/code&gt; inside&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ls burrito_out/
data_collector_linux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using ssh, I moved the binary to the other machine with Ubuntu. There, I executed the binary, the migrations were applied, and the application started.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ DATABASE_PATH=/tmp/data_collector_prod.db ./data_collector_linux
00:50:55.830 [info] == Running 20230819231423 DataCollector.Repo.Migrations.CreateInstruments.change/0 forward
00:50:55.839 [info] create table instruments
00:50:55.844 [info] == Migrated 20230819231423 in 0.0s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After a few seconds, the database had values&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sqlite3 /tmp/data_collector_prod.db
SQLite version 3.39.3 2022-09-05 11:02:23
sqlite&amp;gt; select * from instruments;
1|instrument_374|7|2023-08-21T00:50:56|2023-08-21T00:50:56
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As a side note, while writing this post, I recalled a somewhat related article I wrote in Spanish 9 years ago on &lt;a href=&quot;https://juanpabloaj.com/2014/09/19/empaquetando-y-distribuyendo-con-pex/&quot;&gt;how to create a self-contained Python executable&lt;/a&gt;. How time flies!&lt;/p&gt;

&lt;p&gt;I hope you find this post useful. If you have any suggestions or feedback on the post, please feel free to reach out to me.&lt;/p&gt;

&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/burrito-elixir/burrito&quot;&gt;Burrito repository&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://juanpabloaj.com/2023/08/19/elixir-and-sqlite3/&quot;&gt;Elixir and Ecto with SQLite3&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ziglang.org/learn/getting-started/&quot;&gt;Zig - Getting Started&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://juanpabloaj.com/2014/09/19/empaquetando-y-distribuyendo-con-pex/&quot;&gt;Empaquetando y distribuyendo código python con pex&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>Elixir and Ecto with SQLite3</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2023-08-19T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2023/08/19/elixir-and-sqlite3</id>
    <content type="html">&lt;p&gt;There have been instances where I required data persistence with an Elixir application although I don’t want to start a PostgreSQL instance. For small applications or tasks, SQLite3 sounds like a good alternative, especially if you are running the app on a small machine.&lt;/p&gt;

&lt;p&gt;In this post, I’m going to show how to use Elixir and Ecto with SQLite3. This is strongly based on &lt;a href=&quot;https://fly.io/docs/elixir/advanced-guides/sqlite3/&quot;&gt;an article from fly.io&lt;/a&gt; although that article is oriented to Phoenix, I’m going to focus on creating a small Elixir project. The project will have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GenServer&lt;/code&gt; that writes a random value every second into the SQLite database.&lt;/p&gt;

&lt;p&gt;I will be using Elixir version 1.15.2 and Erlang version 26.0.2.&lt;/p&gt;

&lt;p&gt;First, create the project’s directory with a supervisor.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mix new data_collector --sup
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ecto_sqlite3&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mix.exs&lt;/code&gt;, you can find more details in its &lt;a href=&quot;https://github.com/elixir-sqlite/ecto_sqlite3&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   defp deps do
 [
  {:ecto_sqlite3, &quot;~&amp;gt; 0.10&quot;}
    ...
 ]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Fetch the dependencies&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mix deps.get
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lib/data_collector/ecto.ex&lt;/code&gt; with&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;defmodule DataCollector.Repo do
    use Ecto.Repo, otp_app: :data_collector, adapter: Ecto.Adapters.SQLite3
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config/config.exs&lt;/code&gt; with&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;import Config

config :data_collector,
  ecto_repos: [DataCollector.Repo]

config :data_collector, DataCollector.Repo,
  database: Path.expand(&quot;../data_collector_#{Mix.env()}.db&quot;, Path.dirname(__ENV__.file)),
  pool_size: 5
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a schema &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lib/data_collector/instrument.ex&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;defmodule DataCollector.Instrument do
  use Ecto.Schema
  import Ecto.Changeset

  schema &quot;instruments&quot; do
    field(:name, :string)
    field(:measurement, :integer)

    timestamps()
  end

  def changeset(instrument, params \\ %{}) do
    instrument
    |&amp;gt; cast(params, [:name, :measurement])
    |&amp;gt; validate_required([:name, :measurement])
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And a migration&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mix ecto.gen.migration create_instruments

# priv/repo/migrations/2023MMDD_create_instruments.exs
defmodule DataCollector.Repo.Migrations.CreateInstruments do
  use Ecto.Migration

  def change do
    create table(:instruments) do
      add(:name, :string)
      add(:measurement, :integer)

      timestamps()
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create the database and apply the migrations&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mix ecto.create
$ mix ecto.migrate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After that, you should see a file called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data_collector_dev.db&lt;/code&gt;, If you open it with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sqlite3&lt;/code&gt;, you should see the table &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;instruments&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sqlite3 data_collector_dev.db
sqlite&amp;gt; .tables
instruments         schema_migrations
sqlite&amp;gt; .schema instruments
CREATE TABLE IF NOT EXISTS &quot;instruments&quot; (&quot;id&quot; INTEGER PRIMARY KEY AUTOINCREMENT, &quot;name&quot; TEXT, &quot;measurement&quot; INTEGER, &quot;inserted_at&quot; TEXT NOT NULL, &quot;updated_at&quot; TEXT NOT NULL);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GenServer&lt;/code&gt; to insert data every second into the database&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# lib/data_collector/worker.ex
defmodule DataCollector.Worker do
  use GenServer

  alias DataCollector.{Instrument, Repo}

  def start_link(_opts) do
    GenServer.start_link(__MODULE__, nil, name: __MODULE__)
  end

  def init(_opts) do
    Process.send_after(self(), :work, 1000)
    {:ok, nil}
  end

  def handle_info(:work, state) do
    data = %{
      name: &quot;instrument_#{Enum.random(1..1000)}&quot;,
      measurement: Enum.random(1..100)
    }

    %Instrument{}
    |&amp;gt; Instrument.changeset(data)
    |&amp;gt; Repo.insert()

    Process.send_after(self(), :work, 1000)
    {:noreply, state}
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Add Repo and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GenServer&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lib/data_collector/application.ex&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;children = [
  {DataCollector.Repo, []},
  DataCollector.Worker
]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Start the processes, in the logs you should see the inserts into the database&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mix run --no-halt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you check the database, you should see the values inserted by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GenServer&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sqlite3 data_collector_dev.db
sqlite&amp;gt; select * from instruments limit 2;
1|instrument_547|30|2023-08-19T23:43:07|2023-08-19T23:43:07
2|instrument_334|86|2023-08-19T23:43:08|2023-08-19T23:43:08
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At this point, the tutorial could be complete although I will add how to create the release, if you are not interested in how to create a release you can stop here.&lt;/p&gt;

&lt;p&gt;Now, let’s modify the content of config/config.exs to the following.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# config/config.exs
import Config

# Configures Elixir&apos;s Logger
config :logger, :console,
  format: &quot;$time $metadata[$level] $message\n&quot;,
  metadata: [:request_id]

config :data_collector,
  ecto_repos: [DataCollector.Repo]

import_config &quot;#{config_env()}.exs&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And add these three new config files:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# config/dev.exs
import Config

config :data_collector, DataCollector.Repo,
  database: Path.expand(&quot;../data_collector_dev.db&quot;, Path.dirname(__ENV__.file)),
  pool_size: 5


# config/prod.exs
import Config

# Do not print debug messages in production
config :logger, level: :info


# config/runtime.exs
import Config

if config_env() == :prod do
  database_path =
    System.get_env(&quot;DATABASE_PATH&quot;) ||
      raise &quot;&quot;&quot;
      DATABASE_PATH environment variable is missing.
      For example: /data/name/name.db
      &quot;&quot;&quot;

  config :data_collector, DataCollector.Repo,
    database: database_path,
    pool_size: String.to_integer(System.get_env(&quot;POOL_SIZE&quot;) || &quot;10&quot;)
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a release file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lib/data_collector/release.ex&lt;/code&gt; with functions related to the migration, you can find more details in this &lt;a href=&quot;https://fly.io/phoenix-files/how-to-migrate-mix-release-projects/&quot;&gt;fly.io post&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;defmodule DataCollector.Release do
  @app :data_collector

  def migrate do
    for repo &amp;lt;- repos() do
      {:ok, _, _} =
        Ecto.Migrator.with_repo(
          repo,
          &amp;amp;Ecto.Migrator.run(&amp;amp;1, :up, all: true)
        )
    end
  end

  def rollback(repo, version) do
    {:ok, _, _} =
      Ecto.Migrator.with_repo(
        repo,
        &amp;amp;Ecto.Migrator.run(&amp;amp;1, :down, to: version)
      )
  end

  defp repos do
    Application.load(@app)
    Application.fetch_env!(@app, :ecto_repos)
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now you can create the release, apply the migration over it, and start it.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ MIX_ENV=prod mix release
$ DATABASE_PATH=/tmp/data_collector_prod.db _build/prod/rel/data_collector/bin/data_collector eval &quot;DataCollector.Release.migrate&quot;

$ DATABASE_PATH=/tmp/data_collector_prod.db _build/prod/rel/data_collector/bin/data_collector start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you check the release’s database, you should see the values inserted by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GenServer&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sqlite3 /tmp/data_collector_prod.db
sqlite&amp;gt; select * from instruments limit 1;
1|instrument_751|90|2023-08-20T00:58:26|2023-08-20T00:58:26
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That concludes the tutorial.&lt;/p&gt;

&lt;p&gt;I hope this post can be useful for you. If you have any suggestions or feedback on the post, please feel free to reach out to me.&lt;/p&gt;

&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://fly.io/docs/elixir/advanced-guides/sqlite3/&quot;&gt;Fly.io Advanced Guides for SQLite3&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/elixir-sqlite/ecto_sqlite3&quot;&gt;Ecto SQLite3 on GitHub&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://fly.io/phoenix-files/how-to-migrate-mix-release-projects/&quot;&gt;How to Migrate Mix Release Projects on Fly.io&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://elixir-lang.org/getting-started/mix-otp/config-and-releases.html&quot;&gt;Elixir Getting Started with Mix OTP, Config and Releases&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hexdocs.pm/phoenix/releases.html#ecto-migrations-and-custom-commands&quot;&gt;Phoenix Ecto Migrations and Custom Commands&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>Distribuir variables con consul/envconsul</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2019-02-01T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2019/02/01/distribuir-variables-con-envconsul</id>
    <content type="html">&lt;p&gt;El siguiente ejemplo pretende mostrar como almacenar variables en consul y mediates envconsul utilizarlas como variables de ambiente en un servicio. Se realizará utilizando contenedores docker, el código fuente se encuentra disponible en el repositorio &lt;a href=&quot;https://github.com/juanpabloaj/envconsul_with_a_service&quot;&gt;envconsul with a service&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Levantar consul, usando el docker-compose de &lt;a href=&quot;https://github.com/juanpabloaj/envconsul_with_a_service/blob/master/docker-compose.yaml&quot;&gt;este enlace&lt;/a&gt; y el comando&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Crear una variable llamada &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max_conns&lt;/code&gt; de valor 10 y prefijo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hello-app&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker-compose exec consul-server-bootstrap consul kv put hello-app/max_conns 10
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Levantar el servicio con el docker-compose &lt;a href=&quot;https://github.com/juanpabloaj/envconsul_with_a_service/blob/master/docker-compose-services.yaml&quot;&gt;del siguiente enlace&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker-compose -f docker-compose-services.yaml build
docker-compose -f docker-compose-services.yaml up -d
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/juanpabloaj/envconsul_with_a_service/blob/master/hello.py&quot;&gt;El servicio&lt;/a&gt; está desarrollado con python/flask, cada vez que recibe una consulta retorna el valor de la variable de entorno &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max_conns&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# -*- coding: utf-8 -*-
import os
from flask import Flask
from flask import jsonify
app = Flask(__name__)

@app.route(&quot;/&quot;)
def hello():
    return jsonify(value=os.environ[&apos;max_conns&apos;])

if __name__ == &apos;__main__&apos;:
   app.run(host=&apos;0.0.0.0&apos;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;El servicio se ejecuta en un &lt;a href=&quot;https://github.com/juanpabloaj/envconsul_with_a_service/blob/master/Dockerfile&quot;&gt;contener docker&lt;/a&gt;, es iniciado y mantenido en ejecución por envconsul, el cual obtiene las variables desde consul y las disponibiliza como variables de entorno. Si una variable es actualizada, envconsul reinicia el servicio.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;CMD envconsul \
    -consul-addr &quot;consul-server-bootstrap:8500&quot; \
    -prefix hello-app \
    python hello.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Consultar al servicio&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl localhost:5000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Para obtener el valor definido anteriormente&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{&quot;value&quot;:&quot;10&quot;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Actualizar el valor de la variable&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker-compose exec consul-server-bootstrap consul kv put hello-app/max_conns 20
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Volvemos a invocar el servicio&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl localhost:5000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finalmente obtenemos el último valor asignado a la variable&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{&quot;value&quot;:&quot;20&quot;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

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

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/juanpabloaj/envconsul_with_a_service&quot;&gt;envconsul with a service&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;https://github.com/hashicorp/envconsul&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>Phoenix, cambiando nivel de log de una aplicación en ejecución</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2018-11-03T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2018/11/03/cambiando-nivel-de-log-de-phoenix</id>
    <content type="html">&lt;p&gt;Para cambiar el nivel de log sin reiniciar la aplicación.&lt;/p&gt;

&lt;p&gt;Iniciar Phoenix con elixir y agregar el argumento &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sname&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;elixir --sname myapp -S mix phx.server
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Conectar a Phoenix with a terminal remota &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;remsh&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;iex --sname baz --remsh myapp@${HOSTNAME}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Cambiar el nivel del log de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Logger&lt;/code&gt; y del &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;backend&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;iex(myapp@ecb1011caa1e)6&amp;gt; Logger.configure(level: :debug)
:ok
iex(myapp@ecb1011caa1e)5&amp;gt; Logger.configure_backend(:console, [level: :debug])
:ok
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Desde ahora el nivel de log está en debug&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;15:21:07.521 [debug]...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;https://christopherjmcclellan.wordpress.com/2018/06/02/how-to-change-elixir-log-levels-for-a-running-application/&lt;/li&gt;
  &lt;li&gt;https://hexdocs.pm/iex/IEx.html&lt;/li&gt;
  &lt;li&gt;https://hexdocs.pm/logger/Logger.html&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>Usando el git hook commit-msg con las id de issue</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2018-10-30T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2018/10/30/hook-commit-msg-e-issues</id>
    <content type="html">&lt;p&gt;Hace algún tiempo escribí un post sobre &lt;a href=&quot;/2013/07/24/Automatizando-tareas-con-githooks/&quot;&gt;los hook de git y su utilidad para automatizar tareas&lt;/a&gt;, hoy quiero mostrar un ejemplo que he estado usando los últimos días, el hook &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;commit-msg&lt;/code&gt; para no olvidar agregar el id de issue en los commits.&lt;/p&gt;

&lt;p&gt;Si utilizas github/gitlab y su sistema de issues, es una buena práctica asociar los commits a issues.&lt;/p&gt;

&lt;p&gt;Si eres como yo probablemente muchas veces has olvidado agregar el id del issue en el commit, bueno para eso puedes usar el hook &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;commit-msg&lt;/code&gt;, el cual se activa después que el mensaje de commit es generado y antes que el commit es agregado. (más detalles en &lt;a href=&quot;https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks&quot;&gt;Customizing Git - Git Hooks&lt;/a&gt;), con algo como esto&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#!/bin/bash

MSG=&quot;$1&quot;

if ! egrep -qE &quot;#[0-9]+&quot; &quot;$MSG&quot;;then
    cat &quot;$MSG&quot;
    echo &quot;Your commit message must contain some issue reference &apos;#...&apos;&quot;
    exit 1
fi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;https://gist.github.com/juanpabloaj/fe7b8203ed967488d22c004c13846cfa&lt;/p&gt;

&lt;p&gt;Y cuando no quieras que el hook sea activado usa la opción&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git commit --no-verify
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Algunas ventajas de agregar los id en cada commit son cosas como: cuando vayas a crear un nuevo tag puedes saber cuantas issues agregaste desde el último tag (donde 1.0.1 representa el último tag creado), y revisar en github/gitlab el detalle de los issues.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git log --oneline 1.0.1..HEAD | grep \# | sed &apos;s/.*\(\#[0-9]*\).*/\1/&apos; | sort | uniq -c
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
  </entry>
  
  <entry>
    <title>Phoenix y Plug.RequestId</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2018-10-18T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2018/10/18/phoenix-y-plug-requestid</id>
    <content type="html">&lt;p&gt;Para que cada request tenga un id único y sea mostrado en el log&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Crear proyecto&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; mix phx.new  --no-ecto request
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Agregar al archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lib/request_web/endpoint.ex&lt;/code&gt;&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; plug Plug.RequestId
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Editar el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config/dev.exs&lt;/code&gt; para mostrar el id del request en el log&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; config :logger, :console,
   format: &quot;[$level] $metadata$message\n&quot;,
   metadata: [:request_id]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Con esto, por cada request se debería obtener una linea de log similar a&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[info] request_id=2lfdtb54lt7i3bdppk0000fh GET /
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Si en el request se envía el header &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x-request-id&lt;/code&gt; con un valor entre 20 y 200 caracteres, este se mantiene.&lt;/p&gt;

&lt;p&gt;Con&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl -H &quot;x-request-id: 12345678901234567890&quot; http://localhost:4000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Se registra en el log&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[info] request_id=12345678901234567890 GET /
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Más información en&lt;/p&gt;

&lt;p&gt;https://hexdocs.pm/plug/Plug.RequestId.html&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Compilando gcc/g++ sin permiso root</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2016-11-16T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2016/11/16/compilando-gcc-sin-permiso-root</id>
    <content type="html">&lt;p&gt;En un servidor necesitaba una versión de g++ más actual y no tenía permisos de root, por lo que tuve que compilar el compilador manualmente. En este post voy a describir los pasos que realicé.&lt;/p&gt;

&lt;p&gt;Si bien lo que me interesa es instalar g++, en lo que sigue voy a hablar de gcc ya que ese es el nombre del paquete que voy a instalar.&lt;/p&gt;

&lt;p&gt;Primero instalar &lt;a href=&quot;http://zlib.net/&quot;&gt;zlib&lt;/a&gt;, una de las dependencias de gcc.&lt;/p&gt;

&lt;p&gt;Descargar, compilar e instalar zlib&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;wget https://github.com/madler/zlib/archive/v1.2.7.tar.gz
mv v1.2.7 zlib-1.2.7.tar.gz
tar xvfz zlib-1.2.7.tar.gz
cd zlib-1.2.7
./configure --prefix=$HOME/opt
make
make install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Agregar la ubicación de zlib a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LD_LIBRARY_PATH&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.bashrc&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/opt/lib
export LD_LIBRARY_PATH
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Recargar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.bashrc&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;source ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ahora gcc, descargar &lt;a href=&quot;https://www.gnu.org/software/gsrc/&quot;&gt;gsrc&lt;/a&gt;, código fuente de varios paquetes gnu&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;wget http://ftp.gnu.org/gnu/gsrc/gsrc-2014.10.11.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Seguir las instrucciones del sitio de &lt;a href=&quot;https://www.gnu.org/software/gsrc/&quot;&gt;gsrc&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd gsrc
./bootstrap
./configure --prefix=$HOME/gnu
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Compilar lo gcc/g++&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;make -C gnu/gcc
make -C gnu/gcc install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Agregar la ubicación de gcc al &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATH&lt;/code&gt; y de librerías a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LD_LIBRARY_PATH&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PATH=$HOME/gnu/bin:$PATH
LD_LIBRARY_PATH=$HOME/gnu/lib:$HOME/gnu/lib64:$HOME/opt/lib:$LD_LIBRARY_PATH

export PATH
export LD_LIBRARY_PATH
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Recargar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.bashrc&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;source ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Con los pasos anteriores debería estar disponible para utilizar g++.&lt;/p&gt;

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

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/gsrc/&quot;&gt;gsrc&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://zlib.net/&quot;&gt;zlib&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>Python y algunos métodos especiales de clase</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2016-08-06T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2016/08/06/Algunos-metodos-especiales-de-clase</id>
    <content type="html">&lt;p&gt;Este post es para las personas que están comenzando a utilizar clases en python, es un poco más que lo básico, voy a mostrar algunos ejemplos de métodos especiales de clase como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__str__&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__call__&lt;/code&gt;. Los ejemplos están probados con python 3.5.&lt;/p&gt;

&lt;h3 id=&quot;__-str-__&quot;&gt;__ str __&lt;/h3&gt;

&lt;p&gt;Primero creemos una clase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Animal&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class Animal:
    def __init__(self, nombre):
        self.nombre = nombre
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y un objeto de la clase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Animal&lt;/code&gt; llamado &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;perro&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; perro = Animal(&apos;bobby&apos;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Para mostrar el contenido del atributo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nombre&lt;/code&gt;, es necesario llamarlo directamente&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; print(perro.nombre)
bobby
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Si usamos print sobre el objeto veríamos algo como&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; print(perro)
&amp;lt;__main__.Animal object at 0x1053fab38&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Cambiemos el mensaje que muestra el objeto al usar print, agregando el método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__str__&lt;/code&gt; a la clase&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class Animal:
    def __init__(self, nombre):
        self.nombre = nombre
    def __str__(self):
        return nombre
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ahora al usar print&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; perro = Animal(&apos;bobby&apos;)
&amp;gt;&amp;gt;&amp;gt; print(perro)
bobby
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;__-call-__&quot;&gt;__ call __&lt;/h3&gt;

&lt;p&gt;Para interactuar con un objeto podemos crear métodos, por ejemplo, uno llamado &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hablar&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class Animal:
    def __init__(self, nombre):
        self.nombre = nombre
    def __str__(self):
        return nombre
    def hablar(self, mensaje):
        return &apos;Hola, mi nombre es {}, {}&apos;.format(self.nombre, mensaje)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ahora puedo llamar el método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hablar&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; perro = Animal(&apos;bobby&apos;)

&amp;gt;&amp;gt;&amp;gt; perro.hablar(&apos;mucho gusto!&apos;)
&apos;Hola, mi nombre es bobby, mucho gusto!&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Pero si intento llamar directamente al objeto (notar los “()” después del nombre del objeto)&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; print(perro())
Traceback (most recent call last):
  File &quot;&amp;lt;stdin&amp;gt;&quot;, line 1, in &amp;lt;module&amp;gt;
  TypeError: &apos;Animal&apos; object is not callable
  &apos;Animal&apos; object is not callable
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Obtengo ese mensaje, no puedo llamar directamente al objeto de la clase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Animal&lt;/code&gt;, para esto es necesario agregar el método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__call__&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class Animal:
    def __init__(self, nombre):
        self.nombre = nombre
        self.llamados = 0
    def __str__(self):
        return nombre
    def hablar(self, mensaje):
        return &apos;Hola, mi nombre es {}, {}&apos;.format(self.nombre, mensaje)
    def __call__(self):
        self.llamados +=1
        return self.hablar(&apos;he sido llamado {} veces.&apos;.format(self.llamados))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Con esto cada vez el que objeto sea llamado retornará un mensaje e incrementará un atributo.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; perro = Animal(&apos;bobby&apos;)

&amp;gt;&amp;gt;&amp;gt; print(perro())
Hola, mi nombre es bobby, he sido llamado 1 veces.

&amp;gt;&amp;gt;&amp;gt; print(perro())
Hola, mi nombre es bobby, he sido llamado 2 veces.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Espero que estos ejemplos ayuden a crear formas más fáciles de interactuar con los objetos de tus clases.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Bittorrent en el navegador con webtorrent</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2015-12-08T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2015/12/08/bittorrent-en-el-navegador-con-webtorrent</id>
    <content type="html">&lt;p&gt;En este post pretendo mostrar un ejemplo simple de como utilizar el protocolo Bittorrent en el navegador utilizando &lt;a href=&quot;https://github.com/feross/webtorrent&quot;&gt;webtorrent&lt;/a&gt;. Prefiero omitir la explicación de conceptos como seed o leechers utilizados en Bittorrent, esos detalles se pueden leer el &lt;a href=&quot;https://en.wikipedia.org/wiki/BitTorrent&quot;&gt;wikipedia&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;La base de los siguientes ejemplos son del &lt;a href=&quot;https://webtorrent.io/intro&quot;&gt;get started de webtorrent&lt;/a&gt;, solo intento mostrar un poco más de detalle en cada paso.&lt;/p&gt;

&lt;p&gt;Para utiliza los ejemplos es necesario disponer de &lt;a href=&quot;https://nodejs.org/&quot;&gt;nodejs&lt;/a&gt; y algunas otras utilidades como &lt;a href=&quot;http://browserify.org/&quot;&gt;browserify&lt;/a&gt; y &lt;a href=&quot;http://www.browsersync.io/&quot;&gt;browser-sync&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;seed&quot;&gt;Seed&lt;/h3&gt;

&lt;p&gt;El ejemplo será una página la cual al arrastrar un archivo sobre ella comenzara a hacer de seed.&lt;/p&gt;

&lt;p&gt;Además de webtorrent, para poder arrastrar archivos sobre la página se necesita drag-drop&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm install webtorrent drag-drop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Para que el seed sirva el contenido creamos el archivo javascript&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// browser-seed.js
var dragDrop = require(&apos;drag-drop&apos;)
var WebTorrent = require(&apos;webtorrent&apos;)

var client = new WebTorrent()
console.log(&apos;webtorrent created&apos;)

// When user drops files on the browser, create a new torrent and start seeding it!
dragDrop(&apos;body&apos;, function (files) {
  client.seed(files, function (torrent) {
    console.log(&apos;Client is seeding &apos; + torrent.infoHash)
    console.log(torrent.magnetURI)
  })
})
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;En las últimas lineas se envía a consola en hash del torrent y la &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;magnetURI&lt;/code&gt;, esta última deberemos usarla en el leecher, es la dirección con la cual el leecher sabe que descargar.&lt;/p&gt;

&lt;p&gt;Para utilizar el archivo javascript desde el navegador es necesario instalar &lt;a href=&quot;http://browserify.org/&quot;&gt;browserify&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm install -g browserify
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y ejecutar&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;browserify browser-seed.js -o js/browser-seed.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ahora podemos llamar a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;js/browser-seed.js&lt;/code&gt; desde &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.html&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;utf-8&quot;&amp;gt;
    &amp;lt;title&amp;gt;&amp;lt;/title&amp;gt;
    &amp;lt;style media=&quot;screen&quot;&amp;gt;
      body {
        height: 600px;
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;script src=&quot;js/browser-seed.js&quot; charset=&quot;utf-8&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Como servidor del archivo html voy a usar &lt;a href=&quot;http://www.browsersync.io/&quot;&gt;browser-sync&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;browser-sync start --server --files=&apos;*.html,*.js&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Con la página funcionando solo falta arrastrar un archivo sobre ella, para lo cual creé un archivo llamado &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fecha.txt&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;date &amp;gt; fecha.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Después de arrastrar el archivo, en la consola del navegador se debería ver algo como&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;webtorrent created
Client is seeding 0d12d731c700a28fb80bb9e90e5baa3829ec7db6
magnet:?xt=urn:btih:0d12d731c700a28fb80bb9e90e5baa3829ec7db6&amp;amp;dn=fecha.txt&amp;amp;tr=wss%3A%2F%2Ftracker.webtorrent.io
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Lo cual indica que el seed está arriba. La última linea es la magnetURI a utilizar en el leecher.&lt;/p&gt;

&lt;h3 id=&quot;leecher&quot;&gt;Leecher&lt;/h3&gt;

&lt;p&gt;Para el leecher, el que se encarga de la descarga, en un directorio diferente al seed creamos el archivo javascript&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// client.js
var client = new WebTorrent()

var torrentId = &apos;magnet:?xt=urn:btih:0d12d731c700a28fb80bb9e90e5baa3829ec7db6&amp;amp;dn=fecha.txt&amp;amp;tr=wss%3A%2F%2Ftracker.webtorrent.io&apos;

client.add(torrentId, function (torrent) {

  console.log(torrent)
  // Torrents can contain many files. Let&apos;s use the first.
  var file = torrent.files[0]

  file.appendTo(&apos;body&apos;)
})
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y el respectivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.html&lt;/code&gt;, en este caso no usé webtorrent con browserify, sino lo cargué directamente desde un &lt;a href=&quot;https://en.wikipedia.org/wiki/Content_delivery_network&quot;&gt;CDN&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;utf-8&quot;&amp;gt;
    &amp;lt;title&amp;gt;&amp;lt;/title&amp;gt;
    &amp;lt;script src=&quot;https://cdn.jsdelivr.net/webtorrent/latest/webtorrent.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;

    &amp;lt;script src=&quot;client.js&quot; charset=&quot;utf-8&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Al abrir este archivo html en el navegador, debería comenzar a hacer la descarga desde el seed y cuando este completo presentar el contenido obtenido en el body, mostrando algo similar a la imagen siguiente&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://f.cl.ly/items/0K3p1a2M3k0k1D1G3R3R/index_html.png&quot; alt=&quot;leecher&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Con lo descrito en el post es posible, desde el navegador, servir y descargar contenido sobre el protocolo Bittorrent.&lt;/p&gt;

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

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/feross/webtorrent&quot;&gt;Webtorrent&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://webtorrent.io/intro&quot;&gt;Webtorrent - Get started&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>Testing sobre angularjs con karma</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2015-08-22T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2015/08/22/testing-sobre-angularjs-con-karma</id>
    <content type="html">&lt;p&gt;Angularjs es genial para desarrollar aplicaciones web rápidamente, pero antes que un proyecto se escape de nuestro entendimiento es necesario tomar medidas, una buena opción es mantenerlo cubierto con unit tests.&lt;/p&gt;

&lt;p&gt;He encontrado varios artículos del tema, pero pocos que comienzan desde cero, orientados al que nunca ha usado karma.&lt;/p&gt;

&lt;p&gt;En este articulo voy a mostrar como preparar el entorno de desarrollo para testear una factory de angularjs usando &lt;a href=&quot;http://karma-runner.github.io/&quot;&gt;karma&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;pre-requisitos&quot;&gt;Pre requisitos&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Tener instalados nodejs, npm y bower.&lt;/li&gt;
  &lt;li&gt;Algún conocimiento de &lt;a href=&quot;https://angularjs.org/&quot;&gt;Angularjs&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;angular-y-angular-mocks&quot;&gt;angular y angular-mocks&lt;/h3&gt;

&lt;p&gt;La instalación de angular la vamos realizar con bower. Primero, inicializar bower&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bower init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;E instalar angular&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bower install angular#1.4.4 --save-dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Para poder utilizar los test es necesario instalar angular-mocks&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bower install angular-mocks#1.4.4 --save-dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Es importante que el número de versión de angular-mocks sea el mismo que el de angular. Por eso forcé la versión con &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#1.4.4&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;código-angular&quot;&gt;Código angular&lt;/h3&gt;

&lt;p&gt;Como ejemplo voy a crear un factory de angular&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir js
touch js/services.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Con el siguiente contenido&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// js/services.js
angular.module(&apos;factories&apos;, [])
  .factory(&apos;Users&apos;, function(){
    var users = [];
    return {
        add: function(user){
          users.push(user);
        },
        all: function(){
            return users;
        }
    };
  });
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;instalación-de-karma&quot;&gt;Instalación de karma&lt;/h3&gt;

&lt;p&gt;Para poder utilizar karma, instalarla globalmente&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm install -g karma-cli
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Después, inicializar el archivo package.json y agregar karma como dependencia&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm init
npm install karma --save-dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;configuración-de-karma&quot;&gt;Configuración de karma&lt;/h3&gt;

&lt;p&gt;Inicializar karma&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;karma init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Karma preguntará por algunas preferencias a utilizar, como test framework, navegador, etc. Se puede seleccionar entre las opciones con la tecla &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tab&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Las que yo escogí:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt; jasmine

&amp;gt; no

&amp;gt; PhantomJS

&amp;gt; js/*.js
&amp;gt; test/*.js

&amp;gt;

&amp;gt; yes
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Dependiendo de lo anterior será instalado lo necesario, agregado al archivo package.json y creado un archivo llamado &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;karma.conf.js&lt;/code&gt; con nuestras preferencias.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://jasmine.github.io/2.3/introduction.html&quot;&gt;Jasmine&lt;/a&gt; es el test framework que vamos a utilizar. Prefiero PhantomJS, así todo se ejecuta en consola sin necesidad de lanzar chrome o firefox.&lt;/p&gt;

&lt;p&gt;Los expresiones &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;js/*.js&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test/*.js&lt;/code&gt; representan los archivos que debe cargar karma, estos son agregados en una lista en el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;karma.conf.js&lt;/code&gt;, en dicha lista se debe agregar la ubicación de angularjs y angular-mocks. Similar a&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;files: [
  &apos;bower_components/angular/angular.js&apos;,
  &apos;bower_components/angular-mocks/angular-mocks.js&apos;,
  &apos;js/*.js&apos;,
  &apos;test/*.js&apos;
],
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;creando-los-test-y-lanzando-karma&quot;&gt;Creando los test y lanzando karma&lt;/h3&gt;

&lt;p&gt;Ahora crear el directorio y archivos donde van a estar los tests.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir test
touch test/services.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;El archivo test/services.js debe tener el siguiente contenido&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;describe(&apos;Users&apos;, function(){

  beforeEach(module(&apos;factories&apos;));

  var users;

  beforeEach(inject(function(_Users_){
    users = _Users_;
  }));

  it(&apos;empty users length 0&apos;, function(){
    expect(users.all().length).toBe(0);
  });

  it(&apos;One user return length 1&apos;, function(){
    users.add({name:&apos;user name&apos;});

    expect(users.all().length).toBe(1);
  });
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Donde se carga el modulo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;factories&lt;/code&gt;, el factory &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Users&lt;/code&gt; y describen los tests.&lt;/p&gt;

&lt;p&gt;Finalmente lanzar los tests&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;karma start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Con lo cual se deberían ejecutar los tests y ver como los dos pasaron.&lt;/p&gt;

&lt;p&gt;Lo presentado es un primer ejemplo muy simple, para revisar más detalles sobre karma, dejo algunos enlaces más abajo.&lt;/p&gt;

&lt;p&gt;El código fuente descrito está disponible en el repositorio&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/juanpabloaj/simple-karma-test&quot;&gt;https://github.com/juanpabloaj/simple-karma-test&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/juanpabloaj/simple-karma-test&quot;&gt;simple-karma-test&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://karma-runner.github.io/&quot;&gt;karma&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.smashingmagazine.com/2014/10/introduction-to-unit-testing-in-angularjs/&quot;&gt;An Introduction To Unit Testing In AngularJS Applications&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.airpair.com/angularjs/posts/testing-angular-with-karma&quot;&gt;Testing AngularJS Apps Using Karma&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>Hooks para npm y bower</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2015-05-21T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2015/05/21/hooks-para-npm-y-bower</id>
    <content type="html">&lt;p&gt;Hace algún tiempo escribí un post sobre algunos hooks que tiene git y &lt;a href=&quot;http://juanpabloaj.com/2013/07/24/Automatizando-tareas-con-githooks/&quot;&gt;como es posible automatizar tareas con ellos&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;npm también dispone de &lt;a href=&quot;https://docs.npmjs.com/misc/scripts#examples&quot;&gt;algunos hooks&lt;/a&gt;, como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;preinstall&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postinstall&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Estos deben ser configurados en la sección &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts&lt;/code&gt; del archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
&quot;scripts&quot;: {
    &quot;postinstall&quot;: &quot;ejecutar un comando después de install&quot;
}
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Por ejemplo, si queremos que después de instalar las dependencia de node se instalen las de bower, podemos usar el hook &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postinstall&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;postinstal&quot;: &quot;bower install&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Con lo cual, después de ejecutar el comando&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Automáticamente se ejecutara&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bower install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Del mismo modo, tenemos los &lt;a href=&quot;https://github.com/bower/bower/blob/master/HOOKS.md&quot;&gt;hook de bower&lt;/a&gt;, Estos deben ser configurados en el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.bowerrc&lt;/code&gt;. Si queremos que después de la instalación de bower se copien algunos archivos desde &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bower_componets&lt;/code&gt; a otro directorio, podemos user el hook &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postinstall&lt;/code&gt; de bower&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
    &quot;scripts&quot;: {
        &quot;postinstall&quot;: &quot;cp bower_components/some-package/build/some-package.min.js public&quot;
    }
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Mucho de lo anteriormente descrito se puede hacer con &lt;a href=&quot;http://gruntjs.com/&quot;&gt;grunt&lt;/a&gt;/&lt;a href=&quot;http://gulpjs.com/&quot;&gt;gulp&lt;/a&gt;, pero en algunos casos, cuando queremos automatizar tareas simples es posible prescindir de grunt.&lt;/p&gt;

&lt;p&gt;Un post interesante sobre como crear scripts para npm es &lt;a href=&quot;http://blog.keithcirkel.co.uk/how-to-use-npm-as-a-build-tool/&quot;&gt;How to Use npm as a Build Tool de Keith Cirkel&lt;/a&gt;, donde describe como crear scripts para ejecutar con npm y como crear &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;post-&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pre-&lt;/code&gt; hook para ellos.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Probando paquetes en diferentes versiones de python con tox</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2015-02-12T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2015/02/12/probando-paquetes-con-tox</id>
    <content type="html">&lt;p&gt;Cuando creas un paquete para python y quieres testearlo sobre varias versiones, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python2.7&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python3.3&lt;/code&gt;, etc, es posible hacerlo creando manualmente varios entornos virtuales con virtualenv, uno para cada versión, o automatizar este proceso con tox.&lt;/p&gt;

&lt;p&gt;Para instalar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tox&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip install tox
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Para utilizarlo es necesario crear un archivo de configuración &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tox.ini&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[tox]
envlist = py26, py27
[testenv]
deps=nose
commands=nosetest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y lanzar tox&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tox
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;En el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tox.ini&lt;/code&gt; se especifican algunos paramétros como:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;envlist&lt;/code&gt; describe los entornos a utilizar. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tox&lt;/code&gt; interpreta &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;py26&lt;/code&gt; como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python2.6&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;py27&lt;/code&gt; como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python2.7&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deps&lt;/code&gt;, las dependencias a instalar en cada entorno.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;commands&lt;/code&gt; comandos a utilizar en cada entorno después de instalar las dependencias.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cada uno de los entornos creados es independiente entre ellos e independiente del entorno principal del sistema. Ellos son almacenados como entornos virtuales en un directorio llamado &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.tox&lt;/code&gt;, ubicado donde llamamos a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tox&lt;/code&gt;, son creados la primera vez que &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tox&lt;/code&gt; es ejecutado y reutilizados la siguientes veces, por lo que la primera vez puede tomar un par de segundos más que las siguientes.&lt;/p&gt;

&lt;p&gt;Normalmente, además de lanzar los test, me gusta verificar el code style, &lt;a href=&quot;https://www.python.org/dev/peps/pep-0008/&quot;&gt;PEP8&lt;/a&gt;, por que lo que en el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tox.ini&lt;/code&gt; agrego un entorno donde no se ejecutan los test, solo se instala y ejecuta &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;flake8&lt;/code&gt; para verificar el code style.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[tox]
envlist = flake8, py27, py34

[testenv]
deps=nose
commands=nosetest

[testenv:flake8]
deps = flake8
commands = flake8
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

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

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://tox.readthedocs.org/&quot;&gt;Documentación de tox&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.mediawiki.org/wiki/Continuous_integration/Tutorials/Test_your_python&quot;&gt;Continuous integration/Tutorials/Test your python&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://pypi.python.org/pypi/flake8&quot;&gt;flake8&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>Nodejs, express y Heroku</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2014-11-26T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2014/11/26/node-express-y-heroku</id>
    <content type="html">&lt;p&gt;Este post va dedicado a todos los que aun no han probado servicios para alojar aplicaciones, como Heroku, y a los que quieren comenzar con nodejs en producción.&lt;/p&gt;

&lt;p&gt;Cuando quieres levantar una aplicación tienes que considerar varios factores: programación, diseño, configuración del servidor, entre otras cosas.&lt;/p&gt;

&lt;p&gt;Puedes asumir toda esa carga o buscar apoyo en servicios ya existentes y enfocarte en lo central: desarrollar tu aplicación.&lt;/p&gt;

&lt;p&gt;En este post mostraré como crear una aplicación sencilla con nodejs que retorne un mensaje y como dejarla alojada en Heroku.&lt;/p&gt;

&lt;h2 id=&quot;pre-requisitos&quot;&gt;pre requisitos&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://nodejs.org/&quot;&gt;nodejs&lt;/a&gt; y su gestionador de paquetes &lt;a href=&quot;https://www.npmjs.org/&quot;&gt;npm&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Crear una cuenta en &lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Instalar la gema heroku: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem install heroku&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Tener algún conocimiento de git.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si no quieres dedicar mucho tiempo a instalaciones o modificar tu sistema para este ejemplo, puedes usar un entorno de desarrollo en la nube, como &lt;a href=&quot;https://www.nitrous.io/&quot;&gt;nitrous&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;comenzando-con-nodejs&quot;&gt;Comenzando con nodejs&lt;/h2&gt;

&lt;p&gt;Primero crearemos un archivo llamado &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt;, el cual almacenara información de tu aplicación, para facilitar la creación del mismo podemos usar el comando&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm&lt;/code&gt; preguntara algunas cosas como nombre de la aplicación, descripción, licencia, etc.&lt;/p&gt;

&lt;p&gt;Sobre nodejs utilizaremos &lt;a href=&quot;http://expressjs.com/&quot;&gt;express&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm install express --save
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;El argumento &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--save&lt;/code&gt; dejará registrado el paquete instalado como una dependencia, de esta forma, si compartes la aplicación, para instalar las dependencias bastará con usar el comando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Al ser una aplicación simple que retorna un mensaje, basta con un pequeño script&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// index.js
var express = require(&apos;express&apos;);
var app = express();

app.set(&apos;port&apos;, (process.env.PORT || 8080))

app.get(&apos;/&apos;, function(req, res){
  res.json({ mensaje: &apos;Un ejemplo de nodejs, express y Heroku&apos;});
});

app.listen(app.get(&apos;port&apos;));
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Como un detalle preferí que el mensaje fuera retornado en &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSON&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Verificamos que todo funcione como esperamos lanzando nuestra app&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;node index.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Deberíamos poder ver el resultado en&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;http://localhost:8080
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Si todo funciona bien hacemos un commit con nuestros archivos&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git add index.js package.json
git commit -m &quot;primer commit&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;subiendo-todo-a-heroku&quot;&gt;Subiendo todo a Heroku&lt;/h2&gt;

&lt;p&gt;Teniendo instalada la gema de Heroku, es necesario logearnos con nuestras credenciales&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;heroku login
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Al subir la aplicación, Heroku debe poder determinar como iniciarla, esto se específica creando el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Procfile&lt;/code&gt; con la siguiente linea&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;web: node index.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y lo agregamos al repositorio&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git add Procfile
git commit -m &quot;Procfile agregado&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sólo nos queda crear la app en heroku&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;heroku create
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Lo cual mostrará la url donde estará alojada nuestra app y agregará el remoto &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;heroku&lt;/code&gt; al repositorio local.&lt;/p&gt;

&lt;p&gt;Ahora podemos subir los cambios a Heroku&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git push heroku master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Cada vez que hagamos push a la rama master de Heroku, nuestros cambios serán publicados.&lt;/p&gt;

&lt;p&gt;Más detalles se pueden encontrar en el sitio de &lt;a href=&quot;https://devcenter.heroku.com/articles/getting-started-with-nodejs&quot;&gt;Getting started de Heroku&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Un buen tutorial para continuar es &lt;a href=&quot;http://scotch.io/tutorials/javascript/build-a-restful-api-using-node-and-express-4&quot;&gt;Build a RESTful API Using Node and Express 4&lt;/a&gt;.&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://scotch.io/tutorials/javascript/build-a-restful-api-using-node-and-express-4&quot;&gt;Build a RESTful API Using Node and Express 4&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://devcenter.heroku.com/articles/getting-started-with-nodejs&quot;&gt;Getting Started with Node.js on Heroku&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>Empaquetando y distribuyendo código python con pex</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2014-09-19T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2014/09/19/empaquetando-y-distribuyendo-con-pex</id>
    <content type="html">&lt;p&gt;Un archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.pex&lt;/code&gt; es un comprimido (zip) que nos permite ejecutar código python contenido en él, ofreciendo una alternativa para la distribución aplicaciones y dependencias. Más detalles en &lt;a href=&quot;https://pex.readthedocs.org/en/latest/whatispex.html#what-are-pex-files&quot;&gt;What are pex files&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En realidad, almacenar y ejecutar código python en un archivo comprimido no es algo nuevo, pero el paquete &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pex&lt;/code&gt; nos puede simplificar la tarea.&lt;/p&gt;

&lt;h3 id=&quot;instalar-pex&quot;&gt;Instalar pex&lt;/h3&gt;

&lt;p&gt;Lo primero, instalar pex&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip install pex
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;el-primer-pex-para-distribuir-librerías&quot;&gt;El primer .pex para distribuir librerías&lt;/h3&gt;

&lt;p&gt;Supongamos que necesito utilizar en varias maquinas un script llamado &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hello.py&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#!/usr/bin/python
# -*- coding: utf-8 -*-
import requests

def main():
    print &quot;hello with {}&quot;.format(requests.__name__)

if __name__ == &apos;__main__&apos;:
    main()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;El cual depende de la librería &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requests&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Si intento la ejecución y no tengo la librería instalada&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ python hello.py
Traceback (most recent call last):
  File &quot;hello.py&quot;, line 3, in &amp;lt;module&amp;gt;
    import requests
ImportError: No module named requests
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Obtengo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ImportError&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Construiremos un &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.pex&lt;/code&gt; que contenga lo necesario para ejecutar el &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hello.py&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pex -v -r request -o request.pex
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;El cual podemos utilizar con&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ./requests.pex hello.py
hello with requests
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Lo anterior se realizo sin la necesidad de instalar la librería, solo quedó almacenada en el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requests.pex&lt;/code&gt;, el cual puede ser enviado y reutilizado en otras máquinas.&lt;/p&gt;

&lt;h3 id=&quot;todo-lo-necesario-en-un-pex&quot;&gt;Todo lo necesario en un .pex&lt;/h3&gt;

&lt;p&gt;En el ejemplo anterior se almaceno la librería a utilizar en el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.pex&lt;/code&gt;, ahora me interesa incluir el script en el archivo de distribución.&lt;/p&gt;

&lt;p&gt;Para lo cual es necesario organizar nuestro código como un paquete de python, similar a uno de pip.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;simple/
├── setup.py
└── simple
    └── __init__.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Con un archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;simple/setup.py&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#!/usr/bin/python
# -*- coding: utf-8 -*-
from setuptools import setup

setup(
    name=&apos;simple&apos;,
    version=&apos;0.0.1&apos;,
    packages=[&apos;simple&apos;]
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y el script &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;simple/simple/__init__.py&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#!/usr/bin/python
# -*- coding: utf-8 -*-
import requests

def main():
    print &quot;hello with {}&quot;.format(requests.__name__)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Para construir el pex que contiene la librería requests y el script&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pex -v -r requests --no-wheel -s simple -e simple:main -o hello_requests.pex
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;El cual se puede usar con&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ./hello_requests.pex
hello with requests
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;El pex construido se puede distribuir y utilizar en otras maquinas sin necesidad de instalar las dependencias, ya que están auto contenidas en el archivo.&lt;/p&gt;

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

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://pex.readthedocs.org/&quot;&gt;Documentación de Pex&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://pex.readthedocs.org/en/latest/whatispex.html#what-are-pex-files&quot;&gt;What are pex files&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>Virtualenv y virtualenvwapper</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2014-08-03T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2014/08/03/Virtualenv-y-virtualenvwapper</id>
    <content type="html">&lt;p&gt;Para gestionar varios entornos creados por virtualenv, virtualenvwapper.&lt;/p&gt;

&lt;p&gt;Instalar virtualenv y virtualenvwapper (usar sudo de ser necesario).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip install virtualenv
pip install virtualenvwapper
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Crear directorio para almacenar la información de cada entorno virtual.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir ~/Envs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Agregar al archivo de configuración de bash, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.bashrc&lt;/code&gt;, la variable que almacena la ubicación de los entornos virtuales y la carga del script de virtualenvwapper&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;export WORKON_HOME=~/Envs
source /usr/local/bin/virtualenvwrapper.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;El directorio de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virtualenvwrapper.sh&lt;/code&gt; puede variar en algunos casos.&lt;/p&gt;

&lt;p&gt;Con lo anterior, al abrir una nueva terminal, se podrán crear entornos virtuales más fácilmente, con el comando&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkvirtualenv env1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y activar con&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;workon env1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;hooks&quot;&gt;hooks&lt;/h2&gt;

&lt;p&gt;Una característica interesante de virtualenvwapper son sus hooks, ganchos, son script que se ejecutan después de una acción.&lt;/p&gt;

&lt;p&gt;Por ejemplo, el hook &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postactivate&lt;/code&gt; será ejecutado después que un entorno sea activado, después de hacer &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;workon env1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Los hooks están almacenados en el directorio &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$WORKON_HOME&lt;/code&gt;.&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://virtualenvwrapper.readthedocs.org/&quot;&gt;virtualenvwapper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Deployment a openshift con codeship</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2014-07-23T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2014/07/23/Deployment-a-openshift-con-codeship</id>
    <content type="html">&lt;p&gt;En este post se explica como usar el deployment de codeship para enviar el código fuente disponible en un repositorio git a una app de openshift.&lt;/p&gt;

&lt;p&gt;Para los pasos siguientes se necesita disponer de :&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Una app en openshift y la dirección del repositorio git respectivo.&lt;/li&gt;
  &lt;li&gt;Un proyecto creado en codeship.&lt;/li&gt;
  &lt;li&gt;Un repositorio git alojado en bitbucket o github.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para que codeship pueda subir los cambios a la app en openshift, guardar la llave publica del proyecto de codeship en un archivo de texto, la cual se encuentra disponible en&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Project settings &amp;gt; General &amp;gt; SSH public key
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y agregar la llave publica de codeship a la app de openshift&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rhc sshkey add codeship llave_ssh_publica.pub
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Agregar al deployment script de codeship, ubicado en&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Project settings &amp;gt; deployment
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Las lineas para clonar nuestro repositorio y hacer push a openshift con los cambios actuales&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git remote add openshift repositorio_de_openshift_app
git push openshift master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Con esto, los cambios en la rama master serán enviados a la app de openshift.&lt;/p&gt;

&lt;p&gt;Podría pensarse que es más simple enviar directamente desde nuestro repositorio local al de openshift, pero al pasar por codeship nos aseguramos que antes se pasar a producción siempre sean lanzados los test, y si alguno falla, no sean subidos los nuevos cambios. Además de quedar registrados todos lo mensajes generados por openshift.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Lanzando tests de python con grunt</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2014-06-28T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2014/06/28/lanzando-tests-de-python-con-grunt</id>
    <content type="html">&lt;p&gt;En el ciclo de desarrollo: escribir un test que falla, modificar el código para que el test pase e iterar, hay tareas que se repiten, como lanzar los test después de hacer modificaciones.&lt;/p&gt;

&lt;p&gt;Llamar a los tests implica usar un comando como&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python -m unittest tests
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;O desde un &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setup.py&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python setup.py test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;En cualquiera de los dos casos anteriores es necesario pasar del editor a otra consola y ejecutar un comando cada vez que se realiza una modificación.&lt;/p&gt;

&lt;p&gt;Para facilitar el proceso descrito es preferible usar alguna herramienta que vigile los archivos modificados, y cuando corresponda, lance tareas establecidas.&lt;/p&gt;

&lt;p&gt;A continuación se presenta &lt;a href=&quot;http://gruntjs.com/&quot;&gt;grunt&lt;/a&gt;, una solución para el problema propuesto.&lt;/p&gt;

&lt;h3 id=&quot;instalando-grunt&quot;&gt;Instalando Grunt&lt;/h3&gt;

&lt;p&gt;Para instalar grunt globalmente (en todo el sistema) es necesario tener &lt;a href=&quot;http://nodejs.org/&quot;&gt;nodejs&lt;/a&gt; y su package manager &lt;a href=&quot;https://www.npmjs.org/&quot;&gt;npm&lt;/a&gt;. En mi caso fue fácil instalar nodejs, ya que estaba trabajado en una box de &lt;a href=&quot;https://www.nitrous.io/&quot;&gt;nitrous.io&lt;/a&gt;, bastó con &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parts install nodejs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Con npm, instalar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grunt-cli&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm install -g grunt-cli
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Crear un archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; con nombre de proyecto y versión, en el cual se registraran las dependencias&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// package.json
{
  &quot;name&quot;: &quot;pythontest&quot;,
  &quot;version&quot;: &quot;0.0.1&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;E instalar lo necesario para grunt en el proyecto&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm install grunt grunt-contrib-watch --save-dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;La opción &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--save-dev&lt;/code&gt; se encargará de registrar las dependencias en el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Después de las instalaciones el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; debería tener un contenido similar a&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// package.json
{
  &quot;name&quot;: &quot;pythontest&quot;,
  &quot;version&quot;: &quot;0.0.1&quot;,
  &quot;devDependencies&quot;: {
    &quot;grunt&quot;: &quot;^0.4.5&quot;,
    &quot;grunt-contrib-watch&quot;: &quot;^0.6.1&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y se ha creado un directorio llamado &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; que contiene las dependencias.&lt;/p&gt;

&lt;h3 id=&quot;definición-de-tareas&quot;&gt;Definición de tareas&lt;/h3&gt;

&lt;p&gt;Para la configuración de grunt y definición de tareas es necesario crear el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gruntfile.js&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;module.exports = function(grunt){
    grunt.initConfig({
        watch: {
            grunt: {
                files: [&apos;Gruntfile.js&apos;]
            },
            python: {
                files : [&apos;./tests/*.py&apos;,&apos;./libs/*/*.py&apos;],
                tasks: [&apos;pythontest&apos;],
            },
        }
    });

    grunt.registerTask(&apos;pythontest&apos;, function(){
        grunt.util.spawn({
            cmd: &apos;python&apos;,
            args: [&apos;setup.py&apos;,&apos;test&apos;],
            opts: {stdio: &apos;inherit&apos;},
        });
    });

    grunt.registerTask(&apos;default&apos;, [&apos;watch&apos;]);

};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y lanzar grunt&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;grunt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Con lo cual, cada vez que un archivo definido en &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;files&lt;/code&gt; sea modificado será ejecutada la tarea &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pythontest&lt;/code&gt; que lanza los test.&lt;/p&gt;

&lt;p&gt;La opción &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;opts: {stdio: &apos;inherit&apos;}&lt;/code&gt; permite que la salida del comando ejecutado sea mostrada, sin esto, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python setup.py test&lt;/code&gt; sería lanzado pero no visualizado el resultado.&lt;/p&gt;

&lt;h3 id=&quot;archivos-modificados-en-git&quot;&gt;Archivos modificados en git&lt;/h3&gt;

&lt;p&gt;Otra cosa que verifico son los archivos agregados a git.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git status
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Por lo que también me es útil agregar una tarea que se ejecute cada vez que se modifica el index de git &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.git/index&lt;/code&gt; .&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gitindex: {
    files : [&apos;.git/index&apos;],
    tasks: [&apos;gitst&apos;],
},
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y registrar la tarea&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;grunt.registerTask(&apos;gitst&apos;, function(){
    grunt.util.spawn({
        cmd: &apos;git&apos;,
        args: [&apos;status&apos;],
        opts: {stdio: &apos;inherit&apos;},
    });
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;conclusión&quot;&gt;Conclusión&lt;/h3&gt;

&lt;p&gt;Con lo descrito anteriormente es posible dejar a grunt en una terminal independiente vigilando que archivos son modificados y lanzando tareas previamente definidas.&lt;/p&gt;

&lt;p&gt;Herramientas como grunt permiten reducir el tiempo utilizado en tareas repetitivas y enfocarse en el ciclo de desarrollo.&lt;/p&gt;

&lt;p&gt;El código final de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gruntfile.js&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; está alojando en un &lt;a href=&quot;https://gist.github.com/juanpabloaj/4dbb58be44ac18b681b1&quot;&gt;gist de github&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Virtualenv y requirements</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2014-04-05T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2014/04/05/virtualenv-y-requirements</id>
    <content type="html">&lt;p&gt;En un post anterior, &lt;a href=&quot;http://juanpabloaj.com/2011/11/19/Una-vista-rapida-a-virtualenv/&quot;&gt;Una vista rápida a virtualenv&lt;/a&gt;, vimos como usar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virtualenv&lt;/code&gt; desde cero.&lt;/p&gt;

&lt;p&gt;Ahora veremos un ejemplo de como instalar las librerías necesarias para comenzar a trabajar.&lt;/p&gt;

&lt;p&gt;Con el comando&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip freeze
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Obtenemos la lista de librerías instaladas, que no están en la librería estándar.&lt;/p&gt;

&lt;p&gt;Si hacemos lo mismo en un entorno creado con &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virtualenv&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip freeze &amp;gt;&amp;gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Podemos almacenar las lista de librerías utilizadas en el actual proyecto.&lt;/p&gt;

&lt;p&gt;Con el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requirements.txt&lt;/code&gt; podemos instalar las librerías necesarias para comenzar a trabajar en un nuevo entorno creado por &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virtualenv&lt;/code&gt;, usando el comando:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
  </entry>
  
  <entry>
    <title>Instalando PySide</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2013-10-23T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2013/10/23/Instalando-PySide</id>
    <content type="html">&lt;h3 id=&quot;prerequisitos&quot;&gt;Prerequisitos&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;python&lt;/li&gt;
  &lt;li&gt;Qt4.8&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PySide es compatible con la versión 4.8 de Qt.&lt;/p&gt;

&lt;p&gt;Qt 4.8 es descargable desde el sitio de &lt;a href=&quot;http://qt-project.org/downloads&quot;&gt;Qt&lt;/a&gt;. Yo instale la versión &lt;a href=&quot;http://download.qt-project.org/official_releases/qt/4.8/4.8.5/qt-win-opensource-4.8.5-vs2008.exe&quot;&gt;4.8.5&lt;/a&gt; .&lt;/p&gt;

&lt;h3 id=&quot;instalación&quot;&gt;Instalación&lt;/h3&gt;

&lt;p&gt;Desde el sitio de descarga de &lt;a href=&quot;http://qt-project.org/wiki/PySideDownloads&quot;&gt;PySide&lt;/a&gt; descargar e instalar la binario para windows, compatible con versión de python instalado. En mi caso &lt;a href=&quot;http://download.qt-project.org/official_releases/pyside/PySide-1.2.1.win32-py2.7.exe&quot;&gt;PySide-1.2.1.win32-py2.7.exe&lt;/a&gt; .&lt;/p&gt;

&lt;h3 id=&quot;test&quot;&gt;Test&lt;/h3&gt;

&lt;p&gt;Para probar, usar las lineas&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;import PySide
from PySide.QtCore import *

print PySide.__version__
print PySide.QtCore.__version__
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Para obtener la salida&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1.2.1
4.8.5
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

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

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://buildawebsitecontent.blogspot.com/2013/04/install-pyside-on-windows-xp.html&quot;&gt;Install PySide on Windows XP&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://qt-project.org/wiki/PySide&quot;&gt;Sitio de PySide&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://qt-project.org/wiki/Setting_up_PySide&quot;&gt;Setting_up_PySide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Imposibilidad de imperios galácticos</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2013-09-22T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2013/09/22/Imposibilidad-de-imperios-galacticos</id>
    <content type="html">&lt;p&gt;Si consideramos la velocidad de transporte y comunicación como variables clave en la expansión de un imperio, mientras mayor sea la expansión un imperio necesitara una mayor velocidad de transporte y comunicación.&lt;/p&gt;

&lt;p&gt;Pero, la velocidad de transporte y comunicación tienen una cota que es la velocidad de luz. Luego un imperio no puede tener una velocidad de transporte y comunicación infinita. Luego un imperio no puede extenderse infinitamente.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Automatizando tareas con git hooks</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2013-07-24T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2013/07/24/Automatizando-tareas-con-githooks</id>
    <content type="html">&lt;p&gt;En un repositorio de git con el que trabajo, cada vez que hago un cambio necesito copiar algunos archivos a un directorio específico.&lt;/p&gt;

&lt;p&gt;Lo primero que hice fue crea un archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; con la regla &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;copy&lt;/code&gt; para copiar todo donde correspondía. El cual dejé en la raíz del repositorio.&lt;/p&gt;

&lt;p&gt;Hasta ahí, todo bien. Pero cada vez que había un nuevo cambio, era necesario tener presente la tediosa tarea de hacer&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;make copy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Una forma de automatizar esta tarea es con un hook de git, los cuales son scripts que son ejecutados cuando cierto tipo de acciones relacionadas con git ocurren.&lt;/p&gt;

&lt;p&gt;Cualquier repositorio de git contiene el directorio &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./git/githooks&lt;/code&gt;, con una serie de ejemplos.&lt;/p&gt;

&lt;p&gt;En mi caso, me interesaba que &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make copy&lt;/code&gt; se ejecutara después de realizar un commit, por lo cual bastaba con crear, en el directorio &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.git/githooks&lt;/code&gt;, el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;post-commit&lt;/code&gt;, o modificar el ya existente como ejemplo, y muy importante, darle permisos de ejecución.&lt;/p&gt;

&lt;p&gt;Un hook se ejecuta en el directorio raíz de git, por lo cual, y como mi &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; estaba en esa ubicación , al archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;post-commit&lt;/code&gt; sólo fue necesario agregar&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;make copy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Todas las ordenes de copiado podría haberlas escrito directamente en el hook, pero para algunas cosas prefiero usar make y el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; ya estaba creado.&lt;/p&gt;

&lt;p&gt;En &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;man githooks&lt;/code&gt; está la lista de git hooks disponibles:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;applypatch-msg
pre-applypatch
post-applypatch
pre-commit
prepare-commit-msg
commit-msg
post-commit
pre-rebase
post-checkout
post-merge
pre-receive
post-receive
post-update
pre-auto-gc
post-rewrite
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Utilizando algo similar, pensaba crear un archivo changelog que se modificar automáticamente, ya que para algunos menos amigos de git, es más fácil contar con este tipo de registro de cambios.&lt;/p&gt;

&lt;p&gt;También he leído que el hook &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pre-commit&lt;/code&gt; es utilizado para lanzar tests, lo cual suena a una muy buena practica.&lt;/p&gt;

&lt;p&gt;###Referencias&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://git-scm.com/book/en/Customizing-Git-Git-Hooks&quot;&gt;Customizing Git - Git Hooks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Manipulación de columnas con numpy</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2013-01-15T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2013/01/15/Columnas-con-numpy</id>
    <content type="html">&lt;p&gt;Cuando se manipulan datos es habitual tener que trabajar con columnas, sobre uno o varios archivos.&lt;/p&gt;

&lt;p&gt;Dada una serie de archivos alojados en un directorio. Utilizaremos la función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loadtxt&lt;/code&gt; de la librería de python numpy para capturar el contenido almacenado en columnas, lo cual nos permitirá manipularlo por medio de índices.
Con &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;savetxt&lt;/code&gt;, guardaremos la información en archivos de texto.&lt;/p&gt;

&lt;p&gt;Para finalizar, con la librería matplotlib, se generarán varias imágenes en png con gráficos de los datos.&lt;/p&gt;

&lt;p&gt;Teniendo archivos de la forma:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   0.0        0.9
   1.0        1.2
   2.0        1.8
   3.0        1.3
   4.0        1
   5.0        0.9
   6.0        0.8
   7.0        0.7
   8.0        0.7
   9.0        0.6
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;El siguiente script suma la segunda columna de un par de archivos, repitiendo el proceso para todas las combinaciones de dos archivos en el directorio.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import numpy as np
import matplotlib.pyplot as plt

files = {}

# almacenar nombres de archivo y contenido
dname = &apos;input/&apos;
for f in os.listdir(dname):
    fname = dname + f
    files[f] = np.loadtxt(fname)

# recorrer todos los archivos
for fi in files.keys():
    for fj in files.keys():
        if fi != fj:
            namei = fi.replace(&apos;.txt&apos;,&apos;&apos;)
            namej = fj.replace(&apos;.txt&apos;,&apos;&apos;)
            outfile = &apos;sum_&apos; + namei + &apos;_&apos; + namej

            # primera columna del archivo
            c1 = files[fi][:,0]
            # segunda columna del archivo
            fi_c2 = files[fi][:,1]
            fj_c2 = files[fj][:,1]

            # suma de columnas
            sum_c2 = fi_c2 + fj_c2

            # guardar suma en texto
            np.savetxt(outfile + &apos;.txt&apos;,
                    np.column_stack([c1,sum_c2]),
                    fmt = &apos;%10.2f&apos;)

            plt.clf()
            # curva archivo i
            plt.plot(c1,fi_c2)
            # curva archivo j
            plt.plot(c1,fj_c2)
            # curva archivo suma
            plt.plot(c1,sum_c2)
            # guarda curvas en png
            plt.savefig(outfile)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Una de las imágenes de salida, donde la linea azul y verde representan los datos en las columnas leídas y la roja la suma de ambas.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://f.cl.ly/items/0m0N0M271r1r253H3N1g/sum_file_0_file_1.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;enlaces&quot;&gt;Enlaces&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://matplotlib.org/&quot;&gt;matplotlib&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.numpy.org/&quot;&gt;numpy&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/4535991&quot;&gt;Código del ejemplo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Nbody con Three.js</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2012-12-17T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2012/12/17/nbody-con-three</id>
    <content type="html">&lt;p&gt;&lt;a href=&quot;http://mrdoob.github.com/three.js/&quot;&gt;Three.js&lt;/a&gt; es una librería de javascript para 3D.&lt;/p&gt;

&lt;p&gt;Para mostrar lo simple que es usarla, un ejemplo del problema de los n cuerpos ( &lt;a href=&quot;http://en.wikipedia.org/wiki/N-body_problem&quot;&gt;nbody problem&lt;/a&gt; ). Donde la interacción de las partículas está determinada principalmente por sus distancias, masas y una constante gravitacional.&lt;/p&gt;

&lt;iframe style=&quot;width: 100%; height: 500px&quot; src=&quot;http://jsfiddle.net/juanpablo/nj8Mm/embedded/result&quot; allowfullscreen=&quot;allowfullscreen&quot; frameborder=&quot;0&quot;&gt; &lt;/iframe&gt;

&lt;p&gt;El &lt;a href=&quot;http://jsfiddle.net/juanpablo/nj8Mm/&quot;&gt;script&lt;/a&gt; que determina las posiciones en base a la velocidad, aceleración y fuerzas involucradas:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;container = document.getElementById(&apos;container&apos;);

scene = new THREE.Scene();

camera = new THREE.PerspectiveCamera(45, window.innerWidth /
        window.innerHeight, 1, 10000);
camera.position.z = 500;
scene.add(camera);

renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);

pointlight = new THREE.PointLight(0xffffff);
ambientlight = new THREE.AmbientLight(0x101010);

directlight = new THREE.DirectionalLight(0xffffff, 1);
directlight.position.set(1, 1, 0).normalize();

scene.add(ambientlight);
scene.add(pointlight);
scene.add(directlight);

sgeometry = new THREE.SphereGeometry(3,16,16);
smaterial = new THREE.MeshPhongMaterial({color: 0x0000ff});

// algunas constantes
var spheres = new Array();
var n = 10 ;
var g = 6.670*0.01;
var m = 0.5;

// posiciones iniciales
for (var i = 0; i &amp;lt; n ; i += 1) {
    spheres[i] = new THREE.Mesh(sgeometry, smaterial);
    scene.add(spheres[i]);
    spheres[i].position.x += -50 + Math.random()*100;
    spheres[i].position.y += -50 + Math.random()*100;
    spheres[i].velocity = new THREE.Vector3(0,0,0);
    spheres[i].m = m;
}

container.appendChild(renderer.domElement);
var fx, fy, fz, dx, dy, dz, d2, d, f, ax, ay, az;
function render() {
    requestAnimationFrame(render);
    // fuerzas
    for (var i = 0; i &amp;lt; spheres.length; i += 1) {
        fx = 0;
        fy = 0;
        fz = 0;
        for (var j = 0; j &amp;lt; spheres.length; j += 1) {
            if (i != j ) {
                dx = spheres[i].position.x - spheres[j].position.x;
                dy = spheres[i].position.y - spheres[j].position.y;
                dz = spheres[i].position.z - spheres[j].position.z;
                d2 = dx*dx + dy*dy + dz*dz;
                d2 = d2 + 1;
                d = Math.sqrt(d2);
                f = -1 * g * spheres[i].m * spheres[j].m / d2;
                fx += f * dx/d;
                fy += f * dy/d;
                fz += f * dz/d;
            }
        }
        ax = fx / m;
        ay = fy / m;
        az = fz / m;
        spheres[i].velocity.x +=  ax;
        spheres[i].velocity.y +=  ay;
        spheres[i].velocity.z +=  az;
        spheres[i].position.x += spheres[i].velocity.x;
        spheres[i].position.y += spheres[i].velocity.y;
        spheres[i].position.z += spheres[i].velocity.z;
    }
    renderer.render(scene, camera);
}
render();
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

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

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.hdmagazine.org/&quot;&gt; Celia Cintas. THREE.JS ¿va a hacer todo eso por mi ? Hackers &amp;amp; Developers, 1.&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mrdoob/three.js/&quot;&gt;Three.js - github&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://mrdoob.github.com/three.js/docs/53/#Manual/Introduction/Creating-a-scene&quot;&gt;Three.js - Creating a scene&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Google script filtro de tiempo para Gmail</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2012-06-28T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2012/06/28/google-script-filtro-de-tiempo</id>
    <content type="html">&lt;p&gt;Hace algunos días que buscaba algún filtro para Gmail que se activara a cierta
hora.&lt;/p&gt;

&lt;p&gt;Me explico, todos los días me llegan algunas notificaciones por mail, las
cuales me gusta tener presente durante el día, pero al final del mismo ya no
tienen importancia, por lo que buscaba alguna forma para que se archivaran
automáticamente todos los días a cierta hora. Un filtro común no era adecuado,
ya que al llegar la notificación se archivaría inmediatamente.&lt;/p&gt;

&lt;p&gt;Cuando estaba creando un documento en google docs, vi que estaba la opción de
crear scripts, revise un poco la documentación, y realizar lo que necesitaba no
fue muy complejo.&lt;/p&gt;

&lt;p&gt;Desde google docs se crea un script&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function archiveNotification() {
  var threads = GmailApp.getInboxThreads();

  for ( var i = 0 ; i &amp;lt; threads.length; i++){
    var subject = threads[i].getFirstMessageSubject();

    if ( subject == &quot;Notification Subject&quot; ){
      //Logger.log(subject);
      GmailApp.moveThreadToArchive(threads[i])
    }

  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Básicamente, consiste en revisar la bandeja de entrada y buscar el thread que
tenga el subject de las notificaciones.&lt;/p&gt;

&lt;p&gt;Al ejecutarlo la primera vez es necesario conceder algunas autorizaciones para
que el script pueda tener acceso a Gmail.&lt;/p&gt;

&lt;p&gt;El la zona superior del editor, en Resources, se puede agregar el trigger de
tiempo, entre otros.&lt;/p&gt;

&lt;p&gt;De la misma forma se puede interactuar con varios de los servicios de Google.&lt;/p&gt;

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

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/3015108&quot;&gt;Script source - gist &lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developers.google.com/apps-script/your_first_script&quot;&gt;Google script - Building Your First Script&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developers.google.com/apps-script/class_gmailapp&quot;&gt;Google script - Class GmailApp&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developers.google.com/apps-script/understanding_triggers&quot;&gt;Google script - Understanding Triggers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Multicore con python</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2012-04-12T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2012/04/12/multicore-con-python</id>
    <content type="html">&lt;p&gt;Si nos dicen programación paralela seguro que lo primero en que pensamos es MPI o openMP, incluso en CUDA.&lt;/p&gt;

&lt;p&gt;Pero en algunos casos lo único que necesitamos es aplicar, de manera simple, una operación sobre muchos elementos, y aprovechar el procesador multicore del que disponemos.&lt;/p&gt;

&lt;p&gt;El python, al usar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt; aplicamos una misma función a cada elemento de una lista. Lo que ofrece el paquete &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;multiprocessing&lt;/code&gt;, entre otras cosas, es poder dividir esta tarea entre el número de procesadores que se especifique.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#!/usr/bin/python
# -*- coding: utf-8 -*-
import multiprocessing
from datetime import datetime
def f(x):
    n = int(1e2)
    for i in range(n):
        for i in range(n):
            # computo
            i
    return i*i

def main():
    n = int(1e5)
    np =  multiprocessing.cpu_count()
    pool = multiprocessing.Pool(processes=np)
    l = range(n)
    t0 = datetime.now()
    map(f,l)
    print datetime.now() - t0

    t0 = datetime.now()
    pool.map(f,l)
    print datetime.now() - t0

if __name__ == &quot;__main__&quot;:
    main()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;En un core demoró 50 segundos, versus los 12 al usar cuatro cores.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0:00:50.793201
0:00:12.689651
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Los tiempos fueron medidos en un Intel(R) Xeon(R) E5504 2.00GHz.&lt;/p&gt;

&lt;h3 id=&quot;enlaces&quot;&gt;Enlaces&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://docs.python.org/library/multiprocessing.html&quot;&gt;Multiprocessing python package&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/2371946&quot;&gt;Código en github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>CSS con stylus</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2012-01-28T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2012/01/28/stylus-para-menos-css</id>
    <content type="html">&lt;p&gt;Como ahorrar tiempo al momento de trabajar con CSS?&lt;/p&gt;

&lt;p&gt;He probado un poco con &lt;a href=&quot;http://lesscss.org/&quot;&gt;less&lt;/a&gt;, y es una gran ayuda, especialmente con el uso de variables. Pero después de probar estas soluciones, te preguntas ¿es necesario usar las llaves ({})?.&lt;/p&gt;

&lt;p&gt;Supongo que lo mismo se pregunto &lt;a href=&quot;http://learnboost.github.com/stylus/&quot;&gt;stylus&lt;/a&gt;, bueno en la página dice lo mismo.&lt;/p&gt;

&lt;p&gt;“Que tal si pudiéramos omitir las llaves, los punto y como y los dos puntos ?”&lt;/p&gt;

&lt;p&gt;Lo primero es tener instalado &lt;a href=&quot;http://nodejs.org/&quot;&gt;nodejs&lt;/a&gt; y su gestionador de paquetes &lt;a href=&quot;http://nodejs.org/&quot;&gt;npm&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;E instalar stylus&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm install stylus -g
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y ahora teniendo un archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;font.styl&lt;/code&gt; como este&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;font-size = 14px

body
    font font-size Arial, sans-serif
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Usamos stylus&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;stylus font.styl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Genera&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;body {
    font: 14px Arial, sans-serif;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;No puedo dejar de mencionar el argumento&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;style --watch style.styl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Con esto cada vez que modifique el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;style.styl&lt;/code&gt; se generara automáticamente el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;style.css&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Más detalles en el sitio de &lt;a href=&quot;http://learnboost.github.com/stylus/&quot;&gt;stylus&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>dvtm sobre screen</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2011-12-26T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2011/12/26/dvtm-sobre-screen-terminal-en-fullscreen</id>
    <content type="html">&lt;p&gt;Hace algunos años usé &lt;a href=&quot;http://awesome.naquadah.org/&quot;&gt;awesome window manager&lt;/a&gt;,
probando el tiling en todo su potencial.&lt;/p&gt;

&lt;p&gt;El recuerdo perduro en la memoria y se hacia presente cada vez que tenía que
trabajar con varias terminales, o más
aun, a pantalla completa. Surgía la necesidad de moverse entre
ellas aprovechando lo mejor posible la pantalla.&lt;/p&gt;

&lt;p&gt;Una solución clásica es usar &lt;a href=&quot;http://www.gnu.org/software/screen/&quot;&gt;screen&lt;/a&gt;
que soportan varias terminales a la vez y cosas como split. Sin olvidar
que puedes dejar corriendo tareas en background y recuperarlas.&lt;/p&gt;

&lt;p&gt;Pero la gestión de los espacios sigue siendo tarea del usuario.&lt;/p&gt;

&lt;p&gt;Ahí es donde entra dvtm. Como awesome, se encarga de gestionar las ventanas con
tiling, cada vez que lanzas una shell se acomoda al estilo de layout
que tengas seleccionado.&lt;/p&gt;

&lt;p&gt;En screen como en dvtm la tecla por defecto  es &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt;, por ejemplo con&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;crtl-a c
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Lanza una nueva terminal. Por lo cual, con un &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alias&lt;/code&gt;, cambie dvtm&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;alias dvtm=&apos;TERM=rxvt-256color ; dvtm -m ^q&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hubiera sido mejor especificar estas opciones al momento de la compilación, pero en Lion
he tenido algunos problemas, compila bien, aunque al intentar
lanzara más de tres windows, se cae. Por suerte &lt;a href=&quot;stevelosh.com&quot;&gt;Steve Losh&lt;/a&gt; dejó
unos &lt;a href=&quot;https://gist.github.com/1240857&quot;&gt;binarios compilados en Snow leopard&lt;/a&gt;, que
funcionan bien en Lion.&lt;/p&gt;

&lt;h3 id=&quot;enlaces&quot;&gt;Enlaces&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://awesome.naquadah.org/&quot;&gt;awesome&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.brain-dump.org/projects/dvtm/&quot;&gt;dvtm&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.gnu.org/software/screen/&quot;&gt;screen&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/1240857&quot;&gt;Snow Leopard-compiled DVTM binaries (for Lion users)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>rxvt-unicode con 256 colors para dvtm</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2011-12-21T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2011/12/21/rxvt-unicode-con-256-colors-para-dvtm</id>
    <content type="html">&lt;p&gt;El problema comenzó cuando desde &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dvtm&lt;/code&gt; iniciaba una conexión ssh a una maquina
ubuntu, obtenía este mensaje&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tput: unknown terminal &quot;rxvt-256color&quot;
tput: unknown terminal &quot;rxvt-256color&quot;
tput: unknown terminal &quot;rxvt-256color&quot;
tput: unknown terminal &quot;rxvt-256color&quot;
tput: unknown terminal &quot;rxvt-256color&quot;
tput: unknown terminal &quot;rxvt-256color&quot;
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Entraba con &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TERM=rxvt-256color&lt;/code&gt; ya que &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dvtm&lt;/code&gt; necesita esta terminal para mostrar
los 256 colores.&lt;/p&gt;

&lt;p&gt;Lo que sigue es una traducción rápida de
 &lt;a href=&quot;http://scie.nti.st/2008/10/13/get-rxvt-unicode-with-256-color-support-on-ubunut&quot;&gt;Get rxvt-unicode with 256 color support on Ubuntu&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Descargar el src de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rxvt-unicode&lt;/code&gt; y aplicar el parche para 256 colores&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# descar el fuente
cd ~/src
mkdir rxvt-unicode
cd rxvt-unicode
apt-get source rxvt-unicode
cd rxvt-unicode-9.07

# aplicar parche
patch -p1 &amp;lt; doc/urxvt-8.2-256color.patch

# construir los paquetes
sudo apt-get build-dep rxvt-unicode
dpkg-builpackage -us -uc -rfakeroot

# instalar
cd ..
sudo dpkg -i rxvt-unicode_9.07-2_amd64.deb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Teniendo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rxvt-unicode&lt;/code&gt; instalado  modificar el terminfo&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd ~
infocmp -L rxvt-unicode rxvt-unicode.terminfo

vim rxvt-unicode.terminfo
# cambiar la linea
lines_of_memory#0, max_colors#88, max_pairs#256,
# a
lines_of_memory#0, max_colors#256, max_pairs#32767

# crear el directorio ~/.terminfo
install -d .terminfo
# reconstruir terminfo de rxvt-unicode
tic -o .terminfo/ rxvt-unicode.terminfo
rm rxvt-unicode.terminfo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y finalmente para que &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dvtm&lt;/code&gt; tenga 256 colores&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd ~/.terminfo/r
cp rxvt-unicode rxvt-256color
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Con esto &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dvtm&lt;/code&gt; no debería mostrar más problemas.&lt;/p&gt;

&lt;h3 id=&quot;referencias&quot;&gt;Referencias&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://scie.nti.st/2008/10/13/get-rxvt-unicode-with-256-color-support-on-ubunut&quot;&gt;Get rxvt-unicode with 256 color support on Ubuntu&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Verbatim en beamer</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2011-12-18T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2011/12/18/Verbatim-en-beamer</id>
    <content type="html">&lt;p&gt;Cuando se intenta usar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Verbatim&lt;/code&gt; en &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Beamer&lt;/code&gt; para hacer una presentación con latex,
se pueden presentar problemas al momento de la compilación. La solución está en usar&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[fragile]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;en el frame.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;\documentclass{beamer}
\usepackage[spanish]{babel}
\usepackage[utf8]{inputenc}
\usetheme{Antibes}
\begin{document}
\title{Simple Beamer}
\frame{\titlepage}
\begin{frame}[fragile]
    \frametitle{Hello world}
        \begin{verbatim}
            #!/usr/bin/python
            print &quot;Hello World!&quot;
        \end{verbatim}
\end{frame}
\end{document}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Pasa lo mismo con el paquete &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;listings&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;\documentclass{beamer}
\usepackage[spanish]{babel}
\usepackage[utf8]{inputenc}
\usetheme{Antibes}
\usepackage{listings}
\begin{document}
\title{Simple Beamer}
\frame{\titlepage}
\begin{frame}[fragile]
    \frametitle{Hello world}
        \begin{lstlisting}
            #!/usr/bin/python
            print &quot;Hello World!&quot;
        \end{lstlisting}
\end{frame}
\end{document}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;referencias&quot;&gt;Referencias&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://stackoverflow.com/questions/2981008/latex-problem-with-beamer-and-listings&quot;&gt;LaTex, Problem with Beamer and Listings&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Automata celular con HTML5</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2011-12-11T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2011/12/11/automata-celular-con-HTML5</id>
    <content type="html">&lt;p&gt;Para probar canvas de HTML5 un automata celular con la &lt;a href=&quot;http://en.wikipedia.org/wiki/Rule_110&quot;&gt;regla 110&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;&quot;&gt;
		&lt;img src=&quot;http://f.cl.ly/items/2p3h363K0C3b2y1B0s1z/ss%202011-12-11_at_13.54.51.png&quot; /&gt;
		&amp;lt;/img&amp;gt;
&lt;/div&gt;

&lt;p&gt;Y el &lt;a href=&quot;https://gist.github.com/1461541&quot;&gt;código&lt;/a&gt; :&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot;
	&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&amp;gt;
&amp;lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xmlns:v=&quot;urn:schemas-microsoft-com:vml&quot;&amp;gt;
  &amp;lt;head&amp;gt;
	&amp;lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot;/&amp;gt;
	&amp;lt;script type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&amp;gt;
		function bloques () {
			var canvasContext = document.getElementById(&quot;canvas&quot;).getContext(&quot;2d&quot;);
			canvasContext.fillStyle = &quot;rgba(200,200,200,0.0)&quot;;
			var dx=2;
			var a=new Array();
			var b=new Array();
			for (var i = 0; i &amp;lt; 200; i += 1) a[i]=Math.round(Math.random());
			for (var j = 0; j &amp;lt; a.length; j += 1)
				for (var i = 0; i &amp;lt; a.length; i += 1) {
					canvasContext.fillRect(i*dx,j*dx,dx-1,dx-1);
				};
			canvasContext.fillStyle = &quot;rgba(200,200,200,0.9)&quot;;
			var alpha=0.9;
			for (var j = 0; j &amp;lt; a.length*3/2; j += 1){
				for (var i = 0; i &amp;lt; a.length; i += 1) b[i]=a[i];
				for (var i = 0; i &amp;lt; a.length; i += 1) {
					bj=b[(i+1)%a.length];
					bk=b[i];
					bl=b[(i+a.length-1)%a.length];
					a[i]=r110(bj,bk,bl);
					if (a[i]==1) {
						canvasContext.fillRect(i*dx,j*dx,dx-1,dx-1);
					}
				};
				alpha-=0.004;
				canvasContext.globalAlpha=alpha;
			}
		}
		function r110 (j,k,l) {
			// [rule 110](http://en.wikipedia.org/wiki/Rule_110)
			if( j==1 &amp;amp;&amp;amp; k == 1 &amp;amp;&amp;amp; l==1) return 0;
			if( j==1 &amp;amp;&amp;amp; k == 1 &amp;amp;&amp;amp; l==0) return 1;
			if( j==1 &amp;amp;&amp;amp; k == 0 &amp;amp;&amp;amp; l==1) return 1;
			if( j==1 &amp;amp;&amp;amp; k == 0 &amp;amp;&amp;amp; l==0) return 0;
			if( j==0 &amp;amp;&amp;amp; k == 1 &amp;amp;&amp;amp; l==1) return 1;
			if( j==0 &amp;amp;&amp;amp; k == 1 &amp;amp;&amp;amp; l==0) return 1;
			if( j==0 &amp;amp;&amp;amp; k == 0 &amp;amp;&amp;amp; l==1) return 1;
			if( j==0 &amp;amp;&amp;amp; k == 0 &amp;amp;&amp;amp; l==0) return 0;
		}
	&amp;lt;/script&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body onload=&quot;bloques()&quot;&amp;gt;
	  &amp;lt;canvas id=&quot;canvas&quot; width=&quot;400&quot; height=&quot;400&quot;&amp;gt;
	  &amp;lt;/canvas&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;referencias&quot;&gt;Referencias&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.html5rocks.com/en/&quot;&gt;html5rocks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Una vista rápida a virtualenv</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2011-11-19T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2011/11/19/Una-vista-rapida-a-virtualenv</id>
    <content type="html">&lt;p&gt;Más de alguna vez he querido instalar alguna lib de python para probarla sin tener que modificar mucho el sistema.&lt;/p&gt;

&lt;p&gt;La solución &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virtualenv&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Se puede instalar desde &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;easy_install&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo easy_install virtualenv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;O teniendo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pip&lt;/code&gt;, para instalar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pip&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo su -
curl https://raw.github.com/pypa/pip/master/contrib/get-pip.py | python
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ahora &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virtualenv&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip install virtualenv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Crear un directorio para probar&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir 001 ; cd 001
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Crear un virtual environment, sin ningún paquete previo&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;virtualenv venv --no-site-packages
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Activar el entorno&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;source venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;El prompt debería haber cambiado mostrando la activación del entorno.&lt;/p&gt;

&lt;p&gt;Ahora se pueden instalar paquetes que solo tendrán efectos sobre sobre el entorno.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip install django
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Para verificar que tenemos instalado podemos usar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yolk&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo pip install yolk
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Este nos permite ver que tenemos, con&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;yolk -l
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y para salir de entorno&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;deactivate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Debería haber un cambio en el prompt mostrando la salida.&lt;/p&gt;

&lt;h3 id=&quot;edit-2012-07-12&quot;&gt;Edit 2012-07-12&lt;/h3&gt;

&lt;p&gt;Para instalar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pip&lt;/code&gt; es necesario tener instalado &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python-setuptools&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;En ubuntu/debian basta con&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apt-get install python-setuptools
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;###Referencias
&lt;a href=&quot;http://simononsoftware.com/virtualenv-tutorial/&quot;&gt;virtualenv tutorial&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Mono 10 y ironpython en Ubuntu 10.10</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2011-08-31T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2011/08/31/mono10-y-ironpython-en-ubuntu-1010</id>
    <content type="html">&lt;h3 id=&quot;mono-10&quot;&gt;Mono 10&lt;/h3&gt;
&lt;p&gt;Si necesitas .NET v4 en Linux la opción es mono 10.&lt;br /&gt;
Para facilitar la instalación es recomendable el script &lt;a href=&quot;https://github.com/firegrass/mono-installer-script/blob/master/mono_build.sh&quot;&gt;mono_build.sh&lt;/a&gt;.&lt;br /&gt;
Basta descargar, dar permisos y ejecutar&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ wget -c https://raw.github.com/firegrass/mono-installer-script/master/mono_build.sh
$ chmod u+x mono_build.sh
$ ./mono_build.sh -c -v 2.10 -p ~/mono -m mono
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Donde &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-m&lt;/code&gt; especifica lo que se quiere instalar, estando disponible incluso monodevelop.&lt;br /&gt;
Cuando se complete la instalación debería verse un mensaje de tipo&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
--  Your parallel environment is installed in /home/juanpablo/mono/mono-2.10
--  To start a mono-2.10 environment, run: source mono-2.10-environment
--  To use mono-2.10 to run a cli app, run: mono-2.10 (eg mono-2.10 mono -V)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Por lo que hay que agregar algunas variables al entorno desde &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mono-2.10-environment&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ source mono-2.10-environment
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y para verificar&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mono-2.10 mono -V
Mono JIT compiler version 2.10.5  ....
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Es recomendable agregar esto a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.bashrc&lt;/code&gt;&lt;br /&gt;
Para utilizar mono 10 es necesario anteponer siempre mono-2.10.&lt;/p&gt;
&lt;h3 id=&quot;ironpython&quot;&gt;Ironpython&lt;/h3&gt;

&lt;p&gt;Ahora a clonar ironpython y construir&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git clone https://github.com/IronLanguages/main.git IronLanguages
$ cd IronLanguages
$ xbuild Solutions/IronPython.Mono.sln
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Con lo cual &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ipy&lt;/code&gt;, el interprete, debería estar en &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IronLanguages/bin/Release/ipy.exe&lt;/code&gt;, como depende de mono 10 para utilizarlo es necesario&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mono-2.10 $HOME/IronLanguages/bin/Release/ipy.exe
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Para simplificar agregué estos alias a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.bashrc&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;alias mono=&quot;mono-2.10 mono&quot;
alias ipy=&quot;mono $HOME/IronLanguages/bin/Release/ipy.exe&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

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

&lt;ul&gt;
  &lt;li&gt;http://patrick.qmtech.net/blog/?p=41&lt;/li&gt;
  &lt;li&gt;http://www.mentby.com/doug-blank/building-ironpythonironruby-for-mono-yes.html&lt;/li&gt;
  &lt;li&gt;http://ironpython.codeplex.com/wikipage?title=IronPython%20on%20Mono&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Rails con Passenger nginx en Squeeze</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2011-07-12T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2011/07/12/Rails-con-Passenger-nginx-en-Squeeze</id>
    <content type="html">&lt;h3 id=&quot;pre-requisitos&quot;&gt;Pre requisitos&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ aptitude install build-essential zlib1g-dev libssl-dev libpq-dev libcurl4-openssl-dev curl libreadline-dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Dependiendo de la base de datos a usar van a ser necesarios algunos paquetes, si se va a ocupar sqlite3&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ wget http://www.sqlite.org/sqlite-amalgamation-3.7.2.tar.gz
$ tar xzf sqlite-amalgamation-3.7.2.tar.gz
$ cd sqlite-3.7.2/
$ ./configure
$ make
$ make install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;rvm&quot;&gt;RVM&lt;/h3&gt;

&lt;p&gt;Instalar rvm como root&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ bash &amp;lt; &amp;lt;(curl -s https://rvm.beginrescueend.com/install/rvm)
$ echo &apos;[[ -s &quot;$HOME/.rvm/scripts/rvm&quot; ]] &amp;amp;&amp;amp; . &quot;$HOME/.rvm/scripts/rvm&quot; # Load RVM function&apos; &amp;gt;&amp;gt; ~/.bash_profile
$ source ~/.bash_profile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;rails&quot;&gt;Rails&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rvm install 1.9.2
$ rvm use 1.9.2 --default 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Otros necesarios&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rvm rubygems current
$ gem install rails
$ gem install bundle
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Si falto algún paquete se puede instalar con rvm&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rvm package install zlib
rvm remove 1.9.1
rvm install 1.9.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;passenger&quot;&gt;Passenger&lt;/h3&gt;

&lt;p&gt;Gem instala passenger&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ gem install passenger
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Passenger se debería encargar del resto&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ passenger-install-nginx-module
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Dirá si falta algo, incluso se encargar de instalar nginx de ser necesario. 
La instalación debería terminar con algo como&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-nginx&quot; data-lang=&quot;nginx&quot;&gt;	&lt;span class=&quot;k&quot;&gt;This&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;installer&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;has&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;already&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;modified&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;configuration&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;you!&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;The&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;following&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;configuration&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;snippet&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;was&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;inserted:&lt;/span&gt;

	  &lt;span class=&quot;s&quot;&gt;http&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		  &lt;span class=&quot;kn&quot;&gt;...&lt;/span&gt;
		  &lt;span class=&quot;s&quot;&gt;passenger_root&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/usr/local/rvm/gems/ruby-1.9.2-p180/gems/passenger-3.0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		  &lt;span class=&quot;kn&quot;&gt;passenger_ruby&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/usr/local/rvm/wrappers/ruby-1.9.2-p180/ruby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		  &lt;span class=&quot;kn&quot;&gt;...&lt;/span&gt;
	  &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;


	&lt;span class=&quot;s&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	  &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	  &lt;span class=&quot;kn&quot;&gt;server_name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;www.yourhost.com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	  &lt;span class=&quot;kn&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/somewhere/public&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# &amp;lt;--- be sure to point to &apos;public&apos;!&lt;/span&gt;
	  &lt;span class=&quot;kn&quot;&gt;passenger_enabled&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;on&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;/figure&gt;

&lt;p&gt;El archivo para administrar nginx en &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/init.d/nginx&lt;/code&gt;&lt;/p&gt;

&lt;figure 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;#! /bin/sh&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;### BEGIN INIT INFO&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;# Provides:          nginx&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;# Required-Start:    $all&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;# Required-Stop:     $all&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;# Default-Start:     2 3 4 5&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;# Default-Stop:      0 1 6&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;# Short-Description: starts the nginx web server&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;# Description:       starts nginx using start-stop-daemon&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;### END INIT INFO&lt;/span&gt;

	&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/nginx/sbin:/sbin:/bin:/usr/sbin:/usr/bin
	&lt;span class=&quot;nv&quot;&gt;DAEMON&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/nginx/sbin/nginx
	&lt;span class=&quot;nv&quot;&gt;NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;nginx
	&lt;span class=&quot;nv&quot;&gt;DESC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;nginx
	&lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-x&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$DAEMON&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;0

	&lt;span class=&quot;c&quot;&gt;# Include nginx defaults if available&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /etc/default/nginx &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
			&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; /etc/default/nginx
	&lt;span class=&quot;k&quot;&gt;fi

	&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in
	  &lt;/span&gt;start&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Starting &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$DESC&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &quot;&lt;/span&gt;
			start-stop-daemon &lt;span class=&quot;nt&quot;&gt;--start&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--quiet&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--pidfile&lt;/span&gt; /opt/nginx/logs/&lt;span class=&quot;nv&quot;&gt;$NAME&lt;/span&gt;.pid &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
					&lt;span class=&quot;nt&quot;&gt;--exec&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$DAEMON&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$DAEMON_OPTS&lt;/span&gt;
			&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$NAME&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&quot;&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
	  stop&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Stopping &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$DESC&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &quot;&lt;/span&gt;
			start-stop-daemon &lt;span class=&quot;nt&quot;&gt;--stop&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--quiet&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--pidfile&lt;/span&gt; /opt/nginx/logs/&lt;span class=&quot;nv&quot;&gt;$NAME&lt;/span&gt;.pid &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
					&lt;span class=&quot;nt&quot;&gt;--exec&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$DAEMON&lt;/span&gt;
			&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$NAME&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&quot;&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
	  restart|force-reload&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Restarting &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$DESC&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &quot;&lt;/span&gt;
			start-stop-daemon &lt;span class=&quot;nt&quot;&gt;--stop&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--quiet&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--pidfile&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
					/opt/nginx/logs/&lt;span class=&quot;nv&quot;&gt;$NAME&lt;/span&gt;.pid &lt;span class=&quot;nt&quot;&gt;--exec&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$DAEMON&lt;/span&gt;
			&lt;span class=&quot;nb&quot;&gt;sleep &lt;/span&gt;1
			start-stop-daemon &lt;span class=&quot;nt&quot;&gt;--start&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--quiet&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--pidfile&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
					/opt/nginx/logs/&lt;span class=&quot;nv&quot;&gt;$NAME&lt;/span&gt;.pid &lt;span class=&quot;nt&quot;&gt;--exec&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$DAEMON&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$DAEMON_OPTS&lt;/span&gt;
			&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$NAME&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&quot;&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
	  reload&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			  &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Reloading &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$DESC&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; configuration: &quot;&lt;/span&gt;
			  start-stop-daemon &lt;span class=&quot;nt&quot;&gt;--stop&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--signal&lt;/span&gt; HUP &lt;span class=&quot;nt&quot;&gt;--quiet&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--pidfile&lt;/span&gt;     /opt/nginx/logs/&lt;span class=&quot;nv&quot;&gt;$NAME&lt;/span&gt;.pid &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
				  &lt;span class=&quot;nt&quot;&gt;--exec&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$DAEMON&lt;/span&gt;
			  &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$NAME&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&quot;&lt;/span&gt;
			  &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
		  &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
				&lt;span class=&quot;nv&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/etc/init.d/&lt;span class=&quot;nv&quot;&gt;$NAME&lt;/span&gt;
				&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Usage: &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$N&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; {start|stop|restart|reload|force-reload}&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
				&lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
				&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;esac&lt;/span&gt;

		&lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;0&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Darle los permisos de ejecución&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;chmod +x /etc/init.d/nginx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Subirlo&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/etc/init.d/nginx start 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;###Rails&lt;/p&gt;

&lt;p&gt;Para testar&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rails new blog 
$ cd blog
$ bundle install
$ rake db:migrate
$ rails s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Pueden presentarse problema en el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/opt/nginx/conf/nginx.conf&lt;/code&gt; con las variables&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    server_name  1.2.3.4;
	...
	passenger_enabled on;
	rails_env development; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

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

&lt;p&gt;&lt;a href=&quot;http://www.modrails.com/install.html&quot;&gt;Instalar passenger&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://sourcode.net/debian-squeeze-redmine-nginx-phusion-passenger/&quot;&gt;Debian squeeze redmine nginx phusion passenger&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://juanpabloaj.github.com/rails/debian/rvm/2011/05/22/rails-en-debian.html&quot;&gt;Rails en debian&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Rails en Apache con Passenger</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2011-05-23T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/2011/05/23/rails-en-apache-con-passenger</id>
    <content type="html">&lt;p&gt;Teniendo instalado rails3 y apache2 vamos a instalar passenger&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ gem install passenger
$ gem passenger-install-apache2-module
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;passenger irá guiando la instalación, si necesita dependencias y mostrara las lineas que hay que agregar a los archivos de configuración de apache&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Please edit your Apache configuration file, and add these lines:
LoadModule passenger_module /usr/local/rvm/gems/ruby-1.9.2-p180/gems/passenger-3.0.7/ext/apache2/mod_passenger.so
   	PassengerRoot /usr/local/rvm/gems/ruby-1.9.2-p180/gems/passenger-3.0.7
   	PassengerRuby /usr/local/rvm/wrappers/ruby-1.9.2-p180/ruby
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;terminará con un mensaje similar a este&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Suppose you have a Rails application in /somewhere. Add a virtual host to your
Apache configuration file and set its DocumentRoot to /somewhere/public:

   &amp;lt;VirtualHost *:80&amp;gt;
      ServerName www.yourhost.com
      DocumentRoot /somewhere/public    # &amp;lt;-- be sure to point to &apos;public&apos;!
      &amp;lt;Directory /somewhere/public&amp;gt;
         AllowOverride all              # &amp;lt;-- relax Apache security settings
         Options -MultiViews            # &amp;lt;-- MultiViews must be turned off
      &amp;lt;/Directory&amp;gt;
   &amp;lt;/VirtualHost&amp;gt;

And that&apos;s it! You may also want to check the Users Guide for security and
optimization tips, troubleshooting and other useful information:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;moverse al archivo de los mods de apache&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cd /etc/apache2/mods-available
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;crear el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;passenger.conf&lt;/code&gt; y agregar las lineas antes mostradas&lt;/p&gt;

   	PassengerRoot /usr/local/rvm/gems/ruby-1.9.2-p180/gems/passenger-3.0.7
   	PassengerRuby /usr/local/rvm/wrappers/ruby-1.9.2-p180/ruby

&lt;p&gt;y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;passenger.load&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;LoadModule passenger_module /usr/local/rvm/gems/ruby-1.9.2-p180/gems/passenger-3.0.7/ext/apache2/mod_passenger.so
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;subir el modulo y reiniciar apache&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo a2enmod passenger
$ sudo /etc/init.d/apache2 restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;crear el archivo de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virtualhost&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   &amp;lt;VirtualHost *:80&amp;gt;
      ServerName www.yourhost.com
      DocumentRoot /somewhere/public    # &amp;lt;-- be sure to point to &apos;public&apos;!
      &amp;lt;Directory /somewhere/public&amp;gt;
         AllowOverride all              # &amp;lt;-- relax Apache security settings
         Options -MultiViews            # &amp;lt;-- MultiViews must be turned off
      &amp;lt;/Directory&amp;gt;
   &amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Este es un punto importante, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt; debe ser el directorio &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt; de la aplicación creada por rails.&lt;/p&gt;

&lt;p&gt;###Referencias&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://bootpolish.net/home_howto_installrubyonrails3ondebianlenny&quot;&gt;Rails on debian lenny&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Rails en Debian Lenny</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2011-05-22T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/rails/debian/rvm/2011/05/22/rails-en-debian</id>
    <content type="html">&lt;h2 id=&quot;pre-requisitos&quot;&gt;Pre requisitos&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;curl&lt;/li&gt;
  &lt;li&gt;build-essential&lt;/li&gt;
  &lt;li&gt;zlib1g-dev&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;##Instalar
Instalar rvm como root&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ bash &amp;lt; &amp;lt;(curl -s https://rvm.beginrescueend.com/install/rvm)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Agregarlo a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.bash_profile &lt;/code&gt; y recargar&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ echo &apos;[[ -s &quot;$HOME/.rvm/scripts/rvm&quot; ]] &amp;amp;&amp;amp; . &quot;$HOME/.rvm/scripts/rvm&quot; # Load RVM function&apos; &amp;gt;&amp;gt; ~/.bash_profile
$ source ~/.bash_profile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Instalar ruby&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rvm install 1.9.2 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Este comando me mostraba el siguiente error&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rvm install 1.9.2
-su: /usr/local/rvm/scripts/manage: Permission denied
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Por lo que le di permisos de ejecución al archivo&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ chmod u+x /usr/local/rvm/scripts/manage
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;ruby 1.9.2 por defecto&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rvm use 1.9.2 --default
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Instalar gem&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rvm rubygems current 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Instalar rails y bundle&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ gem install rails
$ gem install bundle
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;##Rails&lt;/p&gt;

&lt;p&gt;Probar rails&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rails new blog 
$ cd blog
$ bundle install
$ rake db:migrate
$ rails s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;debería estar visible en &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localhost:3000&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;##Problemas frecuentes&lt;/p&gt;

&lt;h3 id=&quot;sqlite3&quot;&gt;sqlite3&lt;/h3&gt;

&lt;p&gt;Si hay problemas para instalar sqlite-ruby y sus extensiones, hay que actualizar sqlite3 desde el código fuente&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ wget http://www.sqlite.org/sqlite-amalgamation-3.7.2.tar.gz
$ tar xzf sqlite-amalgamation-3.7.2.tar.gz
$ cd sqlite-3.7.2/
$ ./configure
$ make
$ make install
$ gem install rails sqlite3-ruby
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;###rake&lt;/p&gt;

&lt;p&gt;si al hacer&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rake db:migrate 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;se presentan problemas con &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rake 0.9.0&lt;/code&gt; es recomendable &lt;a href=&quot;https://gist.github.com/984326&quot;&gt;modificar el archivo Rakefile&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;##Referencias&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://rvm.beginrescueend.com/rvm/install/&quot;&gt;rvm install&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://cuasan.wordpress.com/2010/10/13/rails-3-on-debian-with-sqlite-3/&quot;&gt;sqlite3 en lenny&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/984326&quot;&gt;Rakefile modificado&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://stackoverflow.com/questions/5287121/undefined-method-task-using-rake-0-9-0-beta-4&quot;&gt;Undefined method ‘task’ using rake 0.9.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Tocando Mongolab desde rails3</title>
    <link href="http://juanpabloaj.com"/>
    <updated>2011-05-15T00:00:00+00:00</updated>
    <id>http://juanpabloaj.com/mongodb/rails/mongolab/2011/05/15/mongolab-desde-rails3</id>
    <content type="html">&lt;p&gt;Si rails no está instalado&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ gem install rails
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Crear una aplicación&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rails new touchMongoLab --skip-active-record
$ cd touchMongoLab
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Editar el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Edit this Gemfile to bundle your application&apos;s dependencies.
require &apos;rubygems&apos;
require &apos;mongo&apos;
source &apos;http://gemcutter.org&apos;

gem &apos;rails&apos;, &apos;3.1.0.beta1&apos;
gem &quot;mongo_mapper&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Instalar las gemas necesarias&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ bundle install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Crear el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config/initializers/mongo.rb&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;MongoMapper.connection = Mongo::Connection.new(&apos;namexyz.mongolab.com&apos;, port )
MongoMapper.database = &quot;dbname&quot;
MongoMapper.database.authenticate(&apos;user&apos;,&apos;passwd&apos;)

if defined?(PhusionPassenger)
   PhusionPassenger.on_event(:starting_worker_process) do |forked|
	 MongoMapper.connection.connect_to_master if forked
   end 
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Crear el modelo en el archivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app/models/user.rb&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class User
  include MongoMapper::Document
  key :name
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Crear un usuario desde la consola&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rails console
ruby-1.9.2-p180 :006 &amp;gt; user= User.new(:name =&amp;gt; &quot;hola mundo&quot;)
 =&amp;gt; #&amp;lt;User _id: BSON::ObjectId(&apos;4dd097464cfad1e8ab000003&apos;), name: &quot;hola mundo&quot;&amp;gt; 
ruby-1.9.2-p180 :006 &amp;gt; user.save()
 =&amp;gt; true 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Verificar la existencia del usuario en la db&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt; db.users.find()
{ &quot;_id&quot; : ObjectId(&quot;4dd097604cfad1e8ab000004&quot;), &quot;name&quot; : &quot;hola mundo&quot; }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;referencias&quot;&gt;Referencias&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://www.mongodb.org/display/DOCS/Rails+3+-+Getting+Started&quot;&gt;mongoDB &amp;amp;&amp;amp; Rails 3 - Getting Started&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/banker/mongodb-rails3-sample/blob/master/app/models/user.rb&quot;&gt;user.rb&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
</feed>
