Skip to main content

a silhouette of a person's head and shoulders, used as a default avatar

Layan, cursores vistosos para tu plasma

Aunque el confinamiento ya no es la tónica general, seguimos estando muchas horas pendientes de nuestro ordenador, por lo que no es mala idea personalizarlo hasta que es visualmente perfecto para su gusto. Evidentemente, los cursores son parte de esa personalización y hoy toca hablar de un tema como Layan, un pack de cursores vistoso y perfecto para trabajar con nuestro escritorio Plasma de la Comunidad KDE.

Layan, cursores vistosos para tu plasma

Nacidos de la mano y de la mente de vinceliuice nos llega Layan, un tema cuidado y muy visual para nuestro entorno de trabajo.

Y es que con un diseño original y muy simpático nos convierte nuestro cursor en una especie de hoja ovada azulada con tres estilos: sin borde, con borde blanco y con solo borde coloreado.

Layan, cursores vistosos para tu plasma

Y como siempre digo, si os gusta este conjunto de cursores Coffee Cup podéis “pagarlo” de muchas formas en la página de KDE Store, que estoy seguro que el desarrollador lo agradecerá: puntúale positivamente, hazle un comentario en la página o realiza una donación. Ayudar al desarrollo del Software Libre también se hace simplemente dando las gracias, ayuda mucho más de lo que os podéis imaginar, recordad la campaña I love Free Software Day 2017 de la Free Software Foundation donde se nos recordaba esta forma tan sencilla de colaborar con el gran proyecto del Software Libre y que en el blog dedicamos un artículo.

Más información: KDE Store

Cómo cambiar el tema de los cursores en Plasma

Al igual que con los iconos hay varias formas de cambiar el tema de cursores en Plasma, pero la más fácil es:

  • Abrir las Preferencias del Sistema
  • Ir a la sección Tema de Cursor
  • En esta ventana pinchar en “Obtener nuevos temas”
  • Buscar Layan, seleccionar el estilo y dar a instalar.
  • Seleccionar el tema y aplicar.

Si tenéis dificultad, simplemente se debe descargar y extraer el tema en «/usr/share/icons» o «~/.icons».

Rápido, sencillo y efectivo, como la mayoría de cosas en en el escritorio Plasma de la Comunidad KDE.

the avatar of Robert Riemann

Orient: Life at Sea in the 21st Century

The Titanic could accommodate about 2500 passengers who booked either first, second or third class. Wikipedia tells that

those travelling in first class, most of them the wealthiest passengers on board, included prominent members of the upper class, businessmen, politicians, high-ranking military personnel, industrialists, bankers, entertainers, socialites, and professional athletes. Second-class passengers were predominantly middle-class travellers and included professors, authors, clergymen, and tourists. Third-class or steerage passengers were primarily immigrants moving to the United States and Canada.

Much has changed since then.

Life at Sea in the 21st Century

Purpose and passengers of such mega ships (rather kilo ships :wink:) have changed dramatically since then. The ship is no longer a mean of transport. Passengers from Central Europe fly 5000 km to the Orient for a cruise of 500 km to a nearby harbour and back to the point of departure. Many passengers are rather age group 50+ and have cruised around quite a lot already1. Then, there are few younger families and couples as well. Other single travellers fall rather into the category of widows2.

3rd-class cabin on the RMS Olympic, sister ship of the Titantic.

My ship features 1267 twin cabins for 2534 passengers, but if need be, can host up to 2700 passengers–the 1030 crew members excluded. The other ship in the habour, Costas Firenze, has 2116 cabins for up to 5078 passengers (two times the Titanic) and provides for a crew of about 1300 members.

Due to Covid-19, the ships are far from fully booked. In my case the occupation rate was about 40%, a bit more than 1000 people.

Life at sea on this German-operated ship is best compared to Club holidays in Germany3:

  • room service takes care of cabins twice per day
  • all inclusive all you can eat and drink
  • about 5 restaurants and several bars
  • Döner Kebab at the poolside :sweat_smile:
  • SPA area
  • fitness club with courses, volleyball court and running area
  • entertainment program in the lounge, the two theatres or on the open-air stage with shows that involve the dancers and acrobats belonging to the crew and guest artists (stand-up, magician)
  • casino (open when in international waters)
  • a few shops for shopping (VAT-free!)
  • kids club
  • organised day trips (bus, bike and boat tours, etc.)
  • mostly German-speaking crew
  • 99% German-speaking guests/passengers (I spotted two Dutch)
My cabin with balkony.

Consequently, a cruise on this ship is the perfect fit for all those who would like to hang out with Germans, have German bread and bread rolls for every meal, enjoy Sauerkraut, Klöße, Currywurst and Döner Kebab, but at the same time rather prefer a more Mediterranean climate than what Germany can typically offer! Kind of German holidays outside of Germany.

With 1000 German passengers on board, it is easy to make pictures of the scenic locations without people: At 8 PM, everyone is at dinner! Let me take you on a tour.

Pool area.

Pool area.

Running path (opening hours: 6 to 8 AM).

Running path (opening hours: 6 to 8 AM).

Salon area.

Salon area.

Salon area II.

Salon area II.

Salon area III.

Salon area III.

Midnight snackbar: burgers, Belgium fries, cakes, etc.

Midnight snackbar: burgers, Belgium fries, cakes, etc.

Theatre of the ship.

Theatre of the ship.

Sport court.

Sport court.

I have a few more impressions taken at daytime.

View from Deck 12 to the family pool area.

View from Deck 12 to the family pool area.

Spa area.

Spa area.

  1. I know because during some show on the deck, the moderator has asked the question who has been on a cruise before and many hands were raised. ↩︎

  2. There was a meetup of single travellers on the ship. However, I didn’t use the occasion to ask them whether they were really widowed. :see_no_evil: ↩︎

  3. Not that I have ever done club holidays in Germany–but that’s how I imagine it! ↩︎

a silhouette of a person's head and shoulders, used as a default avatar

Podcast 07×10 Resumen y final de temporada

Finalizamos la séptima temporada de video-audios de la Asociación KDE España. Así que me complace compartir con vosotros que ya está disponible el podcast 07×10 Resumen y final de temporada que ha contado con la producción de David Marzal, un interesante programa que sirve tanto como recordatorio como revisión de todo lo que hemos hablado a lo largo de más de un año.

Podcast 07×10 Resumen y final de temporada

Bienvenidos a un nuevo episodio de los podcast de KDE España, el
décimo y último de esta séptima temporada y que, como es tradición, es una resumen de la misma.

En esta ocasión tenemos a David Marzal como productor, uno de los podcasters más prolíficos y eficientes que conozco, miembro de KDE España y de Residuo Cero Región de Murcia.

Y, para variar, los entrevistados fueron:

  • Rubén Gómez: miembro de KDE España, de HackLab Almería y de Document Foundation en la labor de presentador.
  • Baltasar Ortega (un servidor): editor de KDE Blog, secretario de KDE España, miembro de GNU/Linux València y de KDE e.V.

De esta forma, a lo largo de la hora y veinte minutos que duró el podcast revisamos todos los episodios de la séptima temporada y comentamos el estado actual de algunos de esos proyectos de Software Libre, haciendo hincapié en lo más importante de ellos: las personas.

Los enlaces de interés del podcast son:

Aprovecho para poneros el enlace a la lista de los podcast de KDE España de Youtube, por si alguien quiere hacer una maratón y ver como evolucionamos a lo largo del tiempo.

Como siempre, esperamos vuestros comentarios que os aseguro que son muy valiosos para los desarrolladores, aunque sean críticas constructivas (las otras nunca son buenas para nadie). Así mismo, también nos gustaría saber los temas sobre los que gustaría que hablásemos en los próximos podcast.

Podcast 07x10 Resumen y final de temporada


the avatar of Zoltán Balogh

Playing with Shelly

For xmass I got few Shelly lamps to play with. Shelly lamps are simple IoT devices. Super easy to install, configure and use. The Youtube is full with instructions on what can be done with these smart lamps. Naturally my main motivation was to figure out how to hack these devices and how ready my openSUSE servers are with tools and services (spoiler: they are ready)

Look daddy no cloud

Needless to say that like most smart home automation devices the Shelly lamps can be operated via the Shelly cloud. I may cover that area in the next post. But now I am interested in what can be done without the cloud. After all, one big selling point of the Shelly devices is that they are fully operable and functional even without Internet connection just on a WiFi LAN. It means that if I am concerned about the security of my home infrastructure I have an option not to expose my smart devices.

the avatar of Nathan Wolf

Home Assistant for a Newbie

Getting started with Home Assistant, you are presented with lots of options and there is a plethora of opinions to steer you in the “right” direction. The problem I had is that I was paralyzed by the options and, as a consequence, set back my adoption of Home Assistant in my everyday life. In an […]

a silhouette of a person's head and shoulders, used as a default avatar

Navegador Lagrange para Gemini ahora disponible para Android

Ya hay disponible una APK para Android del navegador Lagrange para protocolo Gemini, aunque en una versión Alfa muy temprana de desarrollo

Jaakko Keränen, el desarrollador del navegador Lagrange, para protocolos Gemini, hace un tiempo estaba tratando de portar el código para estar disponible para Android y arquitecturas ARM.

Ya ha anunciado que se ha publicado una primera versión Alfa de la aplicación APK solo para arquitecturas ARM de32 bits.

En el anuncio, nos deja claro que es una muy primera versión de desarrollo, por lo que tengamos en cuenta que pueden faltar de implementar nuevas funcionalidades, algunas pueden no funcionar como se espera y otras simplemente harán que «crashee» la aplicación.

Otros fallos con los que cabe contar, es que solo funciona en orientación vertical, no tiene integración con el sistema operativo y algunos otros problemas, pero quería publicar una primera versión de trabajo para ver cómo se desenvolvía y para que hubiera gente que la probara.

También advierte que esta primera versión es una prueba a sí mismo, para ver si puede crear una APK que se pueda instalar, ya que no es usuario ni desarrollador de Android.

El desarrollo lo ha realizado mediante Android Studio en un sistema Xubuntu y después de lidiar con alguna contrariedad pudo hacer funcionar el entorno para desarrollar Lagrange para Android.

Estos son algunos de los errores encontrados que tiene esta APK y que pronto se irán puliendo:

  • Fallo al crear un marcador por primera vez
  • Bloqueo al abrir una imagen
  • Fallo al actualizar los feeds suscritor
  • Fallo al ver la página de prueba de Emoji
  • Crash al abrir la configuración
  • Los enlaces web no se abren (necesitan un SDL más reciente)

Aunque todavía, como admite su desarrollador, la versión está en fase inicial de desarrollo, es bueno ver que una versión para Android está disponible, lo que ayudará a difundir y extender y utilizar más el protocolo Gemini.

Te dejo un enlace al anuncio oficial en su blog desde donde podrás descargar la APK y si quieres instalarla en tu teléfono y reportar fallos que encuentres.

Enlaces de interés

the avatar of Robert Riemann

Jekyll: Import Disqus comments for Staticman

For some years already, I try to rely for this website on less external resources and avoid ad-powered services to improve the privacy for my dear readers.

Recently, I removed the comments provided by Disqus from this blog, because Disqus introduced too much data sharing with many third parties. Norway just fined this year Disqus 2,5 Mio Euro for tracking without legal basis.

Please find hereafter some tips on how to export comments from Disqus and display them in a privacy-friendly way in your Jekyll blog.

Export Disqus Comments to JSON and YAML

  1. Disqus documents the export and export format at https://docs.disqus.com/developers/export/
  2. Navigate to http://disqus.com/admin/discussions/export/ to export your comments to XML format.

    The XML has principally 3 parts: meta data, a list with webpages and a list with comments that are linked each to a webpage (via a Disqus identifier) and possibly a parent comment in case the comment is a reply.

    For use within Jekyll, I need to restructure the data and have a list of comments for each webpage by my own identifier (e.g. post slug) and convert everything to a format that Jekyll can handle, hence YAML, JSON, CSV, or TSV. I choose YAML.

  3. Install the linux tool xq to manipulate XML files and export to JSON and the tool jq. xq is basically a wrapper of jq.

    pip install xq
    

    Download binaries of jq here: https://stedolan.github.io/jq/download/

  4. I convert then the Disqus XML export into a JSON file with the code in export-disqus-xml2json.sh

  5. Then, I pipe the output through import-json-yaml.rb to split the list of comments into individual files for easy consumption by Jekyll.
# file: 'export-disqus-xml2json.sh'

#!/usr/bin/env sh

xq '.disqus | .thread as $threads | .post | map(select(.isDeleted == "false")) | map(.thread."@dsq:id" as $id | ($threads[] | select(."@dsq:id" == $id)) as $thread | {id: ("disqus-"+."@dsq:id"), date: .createdAt, slug: ($thread.id | tostring | gsub("/$";"") | split("/") | last), name: (if .author.name == "Robert" then "Robert Riemann" else .author.name end), avatar: .author | (if has("username") and .username != "rriemann" then "https://disqus.com/api/users/avatars/"+.username+".jpg" else null end), email: .author | (if has("username") and .username == "rriemann" then "my@mail.com" else null end), message, origin: ($thread.link | tostring | gsub("^https://blog.riemann.cc";"")), replying_to: (if has("parent") then ("disqus-"+.parent."@dsq:id") else null end)})' "$@"

Example comment from the JSON list:

{
  "id": "disqus-4145062197",
  "date": "2018-10-14T22:14:58Z",
  "slug": "versioning-of-openoffice-libreoffice-documents-using-git",
  "name": "Robert Riemann",
  "avatar": null,
  "email": "my@mail.com",
  "message": "<p>I agree, it is not perfect. I have no solution how to keep the noise out of git.</p>",
  "origin": "/2013/04/23/versioning-of-openoffice-libreoffice-documents-using-git/",
  "replying_to": "disqus-4136593561"
}

The script import-json-yaml.rb takes each comment and puts it in YAML format with a unique filenname in the folder named after the slug.

# file: 'import-json-yaml.rb'
#!/usr/bin/env ruby

require 'json'
require 'yaml'
require 'fileutils'
require 'date'

data = if ARGV.length > 0 then
  JSON.load_file(ARGV[0])
else
  JSON.parse(ARGF.read)
end

data.each do |comment|
  FileUtils.mkdir_p comment['slug']
  File.write "#{comment['slug']}/#{comment['id']}-#{Date.parse(comment['date']).strftime('%s')}.yml", comment.to_yaml
end

The output with tree looks like:

_data
├── comments
│   ├── announcing-kubeplayer
│   │   ├── disqus-113988522-1292630400.yml
│   │   └── disqus-1858985256-1424044800.yml
│   ├── requires-owncloud-serverside-backend
│   │   ├── disqus-41270666-1269302400.yml
│   │   ├── disqus-41273219-1269302400.yml
...

Display Comments in Jekyll

Those comments are accessible in jekyll posts/pages via site.data.comments[page.slug]

Most helpful for the integration of comments to Jekyll was the post https://mademistakes.com/mastering-jekyll/static-comments-improved/.

<!-- file: 'my-comments.html' -->
{% assign comments = site.data.comments[page.slug] | sort %}
{% for comment in comments %}
  {% assign index       = forloop.index %}
  {% assign replying_to = comment[1].replying_to | to_integer %}
  {% assign avatar      = comment[1].avatar %}
  {% assign email       = comment[1].email %}
  {% assign name        = comment[1].name %}
  {% assign url         = comment[1].url %}
  {% assign date        = comment[1].date %}
  {% assign message     = comment[1].message %}
  {% include comment index=index replying_to=replying_to avatar=avatar email=email name=name url=url date=date message=message %}
{% endfor %}
<!-- file: 'comment' -->
<article id="comment{% unless include.r %}{{ index | prepend: '-' }}{% else %}{{ include.index | prepend: '-' }}{% endunless %}" class="js-comment comment {% if include.name == site.author.name %}admin{% endif %} {% unless include.replying_to == 0 %}child{% endunless %}">
  <div class="comment__avatar">
    {% if include.avatar %}
      <img src="{{ include.avatar }}" alt="{{ include.name | escape }}">
    {% elsif include.email %}
      <img src="https://www.gravatar.com/avatar/{{ include.email | md5 }}?d=mm&s=60" srcset="https://www.gravatar.com/avatar/{{ include.email | md5 }}?d=mm&s=120 2x" alt="{{ include.name | escape }}">
    {% else %}
      <img src="/assets/img/avatar-60.jpg" srcset="/assets/img/avatar-120.jpg 2x" alt="{{ include.name | escape }}">
    {% endif %}
  </div>
  <div class="comment__inner">
    <header>
      <p>
        <span class="comment__author-name">
          {% unless include.url == blank %}
            <a rel="external nofollow" href="{{ include.url }}">
              {{ include.name }}
            </a>
          {% else %}
            {{ include.name }}
          {% endunless %}
        </span>
        wrote on
        <span class="comment__timestamp">
          {% if include.date %}
            {% if include.index %}<a href="#comment{% if r %}{{ index | prepend: '-' }}{% else %}{{ include.index | prepend: '-' }}{% endif %}" title="link to this comment">{% endif %}
            <time datetime="{{ include.date | date_to_xmlschema }}">{{ include.date | date: '%B %d, %Y' }}</time>
            {% if include.index %}</a>{% endif %}
          {% endif %}
        </span>
      </p>
    </header>
    <div class="comment__content">
      {{ include.message | markdownify }}
    </div>
  </div>
</article>

Receiving New Comments

Like explained in https://mademistakes.com/mastering-jekyll/static-comments/, the software https://staticman.net/ allows to feed POST HTTP requests to Github and Gitlab pull requests, so that comments can be added automatically. Of course, the website requires after each time a rebuild.

I had much trouble to setup Staticman. Eventually, I decided to use a Ruby CGI program that emails me the new comment as an attachment. I like Ruby very much. :wink: Once I figured out how to use the Gitlab API wrapper, I may also use pull requests instead of email attachments.

# file: 'index.rb'
#!/usr/bin/env ruby

Gem.paths = { 'GEM_PATH' => '/var/www/virtual/rriemann/gem' }

require 'cgi'
require 'yaml'
require 'date'
require 'mail'

cgi = CGI.new

# rudimentary validation
unless ENV['HTTP_ORIGIN'] == 'https://blog.riemann.cc' and
       ENV['CONTENT_TYPE'] == 'application/x-www-form-urlencoded' and
       ENV['REQUEST_METHOD'] == 'POST' and
       cgi.params['email']&.first&.strip =~ URI::MailTo::EMAIL_REGEXP and
       cgi.params['age']&.first == '' then # age is a bot honeypot
  print cgi.http_header("status" => "FORBIDDEN")
  print "<p>Error: 403 Forbidden</p>"
  exit
end

output = Hash.new
date = DateTime.now

output['id'] = ENV['UNIQUE_ID']
output['date'] = date.iso8601
output['updated'] = date.iso8601
output['origin'] = cgi.params['origin']&.first
output['slug'] = cgi.params['slug']&.first&.gsub(/[^\w-]/, '') # some sanitizing

output['name'] = cgi.params['name']&.first
output['email'] = cgi.params['email']&.first&.downcase&.strip
output['url'] = cgi.params['url']&.first
output['message'] = cgi.params['message']&.join("\n").encode(universal_newline: true)

output['replying_to'] = cgi.params['replying_to']&.first

#Mail.defaults do
#  delivery_method :sendmail
#end

Mail.defaults do
  delivery_method :smtp, address: "smtp.domain", port: 587, user_name: "smtp_user", password: "smtp_password", enable_starttls_auto: true
end

mail = Mail.new do
  from    'no-reply@domain' # 'rriemann'
  to      'comments-recipient@domain'  # ENV['SERVER_ADMIN']
  reply_to output['email']
  header['X-Blog-Comment'] = output['slug']

  subject "New Comment from #{output['name']} for #{cgi.params['title']&.first}"
  body    <<~BODY
    Hi blog author,

    a new comment from #{output['name']} for https://blog.riemann.cc#{output['origin']}:

    #{output['message']}
  BODY
  add_file(filename: "#{output['id']}-#{date.strftime('%s')}.yml", content: output.to_yaml)
end

mail.deliver

if mail.error_status then
  print cgi.http_header("status" => "SERVER_ERROR")
  cgi.print <<~RESPONSE
    <p><b>Error: </b> #{mail.error_status}</p>

    <p>An error occured. Please try again later.</p>
    <p><a href="javascript:history.back()">Go back</a></p>
  RESPONSE
else
  print cgi.http_header
  cgi.print <<~RESPONSE
    <p><b>Thank you</b> for your fedback! Your comment is published after review.</p>
    <p><a href="#{output['origin']}">Back to the previous page</a></p>
  RESPONSE
end

To make it work with Apache, you may need to add these lines to the Apache configuration (could be a .htaccess file):

DirectoryIndex index.html index.rb
Options +ExecCGI
SetHandler cgi-script
AddHandler cgi-script .rb
a silhouette of a person's head and shoulders, used as a default avatar

Foto de grupo de Akademy-es 2021 #akademyes

No hay evento que se precie que no tenga su correspondiente imagen para la posteridad, y los eventos virtuales no son una excepción. Bienvenidos a una breve pero significativa entrada en la que os presento la foto de grupo de Akademy-es 2021 que se ha tomado, evidentemente, utilizando las limitaciones del espacio que nos ofrecen las ventanas de webconferencia.

Foto de grupo de Akademy-es 2021 #akademyes

Antes, cuando las Akademy-es eran virtuales, era una tradición (que se inició en Almería 2017 y que continuó en Valencia 2018 y siguió en Vigo 2019) que el mismo día de la realización de la misma yo publicara la ansiada foto de grupo.

Este año ha sido una excepción (por diversos motivos) y me ha costado un poco más ponerla ya que he de reconocer que ha sido un diciembre muy movido.

Esta captura de pantalla, que no en realidad foto de grupo, se ha realizado con solo los participantes que pusieron su webcam en el momento de tomar la instantánea y que el sistema permite mostrar en solo una pantalla.. Es por ello que en esta ocasión más que nunca se puede decir que son todos los que están pero no están todos los que son.

Pero, o me enrollo más y os dejo ya la foto de grupo de Akademy-es 2021 de Vigo, en la que no están todos los que son pero si que son todos los que están. Pinchad en la imagen para verlo más grande.

Foto de grupo de Akademy-es 2021 #akademyes

¿Qué es el Akademy-es?

Akademy-es es el encuentro anual de desarrolladores, colaboradores y usuarios de KDE en España, que se celebra desde el año 2006 en distintas ciudades del territorio español y con esta se llegará a la decimasexta edición, lo cual significa una cifra más que aceptable.

Os recuerdo que el registro y la asistencia a las Akademy-es es libre y gratuito, es decir, no te cuesta nada. Se hace únicamente para contar asistente y para organizar la tradicional cena del sábado (que esperamos que vuelva con fuerza).

Más información: KDE España

the avatar of Nathan Wolf

Pi-Hole the Easy Way

Setting up a Pi-Hole for your network is a beautifully simple process. This is a guide whose intent is to give you the confidence to try it yourself. If you are not new to the Raspberry Pi and have accomplished many things with it, this guide is likely a bit too basic. The goal of […]

the avatar of Alessandro de Oliveira Faria