marc walter

Feedback form with mail in PHP

2017-06-03

A simple form that I used to receive feedback from people on a web page. The web app uses JavaScript and only works on current browsers. I receive feedback if JavaScript is executed in the user's browser and the UserAgent of the browser (browser and operating system name and version).

This snippet only needs one file to both display the form and to receive the information.
Also needed is a configured mail server to send this information to me and the user (if she wishes it).

read more

How to configure a visual diff or merge tool in git on Windows

2016-10-15

Resolving merge conflicts can get confusing very fast, a nice GUI tool to facilitate this job is meld. It supports three-way file comparison to see the two different code versions and the currently merged file in the middle.

meld three-way file comparision
Image source http://meldmerge.org/features.html

To resolve the merge conflict with meld using the git-mergetool like this

git mergetool -y <filename>

Only a small change to the ~/.gitconfig file is needed.

On Windows, open %userprofile%\.gitconfig and then configure meld as diff and merge tool like this:

[diff]
    tool = meld
[difftool "meld"]
    cmd = \"C:\\Program Files (x86)\\Meld\\Meld.exe\" $LOCAL $REMOTE
[merge]
    tool = meld
[mergetool "meld"]
    cmd = \"C:\\Program Files (x86)\\Meld\\Meld.exe\" $PWD/$LOCAL $PWD/$BASE $PWD/$REMOTE --output=$PWD/$MERGED

For a little more information on the variables used, look at this stackoverlow comment.

Require a local node.js module from an unknown parent folder

2016-07-18

Require code somewhere upwards in the file tree without knowing the specific number of parent folders needed.
The tree is traversed synchronously.
Code is available on github.

Motivation/Usage

Instead of writing code like this:

try {
  var abc = require('./abc.js');
} catch (ex) {
  try {
    abc = require('../../abc.js');
  } catch (err) {
    abc = require('../../../abc.js');
  }
}

I rather want to write something like this:

var requireUp = require('require-upwards');
var abc = requireUp('abc.js');

Limiting the number of checked folders

Version 1.1 adds an optional parameter to limit the maximum number of iterations.

Given this folder structure:

fixtures
 ├─fix.js
 └─11
   ├─a.js
   └─baum

When starting from the folder fixtures/11/baum

requireUp('fix.js', 1)
# will throw an Error
requireUp('fix.js', 2)
# will return the content of fixtures/fix.js

Tests

Unit tests are located in the folder ./test. To run them, execute

npm run test --silent

Useful npm scripts and snippets

2016-04-17

Execute mocha tests without installing mocha globally

Works both on Windows and Mac
Add to package.json: (Info: Also forces mocha to print the full stack trace when errors occur).

[...]
"scripts": {
  "test": "node ./node_modules/mocha/bin/_mocha --full-trace test"
},
[...]

Then execute npm test on the command line to run all tests from the test folder.

Run istanbul code coverage and mocha tests without installing either globally

Works both on Windows and Mac
Add to package.json: (Info: Also sets the folder for the report)

[...]
"scripts": {
  "cover": "node node_modules/istanbul/lib/cli.js cover --dir test_coverage node_modules/mocha/bin/_mocha test"
},
[...]

Then execute npm run cover on the command line to generate the reports.

Get a list of globally installed packages

E.g. useful when switching between node.js versions

npm list -g --depth=0

Example output:

> npm list -g --depth=0
C:\Program Files\nodejs
+-- eslint-cli@1.1.0
+-- grunt@1.0.1
+-- gulp@3.9.1
+-- istanbul@0.4.3
+-- mocha@2.4.5
+-- nodemon@1.9.2
+-- npm@3.8.6
`-- webpack@1.13.0

Using Bitmasks in JavaScript

2016-03-05

Bitmasks are useful (e.g. for State Machines) and also usable in JavaScript.

Attention: The maximum value for the mask in JS is 2^31-1 (maximum value of int in JS).

Initial usage

No enums available, so use an object instead to create a Bitmask:

var States = {
    HINT: 1,
    NOTICE: 2,
    WARNING: 4,
    ERROR: 8,
    FATAL: 16
};

And use it like this:

var a = States.NOTICE;

a & States.HINT // returns 0

a & States.NOTICE // returns 2 (States.NOTICE)

Checking values against the mask

Two ways of checking the mask:

if ((a & States.NOTICE) === States.NOTICE) console.log(true);

if (a & States.NOTICE) console.log(true);

As long as the value 0 is not part of the Bitmask, the second way works as expected.

read more

Show notifications from scripts in node.js

2016-01-03

So that I never forget when I need it: The module node-notifier can be used to display desktop notifications on windows_, _mac and linux with notify-osd or libnotify-bin.

Example

Straight from the official doc.

const notifier = require('node-notifier');
// String 
notifier.notify('Title', 'Message');

// Object 
notifier.notify({
  'title': 'My notification',
  'message': 'Hello, there!'
});

Another example

From file notify-sample.js adapted from the official doc.

const notifier = require('node-notifier');
const path = require('path');

let options = {
  title: 'Wake up',
  message: "It's time!",
  icon: path.join(__dirname, 'emilia.jpg'), // Absolute path (doesn't work on balloons)
  sound: true, // Only Notification Center or Windows Toasters
}

notifier.notify(options)

What the notification looks like

on win10

read more

Generating a checksum over files or folders in node.js

2015-11-05

I needed a node.js module that generates hashes over files and folders. It should only create a hash over the text content and not over the file properties.

Further Requirements:

  • Return the same hash if the content is the same (do not check for file attributes)
  • Generate a hash over a folder structure
    • Generate the hash over a folder structure using only one loop
  • Support both promises and error-first callbacks
  • unit tests that document the behavior and not only that it does not crash

Entry folder-hash

Description

Create a hash checksum over a folder or a file.
The hashes are propagated upwards, the hash that is returned for a folder is generated over all the hashes of its children.
The hashes are generated with the sha1 algorithm and returned in base64 encoding.

The returned information looks like this:

{ name: 'test', 
  hash: 'qmUXLCsTQGOEF6p0w9V78MC7sJI=',
  children: [
    { name: 'helper', 
      hash: 'x1CX3yVH3UuLTw7zcSitSs/PbGE=',
      children: [
        { name: 'helper.js', hash: 'pHYwd8k/oZV01oABTz9MC8KovkU=' }
      ] },
    { name: 'test.js', hash: 'L/vqpdQhxmD5w62k24m4TuZJ1PM=' }
  ] 
}

Each file returns a name and a hash, and each folder returns additionally an array of children (file or folder elements).

Usage

With promises

var hasher = require('folder-hash');
// e.g. pass element path directly
hasher.hashElement(__dirname).then(function (hash) {
  console.log('Result for folder "' + __dirname + '":');
  console.log(hash.toString());
});

With callbacks

var hasher = require('folder-hash');
// e.g. pass element name and folder path separately
hasher.hashElement('node_modules', __dirname, function (error, hash)) {
  if (error) return console.error('hashing failed:', error);
  console.log('Result for folder "node_modules" in directory "' + __dirname + '":');
  console.log(hash.toString());
});

Behavior

The module meets all of my requirements. The further behavior is documented and verified in the unit tests. Execute npm test or mocha test, and have a look at the test subfolder.

Code

Available on github

Copy folders that contain files with specific extensions

2015-10-15

Recently I used a tool to re-tag and move my music library. This left me a neatly organized music library and also with a music folder that contained a lot of folders that only contained e.g. the album cover (in various formats). But some songs were not picked up by the auto-tagging mechanism, so some music files still persisted in that folder.

That is why I created a script that traverses the folder structure and copies all folders that (directly) contain at least one file out of a list of desired file types (e.g. '.mp3').

Situation

If I would run the script on this folder:

C:\tagged
├─Der dicke Polizist
│ └─und die Hoffnung stirbt zuletzt!
│    folder.jpg
└─ZSK
  ├─[2004] From Protest to Resistance
  │ ├─ folder.jpg
  │ └─ Kein Mensch ist illegal.mp3
  └─[2015] Herz für die Sache
      folder.jpg

I would expect this outcome:

C:\contains_music\tagged
└─ZSK
  └─[2004] From Protest to Resistance
    ├─ folder.jpg
    └─ Kein Mensch ist illegal.mp3

Solution

Criteria

  1. Each album that still contains music should be copied.
  2. But if an album contains no more music should not be copied.
  3. If an artist's folder does not contain any music (also not in subdirectories), it should not be copied

Reasoning

Write a recursive function that walks the directory tree and copies a folder if it contains at least one file with one of the desired file extensions.
If it does not contain any of those files, don't copy it - this will also suffice for criteria 3.

read more

Pour water on a landscape

2015-07-08

Description of the problem

Rain is pouring for a defined duration on a landscape that consists of multiple columns, each with its own height.

Rules

  1. There is an invisible border to the left and to the right of the provided landscape with a height of infinity.
  2. Each hour of rain pours one unit of rain into each column.
  3. The rain flows from a higher to a lower column. If the column to the left and to the right are both lower, then the rain distributes evenly between those two.

Test solver

Reasoning for the solution

1. Bottom up

At first glance it might seem logical to start pouring the rain from above one hour at a time and distribute it like that.
But if the landscape is slowly filled from the bottom up, many many edge cases will never occur and the problem will be a lot easier to implement.

2. Create regions

Instead of working with each column, I chose to group columns of the same height together into a region.
This will reduce the number of elements that need checking and allows me to easily calculate the water capacity of a region and also if the water should flow somewhere from this element.

3. Gather the rain in the trenches/ local minima

If the landscape will get bigger, it will be very inefficient to pour the water into each column.
Instead it would be easier to find all local minima in the landscape and divide the rain among those minima in the beginning.
This of course costs some time in the beginning of the calculation, especially if the worst case should occur: A zigzag landscape.

4. Shortcut if a landscape overflows

I can skip a lot of calculation if I add a case that checks in the beginning if more water will be poured into the landscape than it can take.

Code

The code for solving this problem is split into two files: region.js and solver.js.

  • region.js contains the prototype for each Region instance with the necessary functions to pour rain into itself or another region and merge it with neighbors to create a bigger region. Also it contains the specific border, a region with a height of POSITIVE_INFINITY.
  • solver.js contains the code to create the double-linked list of regions from the entered landscape array, and to pour all the rain into the landscape.
read more

Host a wifi hotspot on Windows 8

2015-03-14

If no Wifi, usb pen drive or network cable is available, it is sometimes useful to start a private Wifi hotspot on your computer.

This is achievable using the netsh tool.

Note: Usually a network card can be either used for receiving or sending a Wifi signal. Connecting to a wireless network and hosting another one at the same time is not possible.

Check if hosting a network is supported by the driver

If you execute the command

netsh wlan show drivers

on the command line, the response should contain the line

...
Hosted network supported  : Yes
...

If it does not, you are out of luck

Register a network

netsh wlan set hostednetwork mode=allow ssid=Horst key=111222333

register.bat

You can omit the key, but you should definitely add a password (even a short one).

Using the created network

To verify the status of the network

netsh wlan show hostednetwork

show_info.bat

To start the network

netsh wlan show hostednetwork

To stop the network

netsh wlan show hostednetwork

For convenience I added both starting and stopping to one batch script.
After a keypress, the wifi network is stopped again.

@ECHO OFF

netsh wlan start hostednetwork

PAUSE

netsh wlan stop hostednetwork

start_and_stop.bat