install ruby @ OS X

OS X comes with a pretty hung ruby (1.8.7) until ‘Mavericks’. ruby 1.8.7 had it’s planned EOL long ago, even debian/stable nowadays comes with a newer one.

So if you’re still running Mountain Lion or older, you may need to install ruby.

I chose rbenv and here’s how I did:

  • RTFM
  • install rbenv: $ brew install rbenv ruby-build
  • add : $ brew install rbenv ruby-build
  • patch .bashrc
  • do a $ rbenv rehash
  • purge all previously installed gems: $ gem list | cut -d ' ' -f 1 | xargs sudo gem uninstall
  • restart terminal
  • install a ruby of choice, and happily bundle install ever after

redmine (rails) + puma + lighttpd

Running redmine with a lightweight ruby on rails/webserver stack on a debian server – puma and lighttpd:

Assumed you’ve got both redmine and lighttpd already installed:

  1. install puma gem:
    $ sudo gem install puma
  2. caution: ArgumentError on ruby 1.8.7
  3. get tools/jungle/init.d/puma to /etc/init.d/
  4. get tools/jungle/init.d/run-puma to /usr/local/bin/
  5. add a puma app:
    $ sudo /etc/init.d/puma add /your/app/path www-data
  6. $ sudo -u www-data mkdir /your/app/path/tmp/puma
  7. puma config in rails app /your/app/path/config/puma.rb
    1
    2
    3
    4
    5
    6
    7
    
    $ cat your/app/path/config/puma.rb
    environment 'production'
    pidfile File.expand_path( File.dirname(__FILE__) + "/../tmp/puma/pid" )
    state_path File.expand_path( File.dirname(__FILE__) + "/../tmp/puma/state" )
    threads 1,4
    port 8082
    activate_control_app
  8. $ grep puma /your/app/path/Gemfile.local
    gem "puma"
  9. lighttpd proxy config:
    1
    2
    
    $ grep 8082 /etc/lighttpd/conf-enabled/10-proxy.conf
    $HTTP["host"] == "redmine.example.com" { proxy.server = ( "" => (("host" => "127.0.0.1", "port" => 8082))) }
  10. $ sudo /etc/init.d/puma start
  11. $ sleep 5 ; cat /your/app/path/tmp/puma/state
  12. $ sudo update-rc.d -f puma defaults

Versions:

  • ruby: 1.8.7-p358 (2012-02-08) [x86_64-linux]
  • rails: 3.2.15
  • lighttpd: 1.4.28
  • puma: 2.7.1
  • redmine: 2.4.0

Catch JavaScript exceptions in UIWebViews

A small but useful category method on UIWebView: Turn uncaught JavaScript Exception into a NSError!

//
// Created by Marcus Rohrmoser on 05.12.13.
// Copyright (c) 2013 Marcus Rohrmoser mobile Software. All rights reserved.
//
 
#import "UIWebView+JavaScriptNSError.h"
 
#define NSERROR_UIWEBVIEW_SCRIPT @"NSERROR_UIWEBVIEW_SCRIPT"
#define NSERROR_UIWEBVIEW_SCRIPT_CODE 1
 
@implementation UIWebView(JavaScriptNSError)
 
-(NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script error:(NSError * __autoreleasing *)error
{
  NSString *errorPrefix = NSERROR_UIWEBVIEW_SCRIPT;
  NSString *exec = [NSString stringWithFormat:@"try { %@ } catch (e) { '%@' + e; }", script, errorPrefix, nil];
  NSString *ret = [self stringByEvaluatingJavaScriptFromString:exec];
 
  if( ![ret hasPrefix:errorPrefix] )
    return ret;
 
  if( error ) {
    NSString *msg = [ret substringFromIndex:errorPrefix.length];
    NSDictionary *ui = @ {
      NSLocalizedDescriptionKey: msg,
      NSFilePathErrorKey:[self.request.URL absoluteString],
      NSURLErrorKey: self.request.URL,
      NSLocalizedFailureReasonErrorKey: msg,
      NSURLErrorFailingURLErrorKey: self.request.URL,
      NSURLErrorFailingURLStringErrorKey: self.request.URL
    };
    *error = [NSError errorWithDomain:NSERROR_UIWEBVIEW_SCRIPT code:NSERROR_UIWEBVIEW_SCRIPT_CODE userInfo:ui];
  }
  return nil;
}
@end

UIColor from hex string, once again

I end up doing this once per year – at least it’s getting leaner each time.

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
static inline NSInteger NSIntegerFromHexDigit(const unichar c)
{
  switch( c ) {
  case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
    return c - '0';
  case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
    return c - 'a' + 10;
  case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
    return c - 'A' + 10;
  default:
    return -1;
  }
}
 
typedef NSUInteger RGBA32;
 
/** RGBA hex color matching /^(?:0x|#)?([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?$/i
 */
static BOOL RGBAFromNSStringHex(NSString *hex, RGBA32 *value)
{
  const NSUInteger len = hex.length;
  if( len < 6 || len > 9 )
    return NO;
  unichar buffer[len];
  [hex getCharacters:buffer range:NSMakeRange(0, len)];
 
  // check if either 6 or 8 char hex
  const BOOL hasHashPrefix = buffer[0] == '#';
  const NSInteger netlen = len - hasHashPrefix;
  if( netlen != 6 && netlen != 8 )
    return NO;
 
  // turn hex to integer
  NSUInteger ret = 0;
  assert(sizeof(ret) >= 4); // need at least 4 bytes
  for( NSInteger i = hasHashPrefix; i < len; i++ ) {
    const NSInteger v = NSIntegerFromHexDigit(buffer[i]);
    if( v < 0 )
      return NO;
    ret <<= 4;
    ret |= v;
  }
  // if 6-char hex assume alpha 0xFF
  if( netlen == 6 ) {
    ret <<= 8;
    ret |= 0xFF;
  }
 
  if( value )
    *value = ret;
  return YES;
}

How to get a UIColor from here should be straightforward.

P.S.: Wikipedia about ‘RGBA’

git version sha in iOS apps

there’s tons of recipes out there how to do this – nevertheless I want to add another one:

xcode-git-sha-info-plist

  1. create a new build phase (here named “Git Sha -> Info.plist”)
  2. paste
    1
    2
    3
    4
    5
    6
    7
    8
    
    # write git version SHA into Info.plist
    #
    # inspired by
    # - http://kswizz.com/post/2686511526/git-xcode-versioning
    # - http://stackoverflow.com/a/12658311
    cd "$PROJECT_DIR"
    # say hello
    /usr/libexec/PlistBuddy -c "Set :CFBundleVersionGitSHA $(git rev-parse --short HEAD)" "$TARGET_BUILD_DIR/$INFOPLIST_PATH"
  3. add key CFBundleVersionGitSHA with placeholder text to your Info.plist

I went for this one because

  1. easy setup,
  2. no build/compiler settings changes,
  3. doesn’t interfere with ‘normal’ versioning,
  4. simplest I’ve seen so far, no dependencies except git,
  5. explicit failure if e.g. git is missing.

Credits:

Rank sql(ite) text search results

When searching for text snippets in sql databases you might want to rank the results according to “how good did it match”. And: the ranking shouldn’t make the query slower.

Let’s take a simple example using the LIKE operator. (I know, FTS does a better job, but let’s stick to like for now).

Assume the search expression ‘a bc de’ and a table ‘my_table’ with text columns ‘title’ and ‘description’.

We want to find all rows with ‘title’ matching all three blank-separated parts of the search term:

SELECT rowid, title
FROM my_table
WHERE (title LIKE '%a%' AND title LIKE '%bc%' AND title LIKE '%de%')

To sort them, we apply a bonus for parts matching the column start:

SELECT rowid, title,
    -- column start bonus
    LIKE('a%', title) +
    LIKE('bc%', title) +
    LIKE('de%', title) +
0 AS bonus
FROM my_table
WHERE ((title LIKE '%a%') AND (title LIKE '%bc%') AND (title LIKE '%de%'))
ORDER BY bonus DESC, title ASC, rowid ASC

Next, we’d like to add a (somewhat smaller) bonus for word-starts:

SELECT rowid, title,
    -- column start bonus
    LIKE('a%', title) * 2 +
    LIKE('bc%', title) * 2 +
    LIKE('de%', title) * 2 +
    -- word start bonus
    LIKE('% a%', title) * 1 +
    LIKE('% bc%', title) * 1 +
    LIKE('% de%', title) * 1 +
0 AS bonus
FROM my_table
WHERE ((title LIKE '%a%') AND (title LIKE '%bc%') AND (title LIKE '%de%'))
ORDER BY bonus DESC, title ASC, rowid ASC

Rows matching the three terms in order get an even bigger bonus:

SELECT rowid, title,
    -- correct order bonus
    LIKE('%a%bc%de%', title) * 5 * 3 +
    -- column start bonus
    LIKE('a%', title) * 2 +
    LIKE('bc%', title) * 2 +
    LIKE('de%', title) * 2 +
    -- word start bonus
    LIKE('% a%', title) * 1 +
    LIKE('% bc%', title) * 1 +
    LIKE('% de%', title) * 1 +
0 AS bonus
FROM my_table
WHERE ((title LIKE '%a%') AND (title LIKE '%bc%') AND (title LIKE '%de%'))
ORDER BY bonus DESC, title ASC, rowid ASC

And finally adding the match on ‘description’ secondary:

SELECT rowid, title, description,
    -- title is primary match:
    -- correct order bonus
    LIKE('%a%bc%de%', title) * 50 * 3 +
    -- column start bonus
    LIKE('a%', title) * 20 +
    LIKE('bc%', title) * 20 +
    LIKE('de%', title) * 20 +
    -- word start bonus
    LIKE('% a%', title) * 10 +
    LIKE('% bc%', title) * 10 +
    LIKE('% de%', title) * 10 +
    -- description is secondary match:
    -- correct order bonus
    LIKE('%a%bc%de%', description) * 5 * 3 +
    -- column start bonus
    LIKE('a%', description) * 2 +
    LIKE('bc%', description) * 2 +
    LIKE('de%', description) * 2 +
    -- word start bonus
    LIKE('% a%', description) * 1 +
    LIKE('% bc%', description) * 1 +
    LIKE('% de%', description) * 1 +
0 AS bonus
FROM my_table
WHERE ((title       LIKE '%a%') AND (title       LIKE '%bc%') AND (title       LIKE '%de%'))
OR    ((description LIKE '%a%') AND (description LIKE '%bc%') AND (description LIKE '%de%'))
ORDER BY bonus DESC, title ASC, description ASC, rowid ASC

You get the idea.

Funny thing is – the whole ranking logic doesn’t hit performance (at least for small texts in the two columns)!

So, key is:

  1. scan the table only once to find match candidates using the LIKE operator,
  2. use the LIKE function(!) plus weighting-factors to compute a bonus for each hit,
  3. evtl. add secondary matching columns.

P.S.: This post was inspired by a chat with Deesa on the way home riding False Creek Ferry.

Ruby: Simple Fast Fourier Transform

by far not as powerful as the Fastest Fourier Transform in the West but maybe sometimes useful for a quick data analysis or de-noising. Reads stdin and writes to stdout.

Algorithm taken from Meyberg, Vachenauer: Höhere Mathematik II and ported to plain ruby myself.

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/usr/bin/env ruby
require 'complex'
 
class Array
  # DFT and inverse.
  # 
  # Algorithm from 
  # 'Meyberg, Vachenauer: Hoehere Mathematik II, Springer Berlin, 1991, page 332'
  #
  # See http://blog.mro.name/2011/04/simple-ruby-fast-fourier-transform/ 
  #
  def fft doinverse = false
    src = self
    # raise ArgumentError.new "Expected array input but was '#{src.class}'" unless src.kind_of? Array
    n = src.length
    nlog2 = Math.log( n ) / Math.log( 2 )
    raise ArgumentError.new "Input array size must be a power of two but was '#{n}'" unless nlog2.floor - nlog2 == 0.0
    n2 = n / 2
    phi = Math::PI / n2
    if doinverse
      phi = -phi
    else
      src.collect!{|c| c /= n.to_f}
    end
 
    # build a sine/cosine table
    wt = Array.new n2
    wt.each_index { |i| wt[i] = Complex.new Math.cos(i * phi), Math.sin(i * phi) }
 
    # bit reordering
    n1 = n - 1
    j = 0
    1.upto(n1) do |i|
      m = n2
      while j >= m
        j -= m
        m /= 2
      end
      j += m
      src[i],src[j] = src[j],src[i] if j > i
    end
 
    # 1d(N) Ueberlagerungen
    mm = 1
    begin
      m = mm
      mm *= 2
      0.upto(m - 1) do |k|
        w = wt[ k * n2 ]
        k.step(n1, mm) do |i|
          j = i + m
          src[j] = src[i] - (temp = w * src[j])
          src[i] += temp
        end
      end
      n2 /= 2
    end while mm != n
    src
  end
end
 
class String
  # parse Complex.new.to_s
  def to_c
    m = @@PATTERN.match self
    return nil if m.nil?
    Complex.new m[1].to_f, m[2].to_f
  end
private
  # float_pat = /(-?\d+(?:\.\d+)?(?:e[+-]?\d+)?)/
  @@PATTERN = /^[ \t\r\n]*(-?\d+(?:\.\d+)?(?:e[+-]?\d+)?)?\s*((?:\s+|[+-])\d+(?:\.\d+)?(?:e[+-]?\d+)?i)?[ \t\r\n]*$/
end
 
values = []
$stdin.each_line do |l|
  c = l.to_c
  if c.nil?
    $stderr.puts "unmatched '#{l}'"
  else
    values << c
  end
end
INVERSE = ARGV[0] == 'inverse'
$stderr.puts INVERSE ? 'inverse' : 'forward'
 
values.fft(INVERSE).each {|i| puts "#{i.real} #{i.image}i"}

WordPress messes up the angle brackets as usual, but there’s a gist for that.

Randnotiz: Die bayerische Frühgotik und der Islam

Neulich war ich auf der Burg zu Burghausen1 und entdeckte auf einem der ältesten Bilder (eine Schutzmantelmadonna) im Palas eine merkwürdige Aufschrift:

Continue Reading »

Vortrag: Index Suche mit CoreData und SQLite

Gestern gab’s einen Mini-Vortrag von mir bei den CocoaHeads München:

Die Folien dazu.

AlcoCalc iPhone App online!

Hurra! Vor einigen Tagen ist die erste Version des Promillerechners im AlcoCalc App Store Link erschienen. Die App merkt sich was Du wann getrunken hast und schätzt nach der Widmark Formel grob den aktuellen und fallenden Promillewert ab:

.