     }
     
     func createRowGapConstraints(keyboard: Keyboard) {
-        var allConstraints: Array<String> = []
-        
-        var canonicalMarginGap: String? = nil
-        var canonicalRowGap: String? = nil
-        
-        for i in 0...keyboard.rows.count {
-            let rowGapName = "rowGap\(i)"
-            let rowGap = self.elements[rowGapName]
-            
-            let isTopMarginGap = (i == 0)
-            let isBottomMarginGap = (i == keyboard.rows.count)
-            
-            if isTopMarginGap {
-                canonicalMarginGap = rowGapName
-                allConstraints += "V:[topSpacer][\(rowGapName)(0)]"
-            }
-            else if isBottomMarginGap {
-                allConstraints += "V:[key\(0)x\(i-1)][\(rowGapName)(\(canonicalMarginGap!))][bottomSpacer]"
-            }
-            else {
-                if !canonicalRowGap {
-                    allConstraints += "V:[key\(0)x\(i-1)][\(rowGapName)]"
-                    allConstraints += "V:[\(rowGapName)(>=5@50)]" // QQQ:
-                    canonicalRowGap = rowGapName
-                }
-                else {
-                    allConstraints += "V:[key\(0)x\(i-1)][\(rowGapName)(\(canonicalRowGap!))]"
-                }
-            }
-            
-            // each row has the same width
-            allConstraints += "[\(rowGapName)(debugWidth)]"
-            
-            // and the same centering
-            self.view.addConstraint(NSLayoutConstraint(
-                item: rowGap,
-                attribute: NSLayoutAttribute.CenterX,
-                relatedBy: NSLayoutRelation.Equal,
-                toItem: self.view,
-                attribute: NSLayoutAttribute.CenterX,
-                multiplier: 1,
-                constant: 0))
-        }
-        
-        for constraint in allConstraints {
-            let generatedConstraints = NSLayoutConstraint.constraintsWithVisualFormat(
-                constraint,
-                options: NSLayoutFormatOptions(0),
-                metrics: layout,
-                views: elements)
-            self.view.addConstraints(generatedConstraints)
-        }
+        self.addGapPair(
+            "rowGap%d",
+            row: 0,
+            startIndex: 0,
+            endIndex: keyboard.rows.count,
+            leftAnchor: "topSpacer",
+            rightAnchor: "bottomSpacer",
+            vertical: true,
+            width: "0")
+        self.addGapsInRange("rowGap%d",
+            row: 0,
+            startIndex: 1,
+            endIndex: keyboard.rows.count - 1,
+            vertical: true,
+            width: ">=5@50")
     }
     
     // TODO: make this a single constraint string??

                    rightAnchor: "rightSpacer",
                    vertical: false,
                    width: nil)
                addGapsInRange(
                    "keyGap%dx%d",
                    row: i,
                    startIndex: 1,
                    endIndex: rowsCount - 1,
                    vertical: false,
                    width: layout["keyGap"]!)
            }
        }
    }

                    rightAnchor: nil,
                    vertical: false,
                    width: nil)
                let keyGap = layout["keyGap"]!
                addGapsInRange(
                    "keyGap%dx%d",
                    row: i,
                    startIndex: 2,
                    endIndex: rowsCount - 2,
                    vertical: false,
                    width: "\(keyGap)")
            }
            else if isEquallySpacedRow {
                addGapPair(
