pragmatic_segmenter 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +730 -0
  7. data/Rakefile +4 -0
  8. data/lib/pragmatic_segmenter.rb +2 -0
  9. data/lib/pragmatic_segmenter/abbreviation.rb +22 -0
  10. data/lib/pragmatic_segmenter/abbreviation_replacer.rb +149 -0
  11. data/lib/pragmatic_segmenter/between_punctuation.rb +78 -0
  12. data/lib/pragmatic_segmenter/cleaner.rb +141 -0
  13. data/lib/pragmatic_segmenter/ellipsis.rb +36 -0
  14. data/lib/pragmatic_segmenter/exclamation_words.rb +19 -0
  15. data/lib/pragmatic_segmenter/languages/amharic.rb +33 -0
  16. data/lib/pragmatic_segmenter/languages/arabic.rb +83 -0
  17. data/lib/pragmatic_segmenter/languages/armenian.rb +33 -0
  18. data/lib/pragmatic_segmenter/languages/burmese.rb +33 -0
  19. data/lib/pragmatic_segmenter/languages/deutsch.rb +132 -0
  20. data/lib/pragmatic_segmenter/languages/english.rb +44 -0
  21. data/lib/pragmatic_segmenter/languages/french.rb +29 -0
  22. data/lib/pragmatic_segmenter/languages/greek.rb +29 -0
  23. data/lib/pragmatic_segmenter/languages/hindi.rb +33 -0
  24. data/lib/pragmatic_segmenter/languages/italian.rb +39 -0
  25. data/lib/pragmatic_segmenter/languages/japanese.rb +58 -0
  26. data/lib/pragmatic_segmenter/languages/persian.rb +56 -0
  27. data/lib/pragmatic_segmenter/languages/russian.rb +60 -0
  28. data/lib/pragmatic_segmenter/languages/spanish.rb +39 -0
  29. data/lib/pragmatic_segmenter/languages/urdu.rb +33 -0
  30. data/lib/pragmatic_segmenter/list.rb +169 -0
  31. data/lib/pragmatic_segmenter/number.rb +35 -0
  32. data/lib/pragmatic_segmenter/process.rb +126 -0
  33. data/lib/pragmatic_segmenter/punctuation.rb +12 -0
  34. data/lib/pragmatic_segmenter/punctuation_replacer.rb +62 -0
  35. data/lib/pragmatic_segmenter/rules.rb +38 -0
  36. data/lib/pragmatic_segmenter/segmenter.rb +81 -0
  37. data/lib/pragmatic_segmenter/sentence_boundary_punctuation.rb +17 -0
  38. data/lib/pragmatic_segmenter/single_letter_abbreviation.rb +37 -0
  39. data/lib/pragmatic_segmenter/types.rb +12 -0
  40. data/lib/pragmatic_segmenter/version.rb +3 -0
  41. data/pragmatic_segmenter.gemspec +25 -0
  42. data/spec/performance_spec.rb +24 -0
  43. data/spec/pragmatic_segmenter_spec.rb +1906 -0
  44. data/spec/spec_helper.rb +1 -0
  45. metadata +150 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ca45ee0335ee1889033c9d0e2482884387311e02
4
+ data.tar.gz: c12268163b15ce37d66dda1aa748a89cf41c7856
5
+ SHA512:
6
+ metadata.gz: 198f92a532b701cc2489b215ec4b2f6cb3c6bc24ede18d179999286cb7f2345637b96afc4e8ba8f04e8ab8a6045d06a63895c534ec597e595f840d8a03e157fe
7
+ data.tar.gz: 92e8c25e5c966a3a5ed1f17dca285615ac12cfe7c5d7a02c760432728d5cc33655eb33978465844e735a6d5c0de4312717c8367f29c97118e21501827a1fabe4
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pragmatic_segmenter.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Kevin S. Dias
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,730 @@
1
+ #Pragmatic Segmenter
2
+
3
+ Pragmatic Segmenter is a rule-based sentence boundary detection gem that works out-of-the-box across many languages.
4
+
5
+ ##Install
6
+
7
+ **Ruby**
8
+ ```
9
+ gem install pragmatic_segmenter
10
+ ```
11
+
12
+ **Ruby on Rails**
13
+ Add this line to your application’s Gemfile:
14
+ ```ruby
15
+ gem 'pragmatic_segmenter'
16
+ ```
17
+
18
+ ##Usage
19
+
20
+ * If no language is specified, the library will default to English.
21
+ * To specify a language use its two-digit [ISO 639-1 code](https://www.tm-town.com/languages).
22
+
23
+ ```ruby
24
+ text = "Hello world. My name is Mr. Smith. I work for the U.S. Government and I live in the U.S."
25
+ ps = PragmaticSegmenter::Segmenter.new(text: text)
26
+ ps.segment
27
+ # => ["Hello world.", "My name is Mr. Smith.", "I work for the U.S. Government and I live in the U.S."]
28
+
29
+ # Specify a language
30
+ text = "Այսօր երկուշաբթի է: Ես գնում եմ աշխատանքի:"
31
+ ps = PragmaticSegmenter::Segmenter.new(text: text, language: 'hy')
32
+ ps.segment
33
+ # => ["Այսօր երկուշաբթի է:", "Ես գնում եմ աշխատանքի:"]
34
+
35
+ # Specify a PDF document type
36
+ text = "This is a sentence\ncut off in the middle because pdf."
37
+ ps = PragmaticSegmenter::Segmenter.new(text: text, language: 'en', doc_type: 'pdf')
38
+ ps.segment
39
+ # => ["This is a sentence cut off in the middle because pdf."]
40
+
41
+ # Turn off text cleaning and preprocessing
42
+ text = "This is a sentence\ncut off in the middle because pdf."
43
+ ps = PragmaticSegmenter::Segmenter.new(text: text, language: 'en', doc_type: 'pdf', clean: false)
44
+ ps.segment
45
+ # => ["This is a sentence cut", "off in the middle because pdf."]
46
+
47
+ # Text cleaning and preprocessing only
48
+ text = "This is a sentence\ncut off in the middle because pdf."
49
+ ps = PragmaticSegmenter::Cleaner.new(text: text, doc_type: 'pdf')
50
+ ps.clean
51
+ # => "This is a sentence cut off in the middle because pdf."
52
+ ```
53
+
54
+ ##Live Demo
55
+
56
+ Try out a [live demo](https://www.tm-town.com/natural-language-processing) of Pragmatic Segmenter in the browser.
57
+
58
+ ##Background
59
+
60
+ According to Wikipedia, [sentence boundary disambiguation](http://en.wikipedia.org/wiki/Sentence_boundary_disambiguation) (aka sentence boundary disambiguation, sentence segmentation) is defined as:
61
+
62
+ > Sentence boundary disambiguation (SBD), also known as sentence breaking, is the problem in natural language processing of deciding where sentences begin and end. Often natural language processing tools require their input to be divided into sentences for a number of reasons. However sentence boundary identification is challenging because punctuation marks are often ambiguous. For example, a period may denote an abbreviation, decimal point, an ellipsis, or an email address – not the end of a sentence. About 47% of the periods in the Wall Street Journal corpus denote abbreviations. As well, question marks and exclamation marks may appear in embedded quotations, emoticons, computer code, and slang. Languages like Japanese and Chinese have unambiguous sentence-ending markers.
63
+
64
+ The goal of **Pragmatic Segmenter** is to provide a "real-world" segmenter that works out of the box across many languages and does a reasonable job when the format and domain of the input text are unknown. Pragmatic Segmenter does not use any machine-learning techniques and thus does not require training data.
65
+
66
+ Pragmatic Segmenter aims to improve on other segmentation engines in 2 main areas:
67
+ 1) Language support (most segmentation tools only focus on English)
68
+ 2) Text cleaning and preprocessing
69
+
70
+ Pragmatic Segmenter is opinionated and made for the explicit purpose of segmenting texts to create translation memories. Therefore, things such as parenthesis within a sentence are kept as one segment, even if technically there are two or more sentences within the segment in order to maintain coherence. The algorithm is also conservative in that if it comes across an ambiguous sentence boundary it will ignore it rather than splitting.
71
+
72
+ **What do you mean by opinionated?**
73
+
74
+ Pragmatic Segmenter is specifically used for the purpose of segmenting texts for use in translation (and translation memory) related applications. Therefore Pragmatic Segmenter takes a stance on some formatting and segmentation gray areas with the goal of improving the segmentation for the above stated purpose. Some examples:
75
+
76
+ - Removes 'table of contents' style long string of periods ('............')
77
+ - Keeps parenthetical sentences within a sentence as one segment for clarity even though technically there are multiple grammatical sentences within the segment
78
+ - Strips out any xhtml code
79
+ - Conservative in cases where the sentence boundary is ambigious and Pragmatic Segmenter does not have a built in rule
80
+
81
+ *There is an option to turn off text cleaning and preprocessing if you so choose.*
82
+
83
+ ## The Golden Rules
84
+
85
+ *The Golden Rules* are a set of tests I developed that can be run through a segmenter to check its accuracy in regards to edge case scenarios. Most of the papers cited below in *Segmentation Papers and Books* either use the WSJ corpus or Brown corpus from the [Penn Treebank](https://catalog.ldc.upenn.edu/LDC99T42) to test their segmentation algorithm. In my opinion there are 2 limits to using these corpora:
86
+ 1) The corpora may be too expensive for some people ($1,700).
87
+ 2) The majority of the sentences in the corpora are sentences that end with a regular word followed by a period, thus testing the same thing over and over again.
88
+
89
+ > In the Brown Corpus 92% of potential sentence boundaries come after a regular word. The WSJ Corpus is richer with abbreviations and only 83% [53% according to Gale and Church, 1991] of sentences end with a regular word followed by a period.
90
+
91
+ Andrei Mikheev - *Periods, Capitalized Words, etc.*
92
+
93
+ Therefore, I created a set of distinct edge cases to compare segmentation tools on. As most segmentation tools have very high accuracy, in my opinion what is really important to test is how a segmenter handles the edge cases - not whether it can segment 20,000 sentences that end with a regular word followed by a period. These example tests I have named the “Golden Rules". This list is by no means complete and will evolve and expand over time. If you would like to contribute to (or complain about) the test set, please open an issue.
94
+
95
+ The Holy Grail of sentence segmentation appears to be **Golden Rule #18** as no segmenter I tested was able to correctly segment that text. The difficulty being that an abbreviation (in this case a.m./A.M./p.m./P.M.) followed by a capitalized abbreviation (such as Mr., Mrs., etc.) or followed by a proper noun such as a name can be both a sentence boundary and a non sentence boundary.
96
+
97
+ ####Golden Rules (English)
98
+
99
+ 1.) **Simple period to end sentence**
100
+ ```
101
+ Hello World. My name is Jonas.
102
+ => ["Hello World.", "My name is Jonas."]
103
+ ```
104
+
105
+ 2.) **Question mark to end sentence**
106
+ ```
107
+ What is your name? My name is Jonas.
108
+ => ["What is your name?", "My name is Jonas."]
109
+ ```
110
+
111
+ 3.) **Exclamation point to end sentence**
112
+ ```
113
+ There it is! I found it.
114
+ => ["There it is!", "I found it."]
115
+ ```
116
+
117
+ 4.) **One letter upper case abbreviations**
118
+ ```
119
+ My name is Jonas E. Smith.
120
+ => ["My name is Jonas E. Smith."]
121
+ ```
122
+
123
+ 5.) **One letter lower case abbreviations**
124
+ ```
125
+ Please turn to p. 55.
126
+ => ["Please turn to p. 55."]
127
+ ```
128
+
129
+ 6.) **Two letter lower case abbreviations in the middle of a sentence**
130
+ ```
131
+ Were Jane and co. at the party?
132
+ => ["Were Jane and co. at the party?"]
133
+ ```
134
+
135
+ 7.) **Two letter upper case abbreviations in the middle of a sentence**
136
+ ```
137
+ They closed the deal with Pitt, Briggs & Co. at noon.
138
+ => ["They closed the deal with Pitt, Briggs & Co. at noon."]
139
+ ```
140
+
141
+ 8.) **Two letter lower case abbreviations at the end of a sentence**
142
+ ```
143
+ Let's ask Jane and co. They should know.
144
+ => ["Let's ask Jane and co.", "They should know."]
145
+ ```
146
+
147
+ 9.) **Two letter upper case abbreviations at the end of a sentence**
148
+ ```
149
+ They closed the deal with Pitt, Briggs & Co. It closed yesterday.
150
+ => ["They closed the deal with Pitt, Briggs & Co.", "It closed yesterday."]
151
+ ```
152
+
153
+ 10.) **Two letter (prepositive) abbreviations**
154
+ ```
155
+ I can see Mt. Fuji from here.
156
+ => ["I can see Mt. Fuji from here."]
157
+ ```
158
+
159
+ 11.) **Two letter (prepositive & postpositive) abbreviations**
160
+ ```
161
+ St. Michael's Church is on 5th st. near the light.
162
+ => ["St. Michael's Church is on 5th st. near the light."]
163
+ ```
164
+
165
+ 12.) **Possesive two letter abbreviations**
166
+ ```
167
+ That is JFK Jr.'s book.
168
+ => ["That is JFK Jr.'s book."]
169
+ ```
170
+
171
+ 13.) **Multi-period abbreviations in the middle of a sentence**
172
+ ```
173
+ I visited the U.S.A. last year.
174
+ => ["I visited the U.S.A. last year."]
175
+ ```
176
+
177
+ 14.) **Multi-period abbreviations at the end of a sentence**
178
+ ```
179
+ I live in the E.U. How about you?
180
+ => ["I live in the E.U.", "How about you?"]
181
+ ```
182
+
183
+ 15.) **U.S. as sentence boundary**
184
+ ```
185
+ I live in the U.S. How about you?
186
+ => ["I live in the U.S.", "How about you?"]
187
+ ```
188
+
189
+ 16.) **U.S. as non sentence boundary with next word capitalized**
190
+ ```
191
+ I work for the U.S. Government in Virginia.
192
+ => ["I work for the U.S. Government in Virginia."]
193
+ ```
194
+
195
+ 17.) **U.S. as non sentence boundary**
196
+ ```
197
+ I have lived in the U.S. for 20 years.
198
+ => ["I have lived in the U.S. for 20 years."]
199
+ ```
200
+
201
+ 18.) **A.M. / P.M. as non sentence boundary and sentence boundary**
202
+ ```
203
+ At 5 a.m. Mr. Smith went to the bank. He left the bank at 6 P.M. Mr. Smith then went to the store.
204
+ => ["At 5 a.m. Mr. Smith went to the bank.", "He left the bank at 6 P.M.", "Mr. Smith then went to the store."]
205
+ ```
206
+
207
+ 19.) **Number as non sentence boundary**
208
+ ```
209
+ She has $100.00 in her bag.
210
+ => ["She has $100.00 in her bag."]
211
+ ```
212
+
213
+ 20.) **Number as sentence boundary**
214
+ ```
215
+ She has $100.00. It is in her bag.
216
+ => ["She has $100.00.", "It is in her bag."]
217
+ ```
218
+
219
+ 21.) **Parenthetical inside sentence**
220
+ ```
221
+ He teaches science (He previously worked for 5 years as an engineer.) at the local University.
222
+ => ["He teaches science (He previously worked for 5 years as an engineer.) at the local University."]
223
+ ```
224
+
225
+ 22.) **Email addresses**
226
+ ```
227
+ Her email is Jane.Doe@example.com. I sent her an email.
228
+ => ["Her email is Jane.Doe@example.com.", "I sent her an email."]
229
+ ```
230
+
231
+ 23.) **Web addresses**
232
+ ```
233
+ The site is: https://www.example.50.com/new-site/awesome_content.html. Please check it out.
234
+ => ["The site is: https://www.example.50.com/new-site/awesome_content.html.", "Please check it out."]
235
+ ```
236
+
237
+ 24.) **Single quotations inside sentence**
238
+ ```
239
+ She turned to him, 'This is great.' she said.
240
+ => ["She turned to him, 'This is great.' she said."]
241
+ ```
242
+
243
+ 25.) **Double quotations inside sentence**
244
+ ```
245
+ She turned to him, "This is great." she said.
246
+ => ["She turned to him, \"This is great.\" she said."]
247
+ ```
248
+
249
+ 26.) **Double quotations at the end of a sentence**
250
+ ```
251
+ She turned to him, \"This is great.\" She held the book out to show him.
252
+ => ["She turned to him, \"This is great.\"", "She held the book out to show him."]
253
+ ```
254
+
255
+ 27.) **Double punctuation (exclamation point)**
256
+ ```
257
+ Hello!! Long time no see.
258
+ => ["Hello!!", "Long time no see."]
259
+ ```
260
+
261
+ 28.) **Double punctuation (question mark)**
262
+ ```
263
+ Hello?? Who is there?
264
+ => ["Hello??", "Who is there?"]
265
+ ```
266
+
267
+ 29.) **Double punctuation (exclamation point / question mark)**
268
+ ```
269
+ Hello!? Is that you?
270
+ => ["Hello!?", "Is that you?"]
271
+ ```
272
+
273
+ 30.) **Double punctuation (question mark / exclamation point)**
274
+ ```
275
+ Hello?! Is that you?
276
+ => ["Hello?!", "Is that you?"]
277
+ ```
278
+
279
+ 31.) **List (period followed by parens and no period to end item)**
280
+ ```
281
+ 1.) The first item 2.) The second item
282
+ => ["1.) The first item", "2.) The second item"]
283
+ ```
284
+
285
+ 32.) **List (period followed by parens and period to end item)**
286
+ ```
287
+ 1.) The first item. 2.) The second item.
288
+ => ["1.) The first item.", "2.) The second item."]
289
+ ```
290
+
291
+ 33.) **List (parens and no period to end item)**
292
+ ```
293
+ 1) The first item 2) The second item
294
+ => ["1) The first item", "2) The second item"]
295
+ ```
296
+
297
+ 34.) **List (parens and period to end item)**
298
+ ```
299
+ 1) The first item. 2) The second item.
300
+ => ["1) The first item.", "2) The second item."]
301
+ ```
302
+
303
+ 35.) **List (period to mark list and no period to end item)**
304
+ ```
305
+ 1. The first item 2. The second item
306
+ => ["1. The first item", "2. The second item"]
307
+ ```
308
+
309
+ 36.) **List (period to mark list and period to end item)**
310
+ ```
311
+ 1. The first item. 2. The second item.
312
+ => ["1. The first item.", "2. The second item."]
313
+ ```
314
+
315
+ 37.) **List with bullet**
316
+ ```
317
+ • 9. The first item • 10. The second item
318
+ => ["• 9. The first item", "• 10. The second item"]
319
+ ```
320
+
321
+ 38.) **List with hypthen**
322
+ ```
323
+ ⁃9. The first item ⁃10. The second item
324
+ => ["⁃9. The first item", "⁃10. The second item"]
325
+ ```
326
+
327
+ 39.) **Alphabetical list**
328
+ ```
329
+ a. The first item b. The second item c. The third list item
330
+ => ["a. The first item", "b. The second item", "c. The third list item"]
331
+ ```
332
+
333
+ 40.) **Errant newline in the middle of a sentence (PDF)**
334
+ ```
335
+ This is a sentence\ncut off in the middle because pdf.
336
+ => ["This is a sentence\ncut off in the middle because pdf."]
337
+ ```
338
+
339
+ 41.) **Errant newline in the middle of a sentence**
340
+ ```
341
+ It was a cold \nnight in the city.
342
+ => ["It was a cold night in the city."]
343
+ ```
344
+
345
+ 42.) **Lower case list separated by newline**
346
+ ```
347
+ features\ncontact manager\nevents, activities\n
348
+ => ["features", "contact manager", "events, activities"]
349
+ ```
350
+
351
+ 43.) **Geo Coordinates**
352
+ ```
353
+ You can find it at N°. 1026.253.553. That is where the treasure is.
354
+ => ["You can find it at N°. 1026.253.553.", "That is where the treasure is."]
355
+ ```
356
+
357
+ 44.) **Named entities with an exclamation point**
358
+ ```
359
+ She works at Yahoo! in the accounting department.
360
+ => ["She works at Yahoo! in the accounting department."]
361
+ ```
362
+
363
+ 45.) **I as a sentence boundary and I as an abbreviation**
364
+ ```
365
+ We make a good team, you and I. Did you see Albert I. Jones yesterday?
366
+ => ["We make a good team, you and I.", "Did you see Albert I. Jones yesterday?"]
367
+ ```
368
+
369
+ 46.) **Ellipsis at end of quotation**
370
+ ```
371
+ Thoreau argues that by simplifying one’s life, “the laws of the universe will appear less complex. . . .”
372
+ => ["Thoreau argues that by simplifying one’s life, “the laws of the universe will appear less complex. . . .”"]
373
+ ```
374
+
375
+ 47.) **Ellipsis with square brackets**
376
+ ```
377
+ "Bohr [...] used the analogy of parallel stairways [...]" (Smith 55).
378
+ => ["\"Bohr [...] used the analogy of parallel stairways [...]\" (Smith 55)."]
379
+ ```
380
+
381
+ 48.) **Ellipsis as sentence boundary (standard ellipsis rules)**
382
+ ```
383
+ If words are left off at the end of a sentence, and that is all that is omitted, indicate the omission with ellipsis marks (preceded and followed by a space) and then indicate the end of the sentence with a period . . . . Next sentence.
384
+ => ["If words are left off at the end of a sentence, and that is all that is omitted, indicate the omission with ellipsis marks (preceded and followed by a space) and then indicate the end of the sentence with a period . . . .", "Next sentence."]
385
+ ```
386
+
387
+ 49.) **Ellipsis as sentence boundary (non-standard ellipsis rules)**
388
+ ```
389
+ I never meant that.... She left the store.
390
+ => ["I never meant that....", "She left the store."]
391
+ ```
392
+
393
+ 50.) **Ellipsis as non sentence boundary**
394
+ ```
395
+ I wasn’t really ... well, what I mean...see . . . what I'm saying, the thing is . . . I didn’t mean it.
396
+ => ["I wasn’t really ... well, what I mean...see . . . what I'm saying, the thing is . . . I didn’t mean it."
397
+ ```
398
+
399
+ 51.) **4-dot ellipsis**
400
+ ```
401
+ One further habit which was somewhat weakened . . . was that of combining words into self-interpreting compounds. . . . The practice was not abandoned. . . .
402
+ => ["One further habit which was somewhat weakened . . . was that of combining words into self-interpreting compounds.", ". . . The practice was not abandoned. . . ."]
403
+ ```
404
+
405
+ ####Golden Rules (German)
406
+
407
+ 1.) **Quotation at end of sentence**
408
+ ```
409
+ „Ich habe heute keine Zeit“, sagte die Frau und flüsterte leise: „Und auch keine Lust.“ Wir haben 1.000.000 Euro.
410
+ => ["„Ich habe heute keine Zeit“, sagte die Frau und flüsterte leise: „Und auch keine Lust.“", "Wir haben 1.000.000 Euro."]
411
+ ```
412
+
413
+ 2.) **Abbreviations**
414
+ ```
415
+ Es gibt jedoch einige Vorsichtsmaßnahmen, die Du ergreifen kannst, z. B. ist es sehr empfehlenswert, dass Du Dein Zuhause von allem Junkfood befreist.
416
+ => ["Es gibt jedoch einige Vorsichtsmaßnahmen, die Du ergreifen kannst, z. B. ist es sehr empfehlenswert, dass Du Dein Zuhause von allem Junkfood befreist."]
417
+ ```
418
+
419
+ 3.) **Numbers**
420
+ ```
421
+ Was sind die Konsequenzen der Abstimmung vom 12. Juni?
422
+ => ["Was sind die Konsequenzen der Abstimmung vom 12. Juni?"]
423
+ ```
424
+
425
+ ####Golden Rules (Japanese)
426
+
427
+ 1.) **Simple period to end sentence**
428
+ ```
429
+ これはペンです。それはマーカーです。
430
+ => ["これはペンです。", "それはマーカーです。"]
431
+ ```
432
+
433
+ 2.) **Question mark to end sentence**
434
+ ```
435
+ それは何ですか?ペンですか?
436
+ => ["それは何ですか?", "ペンですか?"]
437
+ ```
438
+
439
+ 3.) **Exclamation point to end sentence**
440
+ ```
441
+ 良かったね!すごい!
442
+ => ["良かったね!", "すごい!"]
443
+ ```
444
+
445
+ 4.) **Quotation**
446
+ ```
447
+ 自民党税制調査会の幹部は、「引き下げ幅は3.29%以上を目指すことになる」と指摘していて、今後、公明党と合意したうえで、30日に決定する与党税制改正大綱に盛り込むことにしています。
448
+ => ["自民党税制調査会の幹部は、「引き下げ幅は3.29%以上を目指すことになる」と指摘していて、今後、公明党と合意したうえで、30日に決定する与党税制改正大綱に盛り込むことにしています。"]
449
+ ```
450
+
451
+ 5.) **Errant newline in the middle of a sentence**
452
+ ```
453
+ これは父の\n家です。
454
+ => ["これは父の家です。"]
455
+ ```
456
+
457
+ ####Golden Rules (Arabic)
458
+
459
+ 1.) **Regular punctuation**
460
+ ```
461
+ سؤال وجواب: ماذا حدث بعد الانتخابات الايرانية؟ طرح الكثير من التساؤلات غداة ظهور نتائج الانتخابات الرئاسية الايرانية التي أججت مظاهرات واسعة واعمال عنف بين المحتجين على النتائج ورجال الامن. يقول معارضو الرئيس الإيراني إن الطريقة التي اعلنت بها النتائج كانت مثيرة للاستغراب.
462
+ => ["سؤال وجواب:", "ماذا حدث بعد الانتخابات الايرانية؟", "طرح الكثير من التساؤلات غداة ظهور نتائج الانتخابات الرئاسية الايرانية التي أججت مظاهرات واسعة واعمال عنف بين المحتجين على النتائج ورجال الامن.", "يقول معارضو الرئيس الإيراني إن الطريقة التي اعلنت بها النتائج كانت مثيرة للاستغراب."]
463
+ ```
464
+
465
+ 2.) **Abbreviations**
466
+ ```
467
+ وقال د‪.‬ ديفيد ريدي و الأطباء الذين كانوا يعالجونها في مستشفى برمنجهام إنها كانت تعاني من أمراض أخرى. وليس معروفا ما اذا كانت قد توفيت بسبب اصابتها بأنفلونزا الخنازير.
468
+ => ["وقال د‪.‬ ديفيد ريدي و الأطباء الذين كانوا يعالجونها في مستشفى برمنجهام إنها كانت تعاني من أمراض أخرى.", "وليس معروفا ما اذا كانت قد توفيت بسبب اصابتها بأنفلونزا الخنازير."]
469
+ ```
470
+
471
+ 3.) **Numbers and Dates**
472
+ ```
473
+ ومن المنتظر أن يكتمل مشروع خط أنابيب نابوكو البالغ طوله 3300 كليومترا في 12‪/‬08‪/‬2014 بتكلفة تُقدر بـ 7.9 مليارات يورو أي نحو 10.9 مليارات دولار. ومن المقرر أن تصل طاقة ضخ الغاز في المشروع 31 مليار متر مكعب انطلاقا من بحر قزوين مرورا بالنمسا وتركيا ودول البلقان دون المرور على الأراضي الروسية.
474
+ => ["ومن المنتظر أن يكتمل مشروع خط أنابيب نابوكو البالغ طوله 3300 كليومترا في 12‪/‬08‪/‬2014 بتكلفة تُقدر بـ 7.9 مليارات يورو أي نحو 10.9 مليارات دولار.", "ومن المقرر أن تصل طاقة ضخ الغاز في المشروع 31 مليار متر مكعب انطلاقا من بحر قزوين مرورا بالنمسا وتركيا ودول البلقان دون المرور على الأراضي الروسية."]
475
+ ```
476
+
477
+ 4.) **Time**
478
+ ```
479
+ الاحد, 21 فبراير/ شباط, 2010, 05:01 GMT الصنداي تايمز: رئيس الموساد قد يصبح ضحية الحرب السرية التي شتنها بنفسه. العقل المنظم هو مئير داجان رئيس الموساد الإسرائيلي الذي يشتبه بقيامه باغتيال القائد الفلسطيني في حركة حماس محمود المبحوح في دبي.
480
+ => ["الاحد, 21 فبراير/ شباط, 2010, 05:01 GMT الصنداي تايمز:", "رئيس الموساد قد يصبح ضحية الحرب السرية التي شتنها بنفسه.", "العقل المنظم هو مئير داجان رئيس الموساد الإسرائيلي الذي يشتبه بقيامه باغتيال القائد الفلسطيني في حركة حماس محمود المبحوح في دبي."]
481
+ ```
482
+
483
+ 5.) **Comma**
484
+ ```
485
+ عثر في الغرفة على بعض أدوية علاج ارتفاع ضغط الدم، والقلب، زرعها عملاء الموساد كما تقول مصادر إسرائيلية، وقرر الطبيب أن الفلسطيني قد توفي وفاة طبيعية ربما إثر نوبة قلبية، وبدأت مراسم الحداد عليه
486
+ => ["عثر في الغرفة على بعض أدوية علاج ارتفاع ضغط الدم، والقلب،", "زرعها عملاء الموساد كما تقول مصادر إسرائيلية،", "وقرر الطبيب أن الفلسطيني قد توفي وفاة طبيعية ربما إثر نوبة قلبية،", "وبدأت مراسم الحداد عليه"]
487
+ ```
488
+
489
+ ####Golden Rules (Italian)
490
+
491
+ 1.) **Abbreviations**
492
+ ```
493
+ Salve Sig.ra Mengoni! Come sta oggi?
494
+ => ["Salve Sig.ra Mengoni!", "Come sta oggi?"]
495
+ ```
496
+
497
+ 2.) **Quotations**
498
+ ```
499
+ Una lettera si può iniziare in questo modo «Il/la sottoscritto/a.».
500
+ => ["Una lettera si può iniziare in questo modo «Il/la sottoscritto/a.»."]
501
+ ```
502
+
503
+ 3.) **Numbers**
504
+ ```
505
+ La casa costa 170.500.000,00€!
506
+ => ["La casa costa 170.500.000,00€!"]
507
+ ```
508
+
509
+ ####Golden Rules (Russian)
510
+
511
+ 1.) **Abbreviations**
512
+ ```
513
+ Объем составляет 5 куб.м.
514
+ => ["Объем составляет 5 куб.м."]
515
+ ```
516
+
517
+ 2.) **Quotations**
518
+ ```
519
+ Маленькая девочка бежала и кричала: «Не видали маму?».
520
+ => ["Маленькая девочка бежала и кричала: «Не видали маму?»."]
521
+ ```
522
+
523
+ 3.) **Numbers**
524
+ ```
525
+ Сегодня 27.10.14
526
+ => ["Сегодня 27.10.14"]
527
+ ```
528
+
529
+ ####Golden Rules (Spanish)
530
+
531
+ 1.) **Question mark to end sentence**
532
+ ```
533
+ ¿Cómo está hoy? Espero que muy bien.
534
+ => ["¿Cómo está hoy?", "Espero que muy bien."]
535
+ ```
536
+
537
+ 2.) **Exclamation point to end sentence**
538
+ ```
539
+ ¡Hola señorita! Espero que muy bien.
540
+ => ["¡Hola señorita!", "Espero que muy bien."]
541
+ ```
542
+
543
+ 3.) **Abbreviations**
544
+ ```
545
+ Hola Srta. Ledesma. Buenos días, soy el Lic. Naser Pastoriza, y él es mi padre, el Dr. Naser.
546
+ => ["Hola Srta. Ledesma.", "Buenos días, soy el Lic. Naser Pastoriza, y él es mi padre, el Dr. Naser."]
547
+ ```
548
+
549
+ 4.) **Numbers**
550
+ ```
551
+ ¡La casa cuesta $170.500.000,00! ¡Muy costosa! Se prevé una disminución del 12.5% para el próximo año.
552
+ => ["¡La casa cuesta $170.500.000,00!", "¡Muy costosa!", "Se prevé una disminución del 12.5% para el próximo año."]
553
+ ```
554
+
555
+ 5.) **Quotations**
556
+ ```
557
+ «Ninguna mente extraordinaria está exenta de un toque de demencia.», dijo Aristóteles.
558
+ => ["«Ninguna mente extraordinaria está exenta de un toque de demencia.», dijo Aristóteles."]
559
+ ```
560
+
561
+ ####Golden Rules (Greek)
562
+
563
+ 1.) **Question mark to end sentence**
564
+ ```
565
+ Με συγχωρείτε· πού είναι οι τουαλέτες; Τις Κυριακές δε δούλευε κανένας. το κόστος του σπιτιού ήταν £260.950,00.
566
+ => ["Με συγχωρείτε· πού είναι οι τουαλέτες;", "Τις Κυριακές δε δούλευε κανένας.", "το κόστος του σπιτιού ήταν £260.950,00."]
567
+ ```
568
+
569
+ ####Golden Rules (Hindi)
570
+
571
+ 1.) **Full stop**
572
+ ```
573
+ सच्चाई यह है कि इसे कोई नहीं जानता। हो सकता है यह फ़्रेन्को के खिलाफ़ कोई विद्रोह रहा हो, या फिर बेकाबू हो गया कोई आनंदोत्सव।
574
+ => ["सच्चाई यह है कि इसे कोई नहीं जानता।", "हो सकता है यह फ़्रेन्को के खिलाफ़ कोई विद्रोह रहा हो, या फिर बेकाबू हो गया कोई आनंदोत्सव।"]
575
+ ```
576
+
577
+ ####Golden Rules (Armenian)
578
+
579
+ 1.) **Sentence ending punctuation**
580
+ ```
581
+ Ի՞նչ ես մտածում: Ոչինչ:
582
+ => ["Ի՞նչ ես մտածում:", "Ոչինչ:"]
583
+ ```
584
+
585
+ 2.) **Ellipsis**
586
+ ```
587
+ Ապրիլի 24-ին սկսեց անձրևել...Այդպես էի գիտեի:
588
+ => ["Ապրիլի 24-ին սկսեց անձրևել...Այդպես էի գիտեի:"]
589
+ ```
590
+
591
+ 3.) **Period is not a sentence boundary**
592
+ ```
593
+ Այսպիսով` մոտենում ենք ավարտին: Տրամաբանությյունը հետևյալն է. պարզություն և աշխատանք:
594
+ => ["Այսպիսով` մոտենում ենք ավարտին:", "Տրամաբանությյունը հետևյալն է. պարզություն և աշխատանք:"]
595
+ ```
596
+
597
+ ####Golden Rules (Burmese)
598
+
599
+ 1.) **Sentence ending punctuation**
600
+ ```
601
+ ခင္ဗ်ားနာမည္ဘယ္လိုေခၚလဲ။၇ွင္ေနေကာင္းလား။
602
+ => ["ခင္ဗ်ားနာမည္ဘယ္လိုေခၚလဲ။", "၇ွင္ေနေကာင္းလား။"]
603
+ ```
604
+
605
+ ####Golden Rules (Amharic)
606
+
607
+ 1.) **Sentence ending punctuation**
608
+ ```
609
+ እንደምን አለህ፧መልካም ቀን ይሁንልህ።እባክሽ ያልሽዉን ድገሚልኝ።
610
+ => ["እንደምን አለህ፧", "መልካም ቀን ይሁንልህ።", "እባክሽ ያልሽዉን ድገሚልኝ።"]
611
+ ```
612
+
613
+ ####Golden Rules (Persian)
614
+
615
+ 1.) **Sentence ending punctuation**
616
+ ```
617
+ خوشبختم، آقای رضا. شما کجایی هستید؟ من از تهران هستم.
618
+ => ["خوشبختم، آقای رضا.", "شما کجایی هستید؟", "من از تهران هستم."]
619
+ ```
620
+
621
+ ####Golden Rules (Urdu)
622
+
623
+ 1.) **Sentence ending punctuation**
624
+ ```
625
+ کیا حال ہے؟ ميرا نام ___ ەے۔ میں حالا تاوان دےدوں؟
626
+ => ["کیا حال ہے؟", "ميرا نام ___ ەے۔", "میں حالا تاوان دےدوں؟"]
627
+ ```
628
+
629
+ ## Comparison of Segmentation Tools, Libraries and Algorithms
630
+
631
+ Name | Programming Language | License | GRS (English) | GRS (Other Languages)† | Speed‡
632
+ ---------------------------------------------------------------------| -------------------- | --------------------------------------------------- | ------------- | ---------------------- | -------
633
+ Pragmatic Segmenter | Ruby | [MIT](http://opensource.org/licenses/MIT) | 98.04% | 100.00% | 3.84 s
634
+ [TactfulTokenizer](https://github.com/zencephalon/Tactful_Tokenizer) | Ruby | [GNU GPLv3](http://www.gnu.org/copyleft/gpl.html) | 66.67% | 45.45% | 46.32 s
635
+ [OpenNLP](https://opennlp.apache.org/) | Java | [APLv2](http://www.apache.org/licenses/LICENSE-2.0) | 60.78% | 42.42% | 1.27 s
636
+ [Standford CoreNLP](http://nlp.stanford.edu/software/corenlp.shtml) | Java | [GNU GPLv3](http://www.gnu.org/copyleft/gpl.html) | 58.82% | 27.27% | 0.92 s
637
+ [Splitta](http://www.nltk.org/_modules/nltk/tokenize/punkt.html) | Python | [APLv2](http://www.apache.org/licenses/LICENSE-2.0) | 56.86% | 33.33% | N/A
638
+ [Punkt](http://www.nltk.org/_modules/nltk/tokenize/punkt.html) | Python | [APLv2](http://www.apache.org/licenses/LICENSE-2.0) | 47.06% | 45.45% | 1.79 s
639
+ [SRX English](https://github.com/apohllo/srx-english) | Ruby | [GNU GPLv3](http://www.gnu.org/copyleft/gpl.html) | 29.41% | 24.24% | 6.19 s
640
+ [Scapel](https://github.com/louismullie/scalpel) | Ruby | [GNU GPLv3](http://www.gnu.org/copyleft/gpl.html) | 27.45% | 15.15% | 0.13 s
641
+
642
+ †GRS (Other Languages) is the total of the Golden Rules listed above for all languages other than English. This metric by no means includes all languages, only the ones that have Golden Rules listed above.
643
+ ‡ Speed is based on the performance benchmark results detailed in the section "Speed Performance Benchmarks" below. The number is an average of 10 runs.
644
+
645
+ Other tools not yet tested:
646
+ * [FreeLing](http://nlp.lsi.upc.edu/freeling/)
647
+ * [Alpino](http://www.let.rug.nl/vannoord/alp/Alpino/)
648
+ * [trtok](https://github.com/jirkamarsik/trainable-tokenizer)
649
+ * [segtok](https://pypi.python.org/pypi/segtok/1.1.0)
650
+ * [LingPipe](http://alias-i.com/lingpipe/demos/tutorial/sentences/read-me.html)
651
+
652
+ ## Speed Performance Benchmarks
653
+
654
+ To test the relative performance of different segmentation tools and libraries I created a simple benchmark test. The test takes the 50 English Golden Rules combined into one string and runs it 100 times through the segmenter. This speed benchmark is by no means the most scientific benchmark, but it should help to give some relative performance data. The tests were done on a Mac Pro 3.7 GHz Quad-Core Intel Xeon E5 running 10.9.5. For Punkt the tests were run using the [Ruby port](https://github.com/lfcipriani/punkt-segmenter). For Standford CoreNLP the tests were run using the [Ruby port](https://github.com/louismullie/stanford-core-nlp). For OpenNLP the tests were run using the [Ruby port](https://github.com/louismullie/open-nlp).
655
+
656
+ ## Languages with sentence boundary punctuation that is different than English
657
+
658
+ *If you know of any languages that are missing from the list below, please open an issue. Thank you.*
659
+
660
+ **Pragmatic Segmenter** supports the following languages with regards to sentence boundary punctuation that is different than English:
661
+ * Amharic
662
+ * Arabic
663
+ * Armenian
664
+ * Burmese
665
+ * Chinese
666
+ * Greek
667
+ * Hindi
668
+ * Japanese
669
+ * Persian
670
+ * Urdu
671
+
672
+ ##Segmentation Papers and Books
673
+
674
+ * *Handbook of Natural Language Processing* (Second Edition) - Nitin Indurkhya and Fred J. Damerau (2010) [[amazon](http://www.amazon.com/Handbook-Language-Processing-Learning-Recognition/dp/1420085921)]
675
+ * *Sentence Boundary Detection and the Problem with the U.S.* - Dan Gillick (2009) [[pdf](http://dgillick.com/resource/sbd_naacl_2009.pdf) | [mirror](https://s3.amazonaws.com/tm-town-nlp-resources/sbd_naacl_2009.pdf)]
676
+ * *Thoughts on Word and Sentence Segmentation in Thai* - Wirote Aroonmanakun (2007) [[pdf](http://pioneer.chula.ac.th/~awirote/ling/snlp2007-wirote.pdf) | [mirror](https://s3.amazonaws.com/tm-town-nlp-resources/snlp2007-wirote.pdf)]
677
+ * *Unsupervised Multilingual Sentence Boundary Detection* - Tibor Kiss and Jan Strunk (2005) [[pdf](http://www.linguistics.ruhr-uni-bochum.de/~strunk/ks2005FINAL.pdf) | [mirror](https://s3.amazonaws.com/tm-town-nlp-resources/ks2005FINAL.pdf)]
678
+ * *An Analysis of Sentence Boundary Detection Systems for English and Portuguese Documents* - Carlos N. Silla Jr. and Celso A. A. Kaestner (2004) [[pdf](https://www.cs.kent.ac.uk/pubs/2004/2930/content.pdf) | [mirror](https://s3.amazonaws.com/tm-town-nlp-resources/An+Analysis+of+Sentence+Boundary+Detection+Systems+for+English+and+Portuguese+Documents.pdf)]
679
+ * *Periods, Capitalized Words, etc.* - Andrei Mikheev (2002) [[pdf](https://s3.amazonaws.com/tm-town-nlp-resources/cl-prop.pdf)]
680
+ * *Scaled log likelihood ratios for the detection of abbreviations in text corpora* - Tibor Kiss and Jan Strunk (2002) [[pdf](http://www.linguistics.ruhr-uni-bochum.de/~kiss/publications/abbrev.pdf) | [mirror](https://s3.amazonaws.com/tm-town-nlp-resources/abbrev.pdf)]
681
+ * *Viewing sentence boundary detection as collocation identification* - Tibor Kiss and Jan Strunk (2002) [[pdf](http://www.linguistics.rub.de/~kiss/publications/07v-kiss.pdf) | [mirror](https://s3.amazonaws.com/tm-town-nlp-resources/07v-kiss.pdf)]
682
+ * *Sentence Boundary Detection: A Comparison of Paradigms for Improving MT Quality* - Daniel J. Walker, David E. Clements, Maki Darwin and Jan W. Amtrup (2001) [[pdf](https://www.cs.kent.ac.uk/pubs/2004/2930/content.pdf) | [mirror](https://s3.amazonaws.com/tm-town-nlp-resources/walker.pdf)]
683
+ * *A Sentence Boundary Detection System* - Wendy Chen (2000) [[ppt](www.deg.byu.edu/presentations/SpResConf00.chen/SpResConf00.ppt) | [mirror](https://s3.amazonaws.com/tm-town-nlp-resources/SpResConf00.ppt)]
684
+ * *Tagging Sentence Boundaries* - Andrei Mikheev (2000) [[pdf](http://www.aclweb.org/anthology/A00-2035) | [mirror](https://s3.amazonaws.com/tm-town-nlp-resources/A00-2035.pdf)]
685
+ * *Automatic Extraction of Rules For Sentence Boundary Disambiguation* - E. Stamatatos, N. Fakotakis, AND G. Kokkinakis (1999) [[pdf](https://s3.amazonaws.com/tm-town-nlp-resources/Automatic+Extraction+of+Rules+For+Sentence+Boundary+Disambiguation.pdf)]
686
+ * *A Maximum Entropy Approach to Identifying Sentence Boundaries* - Jeffrey C. Reynar and Adwait Ratnaparkhi (1997) [[pdf](https://www.aclweb.org/anthology/A/A97/A97-1004.pdf) | [mirror](https://s3.amazonaws.com/tm-town-nlp-resources/A97-1004.pdf)]
687
+ * *Adaptive Multilingual Sentence Boundary Disambiguation* - David D. Palmer and Marti A. Hearst (1997) [[pdf](http://people.ischool.berkeley.edu/~hearst/papers/cl-palmer.pdf) | [mirror](https://s3.amazonaws.com/tm-town-nlp-resources/cl-palmer.pdf)]
688
+ * *What is a word, What is a sentence? Problems of Tokenization* - Gregory Grefenstette and Pasi Tapanainen (1994) [[pdf](https://files.ifi.uzh.ch/cl/siclemat/lehre/papers/GrefenstetteTapanainen1994.pdf) | [mirror](https://s3.amazonaws.com/tm-town-nlp-resources/GrefenstetteTapanainen1994.pdf)]
689
+ * *Chapter 2: Tokenisation and Sentence Segmentation* - David D. Palmer [[pdf](http://comp.mq.edu.au/units/comp348/ch2.pdf) | [mirror](https://s3.amazonaws.com/tm-town-nlp-resources/ch2.pdf)]
690
+ * *Using SRX standard for sentence segmentation in LanguageTool* - Marcin Miłkowski and Jarosław Lipski [[pdf](http://marcinmilkowski.pl/downloads/ltc-043-milkowski.pdf) | [mirror](https://s3.amazonaws.com/tm-town-nlp-resources/ltc-043-milkowski.pdf)]
691
+
692
+ ## TODO
693
+
694
+ * Add additional language support
695
+ * Add abbreviation lists for any languages that do not currently have one (only relevant for languages that have the concept of abbreviations with periods)
696
+ * Get Golden Rule #18 passing - Handling of a.m. or p.m. followed by a capitalized non sentence starter (ex. "At 5 p.m. Mr. Smith went to the bank. He left the bank at 6 p.m. Next he went to the store." --> ["At 5 p.m. Mr. Smith went to the bank.", "He left the bank at 6 p.m.", "Next he went to the store."])
697
+
698
+ ## Contributing
699
+
700
+ If you find a text that is incorrectly segmented using this gem, please submit an issue.
701
+
702
+ 1. Fork it ( https://github.com/diasks2/pragmatic_segmenter/fork )
703
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
704
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
705
+ 4. Push to the branch (`git push origin my-new-feature`)
706
+ 5. Create a new Pull Request
707
+
708
+ ## License
709
+
710
+ The MIT License (MIT)
711
+
712
+ Copyright (c) 2015 Kevin S. Dias
713
+
714
+ Permission is hereby granted, free of charge, to any person obtaining a copy
715
+ of this software and associated documentation files (the "Software"), to deal
716
+ in the Software without restriction, including without limitation the rights
717
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
718
+ copies of the Software, and to permit persons to whom the Software is
719
+ furnished to do so, subject to the following conditions:
720
+
721
+ The above copyright notice and this permission notice shall be included in
722
+ all copies or substantial portions of the Software.
723
+
724
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
725
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
726
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
727
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
728
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
729
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
730
+ THE SOFTWARE.