     
     private func _drawHorizontalMinorLines(context: DrawingContext, initialPoint: Point) {
         
-        guard let horizontalMinor = horizontalMinor else { return }
+        guard let horizontalMinor = lines.horizontalMinor else { return }
         
         context.strokeColor = horizontalMinor.lineColor
         context.lineWidth = horizontalMinor.lineWidth
         
         var path = Path()
         
-        for y in stride(from: initialPoint.y,
-                        through: initialPoint.y + size.height,
-                        by: horizontalMajor.lineSpacing / Float(horizontalMinor.minorSegmentsPerMajorSegment)) {
-                            
-                            path.move(toX: initialPoint.x, y: y)
-                            path.appendLine(toX: initialPoint.x + size.width, y: y)
+        let stride = lines.horizontalMajor.lineSpacing / Float(horizontalMinor.minorSegmentsPerMajorSegment)
+        
+        for y in _strideVertically(initialPoint: initialPoint, by: stride) {
+            
+            path.move(toX: initialPoint.x, y: y)
+            path.appendLine(toX: initialPoint.x + size.width, y: y)
         }
         
         context.stroke(path)
     }
-}
+    
+    // MARK: - Draw serifs
+    
+    private func _drawTopSerifs(context: DrawingContext, initialPoint: Point) {
+        
+        guard let top = serifs.top else { return }
+        
+        context.strokeColor = top.color
+        context.lineWidth = top.width
+        
+        var path = Path()
+        
+        let stride = Float(top.frequency) * lines.verticalMajor.lineSpacing
+        
+        let topY = initialPoint.y + size.height
+        
+        for x in _strideHorizontally(initialPoint: initialPoint, by: stride) {
+            
+            path.move(toX: x, y: topY)
+            path.appendLine(toX: x, y: topY - top.length)
+        }
+        
+        context.stroke(path)
+    }
+    
+    private func _drawBottomSerifs(context: DrawingContext, initialPoint: Point) {
+        
+        guard let bottom = serifs.bottom else { return }
+        
+        context.strokeColor = bottom.color
+        context.lineWidth = bottom.width
+        
+        var path = Path()
+        
+        let stride = Float(bottom.frequency) * lines.verticalMajor.lineSpacing
+        
+        for x in _strideHorizontally(initialPoint: initialPoint, by: stride) {
+            
+            path.move(toX: x, y: initialPoint.y)
+            path.appendLine(toX: x, y: initialPoint.y + bottom.length)
+        }
+        
+        context.stroke(path)
+    }
+    
+    private func _drawLeftSerifs(context: DrawingContext, initialPoint: Point) {
+        
+        guard let left = serifs.left else { return }
+        
+        context.strokeColor = left.color
+        context.lineWidth = left.width
+        
+        var path = Path()
+        
+        let stride = Float(left.frequency) * lines.horizontalMajor.lineSpacing
+        
+        for y in _strideVertically(initialPoint: initialPoint, by: stride) {
+            
+            path.move(toX: initialPoint.x, y: y)
+            path.appendLine(toX: initialPoint.x + left.length, y: y)
+        }
+        
+        context.stroke(path)
+    }
+    
+    private func _drawRightSerifs(context: DrawingContext, initialPoint: Point) {
+        
+        guard let right = serifs.right else { return }
+        
+        context.strokeColor = right.color
+        context.lineWidth = right.width
+        
+        var path = Path()
+        
+        let stride = Float(right.frequency) * lines.horizontalMajor.lineSpacing
+        
+        let rightmostX = initialPoint.x + size.width
+        
+        for y in _strideVertically(initialPoint: initialPoint, by: stride) {
+            
+            path.move(toX: rightmostX, y: y)
+            path.appendLine(toX: rightmostX - right.length, y: y)
+        }
+        
+        context.stroke(path)
+    }
+    
+    // MARK: - Draw labels
+    
+    private func _drawTopLabels(context: DrawingContext, initialPoint: Point) {
+        
+        guard let top = labels.top else { return }
+        
+        Unimplemented()
+    }
+    
+    private func _drawBottomLabels(context: DrawingContext, initialPoint: Point) {
+        
+        guard let bottom = labels.bottom else { return }
+        
+        Unimplemented()
+    }
+    
+    private func _drawLeftLabels(context: DrawingContext, initialPoint: Point) {
+        
+        guard let left = labels.left else { return }
+        
+        Unimplemented()
+    }
+    
+    private func _drawRightLabels(context: DrawingContext, initialPoint: Point) {
+        
+        guard let right = labels.right else { return }
+        
+        Unimplemented()
+    }
+}
+
+extension Grid.MajorLineParameters: Equatable {
+    
+    /// Returns a Boolean value indicating whether two values are equal.
+    ///
+    /// Equality is the inverse of inequality. For any values `a` and `b`,
+    /// `a == b` implies that `a != b` is `false`.
+    ///
+    /// - Parameters:
+    ///   - lhs: A value to compare.
+    ///   - rhs: Another value to compare.
+    public static func ==(lhs: Grid.MajorLineParameters, rhs: Grid.MajorLineParameters) -> Bool {
+        return lhs.lineColor == rhs.lineColor &&
+            lhs.lineSpacing == rhs.lineSpacing &&
+            lhs.lineWidth == rhs.lineWidth
+    }
+}
+
+extension Grid.MinorLineParameters: Equatable {
+    
+    /// Returns a Boolean value indicating whether two values are equal.
+    ///
+    /// Equality is the inverse of inequality. For any values `a` and `b`,
+    /// `a == b` implies that `a != b` is `false`.
+    ///
+    /// - Parameters:
+    ///   - lhs: A value to compare.
+    ///   - rhs: Another value to compare.
+    public static func ==(lhs: Grid.MinorLineParameters, rhs: Grid.MinorLineParameters) -> Bool {
+        return lhs.lineColor == rhs.lineColor &&
+            lhs.minorSegmentsPerMajorSegment == rhs.minorSegmentsPerMajorSegment &&
+            lhs.lineWidth == rhs.lineWidth
+    }
+}
+
+extension Grid.Lines: Equatable {
+    
+    /// Returns a Boolean value indicating whether two values are equal.
+    ///
+    /// Equality is the inverse of inequality. For any values `a` and `b`,
+    /// `a == b` implies that `a != b` is `false`.
+    ///
+    /// - Parameters:
+    ///   - lhs: A value to compare.
+    ///   - rhs: Another value to compare.
+    public static func ==(lhs: Grid.Lines, rhs: Grid.Lines) -> Bool {
+        return lhs.horizontalMajor == rhs.horizontalMajor &&
+            lhs.horizontalMinor == rhs.horizontalMinor &&
+            lhs.verticalMajor == rhs.verticalMajor &&
+            lhs.verticalMinor == rhs.verticalMinor
+    }
+}
+
+extension Grid.LabelParameters: Equatable {
+    
+    /// Returns a Boolean value indicating whether two values are equal.
+    ///
+    /// Equality is the inverse of inequality. For any values `a` and `b`,
+    /// `a == b` implies that `a != b` is `false`.
+    ///
+    /// - Parameters:
+    ///   - lhs: A value to compare.
+    ///   - rhs: Another value to compare.
+    public static func ==(lhs: Grid.LabelParameters, rhs: Grid.LabelParameters) -> Bool {
+        return lhs.font == rhs.font &&
+            lhs.fontColor == rhs.fontColor &&
+            lhs.fontSize == rhs.fontSize &&
+            lhs.frequency == rhs.frequency &&
+            lhs.offset == rhs.offset
+    }
+}
+
+extension Grid.Labels: Equatable {
+    
+    /// Returns a Boolean value indicating whether two values are equal.
+    ///
+    /// Equality is the inverse of inequality. For any values `a` and `b`,
+    /// `a == b` implies that `a != b` is `false`.
+    ///
+    /// - Parameters:
+    ///   - lhs: A value to compare.
+    ///   - rhs: Another value to compare.
+    public static func ==(lhs: Grid.Labels, rhs: Grid.Labels) -> Bool {
+        return lhs.left == rhs.left &&
+            lhs.right == rhs.right &&
+            lhs.top == rhs.top &&
+            lhs.bottom == rhs.bottom
+    }
+}
+
+extension Grid.SerifParameters: Equatable {
+    
+    /// Returns a Boolean value indicating whether two values are equal.
+    ///
+    /// Equality is the inverse of inequality. For any values `a` and `b`,
+    /// `a == b` implies that `a != b` is `false`.
+    ///
+    /// - Parameters:
+    ///   - lhs: A value to compare.
+    ///   - rhs: Another value to compare.
+    public static func ==(lhs: Grid.SerifParameters, rhs: Grid.SerifParameters) -> Bool {
+        return lhs.frequency == rhs.frequency &&
+            lhs.color == rhs.color &&
+            lhs.width == rhs.width &&
+            lhs.length == rhs.length
+    }
+}
+
+extension Grid.Serifs: Equatable {
+    
+    /// Returns a Boolean value indicating whether two values are equal.
+    ///
+    /// Equality is the inverse of inequality. For any values `a` and `b`,
+    /// `a == b` implies that `a != b` is `false`.
+    ///
+    /// - Parameters:
+    ///   - lhs: A value to compare.
+    ///   - rhs: Another value to compare.
+    public static func ==(lhs: Grid.Serifs, rhs: Grid.Serifs) -> Bool {
+        return lhs.left == rhs.left &&
+            lhs.right == rhs.right &&
+            lhs.top == rhs.top &&
+            lhs.bottom == rhs.bottom
+    }
+}
+
+extension Grid: Equatable {
+    
+    /// Returns a Boolean value indicating whether two values are equal.
+    ///
+    /// Equality is the inverse of inequality. For any values `a` and `b`,
+    /// `a == b` implies that `a != b` is `false`.
+    ///
+    /// - Parameters:
+    ///   - lhs: A value to compare.
+    ///   - rhs: Another value to compare.
+    public static func ==(lhs: Grid, rhs: Grid) -> Bool {
+        return lhs.size == rhs.size &&
+            lhs.lines == rhs.lines &&
+            lhs.labels == lhs.labels &&
+            lhs.serifs == rhs.serifs
+    }
+}

    
    private func _drawVerticalMinorLines(context: DrawingContext, initialPoint: Point) {
        
        guard let verticalMinor = verticalMinor else { return }
        
        context.strokeColor = verticalMinor.lineColor
        context.lineWidth = verticalMinor.lineWidth
        
        var path = Path()
        
        for x in stride(from: initialPoint.x,
                        through: initialPoint.x + size.width,
                        by: verticalMajor.lineSpacing / Float(verticalMinor.minorSegmentsPerMajorSegment)) {
                            
                            path.move(toX: x, y: initialPoint.y)
                            path.appendLine(toX: x, y: initialPoint.y + size.height)
        }
        
        context.stroke(path)

        
        /// Default parameters, where line width is 0.25, line color is 80% gray and the default
        /// number of minor segments per one major segment is 2.
        public static let `default` = MinorLineParameters()
        
        /// The width of lines.
        public var lineWidth: Float
