Commit 4c36dbc6 authored by Devon Kearns's avatar Devon Kearns

Imported Upstream version 0.5

parents
New in Version 0.5 (15 July 2012)
* Support for Ruby 1.9.1
* CSV output
* Output files
* Double character replacement typos
* Homoglyphs - used https://en.wikipedia.org/wiki/Homoglyph
* Added IP to country support
* No longer checks domain popularity by default
* Updated some text
* Updated common misspellings from http://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines
New in Version 0.4 (13 September 2011)
* Bitflipping domains
* Homophone domains (Words that sound the same)
* Vowel swap Typos
Title: URLCrazy Readme
Version: 0.5
Description: UrlCrazy is for the study of domainname typos and URL hijacking
Release Date: July 2012
Author: Andrew Horton (urbanadventurer)
Homepage: www.morningstarsecurity.com/research/urlcrazy
Platforms: Linux, Ruby
License: Copyright Andrew Horton, 2012. You have permission to use and distribute this software. You do not have permission to distribute modified versions without permission. You do not have permission to use this as part of a commercial service unless it forms part of a penetration testing service. For example a commercial service that provides domain protection for clients must obtain a license first. Email me if you require a license.
Description
------------
Generate and test domain typos and variations to detect and perform typo squatting, URL hijacking,
phishing, and corporate espionage.
Use Cases:
o) Detect typo squatters profiting from typos on your domain name
o) Protect your brand by registering popular typos
o) Identify typo domain names that will receive traffic intended for another domain
o) Conduct phishing attacks during a penetration test
Features:
o) Generates 15 types of domain variants
o) Knows over 8000 common misspellings
o) Supports cosmic ray induced bit flipping
o) Multiple keyboard layouts (qwerty, azerty, qwertz, dvorak)
o) Checks if a domain variant is valid
o) Test if domain variants are in use
o) Estimate popularity of a domain variant
Types of Domain Variations Supported
----------------------------------
Character Omission.
These typos are created by leaving out a letter of the domain name, one letter at a time. For example, www.goole.com and www.gogle.com
Character Repeat.
These typos are created by repeating a letter of the domain name. For example, www.ggoogle.com and www.gooogle.com
Adjacent Character Swap.
These typos are created by swapping the order of adjacent letters in the domain name. For example, www.googel.com and www.ogogle.com
Adjacent Character Replacement.
These typos are created by replacing each letter of the domain name with letters to the immediate left and right on the keyboard. For example, www.googke.com and www.goohle.com
Double Character Replacement.
These typos are created by replacing identical, consecutive letters of the domain name with letters to the immediate left and right on the keyboard. For example, www.gppgle.com and www.giigle.com
Adjacent Character Insertion.
These typos are created by inserting letters to the immediate left and right on the keyboard of each letter. For example, www.googhle.com and www.goopgle.com
Missing Dot.
These typos are created by omitting a dot from the domainname. For example, wwwgoogle.com and www.googlecom
Strip Dashes.
These typos are created by omitting a dash from the domainname. For example, www.domain-name.com becomes www.domainname.com
Singular or Pluralise.
These typos are created by making a singular domain plural and vice versa. For example, www.google.com becomes www.googles.com and www.games.co.nz becomes www.game.co.nz
Common Misspellings.
Over 8000 common misspellings from Wikipedia. For example, www.youtube.com becomes www.youtub.com and www.abseil.com becomes www.absail.com
Vowel Swapping.
Swap vowels within the domain name except for the first letter. For example, www.google.com becomes www.gaagle.com.
Homophones.
Over 450 sets of words that sound the same when spoken. For example, www.base.com becomes www.bass.com.
Bit Flipping.
Each letter in a domain name is an 8bit character. The character is substituted with the set of valid characters that can be made after a single bit flip. For example, facebook.com becomes bacebook.com, dacebook.com, faaebook.com,fabebook.com,facabook.com, etc.
Homoglyphs.
One or more characters that look similar to another character but are different are called homogylphs. An example is that the lower case l looks similar to the numeral one, e.g. l vs 1. For example, google.com becomes goog1e.com.
Wrong Top Level Domain.
For example, www.trademe.co.nz becomes www.trademe.co.nz and www.google.com becomes www.google.org
Uses the 19 most common top level domains.
Wrong Second Level Domain.
Uses an alternate, valid second level domain for the top level domain.
For example, www.trademe.co.nz becomes www.trademe.ac.nz and www.trademe.iwi.nz
Tips
--------------------------
The output will often be wider than the width of your terminal. If this bothers you, output your report to a file or increase the width of your terminal.
Supported Keyboard Layouts
---------------------------
Keyboard layouts supported are:
* QWERTY
* AZERTY
* QWERTZ
* DVORAK
Is the domain valid?
--------------------
UrlCrazy has a database of valid top level and second level domains. This information has been compiled from Wikipedia and domain registrars. We know whether a domain is valid by checking if it matches toplevel and second level domains. For example, www.trademe.co.bz is a valid domain in Belize which allows any second level domain registrations but www.trademe.xo.nz isn't because xo.nz isn't an allowed second level domain in New Zealand.
Popularity Estimate
-------------------
We can estimate the relative popularity of a typo by measuring how often that typo appears on webpages. Querying goole.com for the number of search results for a typo gives us a indication of how popular a typo is.
The drawback of this approach is that you need to manually identify and omit legitimate domains such as googles.com
For example, consider the following typos for google.com.
25424 gogle.com
24031 googel.com
22490 gooogle.com
19172 googles.com
19148 goole.com
18855 googl.com
17842 ggoogle.com
IP Address
-------------------
An IP address for a typo domainname indicates it is in use.
Tip: An IP repeating for multiple typos or IPs in a close range shows common ownership. For example, gogle.com, gogole.com and googel.com all resolve to 64.233.161.104 which is owned by Google.
Country Code Database
----------------------
http://en.wikipedia.org/wiki/Top-level_domain
http://en.wikipedia.org/wiki/Country_code_top-level_domain
2nd level domains here:
http://www.iana.org/domains/root/db/
See Also
---------
http://en.wikipedia.org/wiki/Wikipedia:AutoWikiBrowser/Typos
http://en.wikipedia.org/wiki/Wikipedia:Typo
http://en.wikipedia.org/wiki/Typosquatting
Strider is tool with similar aims and is produced by Microsoft http://research.microsoft.com/csm/strider/
Installation
-------------
UrlCrazy requires ruby. If you are using Ubuntu or Debian try:
$ sudo apt-get install ruby.
Credits
--------
Authored by Andrew Horton (urbanadventurer). Andrew is a security consultant for Stratsec.net
Thanks to Ruby on Rails for Inflector which allows plural and singular permutations.
Thanks to Wikipedia for the set of common misspellings, homophones, and homoglyphs.
Thanks to software77.net for their IP to country database
This diff is collapsed.
AFGHANISTAN,AF,AFG,APNIC
ALBANIA,AL,ALB,RIPE
ALGERIA,DZ,DZA,AFRINIC
AMERICAN SAMOA,AS,ASM,APNIC
ANDORRA,AD,AND,RIPE
ANGOLA,AO,AGO,AFRINIC
ANGUILLA,AI,AIA,ARIN
ANTARCTICA,AQ,ATA,ARIN
ANTIGUA AND BARBUDA,AG,ATG,ARIN
ARGENTINA,AR,ARG,LACNIC
ARMENIA,AM,ARM,RIPE
ARUBA,AW,ABW,LACNIC
ASCENSION ISLAND,AC,AC-,RIPE
AUSTRALIA,AU,AUS,APNIC
AUSTRIA,AT,AUT,RIPE
AZERBAIJAN,AZ,AZE,RIPE
BAHAMAS,BS,BHS,ARIN
BAHRAIN,BH,BHR,RIPE
BANGLADESH,BD,BGD,APNIC
BARBADOS,BB,BRB,ARIN
BELARUS,BY,BLR,RIPE
BELGIUM,BE,BEL,RIPE
BELIZE,BZ,BLZ,LACNIC
BENIN,BJ,BEN,AFRINIC
BERMUDA,BM,BMU,ARIN
BHUTAN,BT,BTN,APNIC
BOLIVIA,BO,BOL,LACNIC
BOSNIA AND HERZEGOWINA,BA,BIH,RIPE
BOTSWANA,BW,BWA,AFRINIC
BOUVET ISLAND,BV,BVT,ARIN
BRAZIL,BR,BRA,LACNIC
BRITISH INDIAN OCEAN TERRITORY,IO,IOT,APNIC
BRUNEI DARUSSALAM,BN,BRN,APNIC
BULGARIA,BG,BGR,RIPE
BURKINA FASO,BF,BFA,AFRINIC
BURUNDI,BI,BDI,AFRINIC
CAMBODIA,KH,KHM,APNIC
CAMEROON,CM,CMR,AFRINIC
CANADA,CA,CAN,ARIN
CAPE VERDE,CV,CPV,AFRINIC
CAYMAN ISLANDS,KY,CYM,ARIN
CENTRAL AFRICAN REPUBLIC,CF,CAF,AFRINIC
CHAD,TD,TCD,AFRINIC
CHILE,CL,CHL,LACNIC
CHINA,CN,CHN,APNIC
CHRISTMAS ISLAND,CX,CXR,APNIC
COCOS (KEELING) ISLANDS,CC,CCK,APNIC
COLOMBIA,CO,COL,LACNIC
COMOROS,KM,COM,AFRINIC
CONGO THE DEMOCRATIC REPUBLIC OF THE,CD,COD,AFRINIC
CONGO,CG,COG,AFRINIC
COOK ISLANDS,CK,COK,APNIC
COSTA RICA,CR,CRI,LACNIC
COTE D'IVOIRE,CI,CIV,AFRINIC
CROATIA (local name: Hrvatska),HR,HRV,RIPE
CUBA,CU,CUB,LACNIC
CYPRUS,CY,CYP,RIPE
CZECH REPUBLIC,CZ,CZE,RIPE
DENMARK,DK,DNK,RIPE
DJIBOUTI,DJ,DJI,AFRINIC
DOMINICA,DM,DMA,ARIN
DOMINICAN REPUBLIC,DO,DOM,LACNIC
EAST TIMOR,TP,TMP,APNIC
ECUADOR,EC,ECU,LACNIC
EGYPT,EG,EGY,AFRINIC
EL SALVADOR,SV,SLV,LACNIC
EQUATORIAL GUINEA,GQ,GNQ,AFRINIC
ERITREA,ER,ERI,AFRINIC
ESTONIA,EE,EST,RIPE
ETHIOPIA,ET,ETH,AFRINIC
EUROPEAN UNION,EU,EU,RIPE
FALKLAND ISLANDS (MALVINAS),FK,FLK,LACNIC
FAROE ISLANDS,FO,FRO,RIPE
FIJI,FJ,FJI,APNIC
FINLAND,FI,FIN,RIPE
FRANCE METRO,FX,FRA,RIPE
FRANCE,FR,FRA,RIPE
FRENCH GUIANA,GF,GUF,LACNIC
FRENCH POLYNESIA,PF,PYF,APNIC
FRENCH SOUTHERN TERRITORIES,TF,ATF,APNIC
GABON,GA,GAB,AFRINIC
GAMBIA,GM,GMB,AFRINIC
GEORGIA,GE,GEO,RIPE
GERMANY,DE,DEU,RIPE
GHANA,GH,GHA,AFRINIC
GIBRALTAR,GI,GIB,RIPE
GREECE,GR,GRC,RIPE
GREENLAND,GL,GRL,RIPE
GRENADA,GD,GRD,ARIN
GUADELOUPE,GP,GLP,ARIN
GUAM,GU,GUM,APNIC
GUATEMALA,GT,GTM,LACNIC
GUERNSEY,GG,GGY,RIPE
GUINEA,GN,GIN,AFRINIC
GUINEA-BISSAU,GW,GNB,AFRINIC
GUYANA,GY,GUY,LACNIC
HAITI,HT,HTI,LACNIC
HEARD AND MC DONALD ISLANDS,HM,HMD,ARIN
HOLY SEE (VATICAN CITY STATE),VA,VAT,RIPE
HONDURAS,HN,HND,LACNIC
HONG KONG,HK,HKG,APNIC
HUNGARY,HU,HUN,RIPE
ICELAND,IS,ISL,RIPE
INDIA,IN,IND,APNIC
INDONESIA,ID,IDN,APNIC
IRAN (ISLAMIC REPUBLIC OF),IR,IRN,RIPE
IRAQ,IQ,IRQ,RIPE
IRELAND,IE,IRL,RIPE
ISLE OF MAN,IM,IMN,RIPE
ISRAEL,IL,ISR,RIPE
ITALY,IT,ITA,RIPE
JAMAICA,JM,JAM,ARIN
JAPAN,JP,JPN,APNIC
JERSEY,JE,JEY,RIPE
JORDAN,JO,JOR,RIPE
KAZAKHSTAN,KZ,KAZ,RIPE
KENYA,KE,KEN,AFRINIC
KIRIBATI,KI,KIR,APNIC
KOREA DEMOCRATIC PEOPLE'S REPUBLIC OF,KP,PRK,APNIC
KOREA REPUBLIC OF,KR,KOR,APNIC
KUWAIT,KW,KWT,RIPE
KYRGYZSTAN,KG,KGZ,RIPE
LAO PEOPLE'S DEMOCRATIC REPUBLIC,LA,LAO,APNIC
LATVIA,LV,LVA,RIPE
LEBANON,LB,LBN,RIPE
LESOTHO,LS,LSO,AFRINIC
LIBERIA,LR,LBR,AFRINIC
LIBYAN ARAB JAMAHIRIYA,LY,LBY,AFRINIC
LIECHTENSTEIN,LI,LIE,RIPE
LITHUANIA,LT,LTU,RIPE
LUXEMBOURG,LU,LUX,RIPE
MACAU,MO,MAC,APNIC
MACEDONIA,MK,MKD,RIPE
MADAGASCAR,MG,MDG,AFRINIC
MALAWI,MW,MWI,AFRINIC
MALAYSIA,MY,MYS,APNIC
MALDIVES,MV,MDV,APNIC
MALI,ML,MLI,AFRINIC
MALTA,MT,MLT,RIPE
MARSHALL ISLANDS,MH,MHL,APNIC
MARTINIQUE,MQ,MTQ,ARIN
MAURITANIA,MR,MRT,AFRINIC
MAURITIUS,MU,MUS,AFRINIC
MAYOTTE,YT,MYT,APNIC
MEXICO,MX,MEX,LACNIC
MICRONESIA FEDERATED STATES OF,FM,FSM,APNIC
MOLDOVA REPUBLIC OF,MD,MDA,RIPE
MONACO,MC,MCO,RIPE
MONGOLIA,MN,MNG,APNIC
MONTSERRAT,MS,MSR,RIPE
MOROCCO,MA,MAR,AFRINIC
MOZAMBIQUE,MZ,MOZ,AFRINIC
MYANMAR,MM,MMR,APNIC
Montenegro,ME,MNE,RIPE
NAMIBIA,NA,NAM,AFRINIC
NAURU,NR,NRU,APNIC
NEPAL,NP,NPL,APNIC
NETHERLANDS ANTILLES,AN,ANT,LACNIC
NETHERLANDS,NL,NLD,RIPE
NEW CALEDONIA,NC,NCL,APNIC
NEW ZEALAND,NZ,NZL,APNIC
NICARAGUA,NI,NIC,LACNIC
NIGER,NE,NER,AFRINIC
NIGERIA,NG,NGA,AFRINIC
NIUE,NU,NIU,APNIC
NON-SPEC ASIA PAS LOCATION,AP,AFR,APNIC
NORFOLK ISLAND,NF,NFK,APNIC
NORTHERN MARIANA ISLANDS,MP,MNP,APNIC
NORWAY,NO,NOR,RIPE
OMAN,OM,OMN,RIPE
PAKISTAN,PK,PAK,APNIC
PALAU,PW,PLW,APNIC
PALESTINIAN TERRITORY OCCUPIED,PS,PSE,RIPE
PANAMA,PA,PAN,LACNIC
PAPUA NEW GUINEA,PG,PNG,APNIC
PARAGUAY,PY,PRY,LACNIC
PERU,PE,PER,LACNIC
PHILIPPINES,PH,PHL,APNIC
PITCAIRN,PN,PCN,APNIC
POLAND,PL,POL,RIPE
PORTUGAL,PT,PRT,RIPE
PUERTO RICO,PR,PRI,ARIN
QATAR,QA,QAT,RIPE
RESERVED,ZZ,ZZZ,IANA
REUNION,RE,REU,APNIC
ROMANIA,RO,ROM,RIPE
RUSSIAN FEDERATION,RU,RUS,RIPE
RWANDA,RW,RWA,AFRINIC
SAINT KITTS AND NEVIS,KN,KNA,ARIN
SAINT LUCIA,LC,LCA,ARIN
SAINT VINCENT AND THE GRENADINES,VC,VCT,ARIN
SAMOA,WS,WSM,APNIC
SAN MARINO,SM,SMR,RIPE
SAO TOME AND PRINCIPE,ST,STP,AFRINIC
SAUDI ARABIA,SA,SAU,RIPE
SENEGAL,SN,SEN,AFRINIC
SEYCHELLES,SC,SYC,AFRINIC
SIERRA LEONE,SL,SLE,AFRINIC
SINGAPORE,SG,SGP,APNIC
SLOVAKIA (Slovak Republic),SK,SVK,RIPE
SLOVENIA,SI,SVN,RIPE
SOLOMON ISLANDS,SB,SLB,APNIC
SOMALIA,SO,SOM,AFRINIC
SOUTH AFRICA,ZA,ZAF,AFRINIC
SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS,GS,SGS,LACNIC
SPAIN,ES,ESP,RIPE
SRI LANKA,LK,LKA,APNIC
ST. HELENA,SH,SHN,ARIN
ST. PIERRE AND MIQUELON,PM,SPM,ARIN
SUDAN,SD,SDN,AFRINIC
SURINAME,SR,SUR,LACNIC
SVALBARD AND JAN MAYEN ISLANDS,SJ,SJM,RIPE
SWAZILAND,SZ,SWZ,AFRINIC
SWEDEN,SE,SWE,RIPE
SWITZERLAND,CH,CHE,RIPE
SYRIAN ARAB REPUBLIC,SY,SYR,RIPE
Serbia and Montenegro,CS,CS,RIPE
Serbia and Montenegro,YU,YUG,RIPE
Serbia,RS,SRB,RIPE
TAIWAN; REPUBLIC OF CHINA (ROC),TW,TWN,APNIC
TAJIKISTAN,TJ,TJK,RIPE
TANZANIA UNITED REPUBLIC OF,TZ,TZA,AFRINIC
THAILAND,TH,THA,APNIC
TIMOR-LESTE,TL,TLS,APNIC
TOGO,TG,TGO,AFRINIC
TOKELAU,TK,TKL,APNIC
TONGA,TO,TON,APNIC
TRINIDAD AND TOBAGO,TT,TTO,LACNIC
TUNISIA,TN,TUN,AFRINIC
TURKEY,TR,TUR,RIPE
TURKMENISTAN,TM,TKM,RIPE
TURKS AND CAICOS ISLANDS,TC,TCA,ARIN
TUVALU,TV,TUV,APNIC
UGANDA,UG,UGA,AFRINIC
UKRAINE,UA,UKR,RIPE
UNITED ARAB EMIRATES,AE,ARE,RIPE
UNITED KINGDOM,GB,GBR,RIPE
UNITED KINGDOM,UK,GBR,RIPE
UNITED STATES MINOR OUTLYING ISLANDS,UM,UMI,ARIN
UNITED STATES,US,USA,ARIN
URUGUAY,UY,URY,LACNIC
UZBEKISTAN,UZ,UZB,RIPE
VANUATU,VU,VUT,APNIC
VENEZUELA,VE,VEN,LACNIC
VIET NAM,VN,VNM,APNIC
VIRGIN ISLANDS (BRITISH),VG,VGB,ARIN
VIRGIN ISLANDS (U.S.),VI,VIR,ARIN
WALLIS AND FUTUNA ISLANDS,WF,WLF,APNIC
WESTERN SAHARA,EH,ESH,AFRINIC
YEMEN,YE,YEM,RIPE
ZAMBIA,ZM,ZMB,AFRINIC
ZIMBABWE,ZW,ZWE,AFRINIC
ÅLAND ISLANDS,AX,ALA,RIPE
SAINT MARTIN,MF,MAF,ARIN
File added
class Countrylookup
# This is borrowed from WhatWeb
# Lookup code developed by Matthias Wachter for rubyquiz.com and used with permission.
# Local IPv4 addresses are represented as ZZ according to an ISO convention.
# How to Update Database
# ----------------------
# rm plugins/country-ips.dat plugins/IpToCountry.csv
# wget software77.net/geo-ip/?DL=1 -O plugins/IpToCountry.csv.gz
# gzip -d plugins/IpToCountry.csv.gz
def Countrylookup.startup
# ok, set up @rfile. open once.
folder=File.expand_path(File.dirname(__FILE__))
country_db = folder + "/country-ips.dat"
if File.exists?(country_db)
@rfile=File.open(country_db,"rb")
else
if File.exists?(folder + "/IpToCountry.csv")
# pack that file & do it once
last_start=nil
last_end=nil
last_country=nil
File.open(folder + "/country-ips.dat","wb") do |wfile|
IO.foreach(folder + "/IpToCountry.csv") do |line|
next if line[0..0] =="#"
next if !(line =~ /^"/ )
s,e,d1,d2,co=line.delete!("\"").split(",")
s,e = s.to_i,e.to_i
if !last_start
# initialize with first entry
last_start,last_end,last_country = s,e,co
else
if s==last_end+1 and co==last_country
# squeeze if successive ranges have zero gap
last_end=e
else
# append last entry, remember new one
wfile << [last_start,last_end,last_country].pack("NNa2")
last_start,last_end,last_country = s,e,co
end
end
end
# print last entry
if last_start
wfile << [last_start,last_end,last_country].pack("NNa2")
end
end
# open the DB now
@rfile=File.open(country_db,"rb")
else
raise "Aborting: Cannot find country database."
end
end
f = folder + "/country-codes.txt"
@ccnames={};
File.open(f,"r:UTF-8").readlines.each do |line|
x=line.split(",");
@ccnames[x[1]] = x[0]
end
end
def Countrylookup.ip2cc(ip)
found=[]
if @rfile and ip and ip =~ /^([0-9]{1,3}\.){3}[0-9]{1,3}$/
@rfile.seek(0,IO::SEEK_END)
record_max=@rfile.pos/10-1
# build a 4-char string representation of IP address
# in network byte order so it can be a string compare below
ipstr= ip.split(".").map {|x| x.to_i.chr}.join
# low/high water marks initialized
low,high=0,record_max
while true
mid=(low+high)/2 # binary search median
@rfile.seek(10*mid) # one record is 10 byte, seek to position
str=@rfile.read(8) # for range matching, we need only 8 bytes
# at comparison, values are big endian, i.e. packed("N")
if ipstr>=str[0,4] # is this IP not below the current range?
if ipstr<=str[4,4] # is this IP not above the current range?
#puts # a perfect match, voila!
cc=@rfile.read(2)
found =[cc,@ccnames[cc]]
break
else
low=mid+1 # binary search: raise lower limit
end
else
high=mid-1 # binary search: reduce upper limit
end
if low>high # no entries left? nothing found
#m << {:string=>"No country"}
break
end
end
end
found
end
end
This diff is collapsed.
module ActiveSupport
Inflector.inflections do |inflect|
inflect.plural(/$/, 's')
inflect.plural(/s$/i, 's')
inflect.plural(/(ax|test)is$/i, '\1es')
inflect.plural(/(octop|vir)us$/i, '\1i')
inflect.plural(/(alias|status)$/i, '\1es')
inflect.plural(/(bu)s$/i, '\1ses')
inflect.plural(/(buffal|tomat)o$/i, '\1oes')
inflect.plural(/([ti])um$/i, '\1a')
inflect.plural(/sis$/i, 'ses')
inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
inflect.plural(/(hive)$/i, '\1s')
inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
inflect.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
inflect.plural(/([m|l])ouse$/i, '\1ice')
inflect.plural(/^(ox)$/i, '\1en')
inflect.plural(/(quiz)$/i, '\1zes')
inflect.singular(/s$/i, '')
inflect.singular(/(n)ews$/i, '\1ews')
inflect.singular(/([ti])a$/i, '\1um')
inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '\1\2sis')
inflect.singular(/(^analy)ses$/i, '\1sis')
inflect.singular(/([^f])ves$/i, '\1fe')
inflect.singular(/(hive)s$/i, '\1')
inflect.singular(/(tive)s$/i, '\1')
inflect.singular(/([lr])ves$/i, '\1f')
inflect.singular(/([^aeiouy]|qu)ies$/i, '\1y')
inflect.singular(/(s)eries$/i, '\1eries')
inflect.singular(/(m)ovies$/i, '\1ovie')
inflect.singular(/(x|ch|ss|sh)es$/i, '\1')
inflect.singular(/([m|l])ice$/i, '\1ouse')
inflect.singular(/(bus)es$/i, '\1')
inflect.singular(/(o)es$/i, '\1')
inflect.singular(/(shoe)s$/i, '\1')
inflect.singular(/(cris|ax|test)es$/i, '\1is')
inflect.singular(/(octop|vir)i$/i, '\1us')
inflect.singular(/(alias|status)es$/i, '\1')
inflect.singular(/^(ox)en/i, '\1')
inflect.singular(/(vert|ind)ices$/i, '\1ex')
inflect.singular(/(matr)ices$/i, '\1ix')
inflect.singular(/(quiz)zes$/i, '\1')
inflect.irregular('person', 'people')
inflect.irregular('man', 'men')
inflect.irregular('child', 'children')
inflect.irregular('sex', 'sexes')
inflect.irregular('move', 'moves')
inflect.irregular('cow', 'kine')
inflect.uncountable(%w(equipment information rice money species series fish sheep))
end
end
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment