Completed
Pull Request — master (#14)
by Mischa ter
08:08
created
src/DamerauLevenshtein.php 2 patches
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -225,7 +225,7 @@  discard block
 block discarded – undo
225 225
             $maxCost += $extraSize * $this->insCost;
226 226
         }
227 227
 
228
-        return (int)$maxCost;
228
+        return (int) $maxCost;
229 229
     }
230 230
 
231 231
     /**
@@ -239,7 +239,7 @@  discard block
 block discarded – undo
239 239
             $this->setupMatrix();
240 240
         }
241 241
 
242
-        return (float)(1 - ($this->getSimilarity() / $this->getMaximalDistance()));
242
+        return (float) (1 - ($this->getSimilarity() / $this->getMaximalDistance()));
243 243
     }
244 244
 
245 245
     /**
@@ -266,7 +266,7 @@  discard block
 block discarded – undo
266 266
         $oneSize = mb_strlen($this->compOne, 'UTF-8');
267 267
         $twoSize = mb_strlen($this->compTwo, 'UTF-8');
268 268
 
269
-        $out = '  ' . $this->compOne . PHP_EOL;
269
+        $out = '  '.$this->compOne.PHP_EOL;
270 270
         for ($y = 0; $y <= $twoSize; $y += 1) {
271 271
             if ($y - 1 < 0) {
272 272
                 $out .= ' ';
Please login to merge, or discard this patch.
Indentation   +356 added lines, -356 removed lines patch added patch discarded remove patch
@@ -10,360 +10,360 @@
 block discarded – undo
10 10
 class DamerauLevenshtein
11 11
 {
12 12
 
13
-    /**
14
-     * First string.
15
-     *
16
-     * @var String
17
-     */
18
-    private $compOne;
19
-
20
-    /**
21
-     * Second string.
22
-     *
23
-     * @var String
24
-     */
25
-    private $compTwo;
26
-
27
-    /**
28
-     * Matrix for Damerau Levenshtein distance dynamic programming computation.
29
-     *
30
-     * @var int[][]
31
-     */
32
-    private $matrix;
33
-
34
-    /**
35
-     * Boolean flag determining whether is matrix computed for input strings.
36
-     *
37
-     * @var bool
38
-     */
39
-    private $calculated = false;
40
-
41
-    /**
42
-     * Cost of character insertion (to first string to match second string).
43
-     *
44
-     * @var int
45
-     */
46
-    private $insCost = 1;
47
-
48
-    /**
49
-     * Cost of character deletion (from first string to match second string).
50
-     *
51
-     * @var int
52
-     */
53
-    private $delCost = 1;
54
-
55
-    /**
56
-     * Substitution cost.
57
-     *
58
-     * @var int
59
-     */
60
-    private $subCost = 1;
61
-
62
-    /**
63
-     * Transposition cost.
64
-     *
65
-     * @var int
66
-     */
67
-    private $transCost = 1;
68
-
69
-    /**
70
-     * Constructor.
71
-     *
72
-     * @param string $firstString first string to compute distance
73
-     * @param string $secondString second string to compute distance
74
-     * @param int $insCost Cost of character insertion
75
-     * @param int $delCost Cost of character deletion
76
-     * @param int $subCost Substitution cost
77
-     * @param int $transCost Transposition cost
78
-     */
79
-    public function __construct(
80
-        string $firstString,
81
-        string $secondString,
82
-        int $insCost = 1,
83
-        int $delCost = 1,
84
-        int $subCost = 1,
85
-        int $transCost = 1
86
-    ) {
87
-        if (!empty($firstString) || !empty($secondString)) {
88
-            $this->compOne = $firstString;
89
-            $this->compTwo = $secondString;
90
-        }
91
-
92
-        $this->insCost = $insCost;
93
-        $this->delCost = $delCost;
94
-        $this->subCost = $subCost;
95
-        $this->transCost = $transCost;
96
-    }
97
-
98
-    /**
99
-     * Returns computed matrix for given input strings.
100
-     *
101
-     * @return int[][] matrix
102
-     */
103
-    public function getMatrix(): array
104
-    {
105
-        $this->setupMatrix();
106
-
107
-        return $this->matrix;
108
-    }
109
-
110
-    /**
111
-     * Returns similarity of strings, absolute number = Damerau Levenshtein distance.
112
-     *
113
-     * @return int
114
-     */
115
-    public function getSimilarity(): int
116
-    {
117
-        if (!$this->calculated) {
118
-            $this->setupMatrix();
119
-        }
120
-
121
-        return $this->matrix[mb_strlen($this->compOne, 'UTF-8')][mb_strlen($this->compTwo, 'UTF-8')];
122
-    }
123
-
124
-    /**
125
-     * Procedure to compute matrix for given input strings.
126
-     *
127
-     * @return void
128
-     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
129
-     */
130
-    private function setupMatrix(): void
131
-    {
132
-        $this->matrix = [[]];
133
-
134
-        $oneSize = mb_strlen($this->compOne, 'UTF-8');
135
-        $twoSize = mb_strlen($this->compTwo, 'UTF-8');
136
-        for ($i = 0; $i <= $oneSize; $i += 1) {
137
-            $this->matrix[$i][0] = $i > 0 ? $this->matrix[$i - 1][0] + $this->delCost : 0;
138
-        }
139
-
140
-        for ($i = 0; $i <= $twoSize; $i += 1) {
141
-            // Insertion actualy
142
-            $this->matrix[0][$i] = $i > 0 ? $this->matrix[0][$i - 1] + $this->insCost : 0;
143
-        }
144
-
145
-        for ($i = 1; $i <= $oneSize; $i += 1) {
146
-            // Curchar for the first string
147
-            $cOne = mb_substr($this->compOne, $i - 1, 1, 'UTF-8');
148
-            for ($j = 1; $j <= $twoSize; $j += 1) {
149
-                // Curchar for the second string
150
-                $cTwo = mb_substr($this->compTwo, $j - 1, 1, 'UTF-8');
151
-
152
-                // Compute substitution cost
153
-                if ($this->compare($cOne, $cTwo) == 0) {
154
-                    $cost = 0;
155
-                    $trans = 0;
156
-                } else {
157
-                    $cost = $this->subCost;
158
-                    $trans = $this->transCost;
159
-                }
160
-
161
-                // Deletion cost
162
-                $del = $this->matrix[$i - 1][$j] + $this->delCost;
163
-
164
-                // Insertion cost
165
-                $ins = $this->matrix[$i][$j - 1] + $this->insCost;
166
-
167
-                // Substitution cost, 0 if same
168
-                $sub = $this->matrix[$i - 1][$j - 1] + $cost;
169
-
170
-                // Compute optimal
171
-                $this->matrix[$i][$j] = min($del, $ins, $sub);
172
-
173
-                // Transposition cost
174
-                if ($i > 1 && $j > 1) {
175
-                    // Last two
176
-                    $ccOne = mb_substr($this->compOne, $i - 2, 1, 'UTF-8');
177
-                    $ccTwo = mb_substr($this->compTwo, $j - 2, 1, 'UTF-8');
178
-
179
-                    if ($this->compare($cOne, $ccTwo) == 0 && $this->compare($ccOne, $cTwo) == 0) {
180
-                        // Transposition cost is computed as minimal of two
181
-                        $this->matrix[$i][$j] = min($this->matrix[$i][$j], $this->matrix[$i - 2][$j - 2] + $trans);
182
-                    }
183
-                }
184
-            }
185
-        }
186
-
187
-        $this->calculated = true;
188
-    }
189
-
190
-    /**
191
-     * Returns maximal possible edit Damerau Levenshtein distance between texts.
192
-     *
193
-     * On common substring of same length perform substitution / insert + delete
194
-     * (depends on what is cheaper), then on extra characters perform insertion / deletion
195
-     *
196
-     * @return int
197
-     */
198
-    public function getMaximalDistance(): int
199
-    {
200
-        $oneSize = mb_strlen($this->compOne, 'UTF-8');
201
-        $twoSize = mb_strlen($this->compTwo, 'UTF-8');
202
-
203
-        // Is substitution cheaper that delete + insert?
204
-        $subCost = min($this->subCost, $this->delCost + $this->insCost);
205
-
206
-        // Get common size
207
-        $minSize = min($oneSize, $twoSize);
208
-        $maxSize = max($oneSize, $twoSize);
209
-        $extraSize = $maxSize - $minSize;
210
-
211
-        // On common size perform substitution / delete + insert, what is cheaper
212
-        $maxCost = $subCost * $minSize;
213
-
214
-        // On resulting do insert/delete
215
-        if ($oneSize > $twoSize) {
216
-            // Delete extra characters
217
-            $maxCost += $extraSize * $this->delCost;
218
-        } else {
219
-            // Insert extra characters
220
-            $maxCost += $extraSize * $this->insCost;
221
-        }
222
-
223
-        return (int)$maxCost;
224
-    }
225
-
226
-    /**
227
-     * Returns relative distance of input strings (computed with maximal possible distance).
228
-     *
229
-     * @return float
230
-     */
231
-    public function getRelativeDistance(): float
232
-    {
233
-        if (!$this->calculated) {
234
-            $this->setupMatrix();
235
-        }
236
-
237
-        return (float)(1 - ($this->getSimilarity() / $this->getMaximalDistance()));
238
-    }
239
-
240
-    /**
241
-     * Compares two characters from string (this method may be overridden in child class).
242
-     *
243
-     * @param string $firstCharacter First character
244
-     * @param string $secondCharacter Second character
245
-     * @return int
246
-     */
247
-    protected function compare(string $firstCharacter, string $secondCharacter): int
248
-    {
249
-        return strcmp($firstCharacter, $secondCharacter);
250
-    }
251
-
252
-    /**
253
-     * Returns computed matrix for given input strings (For debugging purposes).
254
-     *
255
-     * @return string
256
-     */
257
-    public function displayMatrix(): string
258
-    {
259
-        $this->setupMatrix();
260
-
261
-        $oneSize = mb_strlen($this->compOne, 'UTF-8');
262
-        $twoSize = mb_strlen($this->compTwo, 'UTF-8');
263
-
264
-        $out = '  ' . $this->compOne . PHP_EOL;
265
-        for ($y = 0; $y <= $twoSize; $y += 1) {
266
-            if ($y - 1 < 0) {
267
-                $out .= ' ';
268
-            } else {
269
-                $out .= mb_substr($this->compTwo, $y - 1, 1, 'UTF-8');
270
-            }
271
-
272
-            for ($x = 0; $x <= $oneSize; $x += 1) {
273
-                $out .= $this->matrix[$x][$y];
274
-            }
275
-
276
-            $out .= PHP_EOL;
277
-        }
278
-
279
-        return $out;
280
-    }
281
-
282
-    /**
283
-     * Returns current cost of insertion operation.
284
-     *
285
-     * @return int
286
-     */
287
-    public function getInsCost(): int
288
-    {
289
-        return $this->insCost;
290
-    }
291
-
292
-    /**
293
-     * Sets cost of insertion operation (insert characters to first string to match second string).
294
-     *
295
-     * @param int $insCost Cost of character insertion
296
-     * @return void
297
-     */
298
-    public function setInsCost(int $insCost): void
299
-    {
300
-        $this->calculated = $insCost == $this->insCost ? $this->calculated : false;
301
-        $this->insCost = $insCost;
302
-    }
303
-
304
-    /**
305
-     * Returns current cost of deletion operation.
306
-     *
307
-     * @return int
308
-     */
309
-    public function getDelCost(): int
310
-    {
311
-        return $this->delCost;
312
-    }
313
-
314
-    /**
315
-     * Sets cost of deletion operation (delete characters from first string to match second string).
316
-     *
317
-     * @param int $delCost Cost of character deletion
318
-     * @return void
319
-     */
320
-    public function setDelCost(int $delCost): void
321
-    {
322
-        $this->calculated = $delCost == $this->delCost ? $this->calculated : false;
323
-        $this->delCost = $delCost;
324
-    }
325
-
326
-    /**
327
-     * Returns current cost of substitution operation.
328
-     *
329
-     * @return int
330
-     */
331
-    public function getSubCost(): int
332
-    {
333
-        return $this->subCost;
334
-    }
335
-
336
-    /**
337
-     * Sets cost of substitution operation.
338
-     *
339
-     * @param int $subCost Cost of character substitution
340
-     * @return void
341
-     */
342
-    public function setSubCost(int $subCost): void
343
-    {
344
-        $this->calculated = $subCost == $this->subCost ? $this->calculated : false;
345
-        $this->subCost = $subCost;
346
-    }
347
-
348
-    /**
349
-     * Returns current cost of transposition operation.
350
-     *
351
-     * @return int
352
-     */
353
-    public function getTransCost(): int
354
-    {
355
-        return $this->transCost;
356
-    }
357
-
358
-    /**
359
-     * Sets cost of transposition operation.
360
-     *
361
-     * @param int $transCost Cost of character transposition
362
-     * @return void
363
-     */
364
-    public function setTransCost(int $transCost): void
365
-    {
366
-        $this->calculated = $transCost == $this->transCost ? $this->calculated : false;
367
-        $this->transCost = $transCost;
368
-    }
13
+	/**
14
+	 * First string.
15
+	 *
16
+	 * @var String
17
+	 */
18
+	private $compOne;
19
+
20
+	/**
21
+	 * Second string.
22
+	 *
23
+	 * @var String
24
+	 */
25
+	private $compTwo;
26
+
27
+	/**
28
+	 * Matrix for Damerau Levenshtein distance dynamic programming computation.
29
+	 *
30
+	 * @var int[][]
31
+	 */
32
+	private $matrix;
33
+
34
+	/**
35
+	 * Boolean flag determining whether is matrix computed for input strings.
36
+	 *
37
+	 * @var bool
38
+	 */
39
+	private $calculated = false;
40
+
41
+	/**
42
+	 * Cost of character insertion (to first string to match second string).
43
+	 *
44
+	 * @var int
45
+	 */
46
+	private $insCost = 1;
47
+
48
+	/**
49
+	 * Cost of character deletion (from first string to match second string).
50
+	 *
51
+	 * @var int
52
+	 */
53
+	private $delCost = 1;
54
+
55
+	/**
56
+	 * Substitution cost.
57
+	 *
58
+	 * @var int
59
+	 */
60
+	private $subCost = 1;
61
+
62
+	/**
63
+	 * Transposition cost.
64
+	 *
65
+	 * @var int
66
+	 */
67
+	private $transCost = 1;
68
+
69
+	/**
70
+	 * Constructor.
71
+	 *
72
+	 * @param string $firstString first string to compute distance
73
+	 * @param string $secondString second string to compute distance
74
+	 * @param int $insCost Cost of character insertion
75
+	 * @param int $delCost Cost of character deletion
76
+	 * @param int $subCost Substitution cost
77
+	 * @param int $transCost Transposition cost
78
+	 */
79
+	public function __construct(
80
+		string $firstString,
81
+		string $secondString,
82
+		int $insCost = 1,
83
+		int $delCost = 1,
84
+		int $subCost = 1,
85
+		int $transCost = 1
86
+	) {
87
+		if (!empty($firstString) || !empty($secondString)) {
88
+			$this->compOne = $firstString;
89
+			$this->compTwo = $secondString;
90
+		}
91
+
92
+		$this->insCost = $insCost;
93
+		$this->delCost = $delCost;
94
+		$this->subCost = $subCost;
95
+		$this->transCost = $transCost;
96
+	}
97
+
98
+	/**
99
+	 * Returns computed matrix for given input strings.
100
+	 *
101
+	 * @return int[][] matrix
102
+	 */
103
+	public function getMatrix(): array
104
+	{
105
+		$this->setupMatrix();
106
+
107
+		return $this->matrix;
108
+	}
109
+
110
+	/**
111
+	 * Returns similarity of strings, absolute number = Damerau Levenshtein distance.
112
+	 *
113
+	 * @return int
114
+	 */
115
+	public function getSimilarity(): int
116
+	{
117
+		if (!$this->calculated) {
118
+			$this->setupMatrix();
119
+		}
120
+
121
+		return $this->matrix[mb_strlen($this->compOne, 'UTF-8')][mb_strlen($this->compTwo, 'UTF-8')];
122
+	}
123
+
124
+	/**
125
+	 * Procedure to compute matrix for given input strings.
126
+	 *
127
+	 * @return void
128
+	 * @SuppressWarnings(PHPMD.CyclomaticComplexity)
129
+	 */
130
+	private function setupMatrix(): void
131
+	{
132
+		$this->matrix = [[]];
133
+
134
+		$oneSize = mb_strlen($this->compOne, 'UTF-8');
135
+		$twoSize = mb_strlen($this->compTwo, 'UTF-8');
136
+		for ($i = 0; $i <= $oneSize; $i += 1) {
137
+			$this->matrix[$i][0] = $i > 0 ? $this->matrix[$i - 1][0] + $this->delCost : 0;
138
+		}
139
+
140
+		for ($i = 0; $i <= $twoSize; $i += 1) {
141
+			// Insertion actualy
142
+			$this->matrix[0][$i] = $i > 0 ? $this->matrix[0][$i - 1] + $this->insCost : 0;
143
+		}
144
+
145
+		for ($i = 1; $i <= $oneSize; $i += 1) {
146
+			// Curchar for the first string
147
+			$cOne = mb_substr($this->compOne, $i - 1, 1, 'UTF-8');
148
+			for ($j = 1; $j <= $twoSize; $j += 1) {
149
+				// Curchar for the second string
150
+				$cTwo = mb_substr($this->compTwo, $j - 1, 1, 'UTF-8');
151
+
152
+				// Compute substitution cost
153
+				if ($this->compare($cOne, $cTwo) == 0) {
154
+					$cost = 0;
155
+					$trans = 0;
156
+				} else {
157
+					$cost = $this->subCost;
158
+					$trans = $this->transCost;
159
+				}
160
+
161
+				// Deletion cost
162
+				$del = $this->matrix[$i - 1][$j] + $this->delCost;
163
+
164
+				// Insertion cost
165
+				$ins = $this->matrix[$i][$j - 1] + $this->insCost;
166
+
167
+				// Substitution cost, 0 if same
168
+				$sub = $this->matrix[$i - 1][$j - 1] + $cost;
169
+
170
+				// Compute optimal
171
+				$this->matrix[$i][$j] = min($del, $ins, $sub);
172
+
173
+				// Transposition cost
174
+				if ($i > 1 && $j > 1) {
175
+					// Last two
176
+					$ccOne = mb_substr($this->compOne, $i - 2, 1, 'UTF-8');
177
+					$ccTwo = mb_substr($this->compTwo, $j - 2, 1, 'UTF-8');
178
+
179
+					if ($this->compare($cOne, $ccTwo) == 0 && $this->compare($ccOne, $cTwo) == 0) {
180
+						// Transposition cost is computed as minimal of two
181
+						$this->matrix[$i][$j] = min($this->matrix[$i][$j], $this->matrix[$i - 2][$j - 2] + $trans);
182
+					}
183
+				}
184
+			}
185
+		}
186
+
187
+		$this->calculated = true;
188
+	}
189
+
190
+	/**
191
+	 * Returns maximal possible edit Damerau Levenshtein distance between texts.
192
+	 *
193
+	 * On common substring of same length perform substitution / insert + delete
194
+	 * (depends on what is cheaper), then on extra characters perform insertion / deletion
195
+	 *
196
+	 * @return int
197
+	 */
198
+	public function getMaximalDistance(): int
199
+	{
200
+		$oneSize = mb_strlen($this->compOne, 'UTF-8');
201
+		$twoSize = mb_strlen($this->compTwo, 'UTF-8');
202
+
203
+		// Is substitution cheaper that delete + insert?
204
+		$subCost = min($this->subCost, $this->delCost + $this->insCost);
205
+
206
+		// Get common size
207
+		$minSize = min($oneSize, $twoSize);
208
+		$maxSize = max($oneSize, $twoSize);
209
+		$extraSize = $maxSize - $minSize;
210
+
211
+		// On common size perform substitution / delete + insert, what is cheaper
212
+		$maxCost = $subCost * $minSize;
213
+
214
+		// On resulting do insert/delete
215
+		if ($oneSize > $twoSize) {
216
+			// Delete extra characters
217
+			$maxCost += $extraSize * $this->delCost;
218
+		} else {
219
+			// Insert extra characters
220
+			$maxCost += $extraSize * $this->insCost;
221
+		}
222
+
223
+		return (int)$maxCost;
224
+	}
225
+
226
+	/**
227
+	 * Returns relative distance of input strings (computed with maximal possible distance).
228
+	 *
229
+	 * @return float
230
+	 */
231
+	public function getRelativeDistance(): float
232
+	{
233
+		if (!$this->calculated) {
234
+			$this->setupMatrix();
235
+		}
236
+
237
+		return (float)(1 - ($this->getSimilarity() / $this->getMaximalDistance()));
238
+	}
239
+
240
+	/**
241
+	 * Compares two characters from string (this method may be overridden in child class).
242
+	 *
243
+	 * @param string $firstCharacter First character
244
+	 * @param string $secondCharacter Second character
245
+	 * @return int
246
+	 */
247
+	protected function compare(string $firstCharacter, string $secondCharacter): int
248
+	{
249
+		return strcmp($firstCharacter, $secondCharacter);
250
+	}
251
+
252
+	/**
253
+	 * Returns computed matrix for given input strings (For debugging purposes).
254
+	 *
255
+	 * @return string
256
+	 */
257
+	public function displayMatrix(): string
258
+	{
259
+		$this->setupMatrix();
260
+
261
+		$oneSize = mb_strlen($this->compOne, 'UTF-8');
262
+		$twoSize = mb_strlen($this->compTwo, 'UTF-8');
263
+
264
+		$out = '  ' . $this->compOne . PHP_EOL;
265
+		for ($y = 0; $y <= $twoSize; $y += 1) {
266
+			if ($y - 1 < 0) {
267
+				$out .= ' ';
268
+			} else {
269
+				$out .= mb_substr($this->compTwo, $y - 1, 1, 'UTF-8');
270
+			}
271
+
272
+			for ($x = 0; $x <= $oneSize; $x += 1) {
273
+				$out .= $this->matrix[$x][$y];
274
+			}
275
+
276
+			$out .= PHP_EOL;
277
+		}
278
+
279
+		return $out;
280
+	}
281
+
282
+	/**
283
+	 * Returns current cost of insertion operation.
284
+	 *
285
+	 * @return int
286
+	 */
287
+	public function getInsCost(): int
288
+	{
289
+		return $this->insCost;
290
+	}
291
+
292
+	/**
293
+	 * Sets cost of insertion operation (insert characters to first string to match second string).
294
+	 *
295
+	 * @param int $insCost Cost of character insertion
296
+	 * @return void
297
+	 */
298
+	public function setInsCost(int $insCost): void
299
+	{
300
+		$this->calculated = $insCost == $this->insCost ? $this->calculated : false;
301
+		$this->insCost = $insCost;
302
+	}
303
+
304
+	/**
305
+	 * Returns current cost of deletion operation.
306
+	 *
307
+	 * @return int
308
+	 */
309
+	public function getDelCost(): int
310
+	{
311
+		return $this->delCost;
312
+	}
313
+
314
+	/**
315
+	 * Sets cost of deletion operation (delete characters from first string to match second string).
316
+	 *
317
+	 * @param int $delCost Cost of character deletion
318
+	 * @return void
319
+	 */
320
+	public function setDelCost(int $delCost): void
321
+	{
322
+		$this->calculated = $delCost == $this->delCost ? $this->calculated : false;
323
+		$this->delCost = $delCost;
324
+	}
325
+
326
+	/**
327
+	 * Returns current cost of substitution operation.
328
+	 *
329
+	 * @return int
330
+	 */
331
+	public function getSubCost(): int
332
+	{
333
+		return $this->subCost;
334
+	}
335
+
336
+	/**
337
+	 * Sets cost of substitution operation.
338
+	 *
339
+	 * @param int $subCost Cost of character substitution
340
+	 * @return void
341
+	 */
342
+	public function setSubCost(int $subCost): void
343
+	{
344
+		$this->calculated = $subCost == $this->subCost ? $this->calculated : false;
345
+		$this->subCost = $subCost;
346
+	}
347
+
348
+	/**
349
+	 * Returns current cost of transposition operation.
350
+	 *
351
+	 * @return int
352
+	 */
353
+	public function getTransCost(): int
354
+	{
355
+		return $this->transCost;
356
+	}
357
+
358
+	/**
359
+	 * Sets cost of transposition operation.
360
+	 *
361
+	 * @param int $transCost Cost of character transposition
362
+	 * @return void
363
+	 */
364
+	public function setTransCost(int $transCost): void
365
+	{
366
+		$this->calculated = $transCost == $this->transCost ? $this->calculated : false;
367
+		$this->transCost = $transCost;
368
+	}
369 369
 }
Please login to merge, or discard this patch.