Kevin Deldyckehttp://kevin.deldycke.com/Open-Source Software EngineerMon, 17 Jun 2013 12:32:00 +0200Fix big HTML table rendering in IEhttp://kevin.deldycke.com/2013/06/html-table-rendering-ie/<p>It is well-known since the burst of the dot-com bubble that <a href="http://en.wikipedia.org/wiki/Tableless_web_design">tables are bad for layout</a>. But tables still makes perfect sense to present huge quantities of tabular data.</p> <p>The thing is, Internet Explorer can't cope with big HTML tables. So when it encounters a huge number of cells, IE9 starts to shift them randomly:</p> <p><img alt="" src="/static/uploads/2013/go-home-internet-explorer-you-are-drunk.png" /></p> <p>You can <a href="http://jsfiddle.net/kiranmn/kYRnV/">go here to reproduce this issue</a>.</p> <p>I absolutely don't care about these issues. Life is short. I have better things to do than fixing IE bugs.</p> <p>Still, at work, things are different. You're trading time for money. And it's up to your customer to choose what you should do with your time. I guess that's the tragedy of becoming a part of the software workforce.</p> <p>That's how I started to dive into IE hell.</p> <p>After some research, I found out the root cause of this issue. It's the presence of extra spaces and line returns between cells. Any sane browser should ignore these. But IE9 simply can't.</p> <p>This issue seems to have been <a href="http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/28d78780-c95c-4c35-9695-237ebb912d90">known since April 2011</a> (at least), but hasn't been addressed by Microsoft yet.</p> <p>And you know how I fixed this ? I fearlessly added the following piece of JavaScript in my initialization code:</p> <div class="codehilite"><pre><span class="c1">// Fix IE9 cells misalignment</span> <span class="nx">matrix</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s2">&quot;table tr&quot;</span><span class="p">).</span><span class="nx">contents</span><span class="p">().</span><span class="nx">filter</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span> <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">nodeType</span> <span class="o">==</span> <span class="mi">3</span><span class="p">;</span> <span class="p">}).</span><span class="nx">remove</span><span class="p">();</span> </pre></div> <p>The code above just strips all extra spaces from tables it find. You can <a href="https://github.com/Smile-SA/smile_openerp_matrix_widget/commit/c9646dd344e6bc05d5b9f8d33bd3cd6116e1c0f3">see this hack in action</a> in my <a href="http://kevin.deldycke.com/2012/08/announcing-openerp-matrix-widget/">matrix widget for OpenERP 6.0</a>.</p> <p>This is ugly, but makes my customer happy. Life is full of contradictions. And that's normal.</p>Kevin DeldyckeMon, 17 Jun 2013 12:32:00 +0200tag:kevin.deldycke.com,2013-06-17:2013/06/html-table-rendering-ie/Internet ExplorerMicrosoftOpenERPHTMLwebdesignSupport La Quadrature du Net !http://kevin.deldycke.com/2013/06/support-la-quadrature-du-net/<p>6 months ago <a href="https://twitter.com/kdeldycke/status/273711292026597376">I gave 100€</a> to <a href="http://www.laquadrature.net">La Quadrature du Net</a>. It's an advocacy group defending the rights and freedoms of citizens on the Internet. Its reputation is well established and its actions are internationally recognized by the <a href="https://www.eff.org/">Electronic Frontier Foundation</a> and the <a href="http://www.fsf.org/">Free Software Foundation</a>.</p> <p>They didn't reached their fundraising goal last year, but it doesn't matter: <a href="https://support.laquadrature.net/">donation</a> are accepted all year long. If you care about your rights &amp; freedom in a digital society, you should <a href="https://support.laquadrature.net/">contribute</a>.</p> <p>As a gift, you'll received decimals of Pi:</p> <p><img alt="" src="/static/uploads/2013/quadradure-du-net-pi-decimals.jpg" /></p>Kevin DeldyckeSun, 09 Jun 2013 12:41:00 +0200tag:kevin.deldycke.com,2013-06-09:2013/06/support-la-quadrature-du-net/La Quadrature du NetfundraisingdonationcampaigncontributionrightsfreedomInternetadvocacyFree Software FoundationElectronic Frontier Foundationmaildir-deduplicate.py moved to its own repositoryhttp://kevin.deldycke.com/2013/06/maildir-deduplicate-moved/<p><a href="http://kevin.deldycke.com/2010/08/maildir-deduplication-script-python/">In 2010 I created <code>maildir-deduplicate.py</code></a>, a one-of script to detect and remove duplicate copies of emails.</p> <p>Since then, <a href="http://blog.adamspiers.org">Adam</a> added loads of features and refinements to it, promoting himself to the de-facto maintainer. 3 months ago he privately asked me if I could split this script out of its messy home. Which makes sense.</p> <p>This post is just a message to all <code>maildir-deduplicate.py</code> users. The script is no longer available in my generic repository. It now has <a href="https://github.com/kdeldycke/maildir-deduplicate">its own dedicated repository on GitHub</a>, for which Adam has full administration rights.</p>Kevin DeldyckeTue, 04 Jun 2013 12:48:00 +0200tag:kevin.deldycke.com,2013-06-04:2013/06/maildir-deduplicate-moved/GitGitHubmaildirpythonrepositorycodeBehind the Scenes of Omashay's "Where is she ?"http://kevin.deldycke.com/2013/05/where-is-she-behind-the-scenes/<p>Back from holidays, and it's time for me to clear my backlog of draft articles. Here is the last and missing piece of my 2012 production notes series.</p> <p>Let's rewind to year ago, when <a href="http://kevin.deldycke.com/2012/08/where-is-she-music-video-released/"><em>Where is she ?</em> was released</a>:</p> <p> <iframe allowfullscreen="true" frameborder="0" height="344" src="http://www.youtube.com/embed/YjE_uIRVnv8" width="425"></iframe> </p> <h2>Pre-production</h2> <p>Tomasito planned this video and most of its shots in advance. Here is the basic outline of the scenes we arranged during a brainstorming session at my apartment in the end of 2010:</p> <p><img alt="" src="/static/uploads/2013/where-is-she-scenes-timeline.jpg" /></p> <p>We postponed the shooting so many times that these sticky papers were hanging on my wall for 2 years.</p> <p>Eventually this analog timeline led to some sketches and spreadsheets to prepare our shooting:</p> <p><img alt="" src="/static/uploads/2013/where-id-she-preproduction-sketches.jpg" /></p> <p><img alt="" src="/static/uploads/2013/where-is-she-roadbook.png" /></p> <p><img alt="" src="/static/uploads/2013/where-is-she-sequence.png" /></p> <h2>Shooting</h2> <p>The following gear was involved in the making of this video:</p> <ul> <li><a href="http://www.amazon.com/gp/product/B002NEGTTW/ref=as_li_tf_tl?ie=UTF8&amp;tag=kevideld-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399381&amp;creativeASIN=B002NEGTTW">Canon EOS 7D</a></li> <li><a href="http://www.amazon.com/gp/product/B004M170YC/ref=as_li_ss_tl?ie=UTF8&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B004M170YC&amp;linkCode=as2&amp;tag=kevideld-20">Canon EOS 600D (Rebel T3i / Kiss X5)</a></li> <li><a href="http://www.amazon.com/gp/product/B0033PRWSW/ref=as_li_ss_tl?ie=UTF8&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B0033PRWSW&amp;linkCode=as2&amp;tag=kevideld-20">Canon EF 70-200mm f/2.8L IS II USM</a></li> <li><a href="http://www.amazon.com/gp/product/B0007U0GZM/ref=as_li_tf_tl?ie=UTF8&amp;tag=kevideld-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399381&amp;creativeASIN=B0007U0GZM">Sigma 30mm f/1.4 EX DC HSM</a></li> <li><a href="http://www.amazon.com/gp/product/B0014Z3XMC/ref=as_li_tf_tl?ie=UTF8&amp;tag=kevideld-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=B0014Z3XMC">Tokina 11-16mm f/2.8</a></li> <li><a href="http://www.amazon.com/gp/product/B002LVUIXA/ref=as_li_tf_tl?ie=UTF8&amp;tag=kevideld-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399381&amp;creativeASIN=B002LVUIXA">Tamron SP AF 17-50mm f/2.8 XR Di-II VC LD IF lens</a></li> <li><a href="http://www.amazon.com/gp/product/B000V5K3FG/ref=as_li_ss_tl?ie=UTF8&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B000V5K3FG&amp;linkCode=as2&amp;tag=kevideld-20">Canon EF-S 18-55mm f/3.5-5.6 IS II</a></li> <li><a href="http://www.amazon.com/gp/product/B000UMX7FI/ref=as_li_ss_tl?ie=UTF8&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B000UMX7FI&amp;linkCode=as2&amp;tag=kevideld-20">Manfrotto 055XPROB Pro Tripod Legs</a></li> <li><a href="http://www.amazon.com/gp/product/B001AT314M/ref=as_li_ss_tl?ie=UTF8&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B001AT314M&amp;linkCode=as2&amp;tag=kevideld-20">Manfrotto 701HDV Pro Fluid Video Mini Head</a></li> <li><a href="http://www.amazon.com/gp/product/B0020LB0MO/ref=as_li_ss_tl?ie=UTF8&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B0020LB0MO&amp;linkCode=as2&amp;tag=kevideld-20">Glidecam HD-2000</a></li> <li>a basic Canon Monopod 100</li> <li><a href="http://www.amazon.com/gp/product/B003A2BU5E/ref=as_li_tf_tl?ie=UTF8&amp;tag=kevideld-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399381&amp;creativeASIN=B003A2BU5E">LCD ViewFinder</a></li> </ul> <p>I shot the video in 2012 in two days (1 &amp; 18 May) with some help from Robin (who makes a cameo appearance as the upset tourist). Here is the <strong>behind the scenes video</strong>:</p> <p> <iframe allowfullscreen="true" frameborder="0" height="344" src="http://www.youtube.com/embed/xtLz6jfSp-I" width="425"></iframe> </p> <p>And some extra photos of the shooting:</p> <p><img alt="" src="/static/uploads/2013/where-is-she-behind-the-scenes-001.jpg" /></p> <p><img alt="" src="/static/uploads/2013/where-is-she-behind-the-scenes-003.jpg" /></p> <p><img alt="" src="/static/uploads/2013/where-is-she-behind-the-scenes-006.jpg" /></p> <p><img alt="" src="/static/uploads/2013/where-is-she-behind-the-scenes-008.jpg" /></p> <p><img alt="" src="/static/uploads/2013/where-is-she-behind-the-scenes-009.jpg" /></p> <p><img alt="" src="/static/uploads/2013/where-is-she-behind-the-scenes-010.jpg" /></p> <p><img alt="" src="/static/uploads/2013/where-is-she-behind-the-scenes-013.jpg" /></p> <p><img alt="" src="/static/uploads/2013/where-is-she-behind-the-scenes-021.jpg" /></p> <p>The <a href="http://kevin.deldycke.com/2012/11/wedding-entrance-paris-video-postcard/">wedding entrance</a> video was the first time I used my <a href="http://www.amazon.com/gp/product/B0020LB0MO/ref=as_li_ss_tl?ie=UTF8&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B0020LB0MO&amp;linkCode=as2&amp;tag=kevideld-20">Glidecam HD-2000</a>. But <em>Where is she ?</em> was the <a href="http://kevin.deldycke.com/2012/08/where-is-she-music-video-released/">first publicly released video</a> featuring my new toy. And while filming with it in Monrmartre, a police patrol car paid us a visit:</p> <p> <iframe allowfullscreen="true" frameborder="0" height="344" src="http://www.youtube.com/embed/EGh-DZjIjHg" width="425"></iframe> </p> <p>No need to say the music video was produced in guerilla style, without any warning nor permission... ;)</p> <h2>Editing</h2> <p>Tomasito edited alone the source footage (1080p, 23.976 fps, 1/50s shutter) in Kdenlive:</p> <p><img alt="" src="/static/uploads/2013/where-is-she-ungraded-kdenlive-timeline.jpg" /></p> <p>At that stage, I just helped him by creating the seamless split screens:</p> <p><img alt="" src="/static/uploads/2013/where-is-she-split-screen-001.jpg" /></p> <p><img alt="" src="/static/uploads/2013/where-is-she-split-screen-002.jpg" /></p> <h2>Color correction</h2> <p>As I said in <a href="http://kdenlive.org/forum/music-video-paris-color-grading-example#comment-18744">Kdenlive's forum</a>, the color correction was a first. I never worked on a project for which any serious color correction was done. Until <em>Where is she ?</em>.</p> <p>I was worried by the final look of it because, <a href="http://kdenlive.org/forum/music-video-paris-color-grading-example#comment-18690">as Marko pointed out</a> in the thread, the footage was captured in all sorts of lighting conditions. It's hard to keep a consistent exposure between all these locations, especially with the tight latitude of a <a href="http://www.amazon.com/gp/product/B002NEGTTW/ref=as_li_tf_tl?ie=UTF8&amp;tag=kevideld-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399381&amp;creativeASIN=B002NEGTTW">Canon 7D</a> (even with a <a href="http://prolost.com/flat">fine-tuned neutral color profile</a>).</p> <p>Robin did all the color correction in Kdenlive and for him, it was a first too. The goal wasn't to apply create a strong style. Color grading was more or less a technical mean, to keep the exposure jumping from shot to shot. Robin invested lots of time in this project and the result exceeded our expectations. The final video is fairly consistent and the cut between scenes is smooth compared to the raw footage.</p> <p>I'd love to show you screenshots of the timeline with all its color parameters. Unfortunately we used an old development version, and when I try to re-open the project with the current version I have on my machine, I end up with this errors before completely crashing Kdenlive:</p> <p><img alt="" src="/static/uploads/2013/kdenlive-missing-color-filters.png" /></p> <p>But by looking at the XML source of the project, I can assert that the whole color correction was entirely made with a combination of these 3 filters only:</p> <ul> <li>RGB adjustment (<code>frei0r.coloradj_RGB</code>)</li> <li>Curves (<code>frei0r.curves</code>)</li> <li>Brightness</li> </ul> <p>If I can't show you all the details, I can still show you a comparison between the raw footage and the color correction pass (the video below has no audio on purpose):</p> <p> <iframe allowfullscreen="true" frameborder="0" height="344" src="http://www.youtube.com/embed/t6cCQV2Jt2U" width="425"></iframe> </p>Kevin DeldyckeMon, 20 May 2013 12:32:37 +0200tag:kevin.deldycke.com,2013-05-20:2013/05/where-is-she-behind-the-scenes/videoyoutubekdenlivemusic videoomashaybehind the scenesmaking ofAddon to restore search range in OpenERP 6.1http://kevin.deldycke.com/2013/04/openerp-61-search-range-addon/<p>In OpenERP 6.1, the default search widget for dates and floats <a href="https://bugs.launchpad.net/openerp-web/+bug/926390/">no longer feature a range</a>:</p> <p><img alt="" src="/static/uploads/2013/openerp-61-no-range-search-widget.png" /></p> <p>This was <a href="https://bugs.launchpad.net/openerp-web/+bug/949990">uncovered</a> by <a href="https://answers.launchpad.net/openobject-server/+question/198725">users</a> in the <a href="https://answers.launchpad.net/openobject-server/+question/198863">community</a>. But it's not a bug, <a href="https://bugs.launchpad.net/openerp-web/+bug/926390/comments/4">it's a feature</a>, a design decision.</p> <p>Worse, <code>datetime</code> search field in OpenERP 6.1 <a href="https://bugs.launchpad.net/openerp-web/+bug/1037658">no longer let you set the time</a>:</p> <p><img alt="" src="/static/uploads/2013/openerp-61-datetime-search-view.png" /></p> <p>To fix these issues, I've created <a href="https://github.com/Smile-SA/smile_openerp_addons_6.1/tree/master/web_smile_search_range"><code>web_smile_search_range</code></a> a module which is available since 2012, but I never advertised it on this blog.</p> <p>This module is based on an <a href="http://bazaar.launchpad.net/~credativ/credativ-openerp/addons-6.1/files/head:/web_searchdaterange/">open-source addon from Credativ</a>. I extended the later to:</p> <ul> <li>Replace single <code>date</code>, <code>datetime</code> and <code>float</code> search fields to a range.</li> <li>Allow selection of time in <code>datetime</code> search fields.</li> </ul> <p>Thus restoring the default behavior from OpenERP 6.0 that was ditched in 6.1.</p> <p>And if you need to dig deeper in the code, you'll quickly find out that the core of the module lie in the <a href="https://github.com/Smile-SA/smile_openerp_addons_6.1/blob/master/web_smile_search_range/static/src/js/search.js"><code>search.js</code> file</a>, which extend in Javascript the search fields models of our interests.</p>Kevin DeldyckeTue, 23 Apr 2013 12:25:36 +0200tag:kevin.deldycke.com,2013-04-23:2013/04/openerp-61-search-range-addon/OpenERPJavascriptBackbone.jsjQueryWebaddonRun OpenERP's ir.cron from command-linehttp://kevin.deldycke.com/2013/04/openerp-ir-cron-script/<p>Here is a simple Python script to trigger an <code>ir.cron</code> job from the command-line system.</p> <p>I created this to let my customer use his proprietary job scheduler to trigger OpenERP tasks. It was tested on OpenERP 6.1.</p> <div class="codehilite"><pre><span class="c">#!/usr/bin/python</span> <span class="kn">import</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="nn">xmlrpclib</span> <span class="kn">import</span> <span class="nn">traceback</span> <span class="kn">import</span> <span class="nn">sys</span> <span class="kn">from</span> <span class="nn">optparse</span> <span class="kn">import</span> <span class="n">OptionParser</span> <span class="n">parser</span> <span class="o">=</span> <span class="n">OptionParser</span><span class="p">()</span> <span class="n">parser</span><span class="o">.</span><span class="n">add_option</span><span class="p">(</span><span class="s">&quot;-d&quot;</span><span class="p">,</span> <span class="s">&quot;--db&quot;</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s">&quot;db_name&quot;</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s">&quot;OpenERP database name&quot;</span><span class="p">,</span> <span class="n">metavar</span><span class="o">=</span><span class="s">&quot;DB_NAME&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s">&quot;openerp&quot;</span><span class="p">)</span> <span class="n">parser</span><span class="o">.</span><span class="n">add_option</span><span class="p">(</span><span class="s">&quot;-p&quot;</span><span class="p">,</span> <span class="s">&quot;--password&quot;</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s">&quot;password&quot;</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s">&quot;OpenERP admin password&quot;</span><span class="p">,</span> <span class="n">metavar</span><span class="o">=</span><span class="s">&quot;ADMIN_PASSWORD&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s">&quot;admin&quot;</span><span class="p">)</span> <span class="n">parser</span><span class="o">.</span><span class="n">add_option</span><span class="p">(</span><span class="s">&quot;-n&quot;</span><span class="p">,</span> <span class="s">&quot;--name&quot;</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s">&quot;cron_name&quot;</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s">&quot;OpenERP ir.cron object name&quot;</span><span class="p">,</span> <span class="n">metavar</span><span class="o">=</span><span class="s">&quot;CRON_NAME&quot;</span><span class="p">)</span> <span class="p">(</span><span class="n">options</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span> <span class="k">assert</span> <span class="n">options</span><span class="o">.</span><span class="n">cron_name</span> <span class="k">try</span><span class="p">:</span> <span class="n">sock</span> <span class="o">=</span> <span class="n">xmlrpclib</span><span class="o">.</span><span class="n">ServerProxy</span><span class="p">(</span><span class="s">&#39;http://localhost:8069/xmlrpc/object&#39;</span><span class="p">)</span> <span class="n">ir_cron_ids</span> <span class="o">=</span> <span class="n">sock</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">options</span><span class="o">.</span><span class="n">db_name</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">options</span><span class="o">.</span><span class="n">password</span><span class="p">,</span> <span class="s">&#39;ir.cron&#39;</span><span class="p">,</span> <span class="s">&#39;search&#39;</span><span class="p">,</span> <span class="p">[(</span><span class="s">&#39;name&#39;</span><span class="p">,</span> <span class="s">&#39;=&#39;</span><span class="p">,</span> <span class="n">options</span><span class="o">.</span><span class="n">cron_name</span><span class="p">)])</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">ir_cron_ids</span><span class="p">:</span> <span class="k">raise</span> <span class="s">&quot;No cron found in OpenERP.&quot;</span> <span class="k">for</span> <span class="n">ir_cron</span> <span class="ow">in</span> <span class="n">sock</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">options</span><span class="o">.</span><span class="n">db_name</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">options</span><span class="o">.</span><span class="n">password</span><span class="p">,</span> <span class="s">&#39;ir.cron&#39;</span><span class="p">,</span> <span class="s">&#39;read&#39;</span><span class="p">,</span> <span class="n">ir_cron_ids</span><span class="p">,</span> <span class="p">[</span><span class="s">&#39;model&#39;</span><span class="p">,</span> <span class="s">&#39;function&#39;</span><span class="p">,</span> <span class="s">&#39;args&#39;</span><span class="p">]):</span> <span class="k">print</span> <span class="s">&quot;</span><span class="si">%s</span><span class="s">, </span><span class="si">%s</span><span class="s"> - (</span><span class="si">%s</span><span class="s">) </span><span class="si">%s</span><span class="s"> </span><span class="si">%s%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">options</span><span class="o">.</span><span class="n">db_name</span><span class="p">,</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s">&#39;%Y-%m-</span><span class="si">%d</span><span class="s"> %H:%M:%S&#39;</span><span class="p">),</span> <span class="n">ir_cron</span><span class="p">[</span><span class="s">&#39;id&#39;</span><span class="p">],</span> <span class="n">ir_cron</span><span class="p">[</span><span class="s">&#39;model&#39;</span><span class="p">],</span> <span class="n">ir_cron</span><span class="p">[</span><span class="s">&#39;function&#39;</span><span class="p">],</span> <span class="n">ir_cron</span><span class="p">[</span><span class="s">&#39;args&#39;</span><span class="p">])</span> <span class="n">sock</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">options</span><span class="o">.</span><span class="n">db_name</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">options</span><span class="o">.</span><span class="n">password</span><span class="p">,</span> <span class="n">ir_cron</span><span class="p">[</span><span class="s">&#39;model&#39;</span><span class="p">],</span> <span class="n">ir_cron</span><span class="p">[</span><span class="s">&#39;function&#39;</span><span class="p">],</span> <span class="o">*</span><span class="nb">eval</span><span class="p">(</span><span class="s">&#39;tuple(</span><span class="si">%s</span><span class="s">)&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">ir_cron</span><span class="p">[</span><span class="s">&#39;args&#39;</span><span class="p">]</span> <span class="ow">or</span> <span class="s">&#39;&#39;</span><span class="p">)))</span> <span class="k">except</span><span class="p">:</span> <span class="n">traceback</span><span class="o">.</span><span class="n">print_exc</span><span class="p">(</span><span class="nb">file</span><span class="o">=</span><span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="p">)</span> <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span> <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">()</span> </pre></div>Kevin DeldyckeThu, 18 Apr 2013 12:46:34 +0200tag:kevin.deldycke.com,2013-04-18:2013/04/openerp-ir-cron-script/OpenERPPythonscriptCLIcronschedulerjobPelican effectshttp://kevin.deldycke.com/2013/04/pelican-effects/<p>Here is a screenshot from <a href="http://www.google.com/webmasters/tools/home">Google's webmaster tool</a> monitoring the average page download time of this site. Can you spot when I switched from <a href="http://kevin.deldycke.com/2013/02/wordpress-to-pelican/">WordPress to Pelican</a> ? :)</p> <p><img alt="" src="/static/uploads/2013/pelican-boost.png" /></p>Kevin DeldyckeFri, 05 Apr 2013 12:03:26 +0200tag:kevin.deldycke.com,2013-04-05:2013/04/pelican-effects/WordPressPelicanPythonblogwebTale of Two: production noteshttp://kevin.deldycke.com/2013/03/tale-two-production-notes/<p>This is the fourth video I've work on for <a href="http://omashay.com">Omashay</a>:</p> <p> <iframe allowfullscreen="true" frameborder="0" height="344" src="http://www.youtube.com/embed/4HtfugU_mGg" width="425"></iframe> </p> <p>This video is a timelapse of a painting Tomasito made in 2007. It's based on a series of photos he took every 10 minutes:</p> <p><img alt="" src="/static/uploads/2012/03/tale-of-two-timelapse.png" /></p> <h2>slowmoVideo</h2> <p>I tried to produce a timelapse out of these images a year ago. In fact, that was the original project I was referring to in my <a href="http://kevin.deldycke.com/2013/03/goodnight-video/">previous article</a>, the project which triggered my initial interest into <a href="http://slowmovideo.granjow.net/">slowmoVideo</a>.</p> <p>But the experiment failed and I abandoned this endeavor. Instead of slow-motion, and because of the low timing resolution of the photos, I assumed a simple slideshow would do it.</p> <h2>Blender</h2> <p>The original photos were not consistent. To make them work as a slideshow, they required some stabilization. I tried the new <a href="http://wiki.blender.org/index.php/Doc:2.6/Manual/Motion_Tracking">tracking features of Blender</a>:</p> <p><img alt="" src="/static/uploads/2013/03/blender-timlapse-stabilization.jpg" /></p> <p>While I could feel the power of the tracking tools, my limited knowledge of Blender stopped me. I abandoned this approach. But one day for sure, I'll give Blender the time it deserves.</p> <h2>vid.stab &amp; Kdenlive</h2> <p>My plan B for stabilization was <a href="http://kevin.deldycke.com/2012/02/stabilizing-cute-baby-goats/">Transcode's vid.stab plugin</a>.</p> <p>But it can't read images: it only takes videos for input. So we'll produce a video file of a simple slideshow in Kdenlive, then feed the result to vid.stab.</p> <p>First, in a separate project, I created a stupid slideshow of 1 photo per frame, without any transition:</p> <p><img alt="" src="/static/uploads/2012/03/redux-generation.png" /></p> <p>To keep details, I exported the project to a high-quality h264 stream composed of I-frames only:</p> <p><img alt="" src="/static/uploads/2012/03/export.png" /></p> <p>I wanted to use a true lossless codec here, but after several trials and errors, this profile was the only one <code>vid.stab</code> was able to digest.</p> <p>I can now apply the stabilization, with a high shakiness parameter to make the algorithm ignore the lack of fluidity:</p> <div class="codehilite"><pre><span class="nv">$ </span>transcode -J stabilize -i ./slideshow-redux.mp4 -y null,null -o dummy <span class="nv">$ </span>transcode -J <span class="nv">stabilize</span><span class="o">=</span><span class="nv">shakiness</span><span class="o">=</span>8 -i ./slideshow-redux.mp4 -y ffmpeg -F huffyuv -o ./slideshow-redux-stabilized.avi </pre></div> <p>Then we extract all frames of the stabilized video to get a new set of photos:</p> <div class="codehilite"><pre><span class="nv">$ </span>mkdir ./timelapse-stabilized <span class="nv">$ </span><span class="nb">cd</span> ./timelapse-stabilized <span class="nv">$ </span>cp ../slideshow-redux-stabilized.avi <span class="nv">$ </span>ffmpeg -i ./slideshow-redux-stabilized.avi -f image2 stab%05d.png </pre></div> <p>From the produced images, I created a new slideshow with proper transitions.</p> <p>I presented the final rendering to Tomasito, and we agreed that the result, while not incredible, was a good excuse to distribute one of his song on YouTube.</p> <p>He planned to published the video, but the final editing step was postponed by several months. And then we both forgot the project.</p> <h2>slowmoVideo, again</h2> <p>Until last January when, after <a href="http://kevin.deldycke.com/2013/02/slowmo-video-ubuntu-12-10/">some efforts</a>, I managed to <a href="http://kevin.deldycke.com/2013/03/goodnight-video/">produce something with slowmoVideo</a>. We resurected the project.</p> <p>I applied the raw slowmoVideo transformation on the initial set of photos. And the result was good enough. But Tomasito wanted more, and stabilized all the 70 images of the original set by hand !</p> <p>After this herculean task, I cropped &amp; resized the images to fit the 1080p resolution:</p> <div class="codehilite"><pre><span class="nv">$ </span>convert -resize 1920x1080 -background black -gravity center -extent 1920x1080 ./manually-stab-keyframes/* pict%04d.png </pre></div> <p><a href="http://kevin.deldycke.com/2013/03/goodnight-video/">As for Goodnight</a>, we tried to get rid of the wide black bars on the sides. <a href="http://wqpx.wordpress.com">QPX</a> created for us a mask made of paint strokes:</p> <p><img alt="" src="/static/uploads/2013/03/video-mask.png" /></p> <p>Then I used that mask to blend the photos with a background fiber texture from <a href="http://subtlepatterns.com">Subtle Patterns</a>:</p> <div class="codehilite"><pre><span class="nv">$ </span>find ./ -iname <span class="s2">&quot;pict*.png&quot;</span> -exec composite <span class="s2">&quot;{}&quot;</span> ./stressed_linen-1080p.png ./Masque-02.png <span class="s2">&quot;{}&quot;</span>-composed.png <span class="se">\;</span> </pre></div> <p>Finally I send these pre-rendered keyframes to slowmoVideo to produce a 4 minutes ultra-slow-motion. Then Tomasito added a title and credits.</p> <p>There is no magic and the final result could have been better if properly shot. What's missing was a steady canvas and good camera positioning, and of course a lower delay between photos. These are the perfect conditions to produce a proper timelapse, and I'm sure we'll demonstrate that in a future project.</p>Kevin DeldyckeTue, 26 Mar 2013 12:32:37 +0100tag:kevin.deldycke.com,2013-03-26:2013/03/tale-two-production-notes/Kdenlivelinuxomashaytimelapseslow-motionslowmoVideoimagemagicktranscodevid.stabBlenderlibvirt commandshttp://kevin.deldycke.com/2013/03/libvirt-commands/<p>List system virtual machines:</p> <div class="codehilite"><pre><span class="nv">$ </span>virsh -c qemu:///system list --all </pre></div> <p>List session VMs:</p> <div class="codehilite"><pre><span class="nv">$ </span>virsh -c qemu:///session list --all </pre></div> <p>Dump a VM configuration to XML file:</p> <div class="codehilite"><pre><span class="nv">$ </span>virsh -c qemu:///system dumpxml vm-name &gt; vm-name-conf.xml </pre></div> <p>Create a new VM by importing its XML configuration:</p> <div class="codehilite"><pre><span class="nv">$ </span>virsh -c qemu:///system define vm-name-conf.xml </pre></div>Kevin DeldyckeWed, 20 Mar 2013 12:25:36 +0100tag:kevin.deldycke.com,2013-03-20:2013/03/libvirt-commands/CLILinuxlibvirtQEMUvirtual machineOpenERP 6.1 web client hacks: hide buttons with Javascripthttp://kevin.deldycke.com/2013/03/openerp-61-web-javascript-hacks-hide-buttons/<p>Last year I published two articles on hacking OpenERP 6.0 user interface, one to demonstrate <a href="http://kevin.deldycke.com/2012/02/how-to-monkey-patch-openerp-native-javascript/">how to monkey-patch native Javascript behavior</a>, the other to show how to <a href="http://kevin.deldycke.com/2012/05/hacking-openerp-60-user-interface-javascript/">tweak widgets</a></p> <p>Both methods are based on an injection of inline Javascript code via XML view definition. In OpenERP 6.1, as <a href="http://kevin.deldycke.com/2012/02/how-to-monkey-patch-openerp-native-javascript/#comment-769313088">highlighted by Timothy</a> you can no longer leverage this dirty trick: Javascript is stripped out of the XML stream.</p> <p>But I found new ways of hacking OpenERP's web client in 6.1. Following these discoveries, I've created a the <a href="https://github.com/Smile-SA/smile_openerp_addons_6.1/tree/master/web_smile_hide_buttons/">experimental <code>web_smile_hide_buttons</code> addon</a> to hide the hard-coded <code>create</code> and <code>duplicate</code> buttons on <code>form</code> views.</p> <p>This module is not generic: it just demonstrate how to distribute dirty patches to the web client. It currently:</p> <ul> <li>Hide <code>create</code> buttons on all list views (affect <code>tree</code> views and <code>many2one</code> search view pop-ups),</li> <li>Hide the <code>save</code> button on <code>form</code> views,</li> <li>Hide <code>create</code> and <code>duplicate</code> button on all read-only <code>form</code> views,</li> <li>Only apply these transformations to a configurable subset of models.</li> </ul> <p>The core of the module lies in the <a href="https://github.com/Smile-SA/smile_openerp_addons_6.1/blob/master/web_smile_hide_buttons/static/src/js/custom.js"><code>/static/src/js/custom.js</code></a> file. Here is an excerpt of that file, which sums-up my hacks:</p> <div class="codehilite"><pre><span class="nx">openerp</span><span class="p">.</span><span class="nx">web_smile_hide_buttons</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">openerp</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// Models for which we&#39;ll hide create and duplicate buttons</span> <span class="kd">var</span> <span class="nx">MODELS_TO_HIDE</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;res.partner&#39;</span><span class="p">];</span> <span class="c1">// Hide the create button on all list views, which affect tree views and many2one pop-up search view</span> <span class="nx">openerp</span><span class="p">.</span><span class="nx">web</span><span class="p">.</span><span class="nx">ListView</span><span class="p">.</span><span class="nx">include</span><span class="p">({</span> <span class="nx">start</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span> <span class="kd">var</span> <span class="nx">ret</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_super</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="nx">arguments</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">res_model</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">dataset</span><span class="p">.</span><span class="nx">model</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="nx">$</span><span class="p">.</span><span class="nx">inArray</span><span class="p">(</span><span class="nx">res_model</span><span class="p">,</span> <span class="nx">MODELS_TO_HIDE</span><span class="p">)</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span> <span class="nx">self</span><span class="p">.</span><span class="nx">options</span><span class="p">.</span><span class="nx">addable</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span> <span class="p">};</span> <span class="k">return</span> <span class="nx">ret</span><span class="p">;</span> <span class="p">},</span> <span class="p">});</span> <span class="c1">// Hide the save button on form views</span> <span class="nx">openerp</span><span class="p">.</span><span class="nx">web</span><span class="p">.</span><span class="nx">FormView</span><span class="p">.</span><span class="nx">include</span><span class="p">({</span> <span class="nx">on_loaded</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span> <span class="kd">var</span> <span class="nx">ret</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_super</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="nx">arguments</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">res_model</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">dataset</span><span class="p">.</span><span class="nx">model</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="nx">$</span><span class="p">.</span><span class="nx">inArray</span><span class="p">(</span><span class="nx">res_model</span><span class="p">,</span> <span class="nx">MODELS_TO_HIDE</span><span class="p">)</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span> <span class="k">this</span><span class="p">.</span><span class="nx">$element</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s1">&#39;button.oe_form_button_save&#39;</span><span class="p">).</span><span class="nx">remove</span><span class="p">();</span> <span class="p">};</span> <span class="k">return</span> <span class="nx">ret</span><span class="p">;</span> <span class="p">},</span> <span class="p">});</span> <span class="c1">// Hide the create and duplicate button on all page views (i.e. read-only form views)</span> <span class="nx">openerp</span><span class="p">.</span><span class="nx">web</span><span class="p">.</span><span class="nx">PageView</span><span class="p">.</span><span class="nx">include</span><span class="p">({</span> <span class="nx">on_loaded</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span> <span class="kd">var</span> <span class="nx">ret</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_super</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="nx">arguments</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">res_model</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">dataset</span><span class="p">.</span><span class="nx">model</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="nx">$</span><span class="p">.</span><span class="nx">inArray</span><span class="p">(</span><span class="nx">res_model</span><span class="p">,</span> <span class="nx">MODELS_TO_HIDE</span><span class="p">)</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span> <span class="k">this</span><span class="p">.</span><span class="nx">$element</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s1">&#39;button.oe_form_button_create&#39;</span><span class="p">).</span><span class="nx">remove</span><span class="p">();</span> <span class="k">this</span><span class="p">.</span><span class="nx">$element</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s1">&#39;button.oe_form_button_duplicate&#39;</span><span class="p">).</span><span class="nx">remove</span><span class="p">();</span> <span class="p">};</span> <span class="k">return</span> <span class="nx">ret</span><span class="p">;</span> <span class="p">},</span> <span class="p">});</span> <span class="p">};</span> </pre></div> <p>As you can see in the <a href="https://github.com/Smile-SA/smile_openerp_addons_6.1/blob/master/web_smile_hide_buttons/static/src/js/custom.js">full version of the code above</a>, I tried to hide <code>create</code> entries of <code>many2one</code> context menus, but failed to.</p> <p>And to make the module really complete, I still have to find a way to hide <code>create</code> &amp; <code>modify</code> entries of <code>many2one</code> drop-down menus. If you have some working code that's doing this, feel free to send me a pull request on GitHub.</p>Kevin DeldyckeThu, 14 Mar 2013 12:25:36 +0100tag:kevin.deldycke.com,2013-03-14:2013/03/openerp-61-web-javascript-hacks-hide-buttons/OpenERPJavascriptBackbone.jsjQueryWeb