Showing 20 most recent blog posts
Browse by tags or view all

How to build video games for Windows using Crystal

Crystal Programming Language does not yet support Windows, but there's an awesome work-in-progress fork that already allows compiling some Crystal programs and getting native Windows executables. None of that work is mine, I just rehashed their instructions and added good news that one can already make proper video games for Windows.

Note that, even though there are multiple mentions of Windows Subsystem for Linux here, it is used only for one of the build steps. The resulting binaries run natively on Windows, no strings attached.

Basic Crystal setup

You need a POSIX-compatible system that Crystal officially supports (like Linux) and also Windows. If you are already on Windows 10, the obvious choice is Bash on Ubuntu on Windows. If on a different OS, use a virtual machine with Windows — VirtualBox is a good choice.

Created (updated ) | Comment

Advanced uses of Travis CI with Nim

There have been a few guides describing the use of Circle CI, originating from here. But in my opinion Travis CI is a superior service, because it has more options and is more reliable.

Let's start with the minimal Travis configuration that allows you to test Nim projects.

 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.travis.ymllanguage: c
install:
  - |
    # Download the latest release of Nim into the "nim-master" folder
    git clone -b master --depth 1 git://github.com/nim-lang/nim nim-master/
    cd nim-master
    # Download the latest release of Nim's prepared C sources, for bootstrapping
    git clone -b master --depth 1 git://github.com/nim-lang/csources csources/
    cd csources
    # Build C sources
    sh build.sh
    cd ..
    # This concludes the first step of bootstrapping, don't need C sources anymore
    rm -rf csources
    # Use the executable built from C sources to compile the build tool
    bin/nim c koch
    # Compile Nim in release mode, using the Nim compiler we already have
    ./koch boot -d:release
    cd ..
before_script:
  # Add the 'bin' folder to PATH
  - export PATH="nim-master/bin:$PATH"
script:
  # Run 'tests/all.nim'. Feel free to change this, but it needs to be a program
  # that returns a non-zero status code in case of failure. The testing facilities
  # in Nim's standard library do this.
  - nim compile --verbosity:0 --run tests/all
Created | Comment

Use KWallet for any command, including SSH password

ksshaskpass is a KDE-based passphrase dialog for use with OpenSSH. It is intended to be called by the ssh-add(1) program and not invoked directly. It allows ssh-add(1) to obtain a passphrase from a user [...]

So this utility is useful if you want to store the passphrases to your SSH keys in the KDE Wallet (there are plenty of instructions on how to do that).

But all it really does is receive a string as an argument, tries to query KWallet for a password saved under this key string (or asks for this password in a dialog and stores it), then writes it to stdout. This means that ksshaskpass can be used to store any kind of password in KWallet for use in your Bash scripting.

We will be using Bash, ksshaskpass, sshpass.

Created | Comment

Zoom the screen with Alt+Scroll in KDE

Install xbindkeys, qdbus.

Enable KWin zoom effect. For best experience, lower the zoom multiplier.

Add this to .xbindkeysrc in your home folder (or create the file):

~/.xbindkeysrc"qdbus org.kde.kglobalaccel /component/kwin invokeShortcut view_zoom_in"
    alt + b:4
"qdbus org.kde.kglobalaccel /component/kwin invokeShortcut view_zoom_out"
    alt + b:5
Created | Comment

Detailed assert macro for Crystal

assert 2 + 2 == 5
#< 2 + 2 => 4 == 5 <= 5 (AssertionError)
assert "a,b,c".split == "a b c".split
#< "a,b,c".split => ["a,b,c"] == ["a", "b", "c"] <= "a b c".split (AssertionError)
assert [2, 4, 6].any? &.odd?
#< [2, 4, 6].any?(&.odd?) (AssertionError)
Created | Comment

Extract keys from Python's format strings

Sometimes in Python you may need to diagnose some format strings. Maybe they are supposed to be provided by the user and you need to know which keys to fill it with. Another prominent example is translation software: format string placeholders are definitely a thing there, and you may want to do something special about them.

First, let's get the old-style format strings out of the way. I haven't seen any introspection capabilities for them in the standard library, so instead this neat workaround can be used: a format string is formatted by a dict-like object, which really just stores every key that it gets asked for.

Created (updated ) | Comment

Intersection and difference of two rectangles

The problem of intersection of two rectangles is very easy to solve. But difference of two rectangles is something considered much less frequently.

To clarify, we will be looking only at rectangles that are parallel to the 2D axes.

Rectangle intersection cases

Obviously, when one rectangle chomps away a part of another, typically it can no longer be represented as just one rectangle. The illustration shows these different cases. The solution described here represents the difference as a sum of multiple rectangles. It does not try to represent it in as few rectangles as possible, because there are multiple ways to do that and no objective way to pick one.

Created (updated ) | Comment

Hide Flask-Admin behind simple HTTP auth

This example is about Flask-Admin, which is a library that adds a smart automatic CRUD panel according to your data models (typically SQLAlchemy models).

If you have a simple website or want to separate your normal user authentication system from the admin login, or just want a quick temporary solution for securing your admin panel, here is how you can do it using simple HTTP authentication:

Created (updated ) | Comment

Speed up login+startup on a machine with 1 user

If you are the sole user of your computer, you may want to just enable autologin without asking for password. But most often this is not an option. So when you turn on your computer, you wait for the login screen to appear, then enter the password, then wait for the auto-start programs to complete loading (or cope with the slowness).

Instead, you can have your system automatically log into your account and let the startup process take place, but also lock the screen, so the password still needs to be entered. The difference is, you can turn on your computer, then walk away somewhere, and be sure that it's 100% ready for work when you come back. Even without walking away, the time you take to enter your password is used for startup, so it's still quicker.

I realize that suspending may be an even better solution, but it's not always an option.

Created (updated ) | Comment

Decode a UTF-8 string that may be cut off

Let's say we got some bytestring through a socket, but it was cut off in the middle of a UTF-8 character.

We can simulate this:

bs = "приклад".encode('utf-8')[:-1]  # last byte was lost
print(bs)
#< b'\xd0\xbf\xd1\x80\xd0\xb8\xd0\xba\xd0\xbb\xd0\xb0\xd0'
bs.decode('utf-8')
# UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd0 in position 12: unexpected end of data

So, is this string completely undecodable? Can't we just get "прикла"?
Don't worry, I have a solution. Works with 3.x and 2.7!

1
2
3
4
5
6
7
8
import io
import codecs

bs = b'\xd0\xbf\xd1\x80\xd0\xb8\xd0\xba\xd0\xbb\xd0\xb0\xd0'
stream = io.BytesIO(bs)
stream_reader = codecs.getreader('utf-8')(stream)
print(stream_reader.read())
#< прикла
Created | Comment

Flask+SQLAlchemy with multiple dababases and shared models

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String

database_uris = ['sqlite:///a.sqlite', 'sqlite:///b.sqlite']

engines = [create_engine(uri, convert_unicode=True) for uri in database_uris]
scoped_sessions = [scoped_session(sessionmaker(engine)) for engine in engines]

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String(50), unique=True)
    email = Column(String(120), unique=True)
Created (updated ) | Comment

Sort-by, min-by, max-by in Nim

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import strutils, algorithm, future

var names = "Brian Chris Pamela Michael Tammy Michelle Roy Timothy".split()

# Find shortest and longest name
block:
  proc `<`(a, b: string): bool =
    a.len < b.len

  echo min(names), " and ", max(names)
  #< Roy and Michelle

# Sort names by length
names.sort((a, b) => cmp(a.len, b.len))
echo names
#< @[Roy, Brian, Chris, Tammy, Pamela, Michael, Timothy, Michelle]
Created (updated ) | Comment

Avoid problems when installing Nim on Windows

First off, decide if you want to go for x64 or x86 and stick to that choice, whenever you are provided with such a choice. x64 seems to work fine.

Installation instructions for Nim 0.10.2 on Windows

  • Download .exe installer

  • Execute it

  • Check "C Compiler (MinGW)". Everything else that is not already checked is optional but is nice to have.

  • "C:\Nim" installation path works well.

Created (updated ) | Comment

Interesting proc overloads with parameter constraints in Nim

Overloading on constants

Let's say you have a function that returns a seq of N bytes, such as this one.

proc urandom*(size: Natural): seq[uint8]
  ## Returns a ``seq`` of random integers ``0 <= n < 256`` provided by
  ## the operating system's cryptographic source
  ## 
  ## POSIX: Reads and returns `size` bytes from the file ``/dev/urandom``.

It's a useful function, and all is well. But what if you want to give the result of urandom(32) to a function that takes an array of 32 bytes? Converting a seq to an array of fixed size is surprisingly complicated and dirty (but I may be missing something).

Long story short, you can use static[T] to provide an alternative generic function that returns arrays of fixed size.

proc urandom*(size: static[Natural]): array[size, uint8]
Created | Comment

Use compiler-specific functions in Nim

C compilers, like GCC, provide various "builtin" compiler-specific extensions (functions). Sure, using them may be looked down upon, but sometimes they can give you access to hardware-optimized operations that significantly boost performance. You can always provide a slower fallback.

Let's take as an example the operation "find how many bytes a number would take up". I needed this to implement a function that returns a random number in a specific range, using an entropy source that just gives bytes, such as /dev/urandom.

Created | Comment

Make a Nim module available to all your projects

If you want to have some module available for all your quick projects in Nim, instead of adding it to --path every time, you can just turn it into a Nimble package.

Just add a file like this to the directory:

cool_utilities.nimble[Package]
name: "cool_utilities"
version: "0.1"
author: "Me"
description: "Useful stuff"
license: "MIT"

And use nimble install inside it to install this module or update it after you've made some changes.

Created | Comment