<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Openbloc]]></title><description><![CDATA[Engineering Smart Solutions]]></description><link>https://blog.openbloc.com/</link><image><url>https://blog.openbloc.com/favicon.png</url><title>Openbloc</title><link>https://blog.openbloc.com/</link></image><generator>Ghost 3.21</generator><lastBuildDate>Wed, 15 Apr 2026 21:15:51 GMT</lastBuildDate><atom:link href="https://blog.openbloc.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Easy Ubuntu Hardening for Web Developers]]></title><description><![CDATA[Automatically harden your Ubuntu server with the open source tools Inspec, Ansible and the DevSec framework.]]></description><link>https://blog.openbloc.com/automated-hardening-for-ubuntu/</link><guid isPermaLink="false">5ef246f087cd5c00c73ea85b</guid><category><![CDATA[ubuntu]]></category><category><![CDATA[tutorial]]></category><category><![CDATA[open-source]]></category><dc:creator><![CDATA[Maxime Rouyrre]]></dc:creator><pubDate>Wed, 24 Jun 2020 11:44:58 GMT</pubDate><media:content url="https://cdn.openbloc.fr/2020/06/Capture-d--cran-de-2020-06-17-13-40-37.png" medium="image"/><content:encoded><![CDATA[<img src="https://cdn.openbloc.fr/2020/06/Capture-d--cran-de-2020-06-17-13-40-37.png" alt="Easy Ubuntu Hardening for Web Developers"><p>You may have good reasons to focus on developing your disrupting app. And you may well be a very talented developer. But like me, even after years of experience as a web engineer, comes a point where we have to admit we don't know that much about security.</p><p>Unless you only use fully managed solutions to host your web applications, your startup probably has a bunch of servers you have to monitor and maintain. And unless your company has the scale to pay for real DevOps, security engineers, audits or pentests, then quite frankly, we'll mainly focus on finishing the current sprint hoping to get some traction ;)</p><p>Today I got my first Ubuntu VPS from <a href="https://blog.openbloc.com/p/3f54a7d4-a161-4bf0-a9ee-8ea9c6daf259/www.ovh.com">OVH</a>, a fresh new image ready to host the next version of my website. And it's got me thinking: I do remember it's best practice to disable SSH login by password, what else should I do ? Do I need a firewall ? Surely I don't have time to fully audit this default Ubuntu image by myself...</p><p>In this article I'll show you how to harden a default Ubuntu Server 20.04 image using existing open-source tools:</p><ol><li><a href="https://www.inspec.io/">Inspec</a> to identify security issues and misconfiguration</li><li><a href="https://www.ansible.com/">Ansible</a> to automatically harden your server</li><li><a href="https://dev-sec.io/">The DevSec Hardening Framework</a> which provides:<br>- <a href="https://github.com/dev-sec/linux-baseline">An Inspec profile</a><br>- <a href="https://github.com/dev-sec">Ansible / Chef / Puppet recipes</a> to enforce above Inspec profile</li></ol><!--kg-card-begin: markdown--><h2 id="quicksshsetup">Quick SSH setup</h2>
<p>Make sure your server is defined in <code>~/.ssh/config</code></p>
<pre><code>Host servername
	HostName &lt;your server ip address&gt;
	User username
	Port 22
</code></pre>
<p>To ssh into the server with your ssh key without typing the password just run:</p>
<p><code>$ ssh-copy-id -i ~/.ssh/id_rsa.pub servername</code></p>
<h2 id="usinginspecwithlinuxbaselineprofile">Using Inspec with linux-baseline profile</h2>
<p>On the server:</p>
<pre><code class="language-bash"># download and install Inspec
$ wget https://packages.chef.io/files/stable/inspec/4.20.2/ubuntu/20.04/inspec_4.20.2-1_amd64.deb
$ sudo dpkg -i inspec_4.20.2-1_amd64.deb

# clone the linux-baseline profile
$ git clone https://github.com/dev-sec/linux-baseline

# run the Inspec profile
$ inspec exec linux-baseline
</code></pre>
<p><a href="https://www.inspec.io/docs/reference/install/">Inspec installation instructions</a></p>
<p>You should see a similar output:<br>
<img src="https://cdn.openbloc.fr/2020/06/Capture-d--cran-de-2020-06-17-13-01-40.png" alt="Easy Ubuntu Hardening for Web Developers"></p>
<p>Next thing will be to automatically apply better OS settings using Ansible and the recipes provided by the DevSec framework.</p>
<h2 id="usingansibletohardentheserver">Using Ansible to harden the server</h2>
<p>On your local machine:</p>
<pre><code class="language-bash"># install Ansible
$ sudo apt update
$ sudo apt install software-properties-common
$ sudo apt-add-repository --yes --update ppa:ansible/ansible
$ sudo apt install ansible

# install the os and ssh hardening roles
$ ansible-galaxy install dev-sec.os-hardening
$ ansible-galaxy install dev-sec.ssh-hardening
</code></pre>
<p><a href="https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html">Ansible installation instructions</a></p>
<p>We then need to write a playbook for each ansible role:</p>
<pre><code class="language-yaml"># ansible-os-hardening.yaml
- hosts: your-server
  become: true
  roles:
    - dev-sec.os-hardening
    
# ansible-ssh-hardening.yaml 
- hosts: your-server
  become: true
  roles:
    - dev-sec.ssh-hardening
</code></pre>
<p>Finally run these playbooks with the following commands:</p>
<pre><code class="language-bash">$ ansible-playbook -K ansible-os-hardening.yaml
$ ansible-playbook -K ansible-ssh-hardening.yaml
</code></pre>
<p>Then, re-running <code>inspec exec linux-baseline</code> on the server should give a similar output:<br>
<img src="https://cdn.openbloc.fr/2020/06/Capture-d--cran-de-2020-06-17-13-00-59.png" alt="Easy Ubuntu Hardening for Web Developers"></p>
<p>Which is much better!</p>
<h2 id="finalthoughts">Final thoughts</h2>
<p>Though I can't say I have audited the DevSec framework per-se, I hope you now have a better understanding on how you can automate your servers security to stay up-to-date whith industry best practices.</p>
<p>Depending on what you then run on your server, you may have to allow some ports on the Ubuntu firewall, <a href="https://help.ubuntu.com/community/UFW">ufw</a>. Personally while testing <a href="https://caprover.com/">CapRover</a> I just had to run:</p>
<p><code>$ ufw allow 80,443,3000,996,7946,4789,2377/tcp; ufw allow 7946,4789,2377/udp;</code></p>
<h3 id="thanksforreadingandtakecare">Thanks for reading and take care !</h3>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Three.js & 3D interactive animations: a tutorial]]></title><description><![CDATA[Following a three months journey into gamedev with three.js this is how I kept my code clean and organized, starting with the render loop. Avoid spaghetti code and callback hell.]]></description><link>https://blog.openbloc.com/a-simple-and-flexible-render-loop-in-three-js/</link><guid isPermaLink="false">5ef246f087cd5c00c73ea854</guid><category><![CDATA[javascript]]></category><category><![CDATA[learning]]></category><category><![CDATA[tutorial]]></category><category><![CDATA[three.js]]></category><dc:creator><![CDATA[Maxime Rouyrre]]></dc:creator><pubDate>Wed, 02 May 2018 23:20:16 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1474806246163-78af80f5d266?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=bff658f9365937d3abeba1a1ee854c81" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1474806246163-78af80f5d266?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ&s=bff658f9365937d3abeba1a1ee854c81" alt="Three.js & 3D interactive animations: a tutorial"><p>Following my previous post <a href="https://blog.openbloc.fr/gamedev-with-three-js-on-the-modern-web/">GameDev with three.js on the modern web 🚀🎆</a>, where I gave an overview of my three months journey into gamedev with <a href="https://github.com/mrdoob/three.js/">three.js</a> I wanted to share how I kept my code clean and organized, starting with the render loop.</p>
<p>One of the common culprit of developing any non trivial software project is to avoid spaghetti code. You always start with a nice single and simple page of code but soon enough it grows and grows and you have to keep it under control, you need to modularize your code, you need to organize and structure your project into a meaningful and comprehensible one.</p>
<ol>
<li><a href="#span1">How you render 3D things in three.js</a></li>
<li><a href="#span2">Here comes the render loop</a></li>
<li><a href="#span3">PubSubJS</a></li>
<li><a href="#span4">A flexible and simple render loop</a></li>
<li><a href="#span5">Final interactive demo</a></li>
</ol>
<p><span id="span1"></span></p>
<h1 id="howyourender3dthingsinthreejs">How you render 3D things in three.js</h1>
<ol>
<li>Setup the scene</li>
</ol>
<p>You can probably skip this first part if you already touched three.js, sorry for the hello world explanation ;)</p>
<p>You just describe the content of your scene, with code, what you want to show on the screen. Let's take a simple example</p>
<pre><code class="language-javascript">import * as THREE from 'three'

// create a three.js scene
var scene = new THREE.Scene()

// create a camera
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.set(50, 30, 50)
camera.lookAt(0, 0, 0)

// create the renderer
var renderer = new THREE.WebGLRenderer()
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)

// create a simple cube
var geometry = new THREE.BoxGeometry(20, 20, 20)
var material = new THREE.MeshLambertMaterial({color: 0x10a315 })
var cube = new THREE.Mesh(geometry, material)
scene.add(cube)

// add a light so we can see something
var light = new THREE.PointLight(0xFFFF00)
light.position.set(25, 25, 25)
scene.add(light)
</code></pre>
<ol start="2">
<li>Render the scene</li>
</ol>
<p>We just have to call the renderer, passing it the 3D scene and the camera as arguments. It will compute the 2D representation of the 3D scene from the point of view of the camera and display that on the screen.</p>
<pre><code class="language-javascript">renderer.render(scene, camera);
</code></pre>
<p>You should now have rendered a cube! Here's a Codepen to show you the result.</p>
<p data-height="400" data-theme-id="light" data-slug-hash="ZoybEe" data-default-tab="js,result" data-user="blaze33" data-embed-version="2" data-pen-title="Hello world: a simple cube (1/3)" class="codepen">See the Pen <a href="https://codepen.io/blaze33/pen/ZoybEe/">Hello world: a simple cube (1/3)</a> by Maxime R. (<a href="https://codepen.io/blaze33">@blaze33</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<p></p>
<p>The catch is, it's a static image. To have an animated 3D environment at 60 fps you need to actually call <code>renderer.render</code> 60 times per second.</p>
<p><span id="span2"></span></p>
<h1 id="herecomestherenderloop">Here comes the render loop</h1>
<p>If it's not your first <code>three.js</code> tutorial, you know that you have to code a loop that continuously calls <code>renderer.render</code>. And you know you need to use <a href="https://developer.mozilla.org/fr/docs/Web/API/Window/requestAnimationFrame"><code>window.requestAnimationFrame()</code></a> for that.</p>
<p>Here's the simplest example:</p>
<pre><code class="language-javascript">var mainLoop = () =&gt; {
  requestAnimationFrame(mainLoop)
  renderer.render(scene, camera)
}

mainLoop()
</code></pre>
<p>Now we could have a live animation of the static cube, not breathtaking, let's rotate the cube a little bit each time the loop is called to visualize that. Just add the following code in the <code>mainLoop</code> function</p>
<pre><code class="language-javascript">cube.rotation.x += Math.PI / 180
cube.rotation.y += Math.PI / 180
cube.rotation.z += Math.PI / 180
</code></pre>
<p>Pi being 180 degrees, it rotates the cube along each axis by one degree each frame. Try to add each of the three lines one by one to visualize how each axis of rotation is affected. Here's the demo:</p>
<p data-height="400" data-theme-id="light" data-slug-hash="yjXYjz" data-default-tab="js,result" data-user="blaze33" data-embed-version="2" data-pen-title="Hello world: a simple cube that rotates (2/3)" class="codepen">See the Pen <a href="https://codepen.io/blaze33/pen/yjXYjz/">Hello world: a simple cube that rotates (2/3)</a> by Maxime R. (<a href="https://codepen.io/blaze33">@blaze33</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<p></p>
<p>Maybe you see it coming now, you'll have dozens of animated 3D objects, some of them animated, others not, some appear, some disappear, some animations are fired upon user interaction, etc. The thing is: <strong>you cannot add all your logic in the mainLoop function!</strong></p>
<p>The following is a presentation of how I structured my main loop function to keep it simple and flexible in <a href="https://lab.openbloc.fr/droneWorld/">droneWorld</a>.</p>
<p>Let's take a detour to introduce the <a href="https://github.com/mroderick/PubSubJS">PubSubJS</a> library I used to help me along the way.</p>
<p><span id="span3"></span></p>
<h1 id="pubsubjs">PubSubJS</h1>
<blockquote>
<p>PubSubJS is a <a href="https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern">topic-based publish/subscribe</a> library written in JavaScript.</p>
</blockquote>
<p>The gist is, you declare a callback that will be executed when a message is published in PubSub. Why not just call the callback when needed then? Well you could have several different things happening when an event occurs, and they may not all be related. The PubSub architecture allows you to keep your code organized. Taking an example from droneWorld:</p>
<pre><code class="language-javascript">// in sounds/index.js
PubSub.subscribe('x.drones.gun.start', (msg, drone) =&gt; {
    // play sound
}

// in particles/index.js
PubSub.subscribe('x.drones.gun.start', (msg, drone) =&gt; {
    // send bullets
}

// in controls/index.js
// when mouse is clicked:
PubSub.publish('x.drones.gun.start', pilotDrone)
</code></pre>
<p>Now when we click the mouse, an event named <code>x.drones.gun.start</code> is fired with the <code>pilotDrone</code> object as a payload, the message subscribers are fired and a sound is played and bullets are drawn on the screen. This way the different parts of the code stay independent (e.g. you could still draw bullets without the sound system, easily) because the alternative would be to import every callback function in every module where it's needed and you quickly have a callback hell.</p>
<p><span id="span4"></span></p>
<h1 id="aflexibleandsimplerenderloop">A flexible and simple render loop</h1>
<p>Let's define a <code>loops</code> variable, it's an array containing animation functions. We initialize it with the animation we want at first.</p>
<p>As I implemented it, the loops array can contain functions or objects of the following form:</p>
<pre><code class="language-javascript">{
  id: 'myLoop',
  alive: true, // if false, the loop will be removed from the loops array
  loop: (timestamp, delta) =&gt; {doSomething(timestamp, delta)}
}
</code></pre>
<pre><code class="language-javascript">const rotateX = () =&gt; {
    cube.rotation.x += Math.PI / 180
}

const rotateY = () =&gt; {
    cube.rotation.y += Math.PI / 180
}

const rotateZ = () =&gt; {
    cube.rotation.z += Math.PI / 180
}

let loops = [
  rotateX,
  rotateY
]
</code></pre>
<p>Let's define some helpers to add or remove loops to the <code>loops</code> variable.</p>
<pre><code class="language-javascript">const removeLoop = (loop) =&gt; {
  loops = loops.filter(item =&gt; item.id !== loop.id)
}
// declare a subscriber to remove loops
PubSub.subscribe('x.loops.remove', (msg, loop) =&gt; removeLoop(loop))
// declare a subscriber to add a loop
PubSub.subscribe('x.loops.push', (msg, loop) =&gt; loops.push(loop))
// declare a subscriber to add a loop that will be executed first
PubSub.subscribe('x.loops.unshift', (msg, loop) =&gt; loops.unshift(loop))

const cleanLoops = () =&gt; {
  loops.forEach(loop =&gt; {
    if (loop.alive !== undefined &amp;&amp; loop.alive === false &amp;&amp; loop.object) {
      scene.remove(loop.object)
    }
  })
  loops = loops.filter(loop =&gt; loop.alive === undefined || loop.alive === true)
}
</code></pre>
<p>Let's declare <a href="https://github.com/mrdoob/stats.js/">stats.js</a> here. It's a naive helper to show the FPS.</p>
<pre><code class="language-javascript">const stats = new Stats()
document.body.appendChild(stats.dom)
</code></pre>
<p>Let's declare a subscriber that will allow us to start and stop the animation at will.</p>
<pre><code class="language-javascript">let play = true
PubSub.subscribe('x.toggle.play', () =&gt; { play = !play })
</code></pre>
<p>Now we declare the <code>mainLoop</code> function.</p>
<pre><code class="language-javascript">let lastTimestamp = 0
var mainLoop = (timestamp) =&gt; {
  requestAnimationFrame(mainLoop)
  let delta = timestamp - lastTimestamp
  lastTimestamp = timestamp

  if (play) {
    loops.forEach(loop =&gt; {
      loop.loop ? loop.loop(timestamp, delta) : loop(timestamp, delta)
    })
    
    renderer.render(scene, camera)
  }

  cleanLoops()

  stats.update()
}

mainLoop(0)
</code></pre>
<p>And so we have a simple and flexible <code>mainLoop</code> function under 15 lines of code!</p>
<p><span id="span5"></span></p>
<h1 id="finalinteractivedemo">Final interactive demo</h1>
<p>Look at the code to see how easy it is now to add or remove animations from the scene.</p>
<pre><code class="language-javascript">if (someCondition) {
  // starts the cube rotation
  PubSub.publish('x.loops.push', rotateX)
} else {
  // stops the cube rotation
  PubSub.publish('x.loops.remove', rotateX)
}
</code></pre>
<p data-height="400" data-theme-id="light" data-slug-hash="VxWeXj" data-default-tab="js,result" data-user="blaze33" data-embed-version="2" data-pen-title="Hello world: a simple interactive cube (3/3)" class="codepen">See the Pen <a href="https://codepen.io/blaze33/pen/VxWeXj/">Hello world: a simple interactive cube (3/3)</a> by Maxime R. (<a href="https://codepen.io/blaze33">@blaze33</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<p></p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
<p>That's it! Thanks for reading!<br>
Check droneWorld to see three.js in action:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/6o19zDLZzds?rel=0&amp;showinfo=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
<p style="text-align:center">
<a class="ghost-button-thick-border" target="_blank" href="https://lab.openbloc.fr/droneWorld">
    Launch Demo
</a> <a class="ghost-button-thick-border" target="_blank" href="https://github.com/blaze33/droneWorld">Code on Github 
</a> <a class="github-button" href="https://github.com/blaze33/droneWorld" data-icon="octicon-star" data-size="large" data-show-count="true" aria-label="Star blaze33/droneWorld on GitHub">Star</a>
    <a href="https://twitter.com/maxmre?ref_src=twsrc%5Etfw" class="twitter-follow-button" data-show-count="false" data-size="large">Follow @maxmre</a><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</p><!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Game Development with three.js on the modern web 🚀🎆]]></title><description><![CDATA[Building droneWorld with three.js and vanilla modern javascript!

A WebGL experiment I've been working on from time to time since last november to explore the open source gaming possibilities of the modern web.

Play the latest version at https://lab.openbloc.fr/droneWorld !]]></description><link>https://blog.openbloc.com/gamedev-with-three-js-on-the-modern-web/</link><guid isPermaLink="false">5ef246f087cd5c00c73ea853</guid><category><![CDATA[javascript]]></category><category><![CDATA[es6]]></category><category><![CDATA[learning]]></category><dc:creator><![CDATA[Maxime Rouyrre]]></dc:creator><pubDate>Thu, 19 Apr 2018 22:06:50 GMT</pubDate><media:content url="https://cdn.openbloc.fr/2018/04/Capture-du-2018-04-19-01-46-13.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://cdn.openbloc.fr/2018/04/Capture-du-2018-04-19-01-46-13.png" alt="Game Development with three.js on the modern web 🚀🎆"><p>Back in November 2017 I started a journey in the world of game development using the modern <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript">JavaScript</a> toolchain and <a href="https://github.com/mrdoob/three.js">three.js</a>. This article is kinda a summary of the useful bits accumulated during ~3months of part-time work showing what it is to start from scratch with only “classic” web development experience and to end with below game prototype. This was done in the open using only open source tools, this is not your usual Unity or Unreal tutorial ;) Let's see what can be done:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/6o19zDLZzds?rel=0&amp;showinfo=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
<p style="text-align:center">
<a class="ghost-button-thick-border" target="_blank" href="https://lab.openbloc.fr/droneWorld">
    Launch Demo
</a> <a class="ghost-button-thick-border" target="_blank" href="https://github.com/blaze33/droneWorld">Code on Github 
</a> <a class="github-button" href="https://github.com/blaze33/droneWorld" data-icon="octicon-star" data-size="large" data-show-count="true" aria-label="Star blaze33/droneWorld on GitHub">Star</a>
    <a href="https://twitter.com/maxmre?ref_src=twsrc%5Etfw" class="twitter-follow-button" data-show-count="false" data-size="large">Follow @maxmre</a><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</p>
<p><strong>Detailed followups:</strong></p>
<ul>
<li><a href="https://blog.openbloc.fr/a-simple-and-flexible-render-loop-in-three-js/">Three.js &amp; 3D interactive animations: a tutorial</a></li>
</ul>
<p><strong>Summary</strong></p>
<ol>
<li><a href="#span1">Three.js? WebGL? What is this?</a></li>
<li><a href="#span2">Assets: A free world map on AWS</a></li>
<li><a href="#span3">Assets bis: textures</a></li>
<li><a href="#span4">Assets ter: free 3D models</a></li>
<li><a href="#span5">Shaders</a></li>
<li><a href="#span6">Particles</a></li>
<li><a href="#span7">Marketing</a></li>
<li><a href="#span8">Missing parts</a></li>
<li><a href="#span9">What next?</a></li>
</ol>
<p><span id="span1"></span></p>
<h1 id="threejswebglwhatisthis">Three.js? WebGL? What is this?</h1>
<p><a href="https://github.com/mrdoob/three.js">Three.js</a> is a library that helps you build 3D interactive environments right into your browser by leveraging the power of <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API">the WebGL standard</a>. The rendering is hardware-accelerated and it requires no plugin and no software installation, it's just a webpage.</p>
<p><span id="span2"></span></p>
<h1 id="assetsafreeworldmaponaws">Assets: A free world map on AWS</h1>
<p>A huge ressource I stumbled upon while browsing Hacker News is the <a href="https://aws.amazon.com/fr/public-datasets/terrain/">terrain tiles dataset hosted by Amazon</a>. You can get PNGs containing elevation data, like these ones:</p>
<p><span style="align:center;"><img src="https://cdn.openbloc.fr/2018/04/366.png" alt="Game Development with three.js on the modern web 🚀🎆"> <img src="https://cdn.openbloc.fr/2018/04/366-1.png" alt="Game Development with three.js on the modern web 🚀🎆"></span></p>
<p>256x256 PNGs covering the whole world at various zoom levels. It doesn't look like anything at first, you have to extract the red, green and blue values (integers between 0 and 255) of each pixel to compute the elevation value using the following formula:</p>
<pre><code>(red * 256 + green + blue / 256) - 32768
</code></pre>
<p>I used <a href="https://github.com/photopea/UPNG.js/">UPNG.js</a> to decode the images obtained via the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch">fetch API</a>, inside a web worker.<br>
Let's say we build a plane with 256x256 vertices and assign the elevation value to each vertex, we can now build mountains with real world data!</p>
<p><img src="https://cdn.openbloc.fr/2018/04/DOugUYUXUAAacdb.jpg-large.jpeg" alt="Game Development with three.js on the modern web 🚀🎆"></p>
<p>Then you just have to juxtapose several terrain tiles, combining different zoom levels and you can have your own 3D version of google maps:</p>
<p><video src="https://cdn.openbloc.fr/videos/droneWorld_earth_map.webm" autoplay controls loop><source src="https://blog.openbloc.com/gamedev-with-three-js-on-the-modern-web/video.webm" type="video/webm"></video></p>
<p>I believe there's a huge potential of applications having such incredible datasets available in the open, gaming being just one possible application.</p>
<p><span id="span3"></span></p>
<h1 id="assetsbistextures">Assets bis: textures</h1>
<p>I did not use a lot of textures but a good ressource where I found free high-resolution and high quality seamless textures is <a href="https://www.poliigon.com">poliigon</a>. They have some <a href="https://www.poliigon.com/search?is_free=true">free textures</a> of wood, rocks, grass, terrain, etc.</p>
<p><img src="https://cdn.openbloc.fr/2018/04/Capture-du-2018-04-19-02-40-08.png" alt="Game Development with three.js on the modern web 🚀🎆"></p>
<p><span id="span4"></span></p>
<h1 id="assetsterfree3dmodels">Assets ter: free 3D models</h1>
<p>Let's go to <a href="https://sketchfab.com">Sketchfab</a>, a company co-founded by the French guy <a href="https://twitter.com/trigrou">Trigrou</a>. There's a huge collection of 3D models, some of them available under the <a href="https://en.wikipedia.org/wiki/GlTF">glTF format</a> under permissive licences. The glTF format allows for an easy import by thrre.js using its glTF importer, you get the model and its textures in one pass.</p>
<div class="sketchfab-embed-wrapper"><iframe width="800" height="480" src="https://sketchfab.com/models/b81008d513954189a063ff901f7abfe4/embed" frameborder="0" allowvr allowfullscreen mozallowfullscreen="true" webkitallowfullscreen="true" onmousewheel></iframe> <p style="font-size: 13px; font-weight: normal; margin: 5px; color: #4A4A4A;"> <a href="https://sketchfab.com/models/b81008d513954189a063ff901f7abfe4?utm_medium=embed&utm_source=website&utm_campain=share-popup" target="_blank" style="font-weight: bold; color: #1CAAD9;">Battle Damaged Sci-fi Helmet - PBR</a> by <a href="https://sketchfab.com/theblueturtle_?utm_medium=embed&utm_source=website&utm_campain=share-popup" target="_blank" style="font-weight: bold; color: #1CAAD9;">theblueturtle_</a> on <a href="https://sketchfab.com?utm_medium=embed&utm_source=website&utm_campain=share-popup" target="_blank" style="font-weight: bold; color: #1CAAD9;">Sketchfab</a> </p> </div>
<p><span id="span5"></span></p>
<h1 id="shaders">Shaders</h1>
<p><a href="https://en.wikipedia.org/wiki/Shader">Shaders</a> are small programs written in GLSL (openGL Shading Language) designed to run directly, and fastly, on the graphics card allowing you to compute all sorts of graphical effects. As of 2018, webGl allows you to program two types of shaders, vertex shaders, which can manipulate the vertices of your models and fragment shaders which work on each pixel of a frame and output their color.</p>
<p>A good introduction to learn shaders is <a href="https://thebookofshaders.com/?lan=en"><em>The book of shaders</em></a>.</p>
<p>I used shaders to texture the terrain differently depending on the slope of the terrain for example:<br>
<img src="https://cdn.openbloc.fr/2018/04/DRrHqFUW0AAlYcT.jpg-large.jpeg" alt="Game Development with three.js on the modern web 🚀🎆"><br>
The depth of field effect is also done by shaders though I mostly reused existing code in this case.</p>
<p><span id="span6"></span></p>
<h1 id="particles">Particles</h1>
<p>For smoke, explosions, sparks, you need a particle engine. Luckily there's one for three.js: <a href="http://squarefeet.github.io/ShaderParticleEngine/">Shader Particle Engine</a></p>
<p>Even with such libraries it might be tricky to achieve decent and efficient results but it's worth the pain!</p>
<p><img src="https://cdn.openbloc.fr/2018/04/DSe4-hdW4AIT_s2.jpg-large.jpeg" alt="Game Development with three.js on the modern web 🚀🎆"></p>
<p><span id="span7"></span></p>
<h1 id="marketing">Marketing</h1>
<p>I used my <a href="https://twitter.com/maxmre">twitter account @maxmre</a> as a cheap devlog to build a (small) following.</p>
<p>I used the <a href="https://www.reddit.com/r/gamedev/">/r/gamedev subreddit</a> and their weekly threads to get feedback and guidance.</p>
<p>I tried the <a href="https://itch.io">itch.io platform</a> to post droneWorld on <a href="https://maxmre.itch.io/droneworld">https://maxmre.itch.io/droneworld</a>. Though the platform is great for indie gamedevs, it wasn't a match for droneWorld as you have to post a working game to get some traction, it's not really suited for hosting a prototype under construction. Itch.io can also host your devlog but in my case that would have been redundant with what I was doing on twitter.</p>
<p>As I was publishing the game on <a href="https://lab.openbloc.fr/droneWorld">https://lab.openbloc.fr/droneWorld</a> each time I was making some progress I kept the process quite agile by having to have a working build every day.</p>
<p>You must be conscious that the game development process is a pretty specific topic. You may get the attention of your fellow developers but that's not necessarily where your end users will be.</p>
<p><span id="span8"></span></p>
<h1 id="missingparts">Missing parts</h1>
<p>Mobile controls, desktop controls, shaders, texturing, modeling, packaging your javascript, sound environment, game logic, gameplay, bots programming, multiplayer aspects, game feel, performance bottlenecks, what I mainly (re)discovered is that game programming covers a lot of topics, actually it's a whole industry where each part I touched can be a fulltime job inside a big team.</p>
<p><span id="span9"></span></p>
<h1 id="whatnext">What next?</h1>
<p>What topic should I cover to expand this article? Use the comments below, tweet <a href="https://twitter.com/maxmre">@maxmre</a> or write at max at openbloc.fr to let me know!</p>
<p>Thanks for reading :)</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Electric Sheep on Ubuntu Linux 17.10]]></title><description><![CDATA[Electric Sheep is an infinite evolving crowdsourced artwork. We'll see here how to install its client on Ubuntu Linux.]]></description><link>https://blog.openbloc.com/compiling-electric-sheep-on-ubuntu-linux-17-10/</link><guid isPermaLink="false">5ef246f087cd5c00c73ea850</guid><category><![CDATA[artwork]]></category><category><![CDATA[ubuntu]]></category><dc:creator><![CDATA[Maxime Rouyrre]]></dc:creator><pubDate>Thu, 09 Nov 2017 21:35:49 GMT</pubDate><media:content url="https://cdn.openbloc.fr/2017/11/33.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://cdn.openbloc.fr/2017/11/33.jpg" alt="Electric Sheep on Ubuntu Linux 17.10"><p>What is Electric Sheep ? Why would I want this thing ?</p>
<div style="text-align: center"><h3>ART !</h3></div>
<iframe width="560" height="315" src="https://www.youtube.com/embed/ipw4A6AXokk?rel=0" frameborder="0" allowfullscreen></iframe>
<h4 id="doandroidsdreamofelectricsheepsup1sup">Do Androids Dream of Electric Sheep?<a href="#ref_1"><sup>1</sup></a></h4>
<p>If you've never heard of <a href="https://electricsheep.org">Electric Sheep</a>, it is a collaborative abstract artwork.</p>
<blockquote>
<p>When computers &quot;sleep&quot;, the Electric Sheep comes on and the computers communicate with each other by the internet to share the work of creating morphing abstract animations known as &quot;sheep&quot;.</p>
</blockquote>
<blockquote>
<p>Anyone watching one of these computers may vote for their favorite animations using the keyboard. The more popular sheep live longer and reproduce according to a genetic algorithm with mutation and cross-over. Hence the flock evolves to please its global audience. [...]</p>
</blockquote>
<blockquote>
<p>You can design your own sheep and submit them to the gene pool. The result is a collective &quot;android dream&quot;, blending man and machine with code to create an artificial lifeform.</p>
</blockquote>
<h4 id="installationforwindowsormacosx">Installation for Windows or Mac OS X</h4>
<p>Just go to the <a href="https://gold.electricsheep.org/download#download">download page</a>.</p>
<h4 id="installationonlinux">Installation on Linux</h4>
<p>There aren't precompiled binaries for Ubuntu, in fact you're told to install it from source aka. to compile it. It's been a long time I wanted to try Electric Sheep but I never got around to compile it. Eventually I did it and the following is a summary of the steps I followed.</p>
<p>The <a href="https://github.com/scottdraves/electricsheep/wiki/Compiling#building-on-linux">README instructions</a> are pretty succinct but I managed to get it working.</p>
<h5 id="1installsystemdependencies">1. Install system dependencies</h5>
<pre><code class="language-bash">sudo apt install subversion autoconf libtool libgtk2.0-dev libgl1-mesa-dev libavcodec-dev libavformat-dev libswscale-dev liblua5.1-0-dev libcurl4-openssl-dev libxml2-dev libjpeg8-dev libgtop2-dev libboost-dev libboost-filesystem-dev libboost-thread-dev libtinyxml-dev freeglut3-dev glee-dev
sudo apt install libwxgtk3.0-0v5 libwxgtk3.0-dev
</code></pre>
<h5 id="2buildflam3">2. Build flam3</h5>
<p><a href="http://flam3.com/">Flam3</a> is a dependency of Electric Sheep, we need to install it.</p>
<pre><code class="language-bash">git clone git@github.com:scottdraves/flam3.git
cd flam3/
./configure
make
</code></pre>
<p>Now <code>make</code> will probably fail, the fix is to edit <code>Makefile</code> to put the correct version of the failing rules (replaced 1.14 by 1.15 in my case):</p>
<pre><code class="language-bash">ACLOCAL = aclocal-1.14    # -&gt; 1.15
AUTOMAKE = automake-1.14  # -&gt; 1.15
</code></pre>
<pre><code class="language-bash">make
</code></pre>
<h5 id="3buildadebpackageforflam3">3. Build a .deb package for flam3!</h5>
<p><a href="https://help.ubuntu.com/community/CheckInstall"><code>checkinstall</code></a> is a nice tool that we will use to replace the <code>sudo make install</code> step. It builds a <code>.deb</code> package that makes installation <em>and</em> uninstallation easy:</p>
<pre><code class="language-bash">sudo apt install checkinstall
sudo checkinstall
</code></pre>
<p>You can fill all asked questions with the default values, except for the package version that has to be valid (I used <code>3.1.1</code>). Once the <code>.deb</code> is built, just install it:</p>
<pre><code class="language-bash">sudo dpkg -i flam3_3.1.1-1_amd64.deb
</code></pre>
<h5 id="4atlastbuildelectricsheep">4. At last: build Electric Sheep</h5>
<pre><code class="language-bash">git clone git@github.com:scottdraves/electricsheep.git
cd electricsheep/client_generic/
./autogen.sh
./configure
make
sudo checkinstall
sudo dpkg -i client-generic_2.7b33-svn-1_amd64.deb
</code></pre>
<h5 id="5enjoy">5. Enjoy!</h5>
<pre><code class="language-bash">$ electricsheep
$ electricsheep-preferences
</code></pre>
<p>Thanks for reading !</p>
<p><video src="https://cdn.openbloc.fr/videos/esheep-720.mp4" autoplay controls loop></video><br>
<span id="ref_1"></span><br>
<br><br>
[1] <em><a href="https://en.wikipedia.org/wiki/Do_Androids_Dream_of_Electric_Sheep%3F">Do Androids Dream of Electric Sheep?</a> is a science fiction novel by American writer Philip K. Dick, first published in 1968.</em></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Elixir web development 101: collaborative todolist with realtime updates]]></title><description><![CDATA[Part 2:  how to implement a collaborative todo app with realtime updates. Elixir, Phoenix, React, Redux, websockets.]]></description><link>https://blog.openbloc.com/elixir-phoenix-web-development-101-todo-app/</link><guid isPermaLink="false">5ef246f087cd5c00c73ea848</guid><category><![CDATA[elixir]]></category><category><![CDATA[tutorial]]></category><category><![CDATA[javascript]]></category><category><![CDATA[react]]></category><dc:creator><![CDATA[Maxime Rouyrre]]></dc:creator><pubDate>Thu, 26 Oct 2017 23:55:19 GMT</pubDate><media:content url="https://cdn.openbloc.fr/2017/10/glenn-carstens-peters-190592.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://cdn.openbloc.fr/2017/10/glenn-carstens-peters-190592.jpg" alt="Elixir web development 101: collaborative todolist with realtime updates"><p>Following <a href="https://blog.openbloc.fr/elixir-web-development-101-first-steps/">Part 1: introduction &amp; toolchain setup</a> where we saw how to install the required toolchain and start a new app using the Phoenix framework, we'll see how to implement a collaborative todo app with realtime updates.</p>
<p>Todolists aren't something new, in fact, this post is mostly about how I used the <a href="https://10consulting.com/2015/11/18/phoenix-react-redux-example/">Phoenix, React, Redux example</a> article to get something that works.</p>
<p>Prerequisites: having installed Elixir and Phoenix, a reasonable understanding of how React and Redux work.</p>
<p>The code is available at:</p>
<div style="text-align: center;margin: 0 0 1.75em 0">
  <span style="display: inline-block;">
    <a href="https://github.com/blaze33/elixir-phoenix-react-redux-todo-list" target="_blank"><i class="fa fa-github"></i> blaze33/elixir-phoenix-react-redux-todo-list</a>
  </span>
</div>
<p><img src="https://cdn.openbloc.fr/2017/10/todoApp.gif" alt="Elixir web development 101: collaborative todolist with realtime updates"></p>
<h6 id="01boostrappingtheapp">0.1 Boostrapping the app</h6>
<p>We will create a backend Elixir app and a React front-end who will communicate though Websockets.</p>
<pre><code>$ mix phx.new todo_app --module Todo --app todo --no-html --no-brunch
</code></pre>
<p>Edit <code>config/dev.exs</code> with appropriate Postgresql credentials and run:</p>
<pre><code>$ mix ecto.create
</code></pre>
<h6 id="02creatingataskapi">0.2 Creating a task API</h6>
<p>The phoenix framework comes with code generators, we will use <a href="https://hexdocs.pm/phoenix/Mix.Tasks.Phx.Gen.Json.html">phx.gen.json</a> to generate json views backed by <a href="https://github.com/elixir-ecto/ecto">Ecto</a>. As we want a list of tasks for our Todo app, let's proceed:</p>
<pre><code>$ mix phx.gen.json API Task tasks label:string
</code></pre>
<p><img src="https://cdn.openbloc.fr/2017/10/Capture-d--cran-de-2017-10-27-00-12-10.png" alt="Elixir web development 101: collaborative todolist with realtime updates"></p>
<p>As you can see, the generator gives us a Model, View and a Controller. Add the ressource to the <code>:api</code> scope as indicated:</p>
<p><img src="https://cdn.openbloc.fr/2017/10/Capture-d--cran-de-2017-10-27-00-24-52.png" alt="Elixir web development 101: collaborative todolist with realtime updates"></p>
<p>Run <code>mix ecto.migrate</code> and launch the server with <code>mix phx.server</code> and open a webpage <a href="http://localhost:4000">localhost:4000</a>.</p>
<p><img src="https://cdn.openbloc.fr/2017/10/Capture-d--cran-de-2017-10-27-00-24-01.png" alt="Elixir web development 101: collaborative todolist with realtime updates"></p>
<p>Success ! We get an empty page, the database not being yet populated.</p>
<h6 id="03doingadatabasemigrationwithphoenix">0.3 Doing a Database migration with Phoenix</h6>
<p>As you may have noticed, the Task model does not have a field indicating its completion, that's perfect to learn how to do a database migration ! Ecto has a generator for this:</p>
<pre><code>$ mix ecto.gen.migration add_tasks_completed_field
</code></pre>
<p>This create an empty <a href="https://hexdocs.pm/ecto/Ecto.Migration.html">Ecto migration</a> in <code>priv/repo/migrations</code>, let's complete it:</p>
<pre><code class="language-elixir">defmodule Todo.Repo.Migrations.AddTaskCompletedField do
  use Ecto.Migration

  def change do
    alter table(:tasks) do
      add :completed, :boolean, default: false, null: false
    end
  end
end
</code></pre>
<p>And finally run <code>mix ecto.migrate</code>, that's it !</p>
<h6 id="11buildafrontend">1.1 Build a front-end</h6>
<p>The focus of this article not being on how to build a React-Redux app, I'll skip the boring part. Moreover you could download a <a href="https://github.com/reactjs/redux/tree/master/examples/todos">ready todo app from the Redux examples</a> and just adapt it.</p>
<h6 id="12connectthejavascripttoelixirthoughwebsockets">1.2 Connect the Javascript to Elixir though Websockets</h6>
<p>Phoenix delivers a <code>phoenix.js</code> well suited to its <a href="https://hexdocs.pm/phoenix/Phoenix.Channel.html#content">Channels</a>.</p>
<pre><code class="language-bash">$ yarn add phoenix
</code></pre>
<pre><code class="language-javascript">import { Socket } from 'phoenix'

export function configureChannel() {
  const socket = new Socket('ws://127.0.0.1:4000/socket');
  socket.connect();
  const channel = socket.channel('tasks');
  return channel
}
</code></pre>
<p>If you get 404 errors in the developer tools you may need to configure your Endpoint url host to <code>127.0.0.1</code> instead of <code>localhost</code> even though check origin is disabled in dev mode. God knows why, cf. this <a href="https://stackoverflow.com/a/44532408/343834">stackoverflow answer</a>, it almost drove me crazy!</p>
<h6 id="13connectyourreduxactionswiththeelixirchannel">1.3 Connect your redux actions with the Elixir channel</h6>
<p>On the client side, the idea is two sided:</p>
<ul>
<li>Subscribe to server messages and dispatch redux actions accordingly.</li>
<li>Push messages to the server on relevant actions.</li>
</ul>
<p>For example:</p>
<pre><code class="language-javascript">// dispatch an update when receiving one from the server
channel.on('update:todo', todo =&gt; {
  console.log('update:todo', todo);
  dispatch(updateTodoSuccess(todo));
});

// Below function is called on a component click
// We don't bother dispatching an action here, the server
// will answer with a `delete:todo` message, that will
// update the Redux store.
export function deleteTodo(todo) {
  return dispatch =&gt; {
    const payload = { id: todo.id}
    channel.push('delete:todo', payload)
  }
}
</code></pre>
<h6 id="14adaptthebackendtotalktotheclient">1.4 Adapt the backend to talk to the client</h6>
<p>Once again there's a generator to create a Channel:</p>
<pre><code>$ mix phx.gen.channel API
* creating lib/todo_web/channels/api_channel.ex
* creating test/todo_web/channels/api_channel_test.exs

Add the channel to your `lib/todo_web/channels/user_socket.ex` handler, for example:

    channel &quot;api:lobby&quot;, TodoWeb.APIChannel
</code></pre>
<p>The created Channel contains already some code we'll adapt to our use case.</p>
<pre><code class="language-elixir"># Channels can be used in a request/response fashion
# by sending replies to requests from the client
def handle_in(&quot;ping&quot;, payload, socket) do
  {:reply, {:ok, payload}, socket}
end

# It is also common to receive messages from the client and
# broadcast to everyone in the current topic (todo:lobby).
def handle_in(&quot;shout&quot;, payload, socket) do
  broadcast socket, &quot;shout&quot;, payload
  {:noreply, socket}
end
</code></pre>
<p>We have two things to do:</p>
<ul>
<li>Send a list of the tasks once the client connects</li>
<li>Have a CRUD interface over websocket</li>
</ul>
<p>You may think you'll get <code>Task.list_tasks()</code>, serialize it to JSON and send it to the client but the more pythonic way (sorry ;) ) is to use the already created JSON views to do the serialization:</p>
<pre><code class="language-elixir">def join(&quot;api:lobby&quot;, payload, socket) do
  todos = API.Task.list_tasks()
  {:ok, %{tasks: TodoWeb.TaskView.render(&quot;index.json&quot;, tasks: tasks)}, socket}
end
</code></pre>
<p>As for the CRUD interface:</p>
<pre><code class="language-elixir">def handle_in(&quot;new:todo&quot;, payload, socket) do
  {:ok, created} = TodoTest.Todos.create_todo(payload)
  created_json = TodoTestWeb.TodoView.render(&quot;todo.json&quot;, todo: created)
  broadcast! socket, &quot;new:todo&quot;, created_json
  {:reply, {:ok, created_json}, socket}
end

def handle_in(&quot;update:todo&quot;, payload, socket) do
  todo = TodoTest.Todos.get_todo!(payload[&quot;id&quot;])
  TodoTest.Todos.update_todo(todo, payload)
  broadcast! socket, &quot;update:todo&quot;, payload
  {:noreply, socket}
end

def handle_in(&quot;delete:todo&quot;, payload, socket) do
  todo = TodoTest.Todos.get_todo!(payload[&quot;id&quot;])
  TodoTest.Todos.delete_todo(todo)
  broadcast! socket, &quot;delete:todo&quot;, payload
  {:noreply, socket}
end
</code></pre>
<p>And there you have it!</p>
<p><img src="https://cdn.openbloc.fr/2017/10/todoApp.gif" alt="Elixir web development 101: collaborative todolist with realtime updates"></p>
<h6 id="conclusion">Conclusion</h6>
<p>In short I was blown away by how easily the code generators work for you and how Phoenix integrates with websockets through channels. The backend code is very succinct and once you understand how it works, you feel quite productive.<br>
Thanks for reading :)</p>
<p><small>Photo by Glenn Carstens-Peters on Unsplash</small></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Elixir web development 101: introduction & toolchain setup]]></title><description><![CDATA[This article will show you how to install Erlang, Elixir, the Phoenix Framework and how to create a "Hello world" Phoenix app on Ubuntu.]]></description><link>https://blog.openbloc.com/elixir-web-development-101-first-steps/</link><guid isPermaLink="false">5ef246f087cd5c00c73ea84d</guid><category><![CDATA[tutorial]]></category><category><![CDATA[elixir]]></category><dc:creator><![CDATA[Maxime Rouyrre]]></dc:creator><pubDate>Wed, 25 Oct 2017 19:27:00 GMT</pubDate><media:content url="https://cdn.openbloc.fr/2017/10/Capture-d--cran-de-2017-10-25-23-52-34-1.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://cdn.openbloc.fr/2017/10/Capture-d--cran-de-2017-10-25-23-52-34-1.png" alt="Elixir web development 101: introduction & toolchain setup"><p>This tutorial started as a brain dump of my first steps in the world of Erlang, Elixir, Phoenix, etc. I thought it might be useful to share it.</p>
<p><em><a href="https://blog.openbloc.fr/elixir-phoenix-web-development-101-todo-app/">Part 2 : collaborative todolist with realtime updates</a></em></p>
<h6 id="01whatisthis">0.1 What is this ?</h6>
<ul>
<li><a href="https://www.erlang.org/">Erlang</a> is a general-purpose, concurrent, functional programming language</li>
<li><a href="https://elixir-lang.org/">Elixir</a> is a dynamic, functional language designed for building scalable and maintainable applications. Elixir runs on the Erlang virtual machine (BEAM).</li>
<li><a href="http://phoenixframework.org/">Phoenix</a> is a web framework for Elixir.</li>
<li><a href="https://hex.pm/">Hex</a> is a package manager for the Erlang ecosystem.</li>
</ul>
<p>Both <a href="https://github.com/elixir-lang/elixir/releases/tag/v1.5.0">Elixir 1.5</a> and <a href="http://phoenixframework.org/blog/phoenix-1-3-0-released">Phoenix 1.3</a> were released in July 2017 so you may want to give it a fresh look.</p>
<h6 id="02somelinksifounduseful">0.2 Some links I found useful</h6>
<ul>
<li><a href="https://elixirnation.io/">Elixir Nation</a> centralizes the most useful resources</li>
<li><a href="https://elixirforum.com">The Elixir Forum</a> the go-to place to get community support</li>
<li><a href="https://stackoverflow.com/q/16779162/343834">What kind of virtual machine is BEAM (the Erlang VM)? [stackoverflow.com]</a></li>
<li><a href="https://news.ycombinator.com/item?id=14846359">Hacker news comments: Elixir 1.5 released</a></li>
<li><a href="https://news.ycombinator.com/item?id=14876562">Hacker news comments: Phoenix 1.3 released</a></li>
<li><a href="https://adrian-philipp.com/post/why-elixir-has-great-potential">Why the Elixir language has great potential</a></li>
<li><a href="https://hn.algolia.com/?query=Elixir&amp;sort=byPopularity&amp;prefix&amp;page=0&amp;dateRange=all&amp;type=story">Algolia search on Hacker News for 'Elixir'</a></li>
</ul>
<h6 id="03whatisthisarticle">0.3 What is this article ?</h6>
<p>I had no previous experience with Elixir and I'll show you how to get from this:</p>
<p><img src="https://cdn.openbloc.fr/2017/10/Capture-d--cran-de-2017-10-25-23-22-33.png" alt="Elixir web development 101: introduction & toolchain setup"></p>
<p>A fresh Ubuntu 17.10 install. To this:</p>
<p><img src="https://cdn.openbloc.fr/2017/10/Capture-d--cran-de-2017-10-25-23-24-58.png" alt="Elixir web development 101: introduction & toolchain setup"></p>
<p>A Phoenix test application &quot;hello world&quot; running on localhost.</p>
<p>So there's nothing special with the rest of this article but I wouldn't say there's no value in having a step by step documentation of the toolchain setup, especially if you're new to this. I know it can be tedious to track the different steps required with 15 open tabs, not everything being always up-to-date.</p>
<p>In case I forgot to document some steps, just tell me and I'll update the article</p>
<h6 id="11installingerlangandelixir">1.1 Installing Erlang and Elixir</h6>
<p>Cf. <a href="https://elixir-lang.org/install.html">https://elixir-lang.org/install.html</a>. For Ubuntu:</p>
<pre><code>$ wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb &amp;&amp; sudo dpkg -i erlang-solutions_1.0_all.deb
</code></pre>
<p>For Ubuntu 17.10, the Erlang artful repositories aren't yet available, so you'll have to edit <code>/etc/apt/sources.list.d/erlang-solutions.list</code> to point to the zesty repository (which works just fine):</p>
<pre><code>$ cat /etc/apt/sources.list.d/erlang-solutions.list 
### THIS FILE IS AUTOMATICALLY CONFIGURED ###
# You may comment out this entry, but any other modifications may be lost.
deb http://binaries.erlang-solutions.com/debian zesty contrib
$ sudo apt update
$ sudo apt install esl-erlang elixir
</code></pre>
<p>Now we can check Elixir is correctly installed:</p>
<pre><code>$ iex -v
Erlang/OTP 20 [erts-9.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [kernel-poll:false]

IEx 1.5.2
</code></pre>
<h6 id="12installphoenixandcreateatestapplication">1.2 Install phoenix and create a test application</h6>
<p>To install the new <code>phx.new</code> project generator, use the following command:</p>
<pre><code>$ mix archive.install https://github.com/phoenixframework/archives/raw/master/phx_new.ez
</code></pre>
<p>Use it to generate a new project:</p>
<pre><code>$ mix phx.new todoapp
$ cd todoapp
$ mix deps.get
$ cd assets &amp;&amp; npm install &amp;&amp; node node_modules/brunch/bin/brunch build
</code></pre>
<h6 id="13installpostgresqlandcreateatestdatabase">1.3 Install Postgresql and create a test database</h6>
<p>Your test application is configured to use <a href="https://www.postgresql.org/">Postgresql</a> by default. Well need to create test database and get some auth credentials to finalize the Phoenix app setup.</p>
<pre><code>$ sudo apt install postgresql postgresql-contrib
# Postgresql was already installed on my machine so I may have skipped some steps.
$ createuser --interactive
Enter name of role to add: dev                 
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) y
Shall the new role be allowed to create more new roles? (y/n) n
$ createdb testapp_dev
$ psql
psql (9.6.5)
Type &quot;help&quot; for help.
# ALTER USER dev WITH PASSWORD 'password';
# GRANT ALL PRIVILEGES ON DATABASE testapp_dev to dev;
# \q
</code></pre>
<p>Then edit <code>config/dev.exs</code> accordingly:</p>
<pre><code>username: dev,
password: password,
</code></pre>
<p>And run the following command:</p>
<pre><code>$ mix ecto.create
</code></pre>
<p>For your information, <a href="https://github.com/elixir-ecto/ecto">Ecto</a> is a database wrapper and language integrated query for Elixir.</p>
<h6 id="14launchthephoenixapp">1.4 Launch the Phoenix app</h6>
<p>If everything is correctly setup, the following should sufficient:</p>
<pre><code>$ mix phx.server
</code></pre>
<p>If you get an error message regarding <code>inotify-tools</code>, just install it:</p>
<pre><code>$ sudo apt install inotify-tools
</code></pre>
<p>Finally open the website:</p>
<pre><code>$ firefox http://0.0.0.0:4000/
</code></pre>
<h6 id="conclusion">Conclusion</h6>
<p>Now we have setup everything to start some Elixir &amp; Phoenix programming like in these examples:</p>
<ul>
<li><a href="https://10consulting.com/2015/11/18/phoenix-react-redux-example/">Phoenix, React, Redux example</a>: real-time collaborative TODO app</li>
<li><a href="https://www.monterail.com/blog/2015/phoenix-blog">Elixir blog in 15 minutes using Phoenix framework - Step by Step</a></li>
</ul>
<p>Those examples are from 2015, I'll try do something up-to-date for my next article, when I get some time... and some more inspiration :)</p>
<p>Thanks for reading !</p>
<p><em><a href="https://blog.openbloc.fr/elixir-phoenix-web-development-101-todo-app/">Part 2 : collaborative todolist with realtime updates</a></em></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[How to embed dynamic JS content on the Ghost blogging platform]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Ghost is a wonderful blogging platform but what if you wanted to include something dynamic ? Nothing more easy !</p>
<pre><code>&lt;canvas id=&quot;universe&quot;&gt;&lt;/canvas&gt;
&lt;script type=&quot;text/javascript&quot;  src=&quot;https://lab.openbloc.fr/way-of-life/js/lab-bundle.js?380a213f&quot;&gt;Enable javascript</code></pre>]]></description><link>https://blog.openbloc.com/including-a-js-app-in-a-ghost-post/</link><guid isPermaLink="false">5ef246f087cd5c00c73ea84b</guid><category><![CDATA[javascript]]></category><category><![CDATA[tutorial]]></category><category><![CDATA[ghost]]></category><dc:creator><![CDATA[Maxime Rouyrre]]></dc:creator><pubDate>Thu, 20 Jul 2017 14:47:39 GMT</pubDate><media:content url="https://cdn.openbloc.fr/2017/07/max-mckinnon-100429.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://cdn.openbloc.fr/2017/07/max-mckinnon-100429.jpg" alt="How to embed dynamic JS content on the Ghost blogging platform"><p>Ghost is a wonderful blogging platform but what if you wanted to include something dynamic ? Nothing more easy !</p>
<pre><code>&lt;canvas id=&quot;universe&quot;&gt;&lt;/canvas&gt;
&lt;script type=&quot;text/javascript&quot;  src=&quot;https://lab.openbloc.fr/way-of-life/js/lab-bundle.js?380a213f&quot;&gt;Enable javascript please&lt;/script&gt;
</code></pre>
<p>The Ghost preview window will show you the following:</p>
<p><img src="https://cdn.openbloc.fr/2017/07/Capture-du-2017-07-20-16-33-29.png" alt="How to embed dynamic JS content on the Ghost blogging platform"></p>
<p>Demo of the game of life, click to add new cells:</p>
<p><canvas id="universe" style="width: 100%;"></canvas></p>
<script type="text/javascript" src="https://lab.openbloc.fr/way-of-life/js/lab-bundle.js?380a213f">no script</script>
<p>Thanks for reading !</p>
<p>Photo by Max McKinnon on Unsplash</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[How to setup a free CDN and HTTPS everywhere - 75% hosting cost reduction (S3 + Cloudflare)]]></title><description><![CDATA[In this tutorial I will show you how to get a free CDN with Cloudflare on S3 and HTTPS everywhere, also for free. Get a 75% hosting costs reduction!
]]></description><link>https://blog.openbloc.com/heroku-s3-cloudflare-free-cdn-and-https/</link><guid isPermaLink="false">5ef246f087cd5c00c73ea852</guid><category><![CDATA[heroku]]></category><category><![CDATA[hosting]]></category><category><![CDATA[tutorial]]></category><category><![CDATA[cloudflare]]></category><dc:creator><![CDATA[Maxime Rouyrre]]></dc:creator><pubDate>Thu, 13 Jul 2017 21:51:00 GMT</pubDate><media:content url="https://cdn.openbloc.fr/2017/07/ISS_1-small.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://cdn.openbloc.fr/2017/07/ISS_1-small.jpg" alt="How to setup a free CDN and HTTPS everywhere - 75% hosting cost reduction (S3 + Cloudflare)"><p>My <a href="https://blog.openbloc.fr/webassembly-first-steps/">Webassembly 101 tutorial</a> got ~50000 page views after hitting the front page of hacker news. I got a $12 USD S3 bill in June from Amazon. In this tutorial I will show you how to get a free CDN and HTTPS everywhere with Cloudflare.</p>
<p>This tutorial is written for an Heroku hosted Ghost blog but it should be pretty straightforward to use it for other hosting options.</p>
<p>What is a <a href="https://en.wikipedia.org/wiki/Content_delivery_network">CDN</a> and why would you need it ?</p>
<blockquote>
<p>A content delivery network or content distribution network (CDN) is a geographically distributed network of proxy servers and their data centers. The goal is to distribute service spatially relative to end-users to provide high availability and high performance.</p>
</blockquote>
<p><img src="https://cdn.openbloc.fr/2017/08/Capture-du-2017-08-14-11-31-14.png" alt="How to setup a free CDN and HTTPS everywhere - 75% hosting cost reduction (S3 + Cloudflare)"></p>
<p>In short:</p>
<ol>
<li>Hosting costs reduction</li>
<li>Better performance for end users</li>
<li>Encrypted traffic for more security</li>
</ol>
<h4 id="summary">Summary</h4>
<ol>
<li><a href="#mistakes">Initial mistakes</a></li>
<li><a href="#part1">Fix 1: setup Clouflare in front of your website</a></li>
<li><a href="#part2">Fix 2: update all articles with lower resolution images and CDN urls</a></li>
<li><a href="#part3">Fix 3: Free HTTPS</a></li>
<li><a href="#cached">Cached traffic results</a></li>
<li><a href="#conclusion">Conclusion</a>, TLDR: <strong>75% costs reduction</strong></li>
<li><a href="#bonuses">Bonuses</a></li>
</ol>
<p><a name="mistakes"></a></p>
<h4 id="initialmistakes">Initial mistakes</h4>
<ol>
<li>No <a href="https://en.wikipedia.org/wiki/Content_delivery_network">CDN</a>.</li>
<li>Having hosted high resolution images on S3.</li>
<li>No HTTPS, leading to <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer">lost referrers</a>.
<blockquote>
<p>A Referrer header is not sent by browsers if [...] an unsecured HTTP request is used and the referring page was received with a secure protocol (HTTPS).</p>
</blockquote>
</li>
</ol>
<p>Errors 1 and 2 led to a 12$ bill for the month of June 2017, ~100+Gb of data transferred at $0.09/Gb.</p>
<p><img src="https://cdn.openbloc.fr/2017/07/Capture-du-2017-07-13-22-50-31.png" alt="How to setup a free CDN and HTTPS everywhere - 75% hosting cost reduction (S3 + Cloudflare)"></p>
<p><img src="https://cdn.openbloc.fr/2017/07/Capture-du-2017-07-13-22-49-40.png" alt="How to setup a free CDN and HTTPS everywhere - 75% hosting cost reduction (S3 + Cloudflare)"></p>
<p>Error 3 led to bad analytics because most referrers are not set.</p>
<p><a name="part1"></a></p>
<h4 id="fix1setupclouflareinfrontofyourwebsite">Fix 1: setup Clouflare in front of your website</h4>
<p>Cloudflare has a nice on-boarding process once you register for the free account.</p>
<p>Main steps are:</p>
<ol>
<li>Update the DNS server on you registrar with the ones Cloudflare gives you on the CDN tab:<br>
<img src="https://cdn.openbloc.fr/2017/07/Capture-du-2017-07-13-23-27-57.png" alt="How to setup a free CDN and HTTPS everywhere - 75% hosting cost reduction (S3 + Cloudflare)"><br>
On your registrar dashboard you just have to copy paste above urls:<br>
<img src="https://cdn.openbloc.fr/2017/07/Capture-du-2017-07-13-22-59-34.png" alt="How to setup a free CDN and HTTPS everywhere - 75% hosting cost reduction (S3 + Cloudflare)"></li>
<li>Setup an S3 bucket with a cdn compatible name: <code>cdn.example.com.s3.eu-central-1.amazonaws.com</code> and replace <code>example.com</code> by your website's name. See <a href="https://support.cloudflare.com/hc/en-us/articles/200168926-How-do-I-use-Cloudflare-with-Amazon-s-S3-Service-">the documentation</a> for a more detailed explanation.</li>
</ol>
<blockquote>
<p>If your domain is &quot;example.com&quot; and you want to use the CNAME &quot;files&quot;  you'll need to make sure the S3 bucket name is &quot;files.example.com&quot;. Amazon requires that the CNAME match the bucket name.</p>
</blockquote>
<ol start="3">
<li>Create a cdn CNAME record for the above CDN bucket url.<br>
<img src="https://cdn.openbloc.fr/2017/07/Capture-du-2017-07-13-23-07-57.png" alt="How to setup a free CDN and HTTPS everywhere - 75% hosting cost reduction (S3 + Cloudflare)"></li>
<li>After 24h the DNS have updated and I was able to access my S3 bucket content through <code>cdn.openbloc.fr</code>.</li>
</ol>
<p><a name="part2"></a></p>
<h4 id="fix2updateallarticleswithlowerresolutionimagesandcdnurls">Fix 2: update all articles with lower resolution images and CDN urls</h4>
<p>Pretty straightforward as the title said. Do not store 4000x3000px images ! Use a lower resolution and compress the jpeg images as much as quality permits.</p>
<p><a name="part3"></a></p>
<h4 id="fix3freehttps">Fix 3: Free HTTPS</h4>
<p>Cloudflare offers a nice service: <a href="https://www.cloudflare.com/ssl/">Cloudflare one-click SSL</a>.</p>
<p><img src="https://cdn.openbloc.fr/2017/07/Capture-du-2017-07-13-23-19-59.png" alt="How to setup a free CDN and HTTPS everywhere - 75% hosting cost reduction (S3 + Cloudflare)"></p>
<p>If you don't have an SSL certificate on your origin server, the available free option is Flexible SSL:</p>
<blockquote>
<p><em>Flexible SSL</em></p>
</blockquote>
<blockquote>
<p>Flexible SSL encrypts traffic from Cloudflare to end users of your website, but not from Cloudflare to your origin server. This is the easiest way to enable HTTPS because it doesn’t require installing an SSL certificate on your origin. While not as secure as the other options, Flexible SSL does protect your visitors from a large class of threats including public WiFi snooping and ad injection over HTTP.</p>
</blockquote>
<p><img src="https://cdn.openbloc.fr/2017/07/Capture-du-2017-07-13-23-18-16.png" alt="How to setup a free CDN and HTTPS everywhere - 75% hosting cost reduction (S3 + Cloudflare)"></p>
<p>Enabling it is just one click away:</p>
<p><img src="https://cdn.openbloc.fr/2017/07/Capture-du-2017-07-13-23-21-18.png" alt="How to setup a free CDN and HTTPS everywhere - 75% hosting cost reduction (S3 + Cloudflare)"></p>
<p>Of course, if you already have an SSL certificate on your server, go for the Full SSL option!</p>
<p><a name="cached"></a></p>
<h4 id="cachedtrafficresults">Cached traffic results</h4>
<p>We got ourselves a free CDN and a free HTTPS setup without using Heroku paid SSL. I'll pay next to nothing on my next S3 bill :)</p>
<p>As you can see below 84% of the traffic is now cached:<br>
<img src="https://cdn.openbloc.fr/2017/07/Capture-du-2017-07-13-23-25-30.png" alt="How to setup a free CDN and HTTPS everywhere - 75% hosting cost reduction (S3 + Cloudflare)"></p>
<p><img src="https://cdn.openbloc.fr/2017/07/Capture-du-2017-07-13-23-26-00.png" alt="How to setup a free CDN and HTTPS everywhere - 75% hosting cost reduction (S3 + Cloudflare)"></p>
<p><a name="conclusion"></a></p>
<h4 id="conclusion">Conclusion</h4>
<ol>
<li>June 1st-30th AWS bill: $12.32 USD with 51896 pages viewed.</li>
<li>July 1st-31th AWS bill: $0.20 USD with 3056 pages viewed.</li>
</ol>
<p>The hosting cost went down from $0.24 USD per 1000 pages viewed to $0.06 per 1000 pages viewed. <strong>That's a 75% cost reduction on your hosting bill, for free !</strong></p>
<p>Thanks for reading !</p>
<p><a name="bonuses"></a></p>
<h5 id="bonuses">Bonuses:</h5>
<ol>
<li>
<p><strong>HTTPS everywhere</strong>:</p>
<blockquote>
<p>Redirect all requests with scheme &quot;http&quot; to &quot;https&quot;. This applies to all http requests to the zone.</p>
</blockquote>
<p><img src="https://cdn.openbloc.fr/2017/07/Capture-du-2017-07-13-23-33-24.png" alt="How to setup a free CDN and HTTPS everywhere - 75% hosting cost reduction (S3 + Cloudflare)"></p>
</li>
<li>
<p><strong>Opportunistic Encryption</strong></p>
<blockquote>
<p>Opportunistic Encryption allows browsers to benefit from the improved performance of HTTP/2 and SPDY by letting them know that your site is available over an encrypted connection. Browsers will continue<br>
to show &quot;http&quot; in the address bar, not &quot;https&quot;.</p>
</blockquote>
</li>
</ol>
<p><img src="https://cdn.openbloc.fr/2017/07/Capture-du-2017-07-13-23-34-34.png" alt="How to setup a free CDN and HTTPS everywhere - 75% hosting cost reduction (S3 + Cloudflare)"></p>
<ol start="3">
<li>
<p><strong>Automatic HTTPS Rewrites</strong></p>
<blockquote>
<p>Automatic HTTPS Rewrites helps fix mixed content by changing &quot;http&quot; to &quot;https&quot; for all resources or links on your web site that can be served with HTTPS.</p>
</blockquote>
<p><img src="https://cdn.openbloc.fr/2017/07/Capture-du-2017-07-13-23-37-31.png" alt="How to setup a free CDN and HTTPS everywhere - 75% hosting cost reduction (S3 + Cloudflare)"></p>
</li>
</ol>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[The JavaScript ES2015 Starter Kit]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><i class="fa fa-exclamation-triangle"></i> <em>Attention: this article is probably not researched enough for now. There'll probably never be a JavaScript boilerplate, there's simply <a href="http://andrewhfarmer.com/starter-project/">too many of them</a>! In the meantime you can read my <a href="http://blog.openbloc.fr">other articles</a> but if you'd like to see how to build your own little starter kit, read ahead!</em></p>
<p>Starting a</p>]]></description><link>https://blog.openbloc.com/javascript-es2015-starter-kit/</link><guid isPermaLink="false">5ef246f087cd5c00c73ea84f</guid><category><![CDATA[javascript]]></category><category><![CDATA[es6]]></category><category><![CDATA[es2015]]></category><category><![CDATA[webpack]]></category><category><![CDATA[starter-kit]]></category><dc:creator><![CDATA[Maxime Rouyrre]]></dc:creator><pubDate>Tue, 13 Jun 2017 09:18:00 GMT</pubDate><media:content url="https://cdn.openbloc.fr/2017/06/freddy-castro-133326-2.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://cdn.openbloc.fr/2017/06/freddy-castro-133326-2.jpg" alt="The JavaScript ES2015 Starter Kit"><p><i class="fa fa-exclamation-triangle"></i> <em>Attention: this article is probably not researched enough for now. There'll probably never be a JavaScript boilerplate, there's simply <a href="http://andrewhfarmer.com/starter-project/">too many of them</a>! In the meantime you can read my <a href="http://blog.openbloc.fr">other articles</a> but if you'd like to see how to build your own little starter kit, read ahead!</em></p>
<p>Starting a new project can be tiresome because the toolchain setup can be quite time consuming. The web is full of outdated webpack tutorials, just give me something that works ! Instead of starting from scratch each time, I started to reuse the common parts of my projects. The following is the result of this process.</p>
<p>I present you the <a href="https://babeljs.io/learn-es2015/">ES2015 (EcmaScript2015/ES6)</a> starter kit:</p>
<div style="text-align: center;margin: 0 0 1.75em 0">
  <span style="display: inline-block;">
    <a href="https://github.com/blaze33/es2015-starter" target="_blank"><i class="fa fa-github"></i> blaze33/es2015-starter</a>
  </span>
</div>
<p>The learning curve shouldn't be too steep and it is best suited to quickstart small projects. I had simplicity in mind while developing it.</p>
<h4 id="requirements">Requirements</h4>
<ul>
<li><a href="https://git-scm.com/">git</a>, a distributed version control system.</li>
<li><a href="https://nodejs.org/en/">node.js</a>, includes npm.</li>
<li>Optionally <a href="https://yarnpkg.com/en/">yarn</a>.</li>
</ul>
<h4 id="startinganewjavascriptproject">Starting a new JavaScript project</h4>
<p>It's very easy, simply clone and edit the project:</p>
<pre><code class="language-bash"># clone the repository
git clone git@github.com:blaze33/es6-starter.git my-app
cd my-app
# install the npm packages of the dependencies
# if you don't have yarn installed just npm install
yarn
# start webpack-dev-server
npm run serve
</code></pre>
<p>Now you should have your browser open a new tab that will autoreload once you start editing the files in the <code>src</code> folder.</p>
<p><video class="centered-media" src="https://raw.githubusercontent.com/blaze33/es2015-starter/master/docs/media/es2015-starter-demo-small.mp4" buffered autoplay muted controls loop></video></p>
<p>Happy coding !</p>
<h4 id="features">Features</h4>
<p>ES2015 starter uses:</p>
<ul>
<li><a href="https://webpack.js.org/">webpack</a> to bundle the JavaScript app.</li>
<li><a href="https://github.com/sass/node-sass">node-sass</a> and <a href="https://github.com/webpack-contrib/sass-loader">sass-loader</a> to compile the SCSS files to CSS.</li>
<li><a href="https://github.com/webpack/webpack-dev-server">webpack-dev-server</a>, a development server that provides live reloading.</li>
<li><a href="https://github.com/babel/babel">Babel</a> with preset <code>env</code> to compile ES2015 JavaScript down to a supported version.</li>
<li>Linting check with <a href="https://standardjs.com/">standard.js</a>.</li>
<li><a href="https://necolas.github.io/normalize.css/">normalize.css</a>, makes browsers render all elements more consistently and in line with modern standards.</li>
<li><a href="https://github.com/purifycss/purifycss">purify-css</a>removes unused css.</li>
<li><a href="http://mildrenben.github.io/surface/">surface</a>, a Material Design CSS only framework.</li>
</ul>
<h4 id="conclusion">Conclusion</h4>
<p>Ideally I would like for this starter project to be a live one that would be updated and improved over time.</p>
<p>Contributions, pull requests, questions and comments are welcome: <br><a href="https://github.com/blaze33/es2015-starter"><i class="fa fa-github"></i> blaze33/es2015-starter</a></p>
<p>Thanks for reading !</p>
<h5 id="appendix">Appendix</h5>
<p>If you're curious how I made the above gif, I used <code>recordmydesktop</code> on Ubuntu 17.04. Install it with:</p>
<pre><code class="language-bash">sudo apt install recordmydesktop
</code></pre>
<p>Then I edited and converted the resulting video with <code>ffmpeg</code>:</p>
<pre><code class="language-bash"># install ffmpeg
sudo apt install ffmpeg
# cut the first 2 and last 2 seconds of the video
ffmpeg -ss 2 -i es2015-starter-demo.mp4 -t 88 -c copy es2015-starter-demo-cut.mp4
# generate a custom png palette to use in the final gif 
ffmpeg -y -i es2015-starter-demo-cut.mp4 -vf fps=10,scale=800:-1:flags=lanczos,palettegen palette.png
# generate the final gif
ffmpeg -i es2015-starter-demo-cut.mp4 -i palette.png -filter_complex 'fps=1,scale=800:-1:flags=lanczos,setpts=0.25*PTS[x];[x][1:v]paletteuse' es2015-starter-demo.gif
</code></pre>
<p>That's it !</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[HN frontpage: will your server crash ?]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Yesterday, my <a href="http://blog.openbloc.fr/webassembly-first-steps/">WebAssembly 101 tutorial</a> hit a pretty sweet spot on Hacker News, raising to the #1 one and getting more than 500 points.</p>
<p>If you read Hacker News, you've probably seen many websites go down when they hit the front page, with people resorting to Google cache, when available,</p>]]></description><link>https://blog.openbloc.com/hn-frontpage-will-your-server-crash/</link><guid isPermaLink="false">5ef246f087cd5c00c73ea84e</guid><dc:creator><![CDATA[Maxime Rouyrre]]></dc:creator><pubDate>Wed, 07 Jun 2017 08:47:00 GMT</pubDate><media:content url="https://cdn.openbloc.fr/2017/06/ashley-knedler-102792-1-1.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://cdn.openbloc.fr/2017/06/ashley-knedler-102792-1-1.jpg" alt="HN frontpage: will your server crash ?"><p>Yesterday, my <a href="http://blog.openbloc.fr/webassembly-first-steps/">WebAssembly 101 tutorial</a> hit a pretty sweet spot on Hacker News, raising to the #1 one and getting more than 500 points.</p>
<p>If you read Hacker News, you've probably seen many websites go down when they hit the front page, with people resorting to Google cache, when available, to access the content.</p>
<p><img src="https://cdn.openbloc.fr/2017/06/Capture-du-2017-06-07-07-32-55.png" alt="HN frontpage: will your server crash ?"></p>
<p>So when I saw that my submission started appearing on the front page after 6 or 7 upvotes (yes that's all you need!) I had a moment of doubt and went straight to Google Analytics to see how much traffic was coming. Answer: a lot !</p>
<p>Google Analytics five minutes after hitting the frontpage:<br>
<img src="https://cdn.openbloc.fr/2017/07/Screenshot_2017-06-06-12-01-01-bis.jpg" alt="HN frontpage: will your server crash ?"></p>
<p>Sure, this is a first world problem but I never had so much traffic, my website isn't a static one, I wasn't using a CDN and I had no idea how my server would handle the load.</p>
<h4 id="theghostplatformhostedonheroku">The Ghost platform hosted on Heroku</h4>
<p>My first blog post was about <a href="http://blog.openbloc.fr/welcome-to-ghost/">how I set up this website</a> using <a href="https://ghost.org/">Ghost</a>.</p>
<p>I'm hosted on <a href="http://heroku.com/">Heroku</a> on a single free dyno, you can't really get a smaller instance. So, how did it perform ?</p>
<p><img src="https://cdn.openbloc.fr/2017/06/Capture-du-2017-06-07-07-09-39.png" alt="HN frontpage: will your server crash ?"></p>
<p>To my surprise I didn't even had to scale up my app ! My sole instance flawlessly served all the requests without a single error.</p>
<p>At a mean of 235rpm day, we get:<br>
235rpm.day x 60min/hour x 24hr/day = <strong>338400 requests</strong></p>
<p>At 7 requests per page for <a href="https://blog.openbloc.com/hn-frontpage-will-your-server-crash/www.openbloc.fr">openbloc.fr</a> (that could surely be optimized)<br>
we get <strong>~48000 pages viewed</strong>.</p>
<p>The traffic peaked at ~650rpm, or <strong>~100 pages per minute</strong> but the CPU usage didn't go over 20% and the RAM usage as 250MB.</p>
<p>A big shout out to the <a href="https://ghost.org/">Ghost</a> and <a href="https://www.heroku.com/">Heroku</a> teams is in order.</p>
<h4 id="howtobenchmarkyoursite">How to benchmark your site ?</h4>
<p>A cool tool is <a href="https://httpd.apache.org/docs/2.4/en/programs/ab.html">Apache Benchmark</a>. On Ubuntu you can install it with:</p>
<pre><code class="language-bash">$ sudo apt install apache2-utils
</code></pre>
<p>And then to request 100 pages, 10 pages at a time:</p>
<pre><code class="language-bash">$ ab -n 100 -c 10 http://www.example.com/you-post-url/
</code></pre>
<p>If it takes less than a minute to complete you should be on the safe side :)</p>
<p>That's it !</p>
<h4 id="howmanypeopleuseanadblocker">How many people use an ad-blocker ?</h4>
<p>Beware that the Hacker News audience is pretty tech-savvy so we should get a higher percentage not representative of the general population.</p>
<p>I guess I'll ask Google Analytics how many people <em>don't</em> use an ad-blocker ;)</p>
<p><img src="https://cdn.openbloc.fr/2017/06/Capture-du-2017-06-07-08-18-35.png" alt="HN frontpage: will your server crash ?"></p>
<p>27677 page viewed says GA, 48342 says my server, so I'll say:</p>
<ul>
<li>43% use an ad-blocker,</li>
<li>57% don't.</li>
</ul>
<h4 id="conclusion">Conclusion</h4>
<p>I spent a lot of time hacking this weekend to get the <a href="http://blog.openbloc.fr/webassembly-first-steps/">WebAssembly 101 tutorial</a> possible so I knew the content could be interesting for someone starting in WebAssembly but I would never have expected such a success, it's really overwhelming !</p>
<p>On a personal note, after having gone through some rough times at the beginning of this year, it feels good to be back on track !</p>
<p>Happy hacking !</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[WebAssembly 101: a developer's first steps]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>This tutorial will guide you along the necessary steps to port a JavaScript library of the Conway's game of life to WebAssembly (wasm). This is a simple exercise that is perfect to start beyond a trivial Hello World.</p>
<p>I recently got interested in <a href="http://webassembly.org/">WebAssembly</a> and decided to take the leap</p>]]></description><link>https://blog.openbloc.com/webassembly-first-steps/</link><guid isPermaLink="false">5ef246f087cd5c00c73ea851</guid><category><![CDATA[javascript]]></category><category><![CDATA[webassembly]]></category><category><![CDATA[learning]]></category><category><![CDATA[tutorial]]></category><dc:creator><![CDATA[Maxime Rouyrre]]></dc:creator><pubDate>Sun, 04 Jun 2017 21:43:09 GMT</pubDate><media:content url="https://cdn.openbloc.fr/2017/06/kevin-o-connor-262008-bis-1.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://cdn.openbloc.fr/2017/06/kevin-o-connor-262008-bis-1.jpg" alt="WebAssembly 101: a developer's first steps"><p>This tutorial will guide you along the necessary steps to port a JavaScript library of the Conway's game of life to WebAssembly (wasm). This is a simple exercise that is perfect to start beyond a trivial Hello World.</p>
<p>I recently got interested in <a href="http://webassembly.org/">WebAssembly</a> and decided to take the leap this weekend. WebAssembly is an emerging standard to enable near-native performance for web applications. Basically it's <a href="https://kripken.github.io/talks/wasm.html#/">asm.js done right</a> as stated by <a href="https://twitter.com/kripken">@kripken</a> (Dec. 9th 2015). WebAssembly is still a moving target, with a lot of developments going on. Getting started turns out to be difficult as most of the available information is quickly becoming outdated.</p>
<p>I went through the <a href="https://github.com/mbasso/awesome-wasm/blob/master/README.md">awesome-wasm list</a> which is a good starting point but still had to work two days on this to get some working code.</p>
<p>There's a demo of the game of life re-implemented in wasm at the end of the article :)</p>
<p>The following tutorial was written using Ubuntu 17.04, so your mileage may vary. Assume no knowledge of WebAssembly as I wrote this starting from scratch but I won't detail the ES6 with webpack toolchain. There's a lot more available resources for this on the web. Try finding a more up-to-date tutorial like <a href="http://www.theodo.fr/blog/2016/07/a-comprehensive-introduction-to-webpack-the-module-bundler/">this one</a>.</p>
<p>This article has five parts:</p>
<ul>
<li><a href="#part1">Setup the toolchain</a></li>
<li><a href="#part2">Javascript integration</a></li>
<li><a href="#part3">Beyond Hello World: optimizing a game of life engine</a></li>
<li><a href="#part4">Benchmarking</a> (demo link is there)</li>
<li><a href="#part5">Conclusion</a></li>
</ul>
<h2 id="setupthetoolchainanamepart1a">Setup the toolchain<a name="part1"></a></h2>
<p>The provided packages are a little outdated, I got some warnings. After spending some time installing the latest LLVM build it appeared that the easiest way was to download and install the <a href="https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz">Portable Emscripten SDK for Linux and OS X (emsdk-portable.tar.gz)</a>. <br>Extract the archive and open a terminal in the folder.</p>
<pre><code class="language-bash">$ ./emsdk update
$ ./emsdk install latest
</code></pre>
<p>Now depending on your network speed go make yourself a coffee or read a book.</p>
<blockquote>
<p>The <a href="http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html#download-and-install">Emscripten</a> SDK provides the whole Emscripten toolchain (Clang, Python, Node.js and Visual Studio integration) in a single easy-to-install package, with integrated support for updating to newer SDKs as they are released.</p>
</blockquote>
<p>So we should have everything necessary to start coding some WebAssembly.<br>Once the installation is done, activate the sdk:</p>
<pre><code class="language-bash">$ ./emsdk activate latest
$ source ./emsdk_env.sh  # you can add this line to your .bashrc
</code></pre>
<p>Make some sample C file <code>counter.c</code>:</p>
<pre><code class="language-clike">int counter = 100;

int count() {
    counter += 1;
    return counter;
}
</code></pre>
<p>Compile it to wasm with emcc:</p>
<pre><code class="language-bash">$ emcc counter.c -s WASM=1 -s SIDE_MODULE=1 -o counter.wasm
</code></pre>
<p>And, tada ! We have a beautiful counter.wasm.<br>
<img src="https://cdn.openbloc.fr/2017/06/Capture-du-2017-06-03-15-47-35.png" alt="WebAssembly 101: a developer's first steps"></p>
<h2 id="javascriptintegrationanamepart2a">JavaScript integration<a name="part2"></a></h2>
<p>A standalone .wasm file won't do anything by itself, we need to load it in some client javascript code. I'm using webpack along with <code>wasm-loader</code> to this end. Refer to <a href="https://developer.mozilla.org/en-US/docs/WebAssembly/Using_the_JavaScript_API#Loading_our_wasm_module_and_using_it">the documentation</a> for a more vanilla JavaScript example. Ok, let's do this:</p>
<pre><code class="language-javascript">import Counter from './wasm/counter'
const wasmHelloWorld = () =&gt; {
    const counter = new Counter();
    console.log(&quot;count function result is : &quot; + counter.exports._count());
}
window.onload = wasmHelloWorld
</code></pre>
<p>Loading this code in a sample html page should print <code>101</code> in the console. Except it doesn't. In Firefox 53 you should get a <code>LinkError: import object field 'DYNAMICTOP_PTR' is not a Number</code> instead. What went wrong? I got stuck on this an entire evening, then came <a href="https://stackoverflow.com/a/44349363/343834">StackOverflow to the rescue</a>.<br>
<br>Let's get back to the code, we need to compile the C code with an optimization flag:</p>
<pre><code class="language-bash">$ emcc counter.c -O1 -o counter.wasm -s WASM=1 -s SIDE_MODULE=1
</code></pre>
<p>Now when we do a <code>new Counter()</code>, <code>wasm-loader</code> calls <code>new WebAssembly.Instance(module, importObject);</code></p>
<ul>
<li><code>module</code> is a correct <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module">WebAssembly.Module</a> instance.</li>
<li><code>importObject</code> is the default provided by <code>wasm-loader</code> which appears to not work.</li>
</ul>
<p>The reasons are a little obscure but editing the JavaScript to the following code solves the issue:</p>
<pre><code class="language-javascript">import Counter from './wasm/counter'
const wasmHelloWorld = () =&gt; {
    const counter = new Counter({
      'env': {
        'memoryBase': 0,
        'tableBase': 0,
        'memory': new WebAssembly.Memory({initial: 256}),
        'table': new WebAssembly.Table({initial: 0, element: 'anyfunc'})
      }
    })
    console.log(&quot;count function result is : &quot; + counter.exports._count());
}
window.onload = wasmHelloWorld
</code></pre>
<p>Now, reloading the webpage succeeds !</p>
<p><img src="https://cdn.openbloc.fr/2017/06/Capture-du-2017-06-04-15-19-58.png" alt="WebAssembly 101: a developer's first steps"></p>
<p>As you can see it wasn't that straightforward to get a simple hello world to work. In the following section we'll see an easier way to integrate JS and wasm.</p>
<h2 id="anamepart3abeyondhelloworldoptimizingagameoflifeengine"><a name="part3"></a>Beyond Hello World: optimizing a game of life engine</h2>
<p>While upping my skills in ES6, webpack, babel, etc. I made a <a href="http://lab.openbloc.fr/way-of-life/">little implementation</a> of the game of life. The code is available at <a href="https://github.com/blaze33/way-of-life"><i class="fa fa-github"></i> blaze33/way-of-life</a>.</p>
<p>The <a href="https://github.com/blaze33/way-of-life/blob/v0.0.6/src/js/engine.js#L36">game engine</a> has a double loop iterating over the whole game grid at each step. Though I tried hard to keep it fast, it gets quickly slow once you increase the grid size. With our newfound WebAssembly skills it could be a nice exercise to try running the core game engine as a <code>wasm</code> module.</p>
<p>What needs to be done ?</p>
<ul>
<li>Re-implement the <a href="https://github.com/blaze33/way-of-life/blob/master/src/js/wasm/engine.c">game logic in C</a>.</li>
<li>Compile the C logic to wasm.</li>
<li>Expose the wasm code in the JS one.</li>
<li>Have a way to interact between the C and JS code.</li>
</ul>
<p>We won't go full WebAssembly for now and have the rendering to the canvas done in WebAssembly for now.</p>
<h4 id="compilectowasmwithsomejsgluecode">Compile C to WASM with some JS-glue code</h4>
<p>Notice how we compiled the previous example with <code>-s SIDE_MODULE=1</code> ? This provides a single wasm module that we have to integrate from scratch in the client code. You should know that it doesn't allow for <code>malloc</code> calls in the C code for example. Not really a problem for a hello world but pretty much a big no-no once you try doing more complex stuff. Fortunately you can compile the C code and have emscripten provide a wasm module AND a JS module that serves as a glue to integrate the WebAssembly in the client code. In our case, it will allow us to make <code>malloc</code> calls and have a way to read the allocated memory from the JS side.</p>
<p>The compilation is done as follow:</p>
<pre><code class="language-bash">emcc engine.c -O3 -o engine.js -s WASM=1 -Wall -s MODULARIZE=1
</code></pre>
<p>By setting MODULARIZE we put all the JS output into a function. Unfortunately it's not really a JS module (AMDdefine, CommonJS nor ES6) so we'll just append <code>export {Module as default}</code> to <a href="https://github.com/blaze33/way-of-life/blob/master/src/js/wasm/engine.js"><code>engine.js</code></a>, webpack will do the rest and allow us to import the Module in our ES6 client code:</p>
<pre><code class="language-javascript">import Module from './wasm/engine.js'
module = Module({wasmBinaryFile: 'wasm/engine.wasm'})
</code></pre>
<p>You have to specify the extension in the import as there is an <code>engine.wasm</code> in the same folder. <br><code>wasmBinaryFile</code> is the url used to asynchronously fetch the wasm code, so <a href="https://github.com/blaze33/way-of-life/blob/v0.1.0/webpack.config.js#L71">we tell webpack to serve it</a> using <a href="https://github.com/kevlened/copy-webpack-plugin">copy-webpack-plugin</a>.</p>
<p>Keep this JS <code>module</code> in mind, we'll reuse it later.</p>
<h4 id="callingwasmfunctionsfromjavascript">Calling WASM functions from JavaScript</h4>
<p>By default the C functions are not exposed by emscripten (or maybe not always, correct me if I'm wrong), we need to tell it to do so:</p>
<pre><code class="language-clike">#include &lt;emscripten.h&gt;

EMSCRIPTEN_KEEPALIVE
char *init(int w, int h) {
    width = w;
    height = h;
    current = malloc(width * height * sizeof(char));
    next = malloc(width * height * sizeof(char));
    return current;
}
</code></pre>
<p><code>EMSCRIPTEN_KEEPALIVE</code> does exactly this and we can now call <code>module.asm._init(40, 40)</code> if we wanted to initialize the game with a 40x40 grid.</p>
<p>All the exposed C funtions are available in <code>module.asm</code> and are prefixed with an underscore.</p>
<h4 id="accessingthewasmmodulememoryfromjs">Accessing the wasm module memory from JS</h4>
<p>Emscripten conveniently exposes the module memory through <code>module.HEAP*</code> variables. The <a href="https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#access-memory-from-javascript">recommended way to interact with the memory</a> is with <code>module.getValue</code> and <code>setValue</code>. As this is slower, I'll pursue directly with accessing HEAP8, considering the state is in a char array. Beware: accessing undocumented properties will probably break in the future!</p>
<p>Now we have pretty much all the pieces, I worked hard to piece all this together so let's proceed to the speedup benchmarking with the demo!</p>
<h2 id="anamepart4abenchmarking"><a name="part4"></a>Benchmarking</h2>
<p>Benchmarking is always tricky and I shouldn't probably use this word for looking at an Hello World performance so that the following shouldn't be used to judge wasm performance. The C code is not optimized to be fast but written like the naïve JS implementation I used. That being said we can still have a look to see if the result goes faster than the JS implementation.</p>
<p>I did some performance profiling on Chrome 58.<br>
This is the original JS code:<br>
<img src="https://cdn.openbloc.fr/2017/06/Capture-du-2017-06-05-13-06-10.png" alt="WebAssembly 101: a developer's first steps"></p>
<p>And this is the wasm code:<br>
<img src="https://cdn.openbloc.fr/2017/06/Capture-du-2017-06-05-13-28-44.png" alt="WebAssembly 101: a developer's first steps"></p>
<p>On average the <code>computeNextState</code> which took ~40ms now runs in ~15ms, not orders of magnitude faster but enough to get from ~18FPS to ~40FPS on my laptop.</p>
<p>The improvements were less visible on Firefox 53 as the FPS varied a lot, but it is still present.</p>
<ul>
<li><a href="http://lab.openbloc.fr/way-of-life/?desiredFPS=60&amp;pixelsPerCell=5">Demo up to 60FPS, 5 pixels per cell</a></li>
<li><a href="http://lab.openbloc.fr/way-of-life/?desiredFPS=60&amp;pixelsPerCell=1">Demo up to 60FPS, 1 pixel per cell</a></li>
</ul>
<p>You can play with the url options and also switch the wasm engine to the js one for comparison, have fun!</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/ZLJvpxKVgRk?rel=0" frameborder="0" allowfullscreen></iframe>
<h2 id="conclusionanamepart5a">Conclusion <a name="part5"></a></h2>
<ul>
<li>Starting this was much harder than I envisioned!</li>
<li>Webassembly looks really promising but the toolchain feels a bit heavy and clunky at times.</li>
<li>The documentation is both sparse or too technical but that should improve over time.</li>
<li>Having the emscripten glue code is really necessary for now, even if it seems to add another layer. I initially thought we could get away interfacing directly with the wasm code but I couldn't.</li>
<li>Still pretty happy with the result.</li>
<li>The code is available at <a href="https://github.com/blaze33/way-of-life"><i class="fa fa-github"></i> blaze33/way-of-life</a></li>
</ul>
<p>Thanks for reading ! If you liked this article you can follow me at <a href="https://twitter.com/maxmre">@maxmre</a> for future posts, or you could star the <a href="https://github.com/blaze33/way-of-life">github repo</a>, leave a comment or, you know, just ignore this internet-points-mania, I won't be mad ;)</p>
<p>Also thanks to <a href="https://stackoverflow.com/search?q=webassembly">Stackoverflow</a> and <a href="https://news.ycombinator.com/news">Hacker News</a> for helping me along the way!</p>
<p><a href="https://news.ycombinator.com/item?id=14495893">Hacker News discussion thread</a>.</p>
<h5 id="usefulresources">Useful resources</h5>
<ul>
<li><a href="https://github.com/mbasso/awesome-wasm/blob/master/README.md">Awesome wasm</a></li>
<li><a href="https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html">Interacting with code</a> (between JS and C/C++)</li>
<li><a href="https://developer.mozilla.org/en-US/docs/WebAssembly">MDN documentation</a></li>
<li><a href="https://medium.com/mozilla-tech/why-webassembly-is-a-game-changer-for-the-web-and-a-source-of-pride-for-mozilla-and-firefox-dda80e4c43cb">Why WebAssembly is a game changer for the web — and a source of pride for Mozilla and Firefox</a></li>
<li><a href="https://s3.amazonaws.com/mozilla-games/ZenGarden/EpicZenGarden.html">Epic games Zen Garden Demo</a> (125MB download!)</li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Open sourcing a dead startup]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>The following is not a success story. Pretty atypical for an article topic but I thought it might be of some interest to show you the work of a failed startup. Before starting your own project it's always beneficial to get some feedback from others who tried and, not always,</p>]]></description><link>https://blog.openbloc.com/resuscitating-a-4-year-old-app/</link><guid isPermaLink="false">5ef246f087cd5c00c73ea84c</guid><category><![CDATA[heroku]]></category><category><![CDATA[startup]]></category><dc:creator><![CDATA[Maxime Rouyrre]]></dc:creator><pubDate>Mon, 08 May 2017 09:58:00 GMT</pubDate><media:content url="https://cdn.openbloc.fr/2017/06/pexels-photo-60324.jpeg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://cdn.openbloc.fr/2017/06/pexels-photo-60324.jpeg" alt="Open sourcing a dead startup"><p>The following is not a success story. Pretty atypical for an article topic but I thought it might be of some interest to show you the work of a failed startup. Before starting your own project it's always beneficial to get some feedback from others who tried and, not always, succeeded before you.</p>
<h3 id="thenewcoproject">The NewCo project</h3>
<p>Back in 2012-2013, four people, including myself, launched a startup project called NewCo, as in the New Company. The idea was to offer a place where consumers would exchange information about the products they use and love thus empowering you to make better and faster buying decisions.</p>
<p><img src="https://cdn.openbloc.fr/2017/05/Capture-du-2017-05-08-11-03-15.png" alt="Open sourcing a dead startup"></p>
<p><strong>No prior experience in the web:</strong> four engineers from the same school, a very good one though, but with very little experience in what building a web startup would mean.</p>
<p><strong>No traction:</strong> while I'm sure this space is still promising for new startups, in such a B2C configuration you would need a lot of traction to get things moving. We failed miserably at that, the product wasn't compelling enough to attract readers and contributors.</p>
<p><strong>No money:</strong> we had the idea that once a user had the information he wanted before buying a product, we would just have to show him available resellers in order to get money through affiliate marketing. Well, this way, we made 30€ in a year.</p>
<p><strong>Co-founders disagreements:</strong> trust me, don't wait one year to talk about who owns how much of the company. Maybe you don't have to incorporate right away but have at least a written agreement of some sort.</p>
<p><strong>A working website:</strong> at least being engineers was useful for this.<br><br>
The development was mostly done by <a href="https://github.com/AGASS007">AGASS007</a> and me (<a href="https://github.com/blaze33">blaze33</a>). The stack is old, mainly built around Django 1.4: Python 2.7, Heroku cedar-14 (upgraded from cedar-10), redis, postgresql, celery.</p>
<h3 id="advicetofutureentrepreneurs">Advice to future entrepreneurs</h3>
<ol>
<li>Technology matters as long as it doesn't get in the way of all the rest.</li>
<li>Design, UX, marketing, communication matters a lot ! Don't call yourself NewCo, as in New Company, really ;)</li>
<li>People don't read, much less contribute on the Internet. You can't build your success on asking them to do stuff for you. Build it around what they would naturally do with the right tool (and build that one).</li>
<li>Choose your co-founders wisely. If your co-founder show up one day with another associate without having consulted you first, run ! Trust is everything.</li>
<li>Making money is a necessary evil, I've got a rent to pay, food to buy. The sooner you can break even, the better.</li>
</ol>
<h3 id="resuscitatingtheapp">Resuscitating the app</h3>
<p>Long story short, the <a href="http://newco-prod.herokuapp.com/">original website is still running</a> and I wanted to replace a feedback form that no longer worked by some comment about the startup story. Problem: I could no longer run the website locally and my code push were rejected by heroku. Two days of rabbitholing later I managed to rebuild and deploy the app.</p>
<p><strong>Some technical details:</strong> You know what happens when you don't touch a project for 4 years: it no longer runs!</p>
<p>All in all there was some work, mainly updating dependencies, without breaking the app, to have it run locally first.</p>
<p>Pushing to heroku no longer worked too as they updated their cedar-10 stack to cedar-14 (Ubuntu 10 vs Ubuntu 14 mainly).</p>
<p><a href="https://devcenter.heroku.com/articles/cedar-14-stack#upgrading-the-production-app-to-cedar-14">How to upgrade from the Cedar-10 stack to the Cedar-14 stack</a>.</p>
<p>Still pushing to heroku failed. Turns out I was using an old and no longer supported python version. Adding a <code>runtime.txt</code> with <code>python-2.7.13</code> fixed it.</p>
<p>Another fun thing that can happen in 4 years is that some packages are no longer available on pypi, or not at the version you need. Chasing github repos and installing from them solved it.</p>
<h3 id="opensourcingthecode">Opensourcing the code</h3>
<p>The only useful thing I could still do:<br>
<span style="text-align:center;display: inline-block;width: 100%;"><a href="https://github.com/blaze33/newco-legacy"><i class="fa fa-github"></i> newco-legacy</a></span></p>
<h3 id="conclusion">Conclusion</h3>
<p>I worked one and a half year on this project when the other co-founders decided to go their own way and incorporated their own company without me but still reused all my code and simply told me to sue them if I wasn't happy.</p>
<p>Comes the lawyer who aptly counselled that it would cost more than I would ever get back considering they weren't making any money.</p>
<p>Still I'm grateful for this experience as it gave me a solid technical background that I was able to reuse by working for other more successful startups.</p>
<p>Thanks for reading !</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Welcome to Openbloc]]></title><description><![CDATA[I've decided that after owning openbloc.fr for some years it was time to start sharing some of my whereabouts. Python, Django, Javascript, Ubuntu, etc.]]></description><link>https://blog.openbloc.com/welcome-to-ghost/</link><guid isPermaLink="false">5ef246f087cd5c00c73ea849</guid><category><![CDATA[Getting Started]]></category><category><![CDATA[heroku]]></category><category><![CDATA[hosting]]></category><dc:creator><![CDATA[Maxime Rouyrre]]></dc:creator><pubDate>Sun, 07 May 2017 19:37:00 GMT</pubDate><media:content url="https://cdn.openbloc.fr/2017/06/beautiful-sunrise-2-mod.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://cdn.openbloc.fr/2017/06/beautiful-sunrise-2-mod.jpg" alt="Welcome to Openbloc"><p>Sooo... I've decided that after owning <a href="http://www.openbloc.fr">openbloc.fr</a> for some years it was time to start sharing some of my whereabouts.</p>
<h2 id="gettingstarted">Getting Started</h2>
<p>When I started openbloc as my personal website, though I experimented with Flask and Angular, it was mostly a static website crafted by hand.<br>
I've spent some time investigating <a href="https://www.staticgen.com/">static website generators</a>, <a href="http://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html">hosting on S3</a> or on <a href="https://pages.github.com/">Github Pages</a></p>
<p><img src="https://cdn.openbloc.fr/2017/05/Capture-du-2017-05-08-10-23-01.png" alt="Welcome to Openbloc"></p>
<p>In the end it's still a lot of work to setup and understand those frameworks.</p>
<h3 id="comesghost">Comes Ghost</h3>
<p><img src="https://ghost.org/images/ghost.png" alt="Welcome to Openbloc"><br>
And then I remembered the <a href="https://ghost.org/">ghost platform</a>, which is a little bit more with &quot;batteries included&quot;. It seems to have come a long way since 2013 with a 1.0.0 release almost ready.</p>
<p>I used <a href="https://github.com/cobyism/ghost-on-heroku">ghost-on-heroku</a> to deploy it.</p>
<ol>
<li>Create a new S3 bucket</li>
<li>Create a new IAM role with S3 permissions</li>
<li>Use the provided ID and Key to fill the heroku form</li>
<li>Deploy !</li>
</ol>
<p>For some reason the deploy from github did not copy the source code in the heroku container so I had to fork and clone it for this as I wanted <a href="https://github.com/blaze33/openbloc-blog/commit/237253a0ed33ddfd12c0a390150c6cce6921174a">to update the dependencies</a>.</p>
<h3 id="addingthecustomblogopenbloccomdomain">Adding the custom blog.openbloc.com domain</h3>
<p>At this point ghost was only running at <code>openbloc-blog.herokuapp.com</code> to add a custom domain several steps are required:<br>
<img src="https://cdn.openbloc.fr/2017/05/Capture-du-2017-05-08-10-27-25.png" alt="Welcome to Openbloc"></p>
<ol>
<li>Add a domain on the heroku interface</li>
<li>Add a <code>CNAME</code> record at your DNS provider using the heroku-provided DNS target.</li>
<li>Adding a Let's Encrypt <a href="https://medium.com/@franxyzxyz/setting-up-free-https-with-heroku-ssl-and-lets-encrypt-80cf6eac108e">certificate for a secure https connection</a>: probably later as I would have to upgrade to a paid dyno for now.</li>
</ol>
<h3 id="customizingthedefaultthemecasper">Customizing the default theme: Casper</h3>
<p>I've just added <a href="http://prismjs.com">prism.js</a> to do code highlighting. Also a <code>Makefile</code> to generate the theme zip file:</p>
<pre><code class="language-makefile">zip:
	zip -r openbloc.zip . -x .git\*
</code></pre>
<p>It should work with a lot of languages out of the box, here's some test with a Django model:</p>
<pre><code class="language-python">class BaseModel(models.Model):
    &quot;&quot;&quot; BaseModel
    An abstract base class with timestamps.
    Stores data with postgresql JSON field.
    &quot;&quot;&quot;
    date_created = models.fields.DateTimeField(
        verbose_name=_(&quot;creation date&quot;),
        auto_now_add=True,
    )
    date_modified = models.fields.DateTimeField(
        verbose_name=_(&quot;modification date&quot;),
        auto_now=True,
    )
    data = JSONField(null=True, blank=True)

    class Meta:
        abstract = True

</code></pre>
<p>That's all !</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>