Jorge MarotoSoftware Engineer. Notes about software, infrastructure and the things I build.https://jorge.maroto.me/enAnalizando los datos de las Oposiciones a Maestros 2022, Comunidad Valencianahttps://jorge.maroto.me/oposiciones-maestros-2022-comunidad-valenciana/https://jorge.maroto.me/oposiciones-maestros-2022-comunidad-valenciana/Hace unos días que han terminado las oposiciones para el cuerpo de maestros en la Comunidad Valenciana , y me picaba la curiosidad de cómo habían ido en función de los tribunales y/o provincias. Antes de nada, decir que Mon, 18 Jul 2022 17:55:30 GMT<p>Hace unos días que han terminado las <strong>oposiciones para el cuerpo de maestros en la Comunidad Valenciana</strong>, y me picaba la curiosidad de cómo habían ido en función de los tribunales y/o provincias.</p><blockquote>Antes de nada, decir que toda esta información es pública en la web de la Conselleria de Educación, <em>Cultura y Deporte de la Generalitat Valenciana</em> (<a href="https://ceice.gva.es/es/web/rrhh-educacion/actas-de-tribunales-de-oposiciones-docentes">link directo</a>), por si alguien quiere acceso a la fuente original.</blockquote><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://jorge.maroto.me/content/images/2022/07/image-1.png" class="kg-image"><figcaption>Pantallazo de la web con las actas por especialidad</figcaption></figure><p>Tengo intención de escribir otro <em>blogpost algo más técnico</em> de cómo he conseguido agregar la información – hay <strong>cerca de 4000 archivos PDF</strong>, para las <strong>7 especialidades</strong> y cada uno de los tribunales en las tres provincias (Alicante, Castellón y Valencia)–, pero en éste me quería centrar en comentar los propios datos y dejarlos en formato Google Sheet al final del artículo por si alguien más quiere trastear con ellos.</p><h2 id="an-lisis-de-los-datos">Análisis de los datos</h2><p>Una vez con todos los datos juntos, he realizado algunas agregaciones que me parecieron interesantes para representar en las imágenes que dejo más abajo.</p><h3 id="datos-curiosos">Datos curiosos</h3><ul><li>💃 Con unas 50 personas por tribunal, las especialidades más demandadas fueron <strong>Infantil (147 tribunales y 7376 presentados)</strong> y <strong>Primaria (135 tribunales y 6772 presentados)</strong>.</li><li>🎼 La menos demandada fue la de <strong>Música, con 497 personas</strong> repartidas en 11 tribunales.</li><li>👌 <strong>19 personas en Infantil y 7 en Primaria</strong> han conseguido sacar un 🥇 <strong>10 en ambas partes</strong>. ¡Enhorabuena!</li><li>🔁 El <strong>tribunal V60 de Primaria</strong> es en el que más notas se modificaron, con <strong>19 cambios en el tema, 11 en el caso práctico y 1 en la programación,</strong> aunque sólo 5 de estas personas pasaron de no poder presentarse a la segunda prueba al sí poder hacerlo 🌺.</li></ul><h3 id="resumen-10-0">Resumen 10 / 0</h3><p>A continuación muestro una tabla agrupando a las especialidades por número de 10 en todo (🥇), y 0 en todo (👎).</p><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/image-3.png" class="kg-image"></figure><h3 id="aprobados-por-tribunal">Aprobados por tribunal</h3><p>En cuanto al número de aprobados por tribunal, lo he separado teniendo en cuenta el conseguir superar cada una de las pruebas, para al menos llegar a presentar la programación, o lo que es lo mismo:</p><ul><li>más de 1,25 en el tema.</li><li>más de 1,25 en caso práctico.</li><li>con lo anterior se superaría la prueba 1 con más de un 2,5.</li><li>más de un 5 en la programación o prueba 2.</li></ul><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/ANGLES.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/AUDICIO-I-LLENGUATGE.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/EDUCACIO-FISICA.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/EDUCACIO-INFANTIL--ALICANTE-.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/EDUCACIO-INFANTIL--CASTELL-N-.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/EDUCACIO-INFANTIL--VALENCIA-.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/EDUCACIO-PRIMARIA--ALICANTE-.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/EDUCACIO-PRIMARIA--CASTELL-N-.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/EDUCACIO-PRIMARIA--VALENCIA---1-.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/MUSICA.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/PEDAGOGIA-TERAPEUTICA.png" class="kg-image"></figure><h3 id="modificaciones-en-las-calificaciones">Modificaciones en las calificaciones</h3><p>Las siguientes gráficas representan el número de calificaciones que fueron modificadas del listado provisional al definitivo (probablemente tras una reclamación) para cada una de las partes de la prueba.</p><p>Resulta bastante curioso ver el <strong>tribunal V60 para Educación Primaria</strong>, donde en <strong>el tema hubo 19 modificaciones, en el caso práctico 11 y por último 1 modificación en la prueba 2</strong>.</p><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/ANGLES-1.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/AUDICIO-I-LLENGUATGE-1.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/EDUCACIO-FISICA-1.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/EDUCACIO-INFANTIL--ALICANTE--1.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/EDUCACIO-INFANTIL--CASTELL-N--1.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/EDUCACIO-INFANTIL--VALENCIA--1.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/EDUCACIO-PRIMARIA--ALICANTE--1.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/EDUCACIO-PRIMARIA--CASTELL-N--1.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/EDUCACIO-PRIMARIA--VALENCIA--2.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/MUSICA-1.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2022/07/PEDAGOGIA-TERAP-UTICA.png" class="kg-image"></figure><h2 id="enlaces-de-inter-s">Enlaces de interés</h2><p>Por último, comparto a continuación la web con las actas separadas por especialidad y tribunal, donde hay acceso a cada uno de los PDFs con las calificaciones, así como el Google Sheet que he generado con toda la información agregada.</p><ul><li><a href="https://ceice.gva.es/es/web/rrhh-educacion/actas-de-tribunales-de-oposiciones-docentes">Actas de los tribunales</a> (ceice.gva.es).</li><li><a href="https://docs.google.com/spreadsheets/d/1pAlT-l3rKAiVG9XttO2vgAJ-EpZw0PBNMj98aYJu1gc/edit">Google Sheet con la información agregada</a>.</li></ul>oposicionesdata analyticsMonitoring a Raspberry Pi: Grafana with Prometheushttps://jorge.maroto.me/monitoring-raspberry-pi-grafana/https://jorge.maroto.me/monitoring-raspberry-pi-grafana/In this part, we'll install Grafana with Dokku in our Digital Ocean droplet (5$/month), and after that, use Prometheus as Data Store.Sun, 07 Jun 2020 20:30:00 GMT<p>This is the second part of an article about <strong>how to monitor a Raspberry Pi using Prometheus</strong> and node_explorer. The first part is <a href="https://jorge.maroto.me/monitoring-raspberry-prometheus-node_explorer/">available here</a>.</p><p>In this part, we'll install <a href="https://grafana.com/">Grafana</a> with Dokku in our <a href="https://m.do.co/c/acb59f418e6e" rel="sponsored nofollow"><strong>Digital Ocean</strong> droplet (5$/month)</a>.</p><hr><h2 id="4-install-grafana-in-dokku">4. Install Grafana in Dokku</h2><p>As we did with Prometheus in the first part, we'll create the Dokku application and allow Grafana to write to the data folder.</p><pre><code># Create the Dokku application
dokku apps:create grafana
# Create the directory where we'll store the prometheus data
mkdir -p /var/lib/dokku/data/storage/grafana/
# The Grafana container uses the user id `472`, so we change the permissions to do that directory writable
# Related: https://github.com/grafana/grafana/blob/293ecbdd4fe1e0b636eb7d0a7e0184ace0f20a80/Dockerfile#L39-L40
sudo chown -R 472:472 /var/lib/dokku/data/storage/grafana/</code></pre><p>Locally, we'll create the git repository and add the files needed:</p><pre><code class="language-bash"># Initialize the repository
git init
# Add a new remote called `dokku` with our Dokku host
git remote add dokku [email protected]:grafana</code></pre><!--kg-card-begin: markdown--><ul>
<li><code>Dockerfile</code> (using Grafana as a base, we'll include the specific configuration for nginx)</li>
<li><code>nginx.conf.sigil</code> (just to increase the size limit for POST requests from Grafana, for example to take snapshots of a dashboard).</li>
<li><code>app.json</code> (optional, but I'm using the <a href="https://github.com/crisward/dokku-require">dokku-require</a> plugin, this file configures the mounted volumes).</li>
</ul>
<!--kg-card-end: markdown--><figure class="kg-card kg-code-card"><pre><code class="language-docker">FROM grafana/grafana:7.0.3
COPY ./nginx.conf.sigil .
</code></pre><figcaption>Dockerfile</figcaption></figure><figure class="kg-card kg-code-card"><pre><code class="language-nginx">...
...
client_max_body_size 250m;
...
...</code></pre><figcaption>nginx.conf.sigil</figcaption></figure><figure class="kg-card kg-code-card"><pre><code class="language-json">{
"dokku": {
"volumes": [
{
"host": "/var/lib/dokku/data/storage/grafana/data",
"app": "/var/lib/grafana",
"phases": "run,deploy"
}
]
}
}
</code></pre><figcaption>app.json</figcaption></figure><!--kg-card-begin: markdown--><p>As we're using a Dockerfile Deployment, we're adding this <code>sigil template</code> to our application <code>WORKDIR</code>. It's a copy from the <a href="https://github.com/dokku/dokku/blob/master/plugins/nginx-vhosts/templates/nginx.conf.sigil">default template</a>, just adding the <code>client_max_body_size</code> config, which allows to <code>POST</code> bigger requests, for example when we'll export a Grafana snapshot.</p>
<!--kg-card-end: markdown--><p>After pushing to our Dokku repository, we'll be able to connect using the default domain and port, but we can set those up:</p><pre><code class="language-bash">dokku domains:add grafana grafana.mydomain.com
dokku proxy:ports-set grafana http:80:3000
dokku letsencrypt grafana</code></pre><p>You can now open grafana.mydomain.com in your browser and enter the default user: <em>admin</em> / <em>admin</em>.</p><h2 id="5-connecting-grafana-to-prometheus">5. Connecting Grafana to Prometheus</h2><p>Grafana and Prometheus are working in two different containers, so if we want Grafana to read the data from Prometheus, we have to connect both networks.</p><p>Using Dokku, it's easy to create a new network, and use it in both containers:</p><pre><code class="language-bash">dokku network:create grafana-prometheus
dokku network:set prometheus attach-post-create grafana-prometheus
dokku network:set grafana attach-post-create grafana-prometheus
# After that, we could see a report of the networks per application
dokku@ubuntu-dokku:~$ dokku network:report prometheus
=====> prometheus network information
Network attach post create: grafana-prometheus
Network attach post deploy:
Network bind all interfaces: false
Network web listeners: 172.17.0.7:9090
# But we could use also the name of the container, for example: http://prometheus.web.1:9090</code></pre><p>With this URL, we can create a new datasource from our Grafana website: https://grafana.mydomain.com/datasources, adding the URL of Prometheus.</p><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2020/06/image.png" class="kg-image"></figure><p>After that, we can start running some queries against Prometheus, <a href="https://prometheus.io/docs/prometheus/latest/querying/examples/">there are a bunch of examples on their website</a>.</p><h2 id="6-importing-a-node_exporter-dashboard">6. Importing a node_exporter dashboard</h2><p>An interesting feature of Grafana is the ability to import dashboards; they even have a repository with lots of them.</p><p>Thanks to that, we can find a <a href="https://grafana.com/grafana/dashboards/1860">Node Exporter Full dashboard</a>, which we can import just using the ID (<em>1860</em>) in https://grafana.mydomain.com/dashboard/import, and we'll have a dashboard like the following.</p><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2020/06/Screenshot-2020-06-08-at-00.59.38-1.png" class="kg-image"></figure><h2 id="recap">Recap</h2><p>In this part, we've seen how to install Grafana in Dokku, and also how to connect it to the Prometheus installed <a href="https://jorge.maroto.me/monitoring-raspberry-prometheus-node_explorer/">in the first part of this article</a> to use as a data source.</p><p>As you've seen, this is a cheap way to monitor a server, from a Raspberry Pi at home to a more professional setup at your company, because you can even define alerts to get notified when something goes wrong.</p><h2 id="references">References</h2><ul><li>Grafana: <a href="https://grafana.com/grafana/dashboards/1860">Node Exporter Dashboard</a></li><li>Github: <a href="https://github.com/fahlke/raspberrypi_exporter/pull/1/files">raspberry_exporter</a></li></ul>dokkugrafanaprometheusdockerMonitoring a Raspberry Pi with Prometheus & node_exporter in Dokkuhttps://jorge.maroto.me/monitoring-raspberry-prometheus-node_explorer/https://jorge.maroto.me/monitoring-raspberry-prometheus-node_explorer/This article explains how to install node_exporter in a Raspberry Pi, and Prometheus using Dokku.Sun, 07 Jun 2020 20:00:00 GMT<p></p><p>In recent weeks, I've been having some issues with my Raspberry Pi, which unexpectedly stopped working after a few days, so I asked a question on Twitter, and the following stack was one of the proposals.</p><figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet" data-width="550"><p lang="es" dir="ltr">Desde hace unos días se me está quedando frita la raspberry donde tengo montado <a href="https://twitter.com/hashtag/homeAssistant?src=hash&ref_src=twsrc%5Etfw">#homeAssistant</a>, y no se muy bien el por qué.<br><br>De momento estoy usando @StatusCakeTeam para enterarme, pero no veo un patrón, así que voy a empezar a monitorizar tb los clásicos de CPU/Mem</p>— Jorge (en fase 1) (@patoroco) <a href="https://twitter.com/patoroco/status/1269230080053706753?ref_src=twsrc%5Etfw">June 6, 2020</a></blockquote>
</figure><p><a href="https://prometheus.io/">Prometheus</a> is one of the most popular options when you think about a monitoring solution (time series based, alerting, etc), and one of its sub-projects is <a href="https://github.com/prometheus/node_exporter">node_exporter</a>, which shows a list of metrics that will be consumed by Prometheus.</p><p>Dokku is <em>The smallest PaaS implementation you've ever seen</em>, and I've blogged about it <a href="https://jorge.maroto.me/tag/dokku/">several times because I'm using it for all my personal projects</a> hosted on the smallest droplet at <a href="https://m.do.co/c/acb59f418e6e" rel="sponsored nofollow"><strong>Digital Ocean</strong> (5$/month)</a>.</p><p>I've divided this article into two posts, and these are all the parts:</p><!--kg-card-begin: markdown--><ol>
<li>Export the metrics from the Raspberry Pi using <code>node_exporter</code>.</li>
<li>Make the metrics accessible from the internet (as we'll run Prometheus on a DigitalOcean droplet).</li>
<li>Install Prometheus in dokku.</li>
<li>Install Grafana in dokku.</li>
<li>Connect all the pieces.</li>
<li>Importing a <code>node_exporter</code> dashboard.</li>
</ol>
<!--kg-card-end: markdown--><h2 id="1-exporting-the-metrics">1. Exporting the metrics</h2><!--kg-card-begin: markdown--><p><a href="https://github.com/prometheus/node_exporter"><code>node_exporter</code></a> is a small application that exposes several metrics in a format that Prometheus is able to pull.<br>
The installation is straightforward and consists of downloading the package from <a href="https://github.com/prometheus/node_exporter/releases">the releases tab in Github</a>, and running it (these commands are run on your RPi).</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-code-card"><pre><code class="language-bash"># Download the package
wget https://github.com/prometheus/node_exporter/releases/download/v1.0.0/node_exporter-1.0.0.linux-armv7.tar.gz
# Extract the package
sudo tar -xvf node_exporter-1.0.0.linux-armv7.tar.gz -C /usr/local/bin/ --strip-components=1
# Run the node_exporter
node_exporter</code></pre><figcaption>In my case, as I have a Raspberry Pi 3, I've downloaded the ARMv7 release from the list.</figcaption></figure><p>Once you run the command, you can visit <em>http://<raspberry_IP>:9100/</em>, and click the <strong>metrics</strong> button; in my case it links to http://192.168.0.166:9100/metrics.</p><figure class="kg-card kg-code-card"><pre><code class="language-text"># HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 9.0365e-05
go_gc_duration_seconds{quantile="0.25"} 0.000183073
go_gc_duration_seconds{quantile="0.5"} 0.000413749
go_gc_duration_seconds{quantile="0.75"} 0.0005413
go_gc_duration_seconds{quantile="1"} 0.012291414
go_gc_duration_seconds_sum 2.396249156
go_gc_duration_seconds_count 4209
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 10
# HELP go_info Information about the Go environment.
# TYPE go_info gauge
go_info{version="go1.14.3"} 1
# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use.
# TYPE go_memstats_alloc_bytes gauge
go_memstats_alloc_bytes 3.897568e+06
...
...</code></pre><figcaption>These are the first lines that node_exporter includes</figcaption></figure><p>You don't want to run this command manually every time your Raspberry Pi restarts, so you can add an entry to your crontab:</p><figure class="kg-card kg-code-card"><pre><code class="language-bash">crontab -e
# Add the following line to your crontab and save the file
@reboot /usr/local/bin/node_exporter</code></pre><figcaption>You can reboot your RPi and check that it starts automatically as expected</figcaption></figure><h2 id="2-doing-accessible-node_exporter-from-internet">2. Making node_exporter accessible from the Internet</h2><p>As our Prometheus will be hosted on an external server (<a href="https://m.do.co/c/acb59f418e6e" rel="sponsored nofollow">Digital Ocean</a> in my case), we have to make our RPi accessible from the internet.</p><!--kg-card-begin: markdown--><p>How to do that depends on your router, so I'm going to share a screenshot of my router's configuration, where you only need to set up the port to be mapped to the RPi. In my case, accessing <code><my_ip>:9101</code> from the internet, will be mapped to the port <code>9100</code> on my RPi.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2020/06/Screenshot_07_06_2020__23_05.png" class="kg-image"></figure><h2 id="3-install-prometheus-in-dokku">3. Install Prometheus in Dokku</h2><p>I'm going to explain how to deploy Prometheus on that droplet using Dokku.</p><pre><code class="language-bash"># Create the dokku application
dokku apps:create prometheus
# Create the directory where we'll store the prometheus data
mkdir -p /var/lib/dokku/data/storage/prometheus/
# The prometheus container uses the user `nobody`, so we change the permissions to do that directory writable
# Related: https://github.com/prometheus/prometheus/blob/e963d953eac7d5181024eba2215740835b65c0a9/Dockerfile#L18-L21
sudo chown -R 65534:65534 /var/lib/dokku/data/storage/prometheus/</code></pre><p>Locally, we create a new repository and set up a remote pointing to our Dokku host.</p><pre><code class="language-bash"># Initialize the repository
git init
# Add a new remote called `dokku` with our dokku host
git remote add dokku [email protected]:prometheus
</code></pre><p>Now, we have to create the minimum docker environment:</p><!--kg-card-begin: markdown--><ul>
<li><code>Dockerfile</code> (using the Prometheus image as a base, and just copying the config).</li>
<li><code>prometheus.yml</code> (with the config to scrape).</li>
<li><code>app.json</code> (optional, but I'm using the <a href="https://github.com/crisward/dokku-require">dokku-require</a> plugin, this file configures the mounted volumes).</li>
</ul>
<!--kg-card-end: markdown--><figure class="kg-card kg-code-card"><pre><code class="language-docker">FROM prom/prometheus
COPY ./prometheus.yml /etc/prometheus/prometheus.yml
</code></pre><figcaption>Dockerfile</figcaption></figure><figure class="kg-card kg-code-card"><pre><code class="language-yml">global:
scrape_interval: 15s # Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"]
- job_name: "Raspberry"
static_configs:
- targets: ["<your_public_ip_address>:9101"]
</code></pre><figcaption>prometheus.yml</figcaption></figure><figure class="kg-card kg-code-card"><pre><code class="language-json">{
"dokku": {
"volumes": [
{
"host": "/var/lib/dokku/data/storage/prometheus/data",
"app": "/data/",
"phases": "run,deploy"
}
]
}
}
</code></pre><figcaption>app.json</figcaption></figure><p>After committing all these files and pushing to the Dokku server, you should be able to access Prometheus at the default domain, but maybe you prefer a friendlier URL, like https://prometheus.yourdomain.com:9091/.</p><pre><code class="language-bash"># Configure your desired domain
dokku domains:add prometheus prometheus.yourdomain.com
# Enable the HTTPS using the letsencrypt plugin
dokku letsencrypt prometheus
# Set the proxy ports
dokku proxy:ports-set prometheus http:9090:9090 https:9091:9090</code></pre><p>The last step is to configure the start parameters that Prometheus will use to run the container (more info about the available parameters in <a href="https://prometheus.io/docs/prometheus/latest/storage/#operational-aspects">the prometheus website</a>):</p><pre><code>dokku config:set prometheus DOKKU_DOCKERFILE_START_CMD="--config.file=/etc/prometheus/prometheus.yml --storage.tsdb.path=/data --storage.tsdb.retention.size=1GB --storage.tsdb.retention.time=30d"</code></pre><!--kg-card-begin: markdown--><p>After that, if you open https://prometheus.yourdomain.com:9091/ in your browser, you should see something similar to this under the <code>Status > Targets</code> menu.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://jorge.maroto.me/content/images/2020/06/Screenshot_08_06_2020__00_04.png" class="kg-image"><figcaption>List of targets managed by prometheus</figcaption></figure><p>And you can start playing with the available metrics from the Graph menu (<a href="https://prometheus.io/docs/prometheus/latest/querying/examples/">prometheus query examples</a>).</p><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2020/06/Screenshot_08_06_2020__00_08.png" class="kg-image"></figure><h2 id="recap">Recap</h2><p>In this article we've learned how to consume the metrics that node_exporter generates on our Raspberry Pi, and how to query them using Prometheus.</p><p>In <a href="https://jorge.maroto.me/monitoring-raspberry-pi-grafana/">the next article</a> I'll explain how to install Grafana in Dokku, and how to connect all the pieces.</p><h2 id="references">References</h2><ul><li>Prometheus :: <a href="https://prometheus.io/docs/prometheus/latest/storage/#operational-aspects">Storage Configuration</a>.</li><li>Tutorial: <a href="https://linuxhit.com/prometheus-node-exporter-on-raspberry-pi-how-to-install/">Node Exporter in Raspberry Pi</a>.</li><li>Github: <a href="https://github.com/fahlke/raspberrypi_exporter/pull/1/files">raspberry_exporter</a>.</li></ul>dokkumonitoringprometheusraspberry pidockerUsing Youtube on iOS while the screen is offhttps://jorge.maroto.me/using-youtube-on-ios-while-screen-is-off/https://jorge.maroto.me/using-youtube-on-ios-while-screen-is-off/As Youtube has disabled playing videos in background, using Youtube BG shortcut, you will be able to run Youtube videos in background mode from the "Share menu" in the youtube app.Sun, 23 Jun 2019 11:00:00 GMT<p>Some months ago Youtube presented <code>Youtube Premium</code>, a subscription plan that, among other features, lets you keep playing videos in the background (while you're using another app or after you turn off the screen).</p><p>This easy tweak will let you keep watching YouTube videos in the background as you did in the past, all without jailbreaking your iPhone / iPad.</p><p>TL;DR; using <a href="https://maroto.me/youtube-bg">Youtube BG shortcut</a>, you will be able to play YouTube videos in the background from the "Share" menu in the YouTube app.</p><h2 id="requirements">Requirements</h2><ol><li>Install <a href="https://apps.apple.com/us/app/shortcuts/id915249334">Shortcuts app from the App Store</a>.</li><li>In the official YouTube app, tap the three dots to open "Share", then tap the <code>More</code> button on the bottom right, and again <code>More</code> in the share menu.</li></ol><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2020/05/2019-06-23-enable-shortcuts-1.gif" class="kg-image"></figure><p>3. Install the <a href="https://maroto.me/youtube-bg">Youtube BG shortcut by tapping here</a>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://jorge.maroto.me/content/images/2020/05/2019-06-23-using-youtube-bg.gif" class="kg-image"><figcaption>** Note: if the video's sound stops, you can press play from the bottom menu (as when you change a song in Spotify), and it will play in the background.</figcaption></figure><h2 id="how-it-works">How it works</h2><p>Thanks to <a href="https://ytdl-org.github.io/youtube-dl/index.html"><code>youtube-dl</code></a>, I get the raw video URL, and using the iOS app <a href="https://apps.apple.com/us/app/shortcuts/id915249334">Shortcuts</a>, you can run the whole flow from the share menu of the official YouTube app.</p>iOSshortcutsyoutubeWeCode' talk about Dokkuhttps://jorge.maroto.me/wecode-talk-about-dokku/https://jorge.maroto.me/wecode-talk-about-dokku/Talk about Dokku at WeCode (spanish). Dokku is a pretty tool to create a PaaS (Platform as a Service) in yourself instanceThu, 28 Mar 2019 18:53:00 GMT<p><a href="https://wecodefest.com/">WeCode</a> is a really nice conference in Valladolid (Spain) where some slots are open for attendees to present their own talks, so I decided to talk about one of my latest toys: Dokku.</p><p>Here is the video of the talk (in Spanish), and <a href="https://docs.google.com/presentation/d/18ejgt1MvYEK0-pa7t4HHKUHsXgoHDzbYDhcMXn19MVo/edit?usp=sharing">the slides</a>.</p><figure class="kg-card kg-embed-card"><iframe width="612" height="344" src="https://www.youtube.com/embed/fAEO8nLHXPI?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></figure>talksdokkuTurn off display on MacBook Air 2018https://jorge.maroto.me/turn-off-display-on-macbook-air-2018/https://jorge.maroto.me/turn-off-display-on-macbook-air-2018/How to recover the option to turn off the display (without sleeping) on the MacBook Air 2018Tue, 12 Mar 2019 20:32:00 GMT<p>As you probably know, the MacBook Air released in 2018 includes TouchID as a way to unlock it.
The fingerprint reader is located on the top right, where old Mac keyboards included the <code>Eject</code> key.</p>
<p>You probably didn't use <code>Eject</code> much on your DVD-less MacBook, BUT I used to use <a href="https://apple.stackexchange.com/a/27304">a shortcut <code>Ctrl</code> + <code>Shift</code> + <code>Eject</code> to turn off Mac's screen</a>,
and this is something that I've missed since I bought my new MacBook Air.</p>
<p>I finally solved it by creating an AppleScript in Automator as a service with the following code.</p>
<pre><code class="language-applescript">do shell script ("pmset displaysleepnow")</code></pre>
<figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2019/2019-03-12-Automator.png" class="kg-image" alt="Automator script"></figure>
<p>As we've created a new service, we can assign a shortcut from <strong>System Preferences</strong> > <strong>Keyboard</strong> > <strong>Shortcuts</strong> > <strong>Services</strong>,
in my case, I've assigned <code>Control (^)</code> + <code>Alt</code> + <code>F12</code> as you can see in the image.</p>
<figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2019/2019-03-12-shortcuts.png" class="kg-image" alt="Shortcuts"></figure>
<p>I hope this helps someone, and if you solved this in another way, please let me know :)</p>MacOS XScaling Amazon Aurora at ticketeahttps://jorge.maroto.me/scaling-amazon-aurora-at-ticketea/https://jorge.maroto.me/scaling-amazon-aurora-at-ticketea/Ticketing is a business in which extreme traffic spikes are the norm, rather than the exception. For Ticketea, this means that our traffic can increase by a factor of 60x in a matter of seconds. This usually happens when big events (which have a fixed, pre-announced 'sale start time') go on sale.Fri, 19 May 2017 12:00:00 GMT<p>I wrote a post about how we scaled AWS Aurora at ticketea when a big event went on sale.</p><p>It was originally published on our engineering blog: <strong>Scaling Amazon Aurora at ticketea</strong>, but I'm going to include it in this blog too.</p><hr><p>Ticketing is a business in which extreme traffic spikes are the norm, rather than the exception. For <strong>Ticketea</strong>, this means that <strong>our traffic can increase by a factor of 60x</strong> in a matter of seconds. This usually happens when big events (which have a fixed, pre-announced <em>'sale start time'</em>) go on sale.</p><p>Cloud elasticity has its limits, particularly when reacting to extremely sudden changes in the inbound request rate. This is the reason why, for certain situations, we preferred to perform a pre-planned platform scaling followed by a warm-up.<br>For the sake of context, we host our infrastructure in AWS and we're heavy Amazon Aurora users.</p><p>For Ticketea, a big event usually translates to a surge of traffic, which touches the following components:</p><ul><li>Frontend app servers serving ticketea.com</li><li>API app servers</li><li>Background tasks</li><li>Relational Databases</li></ul><p>The first three resources are easy to scale horizontally (add / remove EC2 instances). We just need to modify <a href="https://docs.aws.amazon.com/autoscaling/latest/userguide/AutoScalingGroup.html">their autoscaling groups</a>, and AWS will do the hard work for us.</p><p>Relational databases are usually much harder to scale. Even though we're using an AWS Aurora cluster with multiple read replicas, scaling the writer node up and down is usually the tricky part. Before we get into it, let's talk a bit about AWS Aurora and how we're using it.</p><p>An Aurora cluster is accessible through two DNS records:</p><ul><li>A writer endpoint (a DNS Record pointing to the currently elected writer node)</li><li>A reader endpoint (a DNS Record which balances among the reader instances)</li></ul><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2020/05/rds_diagram-1.jpg" class="kg-image"></figure><h2 id="understanding-the-failover-process"><strong>Understanding the failover process</strong></h2><p>Failover is the process that Amazon Aurora gives us to promote a node to the writer role (Aurora only allows one writer at a time). The choice of the <em>future writer node</em> is performed using <strong>tiers</strong>. A tier is a config value which is set at instance creation time (and can be changed later).</p><p>When a failover happens (either manually triggered or in reaction to a cluster failure) Aurora will promote the lowest-tier reader node to the writer role.</p><p>As stated before, sometimes we need to scale the writer node vertically. To achieve this result, we force a failover to a beefier instance. Traditionally, we used to do this when the traffic was at its lowest point during the day, because we were afraid of the impact that such operation might have had on our users.<br>That really didn't work out well for the team (it meant that someone had to wake up early / stay up late), so we decided to do some tests to understand how to improve the failover and recovery times.</p><p>The first step was a simple script that issued bursts of queries to the writer node. During the execution, we would perform a manual failover, at which point we'd start to see that some of the queries were OK, but others failed <em>randomly</em>. The errors lasted for a 10-15 second window. We repeated the test several times, and the results were similar.</p><p>We decided to investigate how the Aurora writer and reader endpoints were implemented. Running <code>host</code> on the writer endpoint DNS record (let's suppose <code>tkt-aurora-cluster.cluster-abcdefg.eu-west-1.rds.amazonaws.com</code>), reveals that the endpoint is really a <code>CNAME</code> pointing to the currently elected Aurora writer instance.</p><pre><code class="language-bash">$ host tkt-aurora-cluster.cluster-abcdefg.eu-west-1.rds.amazonaws.com
tkt-aurora-cluster.cluster-abcdefg.eu-west-1.rds.amazonaws.com is an alias for
tkt-aurora-1.abcdefg.eu-west-1.rds.amazonaws.com
tkt-aurora-1.abcdefg.eu-west-1.rds.amazonaws.com is an alias for ec2-12-123-12-12.eu-west-1.compute.amazonaws.com.
ec2-12-123-12-12.eu-west-1.compute.amazonaws.com has address 12.123.12.12</code></pre><p>The reader endpoint works in a similar fashion, with the exception that it's backed by a <em>Round-Robin</em> DNS record pointing to the underlying database instances.</p><p>This explains why we were getting some errors during the failover operation: there is a rather large window of time (10-15 seconds) during which the cluster is adjusting to the new topology and DNS records are switched to reflect it. As you can imagine, DNS manipulation and propagation is not an atomic operation, hence the errors.</p><h2 id="scaling-procedures"><strong>Scaling procedures</strong></h2><p>Once we had gathered more information with this small investigation, we defined four different processes to scale our platform while minimizing the impact on our users. Let's have a look at them.</p><h3 id="horizontal-scaling-of-the-read-cluster"><strong>Horizontal scaling of the read cluster</strong></h3><p>This means adding or removing nodes to our read cluster to increase our read capacity.</p><h4 id="scaling-out"><strong>Scaling out</strong></h4><p>Scaling out is really easy: If you use the AWS Console, you can pick your cluster and choose the <em>Create New Aurora Replica</em> option. In our case, <strong>a new read replica takes ~7 minutes to be ready</strong>, and this operation doesn't cause downtime of any sort. The new node will not be added to the reader DNS endpoint until fully ready.</p><h4 id="scaling-in"><strong>Scaling in</strong></h4><p>This is actually a bit tricky. If we have 3 reader instances, and we decide to terminate one of them, the DNS round-robin will propagate with a certain delay, resulting in traffic being delivered to a dead database instance during a certain period of time.</p><p>Due to that, we decided to use an additional DNS record in <code>Route53</code>. This DNS record is the hostname applications normally connect to. It normally points to the cluster reader endpoint, except during a scale-in operation. In that case, we temporarily point it to a specific database reader instance, while others are being deleted.</p><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2020/05/scale_in.jpg" class="kg-image"></figure><p>In this way we have exact control over the node where the read traffic is routed to, instead of relying on DNS propagation.</p><h3 id="vertical-scaling-of-the-writer-node"><strong>Vertical scaling of the writer node</strong></h3><p>Since Amazon Aurora is not multi-master, if we need more write capacity, we need to change the writer instance type. This means that we need to create a new Aurora instance with a higher capacity and then promote it to the writer role.</p><h4 id="scaling-up"><strong>Scaling up</strong></h4><p>To have more control over the scale-up process, we usually create a new node with more capacity (let's name it <em>new_master</em>). It will be given the <strong>tier 0</strong> which means it'll be the first candidate for promotion to the writer role. As explained in the scale-out section, this process takes ~7 minutes with our main database.</p><p>After that, we perform a manual failover on the cluster, which will promote <em>new_master</em> to writer. Due to DNS propagation delay, you may see some errors during a 10-15 second window (but your application is resilient to these errors, isn't it? :p)</p><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2020/05/sentry.jpg" class="kg-image"></figure><h3 id="scaling-down"><strong>Scaling down</strong></h3><p>This process is the inverse of scaling up. We only modify our <em>old_master</em> instance to have tier 0, and perform the cluster failover. Again, it's possible to see some errors during a 10-15 second window.</p><h2 id="final-conclusions"><strong>Final conclusions</strong></h2><p>Amazon Aurora clusters are managed with CNAME records which point to database instances. It is important to understand how they work to be able to minimize the impact of failover operations.</p><p>Having an additional Route53 record gives us more control during the scale-in operation, and it doesn't make the architecture more complex.</p><p>We're currently performing these processes manually, which means we're still not 100% satisfied with the solution. We have some ideas, but if you have any suggestions, feel free to leave a comment! Also, if you happen to be interested in this sort of scalability and reliability topics, keep in mind that we're hiring :-)</p>ticketeaAWSRDSUIActivityViewController workaround to 'Share in WhatsApp' in iOShttps://jorge.maroto.me/uiactivityviewcontroller-workaround-to-share-in-whatsapp-in-ios/https://jorge.maroto.me/uiactivityviewcontroller-workaround-to-share-in-whatsapp-in-ios/Workaround to be able to use 'Share in WhatsApp' in iOSThu, 19 May 2016 19:06:00 GMT<p><code>UIActivityViewController</code> was introduced in <strong>iOS 6</strong> as a helper to share texts, links or images between apps.</p><p>It's really easy to work with the default services (share on Twitter, Facebook, Mail…), and for several iOS versions now it has also been integrated with third-party apps like Slack or Telegram.</p><p>Using it is simple: you only need to create and present a <code>UIActivityViewController</code> as follows:</p><pre><code class="language-objc">UIViewController *root = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
UIActivityViewController *activityView = [[UIActivityViewControllerWithoutWhatsApp alloc] initWithActivityItems:shareObject applicationActivities:nil];
[root presentViewController:activityView animated:YES completion:nil];
</code></pre><p>A typical setup looks like that, but sometimes you don't want to allow sending SMS or emails from your action, so you can set an array of <code>excludedActivityTypes</code> as follows:</p><pre><code class="language-objc">activityView.excludedActivityTypes = @[UIActivityTypeMessage, UIActivityTypeMail];</code></pre><p>There are several built-in activities, but you can craft your own <code>UIActivity</code> to do specific actions; a good compilation is available in <a href="https://github.com/shu223/UIActivityCollection">Github/UIActivityCollection</a>.</p><p>In our case, because we ran into <a href="http://stackoverflow.com/a/36856840">a bug related to the latest WhatsApp version</a>, which showed this message when trying to share with one of your WhatsApp contacts:</p><blockquote>This item cannot be shared. Please select a different item.</blockquote><p>We decided to workaround it using <code>URLSchemes</code>, and we found <a href="https://github.com/sascha/SSCWhatsAppActivity"><code>SSCWhatsAppActivity</code></a>, a <code>UIActivity</code> subclass which shows an icon on share menu, but it appeared next to the original WhatsApp icon, so we needed to remove the latter first.</p><p>Logically, we looked for the WhatsApp activity identifier and added it to the excludedActivityTypes array as follows:</p><pre><code class="language-objc">activityView.excludedActivityTypes = @[@"net.whatsapp.WhatsApp.ShareExtension"];</code></pre><p>But <strong>it’s not possible to remove third-party activities from the menu</strong>, at least not directly. So, after playing for a few minutes with <code><objc/runtime.h></code>, we finally found a private method that seemed related to our purpose: <code>_shouldExcludeActivityType</code>:</p><pre><code class="language-objc">#import "UIActivityViewControllerWithoutWhatsApp.h"
@interface UIActivityViewController (Private)
- (BOOL)_shouldExcludeActivityType:(UIActivity*)activity;
@end
@implementation UIActivityViewControllerWithoutWhatsApp
- (BOOL)_shouldExcludeActivityType:(UIActivity *)activity
{
if ([[activity activityType] isEqualToString:@"net.whatsapp.WhatsApp.ShareExtension"]) {
return YES;
}
return [super _shouldExcludeActivityType:activity];
}
@end</code></pre><p>And, you know what? It works! Thanks, Apple, for making it so straightforward.</p>iOS2013 Retrospective. My 5 Pros & Conshttps://jorge.maroto.me/2013-retrospective-my-5-pros-cons/https://jorge.maroto.me/2013-retrospective-my-5-pros-cons/Some reflections about this year 2013.Tue, 31 Dec 2013 21:54:00 GMT<p>Just one hour left in 2013, and I would like to do a small retrospective about what 2013 was for me. I really hate this kind of post, because they're egocentric, but I'm really doing it for myself (that's what self-centered means, isn’t it?). Here are my 5 pros & cons of the year.</p>
<h2 id="well-done">Well done!</h2>
<ul>
<li>After too long without writing on <a href="https://blog.patoroco.net/">my old-blog</a>, I decided to start <a href="https://jorge.maroto.me/why-octopress/">this blog</a> and try to write in English (sorry for my English mistakes, I need to practice :)).</li>
<li>This was the year I read the most in my life. I could start talking about which books I read this year, but <a href="https://web.archive.org/web/20140328062034/https://readmill.com/patoroco"><del>my Readmill account</del></a> explains that better :)</li>
<li>I also took an active part in the community: first at <a href="https://jorge.maroto.me/pucela-testing-days-testing-ios-applications/">‘local’ meetings</a>, but this year <a href="https://jorge.maroto.me/codemotion-2013-introduction-to-cocoa-pods/">I gave a talk at Codemotion</a>, a very important conference for me. I also helped <a href="https://jorge.maroto.me/nsspain-2013/">as a volunteer at NSSpain</a>, the best event I've attended.</li>
<li>I started to learn new programming languages (Ruby mainly, but I had my first contact with Node.js too), leaving my comfort zone so far (PHP & Obj-C).</li>
<li>I discovered new sports: snowboard & surf. Thanks to my friends for pushing me to do it!</li>
</ul>
<h2 id="bad">Bad!</h2>
<ul>
<li>This year I traveled very little. In other years I visited several countries, but this year I was very busy with work, so this is one of my 2014 resolutions.</li>
<li>Pocket is a really good tool if you know how to use it. That's not my case: I currently have almost 2000 articles waiting to be read. I’m thinking about removing all of them and starting from scratch. Really, if I haven't read them by now, what would change?</li>
<li>I started going to the gym and I quit. I started running regularly and I quit once more. I need to be more consistent with exercise (I say it again).</li>
<li>I need to improve my English. I read more and watch more English TV series & films, but my level is still low.</li>
<li>I have to spend more time with the people who really matter. Until now, work was my excuse, but one month ago <a href="https://jorge.maroto.me/im-ticketero/">I joined ticketea</a>, so I hope to have more time for people (sorry guys).</li>
</ul>
<p>Maybe at the end of 2014 I’ll be able to look back at these resolutions and smile :)</p>workconferencesI'm ticketerohttps://jorge.maroto.me/im-ticketero/https://jorge.maroto.me/im-ticketero/I've started to work for ticketea, a Spanish ticketing company.Mon, 02 Dec 2013 21:12:00 GMT<p>I’m very proud to announce that as of today I've joined the ticketea team (a ticketing company based in Spain) as an iOS developer.</p>
<p>For the last two years I was split between management, dealing with customers, and finally development tasks, so I wanted to focus on my real passion: development.</p>
<figure class="kg-card kg-embed-card"><blockquote class="twitter-tweet" data-lang="en"><p lang="es" dir="ltr">Primer día ^^ (at <a href="https://twitter.com/ticketea?ref_src=twsrc%5Etfw">@Ticketea</a>) [pic]: <a href="https://t.co/wxx5zkKIOY">http://t.co/wxx5zkKIOY</a> <a href="https://t.co/pOfopJAa4G">pic.twitter.com/pOfopJAa4G</a></p>— Jorge Maroto (@patoroco) <a href="https://twitter.com/patoroco/status/407513770177888256?ref_src=twsrc%5Etfw">December 2, 2013</a></blockquote></figure>
<p>These days have been very intense, but I’m really happy with my new workmates :)</p>
<p>Thank you all for <a href="https://twitter.com/patoroco/status/407513770177888256">the congratulations</a> & <a href="https://twitter.com/patoroco/status/407513560328458240">two</a>.</p>ticketeaworkPucela Testing Days. Testing iOS Applicationshttps://jorge.maroto.me/pucela-testing-days-testing-ios-applications/https://jorge.maroto.me/pucela-testing-days-testing-ios-applications/Talk in Cylicon Valley about iOS applications testing.Sat, 30 Nov 2013 20:12:00 GMT<p>As some of you know, I usually attend <a href="https://cyliconvalley.es/">Cylicon Valley</a>, a developer community at Castilla y León.</p><p>This month, we organized a series of talks about testing called <em>Pucela Testing Days</em> (<a href="https://web.archive.org/web/20170701180811/http://agilecyl.org/2013/11/27/pucelatestingdays-testing-en-ios-y-testing-en-android/">webarchive</a>), so I took part with a talk about the state of the art of iOS testing.</p><p>Here is the video (sorry about the quality, I recorded it myself, so please focus on the audio and check the slides).</p><figure class="kg-card kg-embed-card"><iframe width="459" height="344" src="https://www.youtube.com/embed/6ruv6vMUTtE?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></figure><figure class="kg-card kg-embed-card"><iframe id="talk_frame_78800" src="https://speakerdeck.com/player/44cbde103ce101318fc01afd74a057dc" width="1280" height="960" style="border:0; padding:0; margin:0; background:transparent;" frameborder="0" allowtransparency="true" allowfullscreen="allowfullscreen" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
</figure>talksiOStestingCylicon ValleyCodemotion 2013. Introduction to Cocoa Podshttps://jorge.maroto.me/codemotion-2013-introduction-to-cocoa-pods/https://jorge.maroto.me/codemotion-2013-introduction-to-cocoa-pods/Comments after my talk in Codemotion Madrid 2013 about Cocoa Pods.Sun, 20 Oct 2013 08:38:00 GMT<p>As <a href="https://jorge.maroto.me/codemotion-2013/">I announced some weeks ago</a>, I was at Codemotion talking about CocoaPods. If you want to start using this useful Ruby gem, check out my slides (Spanish)!</p><figure class="kg-card kg-embed-card"><iframe id="talk_frame_78804" src="https://speakerdeck.com/player/3b3986b03ce20131a8d62e270ad3f858" width="1280" height="960" style="border:0; padding:0; margin:0; background:transparent;" frameborder="0" allowtransparency="true" allowfullscreen="allowfullscreen" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
</figure>conferencescodemotioniOStalksCocoaPodsNSSpain 2013https://jorge.maroto.me/nsspain-2013/https://jorge.maroto.me/nsspain-2013/Reflexions about my participation in NSSpain 2013 as volunteer. See you next year!Fri, 20 Sep 2013 10:01:00 GMT<p>A few months ago I first read on Twitter about 'the first iOS dev conference' in Spain. At first it seemed like <em>another</em> conference with some popular Spanish developers talking about common topics, but when the organizers started to announce who was coming, I realized that it would not be a typical meetup.</p><p>The first surprising thing was that ALL the talks would be in English, because many of the speakers would be <em>international celebrities</em>, so the event would be followed around the world.</p><p>The second interesting thing for me was that it would be a four-day event, something very different from the events I usually attend, so with that much time it's possible to talk freely with the speakers and enjoy Logroño’s nightlife during its patron saint’s festival. That was the third reason to finally contact Borja & Luis (the organizers) about the possibility of volunteering, and the result is below (thanks for the photo <a href="https://twitter.com/juanriaza/status/384701058926514176/photo/1">@juanriaza</a>) ;)</p><p>Being a volunteer allowed me to be in contact with everyone, and I enjoyed it because I also attended many talks by VERY smart people such as <a href="https://twitter.com/orta">@orta</a> & <a href="https://twitter.com/fabiopelosin">@fabiopelosin</a> talking about our loved CocoaPods, <a href="https://twitter.com/nachosoto">@NachoSoto</a> explaining how to improve our Core Animation work with a quick review of different ways to do it, or <a href="https://twitter.com/steipete">@steipete</a>, whose talk I could not attend, but where people’s heads exploded trying to understand how the Obj-C runtime works.</p><p>If you want, I started a compilation with some of the slides from this NSSpain, which is available in my gist <a href="https://github.com/NSSpain/NSSpain-Summaries/blob/master/2013.md">NSSpain-Summaries</a>. I can only recommend that you attend next year, and see you there :).</p>iOSNSSpainconferencesCodemotion 2013https://jorge.maroto.me/codemotion-2013/https://jorge.maroto.me/codemotion-2013/Some comments about Codemotion 2013 in MadridFri, 13 Sep 2013 08:01:00 GMT<p><strong>Codemotion</strong> is an event to meet developers from different technologies and places, and it takes place in several countries (see them all at <a href="https://www.codemotionworld.com/">Codemotion World</a>).</p><p>Last year was the first edition in Spain, and I was there as an attendee, even recording some videos about <a href="https://vimeo.com/39783731">storyboard in Xcode</a> or <a href="https://vimeo.com/39267868">how to monetize apps</a>. I also saw some talks about Cocos 2D or development for Kinect, but unfortunately my iPhone's battery didn't last as long as I wanted...</p><p>This year I decided to submit a talk when they opened the call for papers, and it has been included in the schedule!</p><p>If you want to learn a little bit <strong>about what CocoaPods is</strong>, I'll be happy if you attend the talk: <strong>19th October, 11:30 - 12:15 in track 6</strong> <a href="https://web.archive.org/web/20140407042609/http://codemotion.es/talk/19-october/26">webarchive::codemotion.es</a>.</p><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2020/05/image.png" class="kg-image"></figure><p>See you there! :)</p>talksCocoaPodsiOSGiving a little soulhttps://jorge.maroto.me/giving-a-little-soul/https://jorge.maroto.me/giving-a-little-soul/This post is about a book that I wrote to teach how AFNetworking works. It's available in EPUB and Kindle formats.Thu, 12 Sep 2013 17:17:00 GMT<p>I've finally put some order in the web version of <a href="https://afnbook.github.io/"><strong>AFNetworking book</strong></a>, with the help of Octopress + <a href="https://octopressthemes.com/">Octopress themes</a>, so from now on I hope to focus my work on improving the content of the book itself.</p>
<figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2013/20130912-cover.png" class="kg-image" alt="AFNBook"></figure>
<p>If you don't know what this is, I advise you to read the <a href="https://afnbook.github.io/0-disclaimer.html"><strong>disclaimer</strong></a> and don't forget you can collaborate through <a href="https://github.com/afnbook/AFNBook"><strong>github</strong></a> and download the book in <strong>.epub</strong> and <strong>.mobi</strong> for your favorite reader.</p>AFNetworkingObjective-CbooksEditing 404 page on Github pageshttps://jorge.maroto.me/editing-404-page-on-github-pages/https://jorge.maroto.me/editing-404-page-on-github-pages/By default Octopress doesn't include a 404 page, so on Github appear a default page. Here we go to configure one.Sun, 08 Sep 2013 09:52:00 GMT<p>By default Octopress doesn't include a 404 page, so on GitHub it's shown as follows:</p><figure class="kg-card kg-image-card"><img src="https://jorge.maroto.me/content/images/2013/20130908-404github.png" class="kg-image" alt="404 github"></figure><p>Usually, with a Rack server you need to modify the <code>config.ru</code> file to handle exceptions (this website explains this case), but in my case I can't manage the <em>server side</em>, so GitHub gives us another way: they use a 404.html file as the default 404 page, as you can read on <a href="https://help.github.com/articles/custom-404-pages">their documentation</a>.</p><p>In summary, you need to create a new file at the path <code>sources/404.html</code> and it will be used as 404. You can see what mine looks like in 404.html, and this is the code:</p><pre><code class="language-md">---
layout: default
---
<h1 style="text-align: center">Page not found</h1>
<p style="text-align:center">You can find other posts on <a href="https://jorge.maroto.me/archives">Archives</a> of this blog, or directly go to <a href="https://jorge.maroto.me/">the main page</a></p>
<img src="https://jorge.maroto.me/images/404.png" style="max-width: 100%; margin: 0 auto; display: block" />
<small style="display:block; float:right">Credits of the image: <a href="http://refinedmobile.com/404">refinedmobile.com</a></small>
</code></pre>blogoctopressgithubConfiguring Octopresshttps://jorge.maroto.me/some-configurations-that-i-did-to-my-octopress/https://jorge.maroto.me/some-configurations-that-i-did-to-my-octopress/Some configurations that I did to my octopress.Sat, 07 Sep 2013 19:15:00 GMT<p>In the last post I talked about <a href="https://jorge.maroto.me/deploying-octopress-on-github-with-your-domain/">how to deploy octopress on github with your custom domain</a>, but it needs a bit of configuration to be the way I like it. You can find more info about that in <a href="https://octopress.org/docs/configuring/">Octopress configuration</a>, but if you want to know which steps I followed, open the <code>_config.yml</code> file and modify these lines:</p><pre><code class="language-yaml">...
permalink: /:year/:month/:day/:title/
...
category_dir: categories
...
paginate: 5
pagination_dir: # It's blank because I don't want /blog before each link page
</code></pre><p>I found a post about SEO for Octopress websites which explains why and how to remove the redundant /blog prefix, so I followed it :).</p><p>After that, there is a section with 3rd party settings for different social networks and services. I think they are self-explanatory, so I'll just give a few tips:</p><ul><li><a href="https://ansonalex.com/google-plus/how-do-i-find-my-google-plus-user-id-google/">How do you find your G+ user id?</a></li><li>Octopress is a static blog, so if you want comments, you need to use something like Disqus. It's easy (and free!) to create an account, so visit <a href="https://disqus.com/">disqus website</a> and fill your id on <code>_config.yml</code>.</li></ul>octopressDeploying Octopress on github with your domainhttps://jorge.maroto.me/deploying-octopress-on-github-with-your-domain/https://jorge.maroto.me/deploying-octopress-on-github-with-your-domain/Quick summary about how to download and deploy an octopress blog on github.Sat, 07 Sep 2013 08:01:00 GMT<p>I started writing this post because I want a place to remember how to (quickly) install another Octopress, and I'm too lazy to read again all the documentation.</p><p>I followed steps explained on <a href="https://octopress.org/docs/setup/">Octopress documentation</a>, but mainly it consists of cloning the Octopress repo and installing the required gems:</p><pre><code class="language-bash">git clone git://github.com/imathis/octopress.git jorgemaroto.es
cd jorgemaroto.es
bundle install #</code></pre><p>After that, you need to create a repository on GitHub, as explained in their <a href="https://octopress.org/docs/deploying/github/">github guide</a>, you can choose between two options.<br>In my case I'm going to create a repo with my name (<code>patoroco.github.io</code>), so after that I can push all the content to the <strong>master branch</strong>. At this point, you can run the rake task, which works as a wizard to configure everything.</p><pre><code class="language-bash">rake setup_github_pages
rake install
</code></pre><p>By default it uses the classic theme, but I was looking for other options, and finally I decided to use <a href="https://github.com/amelandri/darkstripes"><strong>darkstripes</strong></a> theme, so if you want to try it, follow these steps:</p><pre><code class="language-bash">git clone git://github.com/amelandri/darkstripes.git .themes/darkstripes
rake install['darkstripes'] # again, this will ask you about overriding your current theme
</code></pre><p>At this point, you can run <code>rake preview</code> on your terminal, and your site will be available on http://localhost:4000.<br>OK, this is a good time to publish your blog and start sharing with your friends how cool you are, so first of all you need to create a new repo on your GitHub account with your username, in my case it was http://patoroco.github.io. This would be enough, but I want to use my own domain, so I created a file named <code>CNAME</code> inside source folder (that's <code>jorgemaroto.es/source/CNAME</code>), with the name of my domain:</p><pre><code class="language-text">jorgemaroto.es</code></pre><p>Obviously I needed to change my domain configuration, so I recommend that you check <a href="https://help.github.com/articles/setting-up-a-custom-domain-with-pages">Github Pages with custom domain</a> page, because they explain it better than I do :).</p><p>Finally, you need to edit some parameters in the <code>_config.yml</code> file as follows:</p><pre><code class="language-yaml">url: http://jorgemaroto.es
title: Jorge Maroto
subtitle: Trying to write a blog (again).
author: Jorge Maroto
simple_search: http://google.com/search
description: Here I'll try to write a blog somewhat more technical than in the past, and in English!</code></pre><p>After that, you can run <code>rake deploy</code>, and you can now access your website using the selected domain (it could take a few hours).</p><p>It's important to highlight that with <code>rake deploy</code>, you are only uploading static files to GitHub, so it's recommended to also push your source files (that is, Markdown files, Sass, etc.) uncompiled.<br>Octopress makes it very easy because you always work on a branch named <code>source</code>, and when you deploy to the <code>master</code> branch, it does that automatically, so at this point you only need to push your source branch:</p><pre><code class="language-bash">git push origin source</code></pre><p>In the next post, I'll explain the configuration I did to customize the title, social networks, and more.</p>octopressgithubWhy Octopress?https://jorge.maroto.me/why-octopress/https://jorge.maroto.me/why-octopress/Here I am, trying to write a blog again. This time I hope to be more constant...Fri, 06 Sep 2013 20:01:00 GMT<p>Here I am, trying to write a blog again. This time I hope to be more consistent than <a href="https://blog.patoroco.net/">last time</a>, and I'm also trying to write in English (sorry for any spelling errors), so this is a big challenge for me.</p><p>Ok, and... why <a href="https://octopress.org/">Octopress</a>? My answer is 'why not?'. I've used WordPress for several years, both for personal projects and for work, and I really like it and PHP, but it was time to try other things, and I decided to start to play with Ruby, so let's say that this is a mix of all these things.</p><p>I would like to list some of the things that made me choose Octopress:</p><ul><li>My blog died. Really not, but I've gone almost two years without updating it, so I started to think about a change.</li><li>I want to <strong>practice and improve my English</strong>, so I decided to create a new blog, mainly in English.</li><li><strong>I like markdown</strong>, it's easy to read and edit, it's multi-platform, and there are several apps to work with it (I use Mou, because it's simple and free) and plenty of documentation (<a href="https://daringfireball.net/projects/markdown/">Daring Fireball</a>, where Markdown was born).</li><li>It's a good reason to <strong>play with Ruby</strong>, even if I only edit some plugins, I'll be improving my Ruby skills.</li><li>Octopress comes from Jekyll, so it has many plugins that make every typical blogging task easy and a big <strong>community</strong>.</li><li>Finally... It's cool, and I feel like a hacker! Did you know that I can write this post on my iPhone in Markdown, share it via Dropbox and deploy it to GitHub easily? Furthermore, you can make a pull-request to improve/complete/fix any post. <strong>Kevin Mitnick would dream of this!</strong></li></ul><p>I hope to write several posts about how to install and configure Octopress, so stay tuned if you're interested.</p>octopress