Tuenti RSSesWe're going to Medium!https://corporate.tuenti.com/es/dev/blog/Were-going-to-Medium
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded">Engineering Outreach Committee<br />
<br />
We thought<em> why not?</em>... So off we went. From now on, you can follow the adventures of everyone at Tuenti in the development, product and design teams at our brand new Medium profile <a href="https://medium.com/@tuentimakers" target="_blank">@tuentimakers</a>.<br />
<br />
Of course, we&#39;ll keep the entire history of this blog so you can check out what we&#39;ve written about <a href="http://corporate.tuenti.com/es/dev/blog/Activity-detector" target="_blank">Activity detector</a>, <a href="http://corporate.tuenti.com/es/dev/blog/Tuenti-on-the-Apple-Watch" target="_blank">the Tuenti app for Apple Watch</a> or <a href="http://corporate.tuenti.com/es/dev/blog/tags/.Tuenti%20Challenge%206" target="_blank">the write-ups of the Tuenti Challenge 6</a> whenever you like.<br />
<br />
<a href="https://medium.com/makingtuenti" target="_blank">See you on Medium!</a> &lt;3<br />
<br />
<img alt="" src="http://corporate.tuenti.com/cdn/farfuture/NaUW3ZxHhaMQsly4qOHDzoweNdubwXBOGvybkUUydU4/md5:c09bd2194032a527d088d13f7a2914c9/files/TuentiDev/Tuenti%20Makers.png" style="width: 640px; height: 231px;" /><br />
</div></div></div>Wed, 23 Nov 2016 11:01:17 +0000TuentiDev1631 at https://corporate.tuenti.comActivity detectorhttps://corporate.tuenti.com/es/dev/blog/Activity-detector
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded">by Abel Toledano, Senior Software Engineer<br />
<br />
<p>Sometimes, when you want to do some action in your page using JavaScript it’s very convenient to know whether the user is actually paying attention to your page at that moment, because, as you probably know, the JS in your page can be executing even when it is in background. For example, the user can be reading a different browser tab, or even using a different application and the browser doesn’t have the focus.</p>
<p>In Tuenti we have had to deal with this kind of problems in different situations. One clear example is the Tuenti chat: we want to notify the user about new messages playing a notification sound, but we don’t want to play it when the user is already paying attention to the conversation, we only want to play the notification sound when the page is in background to take the user’s attention.</p>
<p>To achieve this we listen to different browser events to determine whether the user is actually using Tuenti at that moment or not. These are some of the events we listen to:</p>
<h3><a id="focus_and_blur_events_in_window_8"></a><code>focus</code> and <code>blur</code> events in <code>window</code>:</h3>
<p>When a user enters to your page, the browser fires a <code>focus</code> event in the <code>window</code> object. In the same way, when the user changes to a different tab or application, the browser fires a <code>blur</code> event.</p>
<p>Taking this into account, it’s pretty simple to determine whether the user is in your tab:</p>
<pre class="brush: js">
var inTab = true;
window.addEventListener('focus', function () {
inTab = true;
});
window.addEventListener('blur', function () {
inTab = false;
});
</pre>
<p>Pretty simple, isn’t it?</p>
<p>Well… it depends on what you really need. With this simple code you can know whether the user is in your tab, but what happens if the user is in your tab but he has left the computer and is in the bathroom?</p>
<p>So we don’t only need to know if the user is in our tab but also if he is using it. To solve this problem we could connect the laptop webcam and spy the user, but probably our users wouldn’t like that. So we can use a simpler (and more privacy
respectful) solution:</p>
<h3><a id="Mouse_and_keyboard_events_32"></a>Mouse and keyboard events</h3>
<p>We can listen to DOM user interaction events to know if the user is actually using the page, and when we have not heard any event for a given time span (for example 30 seconds) we can assume the user is not active. Some events we can listen to are: <code>click</code>, <code>mousemove</code>, <code>keydown</code>, etc (for desktop devices), or <code>touchstart</code>, <code>touchmove</code>, etc. (for mobile devices).</p>
<p>So we can attach some event listeners to the <code>document</code> and toggle the <code>inTab</code> variable in the previous example to <code>true</code>. But, when we change it to <code>false</code>? when it has elapsed 30 seconds since the last event. This behavior can be implemented with a <code>setTimeout</code>, but we also need to reset that timeout (with a <code>clearTimeout</code>) when we hear a new event.</p>
<p>We can express this solution with a simple state machine:</p>
<p><img src="https://gist.githubusercontent.com/atabel/9b7110abbb89461cb322/raw/969765d3d1aa108ab754d20aad1a986ba191a6d8/state-machine.png" alt="state machine"></p>
<p>Ok, beautiful, let’s implement it. You don’t need to do it! because we have already done it and opensourced a library that you can use: <code>activity-detector</code>:</p>
<h2><a id="How_to_use_44"></a>How to use</h2>
<hr>
<h3><a id="First_install_it_46"></a>First, install it.</h3>
<p>We distribute the lib in <a href="https://www.npmjs.com/package/activity-detector">npm</a>, so you can install it with a simple command:</p>
<pre class="brush: bash">
$ npm install --save activity-detector
</pre>
<h3><a id="Lets_see_a_basic_example_53"></a>Let’s see a basic example</h3>
<pre class="brush: js">
// 1. import the lib:
import createActivityDetector from 'activity-detector';
// 2. create an activity-detector instance:
const activityDetector = createActivityDetector();
// 3. subscribe to events
activityDetector.on('idle', () => {
console.log('The user is not interacting with the page');
});
activityDetector.on('active', () => {
console.log('The user is using the page');
});
</pre>
<p>How this work? the library implements the algorithm we have presented in the previous state machine diagram. When you create an instance of <code>activity-detector</code> you can subscribe to the events <code>active</code> and <code>idle</code>. Those events will be triggered when the user becomes ACTIVE or INACTIVE respectively.</p>
<p>And that’s all. Now you can detect when your user is using your page or not.</p>
<h3><a id="Ok_but_I_dont_use_npm_neither_ES6_Can_I_use_activitydetector_lib_75"></a>Ok, but I don’t use npm neither ES6. Can I use <code>activity-detector</code> lib?</h3>
<p>Of course, we have a production ready build (UMD format) that you can simply include in your page with a simple <code>&lt;script&gt;</code> tag, or require it with any module loader (like require.js). You can find it <a href="https://npmcdn.com/activity-detector/dist/activity-detector.min.js">here</a>.</p>
<p>For example:</p>
<pre class="brush: xml">
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>test activity detector</title>
<script type="text/javascript" src ="https://npmcdn.com/activity-detector/dist/activity-detector.min.js"></script>
</head>
<body>
<div id="user-activity">
</div>
<script type="text/javascript">
var ad = activityDetector();
var userActivity = document.getElementById('user-activity');
ad.on('idle', function () {
userActivity.innerHTML = 'the user is INACTIVE';
});
ad.on('active', function () {
userActivity.innerHTML = 'the user is ACTIVE';
});
</script>
</body>
</html>
</pre>
<h3><a id="Advanced_options_108"></a>Advanced options</h3>
<p><code>activity-detector</code> supports different config options to customize its behavior if you have different needs. For example you can decide which user events should be considered, or defer the <code>activity-detector</code> initialization. For example:</p>
<pre class="brush: js">
const activityDetector = createActivityDetector({
timeToIdle: 10000, // wait 10s of inactivity to consider the user is idle
});
</pre>
<p>You can see the different options reading the docs in the github repo:</p>
<p><a href="https://github.com/tuenti/activity-detector/">https://github.com/tuenti/activity-detector/</a></p>
<p>If you like it and think it’s useful don’t forget to star it. And if you miss some feature or find a bug please open an issue or, even better, send us a pull request!</p>
<iframe src="https://ghbtns.com/github-btn.html?user=tuenti&repo=activity-detector&type=star&count=true&size=large" frameborder="0" scrolling="0" width="160px" height="30px"></iframe>
<script type="text/javascript" src="http://static.corporate.tuenti.com/sites/all/themes/tuentitheme/js/syntaxhighlighter.js"></script><script type="text/javascript">SyntaxHighlighter.all();</script></div></div></div>Wed, 19 Oct 2016 07:41:28 +0000TuentiDev1627 at https://corporate.tuenti.comHMU30: Innovation in Personal Communicationshttps://corporate.tuenti.com/es/dev/blog/HMU30-Innovation-in-Personal-Communications
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded">Outreach Committee<br />
<br />
For another quarter, we come to the end of our most creative 32 non-stop hours with the thirtieth edition of our <a href="http://corporate.tuenti.com/en/dev/hack-me-ups" target="_blank">Hack Me Up</a>. This time the Product track topic was <strong><em>Innovation in Personal Communications</em></strong>,<br />
<br />
As usual, these 32 hours gave complete freedom to its participants to create work groups with colleagues in other areas or teams and develop their own product ideas, apart from their daily jobs.<br />
<br />
In this edition there were several projects registered, amongst which there were ideas on voice calls or chat. And the winners of HMU30 were the following:
<ul>
<li>
<em>Peek and see</em> was the winning project in the Product category. C&eacute;sar, Alejandro, Pablo and Jose&nbsp;made a project using the iOS SDK that transcripts recorded calls as a chat conversation.</li>
<li>
Aar&oacute;n, Edu and Jos&eacute; Antonio&nbsp;raised the Geek cup thanks to their <em>Foostastic</em>, a project like a comunio but for the internal Tuenti league.</li>
</ul>
Despite there being only two winning projects, many of those presented were of excellent technical quality and may be implemented at Tuenti for the use of our clients and users. We&rsquo;ll keep you posted!<br />
<br />
<strong>Congratulations to the winning teams!<br />
<br />
<img alt="" src="http://corporate.tuenti.com/cdn/farfuture/g_qnFtQeAHYYBp5JNNHyYPKivE_r1gD-dOPybQnQ4jA/md5:b1e87cd135bf95f72f26d9c3fab584ea/files/TuentiDev/product.png" style="width: 640px; height: 378px;" /><br />
<img alt="" src="http://corporate.tuenti.com/cdn/farfuture/V_gXSVYM-j0D1mOfArtmxc-3N841q8FoDeOsz2mtjTc/md5:916cb630a56e4e8133d41283ad0bcfaa/files/TuentiDev/geek.png" style="width: 640px; height: 358px;" /></strong><br />
</div></div></div>Fri, 14 Oct 2016 14:13:45 +0000TuentiDev1625 at https://corporate.tuenti.com#TuentiChallenge6: Compilation of solutions and writeupshttps://corporate.tuenti.com/es/dev/blog/TuentiChallenge6-Compilation-of-solutions-and-writeups
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded">Alfredo Beaumont, Senior Software Engineer<br />
<br />
We have compiled some solutions and writeups made by participants that you may find interesting. Hope you like them.<br />
<h3>
Solutions</h3>
<ul>
<li>
<a href="https://github.com/Landertxu/tuentichallenge6" target="_blank">https://github.com/Landertxu/tuentichallenge6</a> by Landertxu</li>
<li>
<a href="https://github.com/ivancea/TuentiChallenge6" target="_blank">https://github.com/ivancea/TuentiChallenge6</a> by Iv&aacute;n Cea Fontenla</li>
<li>
<a href="https://github.com/Santi-7/TuentiChallenge6" target="_blank">https://github.com/Santi-7/TuentiChallenge6</a> by Santiago Gil Begu&eacute;</li>
<li>
<a href="https://github.com/wynkth/TuentiChallenge6" target="_blank">https://github.com/wynkth/TuentiChallenge6</a> by Jose Toro</li>
<li>
<a href="https://github.com/kutyel/tuenti-challenge-6" target="_blank">https://github.com/kutyel/tuenti-challenge-6</a> by Flavio Corpa</li>
<li>
<a href="https://github.com/pedrosorio/tuenti_2016" target="_blank">https://github.com/pedrosorio/tuenti_2016</a> by Pedro Os&oacute;rio</li>
<li>
<a href="https://github.com/xJakub/TuentiChallenge6" target="_blank">https://github.com/xJakub/TuentiChallenge6</a> by Jakub</li>
<li>
<a href="https://github.com/jgarciagarrido/Tuenti-Challenge-6" target="_blank">https://github.com/jgarciagarrido/Tuenti-Challenge-6</a> by Javier</li>
<li>
<a href="https://github.com/alvarogzp/tuenti-challenge-2016" target="_blank">https://github.com/alvarogzp/tuenti-challenge-2016</a> by Alvaro Gutierrez Perez</li>
<li>
<a href="https://github.com/serlabel/tuenti-challenge-6" target="_blank">https://github.com/serlabel/tuenti-challenge-6</a> by Sergio Laguna</li>
<li>
<a href="https://github.com/aokiji/tuenti_challenges" target="_blank">https://github.com/aokiji/tuenti_challenges</a> by Nicolas De Los Santos</li>
<li>
<a href="https://github.com/bmarcote/tuenti_challenge2016" target="_blank">https://github.com/bmarcote/tuenti_challenge2016</a> by Marcote</li>
<li>
<a href="https://github.com/sombra2eternity/tuenti-challenge-2016" target="_blank">https://github.com/sombra2eternity/tuenti-challenge-2016</a> by sombra2eternity</li>
<li>
<a href="https://github.com/Peshka1502/tuenti-challenge-6" target="_blank">https://github.com/Peshka1502/tuenti-challenge-6</a> by Taras Sotnikov</li>
<li>
<a href="https://github.com/AlexITC/tuenti-challenge-6" target="_blank">https://github.com/AlexITC/tuenti-challenge-6</a> by AlexITC</li>
</ul>
<h3>
Writeups</h3>
<a href="https://twitter.com/Landertxu0" target="_blank">@Landertxu0</a> has prepared a complete series of writeups for every problem, you can read them (in Spanish) at:
<ul>
<li>
<a href="http://simulaciones.es/blog/tuenti-challenge-6-primera-parte/" target="_blank">http://simulaciones.es/blog/tuenti-challenge-6-primera-parte/</a></li>
<li>
<a href="http://simulaciones.es/blog/tuenti-challenge-6-segunda-parte/" target="_blank">http://simulaciones.es/blog/tuenti-challenge-6-segunda-parte/</a></li>
<li>
<a href="http://simulaciones.es/blog/tuenti-challenge-6-tercera-parte/" target="_blank">http://simulaciones.es/blog/tuenti-challenge-6-tercera-parte/</a></li>
<li>
<a href="http://simulaciones.es/blog/tuenti-challenge-6-cuarta-parte/" target="_blank">http://simulaciones.es/blog/tuenti-challenge-6-cuarta-parte/</a></li>
<li>
<a href="http://simulaciones.es/blog/tuenti-challenge-6-quinta-parte/" target="_blank">http://simulaciones.es/blog/tuenti-challenge-6-quinta-parte/</a></li>
<li>
<a href="http://simulaciones.es/blog/tuenti-challenge-6-sexta-parte/" target="_blank">http://simulaciones.es/blog/tuenti-challenge-6-sexta-parte/</a></li>
</ul>
</div></div></div>Tue, 21 Jun 2016 09:34:42 +0000TuentiDev1612 at https://corporate.tuenti.comHMU29: and the winners are…https://corporate.tuenti.com/es/dev/blog/HMU29-and-the-winners-are
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded">Outreach Committee<br />
<br />
Another quarter, another Hack Me Up. The 29th edition of our internal programming competition has just finished at the Tuenti office in Madrid. <strong><em>Bots from the sofa</em> was the theme of this edition</strong>, which is why projects were focussed on bot technology.<br />
<br />
With 13 projects presents, these are the final results:
<ul>
<li>
<em>Super Call Saving Player</em>, the winning project in the Product category. Jessica, Manolo and Rayco&nbsp;made a&nbsp;new awesome player for the call saving functionality.</li>
<li>
<em>Tuenti Core</em> was the project that took home the Geek Cup. Sergio&nbsp;made a multiplatform development in C# to show the posibilites of the .net framework. Very geek, indeed.</li>
</ul>
Despite there being only two winning projects, many of those presented were of excellent technical quality and may be implemented at Tuenti for the use of our clients and users. We&rsquo;ll keep you informed ;)<br />
<br />
Congratulations to the winning teams!<br />
<br />
<img alt="" src="http://corporate.tuenti.com/cdn/farfuture/6V2ikh8FlRpIyVaMEVJGsoxFil7xwCIuulBGTngqhmw/md5:4cfdeac4ad25b86dca70dd771cc43648/files/TuentiDev/Product_3.png" style="width: 640px; height: 412px;" /><br />
<img alt="" src="http://corporate.tuenti.com/cdn/farfuture/XgYDCRYvTXulY6W6NwuUYMP6plv_jhRQsGuxH5mss-A/md5:4a21df54240e46fa4054c1ca181e5e1e/files/TuentiDev/Geek_2.png" style="width: 640px; height: 420px;" /><br />
</div></div></div>Fri, 17 Jun 2016 16:55:12 +0000TuentiDev1611 at https://corporate.tuenti.comFinal Challenge in #TuentiChallenge6https://corporate.tuenti.com/es/dev/blog/Final-Challenge-in-TuentiChallenge6
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded">Jose Mar&iacute;a Palacio Lardin, Software Engineer<br />
<br />
In this problem, we are asked to arrange some calls in order to get as many stars as possible. You can read the statement <a href="https://contest.tuenti.net/Challenges?id=20" target="_blank">here</a>. This is an optimization problem: instead of asking for the optimal answer as usual, we can submit as many solutions as we want and keep the one with the highest score.<br />
<br />
There are plenty of possible approaches for this problem and it&rsquo;s not easy to decide which one to use, as it&rsquo;s hard to guess the effectiveness of an approach without actually implementing and experimenting with it. We will evolve from a simple solution to a good one during this write-up, serving as a step-by-step summary of the process that we went through when we developed our solution.<br />
<br />
As we don&rsquo;t need to worry about our initial score, let&rsquo;s start simple: by getting a correct solution. The first greedy algorithm that comes to mind is to pick the call which gives us the maximum amount of stars while there are unassigned calls. To implement this, we will need a way to check if a call fits in a pop and what its starting time would be. After reading the statement carefully one more time, we realize that a call can only have a maximum delay of 40 and, luckily, the average duration of a call is not very long. This simplifies things a lot, because we can check if a call fits in a pop simply by trying all the possible delays. We can represent each pop as an array of integers indicating the calls in progress at a given moment in time, which allows us to insert a new call, delete a call or get the starting time of a new call in time O(duration of the call).<br />
<br />
Our greedy calculates the starting time and the stars for every call in every pop at each step, and the number of steps is potentially the number of calls. Our first impression is that this seems very expensive. Indeed, after implementing it and running it for some minutes, it still has plenty of steps left to finish. We have to start optimizing:
<ul>
<li>
Precalculate the stars for every call and pop with delay 0 in order to avoid computing distances.</li>
<li>
For every call c and pop p, we can cache the amount of stars obtained by establishing c in p. We can check if this number is smaller than the current best to filter.</li>
</ul>
After these optimizations, our program runs substantially faster: after 25 seconds we get a valid solution with score 32191.<br />
<br />
What can we do to improve our solution? If we look at our algorithm again, we can see that there are a lot of ties (after all, we only have 4 possible values of stars if we discard the 0). When two calls (or the same call in two difference pops) have the same number of stars, can we look at something else to decide which one is a better choice? Our idea is to choose the one that places least &ldquo;stress&rdquo; on the pop: we want to maximize the free slots in the pop during the call. Introducing this tiebreaker sees our score increase to 32750.<br />
<br />
However, there are still a lot of ties, so a new idea springs to mind: we can simply order all the calls before starting our greedy with some criteria that don&rsquo;t depend on the current status, and the ties will break naturally. While we are at it, we can order the pops too! It seems like the best way of ordering the pops will be in descending order of their capacity, but the calls are harder. There are a few things that seem important: the duration, the finishing time and the density of a call (ideal stars / duration). After experimenting with some orderings, we can see that the best thing we can do for our greedy is to minimize duration, minimize starting time and maximize density, in that order of priority. With these tweaks we get a score of 35030.<br />
<br />
Even though our score is quite good, we are not satisfied with it. After playing a bit more with our greedy algorithm, we don&rsquo;t see anything that improves our score, so we decide that it&rsquo;s time to apply some form of local search. We encounter a big problem though: there isn&rsquo;t a simple way to transition from a valid state to another. After some time thinking about this with no results, our mind goes back to the greedy algorithm. Given the same input, our greedy always establishes the same calls in the same order, but what if we skipped some of them? Perhaps skipping a call with 5 stars would allow us to later establish two calls with 4 stars, improving our overall score. Indeed, after toying a bit with the algorithm and ignoring a few random calls, we can see that our score changes, and is sometimes higher than 35030. This suggests something interesting: perhaps we can destroy part of our solution and apply the greedy algorithm starting from the new partial solution. Destroying part of our solution means removing some calls from some pops, which seems very easy with our data structures. The only thing left to decide is which calls to remove. It seems like a good idea to remove an interval of continuous calls: this leaves a big empty area for our greedy algorithm to work with.<br />
<br />
After some time implementing all of this we get our reward: if we remove around 50 calls, an iteration takes about 2 seconds and every few iterations we get an improved score! And the best thing is that we can reuse our cache for the next iteration if we are careful and invalidate the correct positions after removing the calls, which makes things orders of magnitude faster: with this approach, an iteration takes an average of 6.4ms. After seeing this, we are almost ready to leave our program executing for the night. Before that, though, we introduce some changes to try to avoid getting stuck on a score:<br />
<ul>
<li>
Add noise to the tiebreakers</li>
<li>
With some small probability, remove non-contiguous intervals of calls instead of contiguous ones</li>
<li>
When reconstructing the solution, we treat the removed calls as we would any other unassigned call. With some small probability, ignore the removed calls completely until all the others unassigned calls have been tried</li>
<li>
When removing calls, try a few options; removing calls from a single pop, from half of the pops, or from all the pops</li>
<li>
Introduce randomness in all the hard-coded values, like the number of calls removed per iteration, number of pops from which to pick calls to remove, etc.</li>
</ul>
Now we are finally ready to execute the program. Here is an evolution of the score over time (in seconds):<br />
<img alt="" src="http://corporate.tuenti.com/cdn/farfuture/BE-qspES8qV777LWUoSrzJcjnfDa9Xmjf7QDYw8RTMY/md5:92e5f63624f50adf99d51a04de64f85b/files/TuentiDev/1_1.png" style="width: 640px; height: 301px;" /><img alt="" src="http://corporate.tuenti.com/cdn/farfuture/mZgk6-dTWznRGcvq1z3_IUzL3l8pQjLfYrb7lBfpFIE/md5:a0f3baab980ad4a779d75f533fad1bbf/files/TuentiDev/2_0.png" style="width: 640px; height: 294px;" /><br />
After 5 days, we get a solution with a score of 36053. Five days is a lot, especially during a contest that only lasts for seven days, but as you can see in the graphs our algorithm improves the solution at a logarithmic speed: it took less than one day to reach 36000 and roughly an hour and a half to reach 35900, so it would have been a good option even with the time restrictions of the contest.<br />
<br />
Our solution is not the optimal one but our algorithm slows down too much to keep going, so it suggests that we are close to it. We may, however, be stuck in some local minima that our greedy reconstruction approach cannot overcome. We gave up at this point, though.<br />
<br />
We hope the four contestants who reached this problem had fun with it, and if you are not one of them you can always try it now! We have <a href="https://github.com/tuenti/tuenti-star-validator" target="_blank">published the submission validator</a> that we used during the contest, so you can use it to validate and get a score from your solutions. If you beat us, have some idea to improve our solution or you used a totally different approach, don&rsquo;t hesitate to share it with us.</div></div></div>Thu, 16 Jun 2016 09:04:58 +0000TuentiDev1610 at https://corporate.tuenti.comTuenti Challenge 6: Bricks and Bridges write-uphttps://corporate.tuenti.com/es/dev/blog/Tuenti-Challenge-6-Bricks-and-Bridges-write-up
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded">Jos&eacute; Mar&iacute;a P&eacute;rez, Software Engineer<br />
<br />
<div>
Hello again! I&#39;m the author of problem 19, <a href="https://contest.tuenti.net/Challenges?id=19" target="_blank">Bricks and Bridges</a> (as well as of problems 6 and 15). Here is the write-up of this problem:<br />
&nbsp;</div>
In this challenge, I tried to create a misleading problem in which things that seem easy are hard and things that seem hard are easy (in the end).<br />
<br />
When you encounter the problem, the first thing you find is the requirement to go through all the nodes on the graph, and the fact that you have to bring down all of the bridges. In order to bring them down, you have to cross them, so instead of finding a <a href="https://en.wikipedia.org/wiki/Hamiltonian_path" target="_blank">hamiltonian path</a>, you need to find a <a href="https://en.wikipedia.org/wiki/Eulerian_path" target="_blank">eulerian path</a> (with some quirks).<br />
<br />
So, for each level, it is possible to solve it if, and only if:
<ul>
<li>
All nodes are connected</li>
<li>
A eulerian path exists (there are a maximum of two odd-degree nodes)</li>
</ul>
How do you find out the degree of the nodes?
<ul>
<li>
For each bridge, check its TOUGHNESS by solving its <a href="https://en.wikipedia.org/wiki/Diophantine_equation" target="_blank">diophantine equation</a>:</li>
</ul>
x[1] * STEPFORCE[1] + x[2] * STEPFORCE[2] + ... + x[n] * STEPFORCE[n] = BRIDGE_TOUGHNESS with x &gt;= 0 and then BRIDGE_DEGREE = sum(x)<br />
(It could be interesting to use some <a href="http://www.fq.math.ca/Scanned/17-4/morito.pdf" target="_blank">papers</a> but dynamic programming is more than enough for this task).<br />
<br />
<img alt="" src="http://corporate.tuenti.com/cdn/farfuture/aWKw3MlS4Z1Uv-9eylFbMdmGPVQlHmA95RVDnRvFnKk/md5:a5f1f0ebb113b5a27586a47345e625aa/files/TuentiDev/Challenge%2019.png" style="width: 620px; height: 173px;" /><br />
We are only looking for a single even-sum solution and/or a single odd-sum solution (to see if the node degree could be odd and/or even).<br />
<br />
There are 3 possible outcomes of this step for each bridge:
<ul>
<li>
It has no solution (all solutions include a negative x or gcd(stepforces) does not divide its toughness): The level is impossible. For example, a bridge with toughness 3 which only has a stepforce of 2, or the same bridge with stepforces 5 and 2.</li>
<li>
All solutions have an even OR odd BRIDGE_DEGREE. Add the corresponding degree to each node the bridge connects (it really only matters if it&rsquo;s even or odd)</li>
<li>
It has solutions with an even AND odd BRIDGE_DEGREE. (We&rsquo;ll call this bridge a &lsquo;BOTH bridge&rsquo;).</li>
</ul>
Once you reach this point, you can try to solve the problem. To do this, you can check all possible combinations of oddness for each BOTH bridge, and just apply the eulerian path rule:
<ul>
<li>
There are 2 nodes with an odd degree, the path goes from one of those to the other.</li>
<li>
There are 0 nodes with an odd degree, the path goes from any node to itself.</li>
<li>
There are more than 2 nodes with an odd degree, the path does not exist.</li>
</ul>
(Remember that it&rsquo;s impossible to have an odd number of odd degree nodes, as, in this case, there would be a bridge going nowhere)<br />
<br />
<br />
Unfortunately, there is a big problem with this solution. Its complexity is exponential for the number of BOTH bridges, as you need to check each possible oddness (even or odd): 2*2*2*2*&hellip;*2 = 2^(number of BOTH bridges).<br />
Taking into account the sheer amount of BOTH bridges, this is not feasible. Thankfully, however, there is a shortcut:<br />
<h3>
Shortcut:</h3>
After processing the diophantine equations, you mark all the bridges in the graph with EVEN, ODD or BOTH tags regarding each diophantine solution. To solve the problem, you need to count the degree of each node and then count the nodes that have an odd degree (EVEN bridges add 0 to its connected nodes, ODD bridges add 1, and BOTH bridges add 0 or 1, whichever you want)<br />
<br />
If you remove the EVEN and ODD bridges, you get a graph consisting of nodes with a partial degree connected by the remaining bridges (those with the BOTH tag; remember that there could be several connected subgraphs) and nodes with a fully calculated degree, which are not connected to any other node.<br />
<br />
At this point, you have to minimize the count of odd degree nodes and check that there are no more than two of them (if there are more than 2 odd-degree fully calculated nodes, you can stop now, as the scenario cannot be solved).<br />
<br />
In order to minimize the count of odd-degree nodes for all the partial-degree connected subgraphs, you just need to add each subgraph&rsquo;s partial degrees together and check if this is EVEN or ODD for each of the subgraphs, which is O(n).<br />
This is the proof for each connected subgraph:<br />
<br />
<u>Problem</u>: Fully connected graph with nodes tagged with either 0 or 1, all arcs could add 0 or 1 to both ends, minimize the count of odd-degree nodes.<br />
<u>Solution</u>: sum(degrees) % 2<br />
<br />
<u>Proof 1</u>:
<ul>
<li>
A 0-arc leaves both ends as they are</li>
<li>
A 1-arc switches both ends (from 0 to 1 and from 1 to 0)</li>
<li>
You can &#39;move&#39; a 1-node around by fixing 1-arcs, and when it&#39;s directly connected to another 1-node, you can turn both of them to 0-nodes with a 1-arc</li>
<li>
In this way, you can turn 1-nodes into 0-nodes by pairs</li>
</ul>
<br />
<u>Proof 2</u>:<br />
You can fuse two nodes together by adding their degrees and removing all the bridges that connect them directly:
<ul>
<li>
If both of them were 0, you would use a 0-arc, thus maintaining the number of 0-nodes</li>
<li>
If both of them were 1, you would use a 1-arc, thus reducing the number of 1-nodes by 2</li>
<li>
If one were 0 and the other were 1, you would use a 0-arc or a 1-arc, depending on where you would like the 1-node to be, but maintaining the number of 1-nodes</li>
</ul>
<br />
To answer your unspoken question, yes, I tried to place the problem in Alice in Wonderland&rsquo;s world, but it felt too forced.<br />
<br />
And so ends my contribution to this year&rsquo;s Tuenti Challenge. I hope you liked it :)</div></div></div>Mon, 13 Jun 2016 11:49:52 +0000TuentiDev1607 at https://corporate.tuenti.comTuenti Challenge 6: Seat change! write-uphttps://corporate.tuenti.com/es/dev/blog/Tuenti-Challenge-6-Seat-change-write-up
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded">Jos&eacute; Mar&iacute;a P&eacute;rez, Software Engineer<br />
<br />
Hi there! I&#39;m the author of problem 15, <a href="https://contest.tuenti.net/Challenges?id=15" target="_blank">Seat change!</a> (as well as of problem 6). Here is a small write-up of this problem:&nbsp;<br />
<br />
When we change seats at Tuenti, a friend always jokes about the tea party scene in Disney&rsquo;s Alice in Wonderland and, in the past, I&#39;ve worked with matrix multiplication... why not combine both of them in this challenge?<br />
<br />
In this problem, you have chairs, probabilities of going from one chair to another chair and a number of seat changes. If you can recognize a <a href="https://en.wikipedia.org/wiki/Markov_chain" target="_blank">Markov Chain</a> in this problem, you&rsquo;re spot on. If you did not recognize it, don&rsquo;t worry, the math is pretty basic:<br />
<br />
Suppose that you organize the probabilities of going from one chair to another after one seat change in a matrix, where rows are starting chairs and columns are ending chairs. If you multiply that matrix by itself, you will get the probability after two seat changes.<br />
In fact, the problem is asking you about the index for the max element in a row of matrix^number_of_seat_changes, using integers to maintain the precision.<br />
<br />
Multiplying two square matrices has a complexity of O(size&sup3;) (less if you use certain algorithms, but this is not the objective of the problem) and there are some optimizations that are useful:<br />
<br />
Depending on whether N is even or odd:<br />
&nbsp;&nbsp;&nbsp; matrix^N = (matrix^(N/2))&sup2;<br />
&nbsp;&nbsp;&nbsp; matrix^N = (matrix^((N-1)/2)&sup2; * matrix<br />
This reduces the complexity of the number of matrix multiplications from O(N) to, O(log2(N)) (at the expense of storing intermediate matrices), and it was intended to be needed in order to solve the problem.<br />
<br />
Another useful optimization is breaking the connection matrix into its connected components and computing them separately. For example, if you have N chairs in two connected components, one of them of size M, the complexity of the matrix multiplication is reduced from O(N&sup3;) to O(M&sup3;) + O((N-M)&sup3;). As the matrices do not change between tries, you can check if this optimization is useful before coding it (Hint: it is). It also has the benefit that you may not need to exponentiate both matrices to the same exponents.<br />
<br />
With those two optimizations, and caching the intermediate results, you could solve the problem with the hard input in a reasonable time (my solution does it in less than one minute).<br />
<br />
Well, that&#39;s it for today. I hope you liked it and remember:<br />
We&#39;re all mad here.<br />
- Lewis Carroll, Alice in Wonderland<br />
<img alt="" src="http://corporate.tuenti.com/cdn/farfuture/kbqRwcG5utS2a4Do_AnNlsKmnv9k03DVyDwssnbNdj0/md5:7a07e06ae7beab84a214f5553358ba1a/files/TuentiDev/Alice_par_John_Tenniel.png" style="width: 640px; height: 418px;" /></div></div></div>Fri, 10 Jun 2016 10:58:31 +0000TuentiDev1606 at https://corporate.tuenti.comTuenti Challenge 6: Through the Looking-Glass write-uphttps://corporate.tuenti.com/es/dev/blog/Tuenti-Challenge-6-Through-the-Looking-Glass-write-up
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded">Jos&eacute; Mar&iacute;a P&eacute;rez, Software Engineer<br />
<br />
Hello, I&#39;m the proud author of Tuenti Challenge 6&#39;s 6th problem, <a href="https://contest.tuenti.net/Challenges?id=6" target="_blank">Through the Looking-Glass</a>.&nbsp;Please hold your fire :<br />
<img alt="" src="http://corporate.tuenti.com/cdn/farfuture/_1sp3-df8F-73hSf12VHn7DZqumGBiZI9gEGKp_wbAs/md5:985ff2a356856125312ebfd09ccec08e/files/TuentiDev/Through_the_looking_glass2.png" style="width: 640px; height: 402px;" />This is one of those infamous non-algorithmic problems with no apparent clues, which this year were featured quite early on in the Challenge. Its position may have been related to the fact that it was quite watered down from the original concept, but let&#39;s get to it:<br />
<br />
The first thing you see upon reaching the problem is its information, or in this case, the lack thereof: there are only two images and some brief text.<br />
If you inspect the html, you will see that one of the images is from wikipedia, and you can safely assume that there&#39;s no information hidden there.<br />
The other image is a little more tricky; it&#39;s a QR with a strange color palette.<br />
<br />
So, what&#39;s the first thing to do with a QR? You need to read it, of course. Use any mobile reader (or just ppm it and transform it, as it&#39;s easy to translate the brightness of colors to black/white) and it will take you to the wikipedia article about <a href="https://en.wikipedia.org/wiki/Piet_Mondrian" target="_blank">Piet Mondrian</a>.<br />
If you read that article carefully, you will notice the small reference to an esoteric programming language named after him, <a href="https://en.wikipedia.org/wiki/Esoteric_programming_language#Piet" target="_blank">piet</a>, whose programs are written as images with a reduced color palette that matches the QR&#39;s. You are on the right track!<br />
<br />
(If you did not see the reference, a simple search in Google for &quot;Piet Mondrian programming&quot;, &quot;Piet Mondrian program&quot; or &quot;Piet Mondrian language&quot; would take you to piet)<br />
<br />
You jump into it, download a piet interpreter (or use an <a href="http://www.bertnase.de/npiet/npiet-execute.php" target="_blank">online one</a>), run the QR and... it does not provide the expected output. It may well be problem number 6, but it was not going to be that easy!<br />
<br />
So either it&#39;s not a piet after all or there are some quirks in the problem, so you return to the image and analyze it:
<ul>
<li>
It has a comment that reads &quot;a piet program qr.randomized.flipped.embedded.withnl.png&quot;: This was a really big oversight on my part. I did not notice that my editor inserted the original filename and a comment. As it was not intended as a clue, I will continue this write-up without it (I think that&#39;s the reason it was featured so early).</li>
<li>
The areas of the QR are well defined... all of them except for the first two lines and the bottom-right corner, which is black and should be clear.</li>
<li>
The color histogram shows that there are only 20 colors, and each color appears in &gt;2000 or &lt;20 pixels, and the last only appear in the two first lines.</li>
</ul>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
You should be certain at this point that you have to run a piet program, but why does it fail?<br />
<br />
Reading more about piet, you see that black is a special color that is used to restrict and stop program flow, and that programs start in the top-left corner. In the QR, the top-left corner is black! In fact, all corners but the top-right are black, so the program must begin there! In hindsight, maybe I should have made the QR print something like &ldquo;Not the solution&rdquo; when interpreted right away.<br />
<br />
So, how should you transform the QR so that the top-right corner becomes the top-left?<br />
The title of the problem reads &quot;<a href="https://en.wikipedia.org/wiki/Through_the_Looking-Glass" target="_blank">Through the Looking-Glass</a>&quot;, which is repeated in capitals in the description, and the fabulous <a href="https://commons.wikimedia.org/wiki/File%3AAlice_through_the_looking_glass.jpg" target="_blank">wikipedia image</a> depicts Alice looking into a mirror... it was always hidden in plain sight!<br />
If you try to run the mirrored image through a piet interpreter, you will receive the correct output:<br />
<br />
Why it&#39;s simply impassible!<br />
<br />
I will finish with the full quote:<br />
<br />
&quot;Why it&#39;s simply impassible!<br />
Alice: Why, don&#39;t you mean impossible?<br />
Door: No, I do mean impassible. (chuckles) Nothing&#39;s impossible!&quot;<br />
<br />
- Lewis Carroll, Through the Looking-Glass, and What Alice Found There<br />
<br />
I hope you enjoyed it as much as I did.<br />
<h3>
Problem development:</h3>
<br />
There were two earlier versions of the problem prior to the one that was finally released:<br />
<br />
The first version had the piet program shared among each of the 4 corners of the QR, in both the original and the mirrored version, so, in order to get the full password, you had to run the QR 8 time: rotate it 4 times, mirror it and rotate it another 4 times, then compose the password with the outputs of the 8 runs. The QR was also going to give you a hint about the corners, but nothing about Piet Mondrian.<br />
<br />
The second version had some 99% or 0% transparencies, just to mess with the interpreters, but it was still regarded as too difficult.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
The third version is what you got in the challenge :)</div></div></div>Wed, 08 Jun 2016 09:05:02 +0000TuentiDev1605 at https://corporate.tuenti.comSo long, #TuentiChallenge6https://corporate.tuenti.com/es/dev/blog/So-long-TuentiChallenge6
<div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded">Daniel Pa&ntilde;eda, Principal Software Engineer &amp; Alfredo Beaumont, Senior Software Engineer<br />
<br />
As is the case each year, we have concluded the second phase of our programming contest with the 10 finalists joining us in our Madrid office to find out first-hand what Tuenti is and who we are.<br />
<br />
First off, <a href="https://contest.tuenti.net/Info/about" target="_blank">as promised</a>, we broke the ice with a little party on the terrace on Thursday afternoon: there was no shortage of drinks, food and music. <strong>The finalists got to see first-hand how we celebrate team achievements in the company ;)</strong><br />
<br />
<img alt="" src="http://corporate.tuenti.com/cdn/farfuture/uIYq6JDrECEltVE-g9bDqEc1kihGbuphc_7zO5my1cM/md5:74aaec4de22f05217f5f18b817fae4bd/files/TuentiDev/terraza.png" style="width: 640px; height: 354px;" /><br />
To conclude the final phase of the Tuenti Challenge, the finalists had to solve another mini-contest of 3 problems within two hours. As expected, they were up to the task and their ideas and code did not disappoint.<br />
<br />
<img alt="" src="http://corporate.tuenti.com/cdn/farfuture/tXnUOn4_E1gQJMFydM5Xn2E5ydIwymP5agF69QPaA6g/md5:245b9160423a33a6289da2a5c0641eb7/files/TuentiDev/1_0.png" style="width: 640px; height: 356px;" /><img alt="" src="http://corporate.tuenti.com/cdn/farfuture/JPgbG9ZI6YUX0T1hb6yWC_jf4XqpA2vzU7VMXEB4_n4/md5:bd6cc095b296f34525eabd50b4699380/files/TuentiDev/2.png" style="width: 640px; height: 338px;" /><br />
This was followed by a workshop with Suso B. on <em>Engineering at Tuenti</em> and the lunch break. In the afternoon, the finalists had several group and individual interviews in order to finalize the decision of the &ldquo;committee of wise men&rdquo; which would decide the final ranking.<br />
<br />
Just an hour ago, we held the awards ceremony and announced the names of the winners. The podium is taken by:<br />
Jakub H.<br />
Eric M.<br />
Jos&eacute; A. O.<br />
<br />
The following participants also reached this second phase (in alphabetical order):<br />
Daniel E.<br />
Endika G.<br />
Jes&uacute;s L. D.<br />
Jonatan H.<br />
Julian S.<br />
Sergio L.<br />
Taras S.<br />
<br />
<img alt="" src="http://corporate.tuenti.com/cdn/farfuture/SmMnDlHYaxu4t8oAikKIBU6KHAm497XT8TpQfZqaXfk/md5:319195f870c6175cf35e00863ed5d345/files/TuentiDev/final%20equipo.png" style="width: 640px; height: 427px;" /><br />
As always, we would like to thank all this year&rsquo;s participants for the time, enthusiasm and hours spent trying to solve our problems.<strong> Thank you very much from the entire engineering team at Tuenti.</strong> And for all of you who missed out, we hope to see you next year in #TuentiChallenge7 :-)</div></div></div>Fri, 27 May 2016 10:21:25 +0000TuentiDev1604 at https://corporate.tuenti.com