18 Sep 2021, 10:23

server update
XXX lists XXX

God dammit ubuntu!

ubuntu

I have to start by admitting one thing: I use to hate servers. Every time I even had to open a remote connection, that would ruin my mood. Granted, I am a web developer, my work depends on it. But still…

All that is just to explain why I haven’t updated my ancient server for a few years

Ok, time to roll up my… well, I don’t really wear long sleeves… Anyway, I take a deep breath and try to upgrade it.

sudo do-release-upgrade

[Enter]

Reading cache

Checking package manager

Cannot upgrade 

An upgrade from 'zesty' to 'bionic' is not supported with this tool. 
=== Command terminated with exit status 1 (Sat Sep 18 16:30:40 2021) ===

sad

Ooops Apparently this upgrading tool doesn’t support my version anymore

I tried ducking around (yes, I use duck duck go), but none of the results was working for me

Got in contact with scaleway and they said: - ubuntu is only upgradeable for 2 major versions. Now you have to destroy your instance, and make a new one.

Dammit, now I will have a new instance with new price. My old instance was super cheap because it was that old.

Ok, it was my fault. I will not complain. lets go!

So I got my new instance and started working on it:

  1. Create my own user & secure it
  2. install and configure nginx and certbot
  3. install docker
  4. git clone my apps, run devops script
  5. spend days and days fixing…

… wait a minute …

it works! 😎

But wait, how is this working? 🤔

it took me months to set up the old server

Simple: Docker

You see, the old server I had to set up app by app

but when I got 2 more developers to work on my side project, I decided to have it all running on docker, so it would be easy to have it working for everyone

I was expecting it would be easier, but having it all working in minutes was unbelievable.

08 Sep 2021, 10:23

Certbot
XXX lists XXX

my certificate is expired and certbot

OMG

This gives me a message “your current client, does not support ACME v2 at all. You will need to migrate to a different one”, but there is nothing I can do to update my certbot.

So I did some googling around, and found nothing that helped me.

It is worth to note that this was in an old server with ubuntu 17.

Now there is one thing I can do: remove it and install it again!

step 1: removing

sudo apt remove certbot
...
certbot removed!

step 2: install it again

sudo apt install certbot
...
...
error!

Oh noes fuuuuuuuuuuuuuuuuuuu!!!!

ok, no panic. lets check the documentation.

sudo snap install --classic certbot

Well, I am not a fan of snap, usually try to keep as much as possible with flatpack, but let’s try

hey, it worked!

so I run

sudo systemctl stop nginx.service
sudo certbot renew
sudo systemctl start nginx.service

open the website and … bob is your uncle!

success

09 Aug 2021, 15:42

Bolero
XXX lists XXX

What do you think about blazor?

What about Elm?

What if Elm architecture was running in blazor, but in F#?

Well, that is what bolero is about.

Fsharp

Getting started

  1. Install dotnet if you haven’t already
  2. go to https://fsbolero.io/ and follow the 3 easy steps to have your app up and running
  3. Continue following this guide.

Understanding the Elm architecture

Bolero is based on the elm architecture.

this is divided in 3 items:

  • Model: it represents the current state of the app.
  • update: this function is the only way to change your model.
  • render: it is how your html will be rendered.

Well, there is also the init function, where you give the initial state of the application.

But that is it. Anything else is built on top of this 3 items.

Simple, no?

Elm architecture

Model

there is only one model, it is global (inside the component) and it contains every detail in the application. your working data, cached values, state of the dropdowns and popups… everything

Example:

type Model =
    {
				page: Page
				date: DateTime
				error: string option
				items: Item list
				others: Other list
				touchInfo: TouchInfo
    }

Update

Nothing can change in the model without being part of this method. It is a blessing and a curse. It is much easier to find out where something is being updated, but you end up with huge update methods. Then you can start passing the update to another function. This helps with the size, and it is ok if you are well organized. but it could also mess up your codebase.

let update message model =
    match message with
    | SetPage page -> { model with page = page }, Cmd.none
    | Error exn -> { model with error = Some exn.Message }, Cmd.none
    | ClearError -> { model with error = None }, Cmd.none
		...

View

The view is called on every update to the model. You can use functions to represent the html, and also include some logic to hide or display items based on the model.

Example:

let view model dispatch =
    div [attr.``class`` "columns"] [
        div[][text " x "]
        div[attr.``class`` "has-text-centered"][
            button[attr.classes ["button"; "is-small"]; on.click (fun _ -> dispatch PreviousDay)][text "<"]
            span[attr.classes ["dashboard-date"]][text (model.date.ToString("yyyy-MM-dd"))]
            button[attr.classes ["button"; "is-small"]; on.click (fun _ -> dispatch NextDay)][text ">"]
        ]

Understanding monads

Nah, just kidding I believe having this basics of functional programming everywhere is one of the reasons of why people never go deep into it. Nobody needs yet another “let me explain functional for dummies” If you are like me, you rather start a project and learn along with it.

aha moments

There are a few moments where I got stuck, but then it all make sense

Any update to the model is automatically reflected in the GUI

yes, you dont have to add any function

The ONLY way to update the GUI is by changing the model

That means anything you want to change must be in the model. Even state of your dropdown, popup, etc

You can use anything from C#

But please don’t overuse it. Try to keep consistent using F# types and functions.

I can modify the default functions

Just because the update function doesn’t have a parameter I want, it doesn’t mean it cannot have.

In this example I was stuck for 2 days trying to access the JavaScript runtime from the client side.

Then I found out I can pass my own update method with that parameter:

let update = update this.JSRuntime Program.mkProgram init update view

I can easily interop with javascript from bolero client

The interop will not only call functions passing integers/strings It will pass objects between javascript and bolero.

let LoadCheckins (js:IJSRuntime) (date:DateTime) = Cmd.OfJS.either js "FromStorage" [| "checkins_" + date.ToString("yyyy-MM-dd") |] CheckinsLoaded Error

12 Jun 2021, 17:50

Hugo blog engine
XXX lists XXX

After almost 10 years of blogging in blogger (with a very low frequency), I decided to self host my blog. So then I had to decide what to go with

Requirements:

  1. Markdown - I have been a web developer for more than 20 years. Because of that, my growing hatred towards WYSYWYG editors peaked while I was working in a custom CMS. In 2013 my company started using redmine (a markdown)

    I got used to markdown while using redmine at work. Since then, I have been using it for everything. Even tocobooks mas markdown as its text editor.

  2. self hosted - I dont want to have my content locked in someone else’s database

  3. no database - it is sad to see the effort the blog engines take to give you version control, when you could just keep your .md files in git. And that is on top of the main reason: you own your text files.

  4. low or no maintenance - I like ruby, but my experience with it is: server needs constant maintenance. Go on the other hand is a lot more stable, and lightweight. Dotnet would be ideal, as I already keep always up to date in my server.

  5. easy to modify - I started programming web apps in PHP in the early 2000’s. I understand why it is so popular for blogging. the fact that you can just include .php files anywhere gives a flexibility that is very dificult to match.

Considering all this points, Hugo seems like the obvious choice (in 2021).

  • markdown - check!

  • self hosted - check!

  • no database - check!

  • low or no maintenance - definitely check!

    hugo generates static html and you can host it anywhere

  • easy to modify - yes

    not as it would be with php, but hey, considering the other benefits, it is a no brainer.

My tips to get it up and running

- Hugo should not be installed in your server.

The installed version is for development and exporting the files. You will copy the generated static site to nginx, apache or something similar.

If you are impatient like me, you might rush into having it all running directly in the server (I even edited the first posts directly there), and then will be thinking: -Ok, I have it running in the server. How do I run as a service now?

- You should host your blog using a simple web server

Since it is just a static site, you can host it anywhere.

- Everything will hardcoded with the baseurl from your config file

It is obvious, but sometimes it take a bit too long to process it.

My theme was looking weird. At first I thought the theme was not working, but then I realised it was the baseUrl

- Keep your local dev environmnet in source control

Or at least your config and md files.

Just in case

Will I continue with this in the Future

Not sure.

So far it seems good.

It took some effort to move away from blogger, but now I have it as markdown files, so it could be easy to migrate again.

08 Mar 2018, 16:38

i18n - vanilla javascript
XXX lists XXX

I am getting tired of all this javascript frameworks.

Some years ago it was almost impossible to maintain a webapp compatible to all relevant browsers without some framework like jquery.

Now browsers have evolved enough to make it optional. And given the choice, I prefer the lightweight simpler approach of using vanilla js.

It is amazing how some simple features are usually done with plugins. One of them is translation. Ok, if you need more extensive support, it might be a good idea to use something but for the basics there is no need for anything more than a json file and one command

Example:

var i18n_en = {
	weekdays: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
  
	short_weekdays: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
	months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
}
var i18n_pt = {
	weekdays: ["Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado", "Domingo"],
	short_weekdays: ["Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"],
	months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"],
}

<button id="butLoginCancel" class="mdc-button translate">but_cancel</button>
for(var el of document.querySelectorAll(".translate")){

    if(i18n[el.innerText])

      el.innerHTML = i18n[el.innerText.toLowerCase()];

}

So here you have it, it will replace all the elements with the .translate class and a content matching your translation json

Ah, and to use the i18n, you just have to load that variable with the selected version:

var i18n = lang=="pt" ? i18n_pt : i18n_en

that is it for now

20 May 2017, 07:30

Tinkerboard
XXX lists XXX

Finally my Asus tinkerboard arrived.

Thinkerboard

Is it awesome? not sure yet…

Yes, it packs more power than raspberry pi, but it falls behind in so many things

The software is basically inexistent You get a standar linux and nothing more With no further ado, lets get it going.

step 1: ssh to it

	ssh linaro@your_ip
	

pwd: linaro

step 2: install go

	wget https://storage.googleapis.com/golang/go1.8.1.linux-armv6l.tar.gz
	tar -C /usr/local -xzf go1.8.1.linux-armv6l.tar.gz
	export PATH=$PATH:/usr/local/go/bin
	

… aaaaaaannnd I am out of space :'(

something is not right here, I have a 32gb sd card, I run fdisk and check that indeed my partition is 29gb but somehow my /root is locked to 2gb

well, anyway, lost a day playing around with that, in the end formatted my sd card before loading the image and it works.

22 Apr 2015, 16:19

did I run my migrations?
XXX lists XXX

Today I had an error message driving me crazy:

 `method_missing': undefined method `export_format' for XXX model

You see, our model is a gem itself, because it is shared by several projects. When we have something in the schema that is not in the database, that is the error we get.

Now, I knew this error from previous executions, but my model was in synch with the DB.

I tried to comment out all my changes, without luck.

Until I realized. This error was in my specs.

I had run the rake db:migrate, but not RACK_ENG=test

In this situation I was happy I fixed the issue, but at the same time extremely angry I wasted 1h with that

Mental note: run both friggin migrations together in the future!

This might help:

alias migrate='rake db:migrate; rake db:migrate RAILS_ENV=test'

thanks to Eumir for this post

02 Oct 2014, 11:16

Go
XXX lists XXX

Go logo

C is fast, but boring, Ruby is slow, but fun. Go is right in between

Let’s start with the fun bits:

  • You don’t import just a file, you import a repository. Reading import “github.com/tiagodll/golib” is beautiful, that alone gets me excited about go.

  • Returning multiple values. Yes, finally! You can set resp, err := MyFunction()

  • Ditching the ;. I never got the reason for it, maybe it is because I learned programming with VB, but to me it just doesn’t make sense.

Now to the boring

  • The name. Seems like nothing, but having a language called go makes google searches useless unless you use golang.
  • Not having try/catch. It sucks. Although returning value, error makes up for it quite well.
  • Having any not used lib/variable as an error instead of warning. It is ok when you have a final version, but that is really annoying while development phase. And the worst of all:
  • the insane amount of extra lines to assign a variable such as
    temp := MyType{id:123}
    GetValueFromMongo(&temp)
    Printf("%v", temp)
    Instead of a simple
    puts get_value_from_mongo(123).to_s

and the grey area

  • Not having classes. I like the idea of having all static methods (unless it is really about the object they are in), but not having classes could have some issues, specially because of inheritance.

Regardless, this is my current language of choice. But this is just the beginning. Let’s see next what go is all about.

10 Aug 2014, 17:06

Dart + start + polymer = ?
XXX lists XXX

So as I said in my Dart, what do we think about it? post, it is an interesting language to look into. It is lacking good libraries, but a problem can also be seen as an opportunity: it is a great time build your own.

Back to the topic, because of the pub system it is very easy to have dart + start or dart + polymer, but not as easy to have both.

There is a teeny-tiny detail it took me a couple of days to realize, but let me save this to the end of the post.

Start is simple, lets begin with that. first, the pubspec

<code file="pubspec.yaml">
name: onemore
description: A sample Polymer application
dependencies:
  polymer: '>=0.11.0'
  start: any
transformers:
- polymer:
    entry_points: web/index.html
</code>

Then all you need to do is to import the package and create a server side dart file to start it. In this example I am only serving static files, it would be just as easy to handle dynamic content with the get(url).

<code file="app.dart">
import 'package:start/start.dart';

main(args) {
  start(port: 3000).then((Server app) { app.static('build/web', jail: false); });
}
</code>

Done, you have a web server running in http://localhost:3000 as soon as you run this code.

Now, the polymer part to have a custom element we need 3 files: the dart, the html and the hosting html file. this custom element expects a String list, and publish (sends to the client) both lst and plist.

<code file="elementlist.dart">
import 'package:polymer/polymer.dart';
import 'dart:convert';

@CustomTag('element-list')
class ElementsList extends PolymerElement {
  @published String list;
  @published List plist;

  ElementsList.created() : super.created(){
    try{
      plist = JSON.decode(list);
      plist.add({"id":"test"});
    }catch(e){
      print(e.toString());
    }
    polymerCreated();
  }
}
</code>

Here in the html we can use mustache style expressions

<code file="elementlist.html">
<link rel="import" href="packages/polymer/polymer.html">
<polymer-element name="element-list" attributes="list">
  <template>
    <div>the list: {{ list }}</div>
    <ul>
      <template repeat="{{elmt in plist}}">
        <li>{{elmt["id"]}}</li>
      </template>
      </ul>
  </template>
  <script type="application/dart" src="elementlist.dart"></script>
</polymer-element>
</code>

and then your index file you just have to add some references and include the custom element element-list.

<code file="index.html">
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sample app</title>
    <script src="packages/web_components/platform.js"></script>
    <script src="packages/web_components/dart_support.js"></script>
    <!-- import the click-counter -->
    <link rel="import" href="elementlist.html">
    <script type="application/dart">export 'package:polymer/init.dart';</script>
    <script src="packages/browser/dart.js"></script>
  </head>
  <body unresolved touch-action="auto">
    before list<br>
    ---------------------<br>
    <element-list id="the_list" list='[{"id":1},{"id":2},{"id":3}]'></element-list>
    ---------------------<br>
  </body>
</html>
</code>

Now, let me explain the little detail that made me lose so much time: start is just serving the folder specified above. The problem is that all the polymer javascript is generated in the build, and stored there. So our start must serve that folder instead. to do that, all we have to do is to change the web to build/web in the start method:

app.static('build/web', jail: false);

That is all folks, hope you enjoy it.

24 Jul 2014, 17:04

Dart, what do we think about it?
XXX lists XXX

yeah, about that…

Google’s attempt to improve on Javascript and get a server-side language at the same time. I have always wanted something else to thrive over javascript, and tried many good options like coffeescript or opal. Most of them are really good and easy to use as long as everything is correct. Sadly that is not what happens. The bug fixing is a vital phase of software development, and in this is the problem with all the languages that compile to javascript. Fixing the code is already hard enough as it is, imagine if you have to debug an auto-generated code in a language you possibly don’t master. For this reason I never adopted any of those for my development projects, and that is why dart quickly got my attention when they announced the dart VM embedded in chrome (ok, it is dartium, a branch of chromium but still counts).

Not just that, it is also a very flexible language where types are recommended but not enforced. syntax is a bit outdated, they opted for the java style to make developers feel comfortable. With languages like ruby and python getting more and more users everyday I am not sure it was the best decision. Although I have to agree, every developer feels familiar to a language with all the semi colons, curly brackets shenanigans that resembles java.

They have also done a good job in their package system, the pub. It feels just the same as using ruby gems.

Dart start is quite close to Sinatra, it is still lacking the template rendering, but it s a good start (pun unintended)

IDE. Ah, the IDE… why always Eclipse google? It is so bad, rebuilds workspace every other minute, hangs all the time. In fact, it hangs so much, my most used terminal command is “killall dart”. Seriously, why Eclipse again?

Overall it is good and I hope it works out. Being a google product, I believe it will be forced upon us like google+ anyway, so why not to make the best of it and enjoy all the benefits?