diff --git a/.github/mergeable.yml b/.github/mergeable.yml new file mode 100644 index 000000000..81d69dc2f --- /dev/null +++ b/.github/mergeable.yml @@ -0,0 +1,21 @@ +mergeable: + pull_requests: + stale: + days: 14 + message: 'This PR is stale. Please follow up!' + + label: + must_include: + regex: '(new-feature)|(documentation)|(bug-fixes)|(enhancement)|(needs-migration)|(packages-updated)|(miscellaneous)' + message: 'Can you please add a valid label! [One of (new-feature) / (documentation) / (bug-fixes) / (enhancement) / (needs-migration) / (packages-updated) / (miscellaneous)]' + must_exclude: + regex: '(do-not-merge)' + message: 'This PR is work in progress. Cannot be merged yet.' + + description: + no_empty: + enabled: true + message: 'Can you please add a description!' + must_exclude: + regex: 'do not merge' + message: 'This PR is work in progress. Cannot be merged yet.' diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 000000000..5026bfca6 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,21 @@ +name-template: $NEXT_PATCH_VERSION +tag-template: $NEXT_PATCH_VERSION +branches: master +template: | + # What's Changed + $CHANGES +categories: + - title: ЁЯЪА Features + label: new-feature + - title: ЁЯРЫ Bug Fixes + label: bug-fixes + - title: ЁЯУЦ Documentation + label: documentation + - title: ЁЯТп Enhancements + label: enhancement + - title: ЁЯЪТ Migrations + label: needs-migration + - title: ЁЯУж Packages Updated + label: packages-updated + - title: ЁЯС║ Miscellaneous + label: miscellaneous diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 000000000..ace51d00b --- /dev/null +++ b/.pylintrc @@ -0,0 +1,433 @@ +[MASTER] + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS + +# Add files or directories matching the regex patterns to the blacklist. The +# regex matches against base names, not paths. +ignore-patterns= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. +jobs=1 + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=yes + +# Specify a configuration file. +#rcfile= + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +# disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. + +disable=invalid-name, + trailing-whitespace, + invalid-characters-in-docstring, + import-error, + too-few-public-methods + +enable= + + +[REPORTS] + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio).You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages +reports=no + +# Activate the evaluation score. +score=yes + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + + +[BASIC] + +# Naming hint for argument names +argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Regular expression matching correct argument names +argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Naming hint for attribute names +attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Regular expression matching correct attribute names +attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Naming hint for class attribute names +class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Regular expression matching correct class attribute names +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Naming hint for class names +class-name-hint=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression matching correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Naming hint for constant names +const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression matching correct constant names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming hint for function names +function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Regular expression matching correct function names +function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Good variable names which should always be accepted, separated by a comma +good-names=e,i,j,k,ex,Run,_ + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no + +# Naming hint for inline iteration names +inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ + +# Regular expression matching correct inline iteration names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Naming hint for method names +method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Regular expression matching correct method names +method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Naming hint for module names +module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression matching correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +property-classes=abc.abstractproperty + +# Naming hint for variable names +variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Regular expression matching correct variable names +variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=119 + +# Maximum number of lines in a module +max-module-lines=1000 + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma,dict-separator + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[SIMILARITIES] + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + +# Minimum lines number of a similarity. +min-similarity-lines=4 + + +[SPELLING] + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_,_cb + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,future.builtins + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict,_fields,_replace,_source,_make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in a if statement +max-bool-expr=5 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of statements in function / method body +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + + +[IMPORTS] + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,TERMIOS,Bastion,rexec + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception +output-format=colorized +max-line-length=119 diff --git a/README.md b/README.md index 3ed4cfa88..26b4942fe 100644 --- a/README.md +++ b/README.md @@ -59,4 +59,17 @@ We have classified entities into four main types i.e. *numeral*, *pattern*, *tem **Numeral, temporal and pattern** have been moved to ner_v2 for language portability with more flexible detection logic. In ner_v1, currently only **text** entity has language support. We will be moving it to ner_v2 without any major API changes. +### **Contribution Guidelines** +Currently, you can contribute to ner_v2 in Chatbot NER either by adding **Training Data** or by contributing **Detection Patterns** in form of regex. +We will work on removing few architectural limitations which will ease out process of adding **ML models** and **New Entities** in future. + +- **Adding Training Data**: You can significantly improve detection capabilities of Chatbot NER by simply adding data in csv files. + For example, date detection in Hindi and Hinglish can be improved by adding data in csv files mentioned in the image below. You can refer to + documentation for [date](https://github.com/hellohaptik/chatbot_ner/tree/develop/ner_v2/detectors/temporal/date), [time](https://github.com/hellohaptik/chatbot_ner/tree/develop/ner_v2/detectors/temporal/time) and [numbers](https://github.com/hellohaptik/chatbot_ner/tree/develop/ner_v2/detectors/numeral/number) respectively if you wish to contribute. + ![Date Contribution](docs/images/date_contribution_example.png) +- **Adding Detection Pattern**: You can simply add custom language patterns for different languages by adding simple functions. An example of adding +custom pattern for detecting number of people can be referred [here](https://github.com/hellohaptik/chatbot_ner/tree/develop/ner_v2/detectors/numeral/number). + +Please refer to general steps of contribution, approval and coding guidelines mentioned +[here](https://github.com/hellohaptik/chatbot_ner/tree/develop/docs/contributing.md). diff --git a/chatbot_ner/urls.py b/chatbot_ner/urls.py index 341208141..6acd460b0 100755 --- a/chatbot_ner/urls.py +++ b/chatbot_ner/urls.py @@ -49,5 +49,9 @@ url(r'^entities/train_crf_model', external_api.train_crf_model), url(r'^entities/languages/v1/(?P.+)$', external_api.entity_language_view), - url(r'^entities/data/v1/(?P.+)$', external_api.entity_data_view) + url(r'^entities/data/v1/(?P.+)$', external_api.entity_data_view), + + # Read unique values for text entity + url(r'^entities/values/v1/(?P.+)$', external_api.read_unique_values_for_text_entity), + ] diff --git a/data/entity_data/airport_code.csv b/data/entity_data/airport_code.csv new file mode 100644 index 000000000..e0a468560 --- /dev/null +++ b/data/entity_data/airport_code.csv @@ -0,0 +1,6951 @@ +value,variants +IXA,Agartala|IXA +AGR,Agra|AGR +AMD,Ahmedabad | AMD | gujarat | ahemdabad | Ahemdabad | ahemabad | amdabad | Gandhinagar | Ahmedab | SVPI | Ahemdabaad | hemdabad | ahemebadad | ahmadabad +IXD,Allahabad|IXD | Allhabaad| ald +ATQ,Amritsar|ATQ | amtistsar +IXU,Aurangabad | IXU | AWB +IXB,Bagdogra|IXB|Siliguri| darjiling | dhupguri +BLR,Bangalore|BLR | Bengaluru | bangaluru | bnglore |blore | Blore | benglour| banaglore | blgr | banglore | bangluru | bengalore | bengalor +RPR,raipur +DXB,dubai +DUB,dublin +IXG,Belgaum | belagum +SYD,sydney +MIA,miami +VER,VER|Veracruz +DHM,dharamsala| dharmasala +PBH,paro | bhutan +BHU,Bhavnagar|BHU +BHO,Bhopal|BHO +BBI,Bhubaneswar | BBI | bbsr | bhuvneshwar | bhuvaneshwar | bhuvneswar | Bhubneswr | cuttack | bbs | orissa | bhubesneshwar | bhuneshwer | Bhubaneswer +BHJ,Bhuj|BHJ +CCU,Calcutta | Kolkata | CCU | kolakta | colkatta | howrah | Dum | Hwh | Hawrah | korkata | kalkata | Culcata +IXC,Chandigarh|IXC | +MAA,Chennai | Madras | MAA | channai +COK,Cochin | COK | Ernakulam | Kochi | ERS | cochi +CJB,Coimbatore|CJB +NMB,Daman|NMB +DED,Dehradun|DED|Dehra dun | DDN | dehardun +DIB,Dibrugarh|DIB | Mohanbari +DMU,Dimapur|DMU +DIU,Diu|DIU | Daman and Diu +GAU,Gauhati|GAU | Guwahati | assam | guvahati | ghy | guwati +GOI,Goa | GOI | Dum | Hwh | gova +GWL,Gwalior|GWL | Guwalior +HBX,Hubli|HBX +HYD,Hyderabad | HYD | hyberbad | Shamsabad | hydarabad| haydrabad | secundrabad | haudarabad +IMF,Imphal|IMF +IDR,Indore|IDR | INDB +JAI,Jaipur | jaip | jaypur +IXJ,Jammu | IXJ | jamu +JGA,Jamnagar|JGA +IXW,Jamshedpur|IXW +JDH,Jodhpur | JDH | jodh +JRH,Jorhat|JRH +KNU,Kanpur|KNU +HJR,Khajuraho|HJR +CCJ,Kozhikode | Calicut | CCJ +IXL,Leh|IXL | Ladakh +LKO,Lucknow | LKO | lakhanw | Lakhnow | LKW +LUH,Ludhiana|LUH +IXM,Madurai|IXM | +IXE,Mangalore|IXE | Mangaluru | manglor | manglor +BOM,Mumbai | Bombay | BOM | Mum | mumabi | mumnai | bombsy | bambay +NAG,Nagpur|NAG | ngp +NDC,Nanded|NDC +CDG,Charles De Gaulle| Paris +ISK,Nasik|ISK | Nashik +DEL,New Delhi | DEL | Delhi | delhi | new delhi | dehli | delgi | dli | Ndls | dli | Dil | dheli | new delh | dilhi | Gaziabad | xelhi | deli +PAT,Patna|PAT | PNC | ptna +PNY,Pondicherry|PNY | Pudducherry +PNQ,Poona |Pune||PNQ +PBD,Porbandar|PBD +SLV,SLV| Shimla | slv +IXZ,Port Blair|IXZ | Andaman | Andaman and Nicobar Island|portblair| fortblair | fortblair +PUT,Puttaparthi +BEK,Rae Bareli | BEK | Bareli | bareilly +RAJ,Rajkot +IXR,Ranchi|IXR|Rachi +SHL,Shillong|SHL +IXS,Silchar|IXS +SXR,Srinagar|SXR +STV,Surat|STV +TEZ,Tezpur|TEZ +TRZ,Tiruchirapally|TRZ|Tiruchirapalli|trichy|trichi|Trichinopoly|Tiruchi| thirupathi +TIR,Tirupati|TIR | triupati | TPW | terupati +TRV,Trivandrum|TRV | Tiruvannanthapuram | Thiruvananthapuram | Thiruvanthapuram | trivandram | thiruvanadhapuram | Tiruvannatapuram +UDR,Udaipur|UDR +BDQ,Vadodara|BDQ | Baroda |badodra | vodra +VNS,Varanasi|VNS | Banaras|varanshi | Varanshi | vanaras +VGA,Vijayawada|VGA | bijaywda +VTZ,Vishakhapatnam | VTZ | Vizag | vishakpatnam Vishakapatam | visakhaptnam | vskp | Vskp | vizak | visakapatnm | visakhapatnam | visakapatanam +TCR,tuticorin | Thoothukkudi | Oothukudi | Tirunelveli | thuthukuti +BKK,Bangkok +SIN,Singapore +DPS,Bali +AUH,Abu Dhabi |Abudhabi | abushabi | abu +SHJ,Sharjah +CMB,Colombo +MRU,Mauritius +LHR,London +HKT,Phuket +KTM,Kathmandu +DAC,Dhaka +KHI,Karachi +SFO,San francisco +BER,Berlin +FRA,Frankfurt +PVG,Shanghai | Pudong +JED,Jeddah +RUH,Riyadh +KWI,Kuwait +MCT,Muscat +KHS,KHS| khasab +DOH,Doha | qatar +YTO,Toronto +HKG,Hong Kong +IXY,Kandla +MNL,Manila +MFM,Macau +AGA,Adagir +JNB,Johannesburg | Johanesburg |Johansburg |Johnnesburg +ACC,Accra +AGX,Agatti Island | Agatti +AHB,Abha +AJL,Aizawl +AKD,Akola +ALA,Almaty +AMM,Amman +AMS,Amsterdam +BDO,Bandung +BEP,Bellary +BFI,Seattle +BGR,Bangor +BKB,Bikaner +BKR,Bokoro +BRE,Bremen +BXN,Bodrum +BXU,Butuan +CAN,Guangzhou +CGO,Zhengzhou +CGP,Chittagong +CLE,Cleveland +CLT,"Charlotte, NC | Douglas" +CNS,Cairns +CNX,Chiang Mai +COH,Cooch Behar +CPT,Cape Town | cpt +CSN,Carson City +DAR,Dar Es Salaam | Es Salaam +DBD,Dhanbad +DBV,Dubrovnik +DMK,Bangkok|bankok | suvarnabhumi +DVO,Davao +EBB,Entebbe +EDI,Edinburgh +EDL,Eldoret +ESB,Ankara +FBD,Faizabad +FIH,Kinshasa +FRU,Bishkek +GAY,Gaya +GIZ,Jazan | Jizan +GOP,Gorakhpur +GUA,Guatemala City +GVA,Geneva +HAN,Hanoi +HEM,Helsinki | finland +HGL,Helgoland +ICN,Seoul All Airports +IXK,Keshod +IXP,Pathankot +IXI,IXI|Lilabari +JLR,Jabalpur | JBP +JMU,Jiamusi +JUB,Juba +KAB,Kariba +KBL,Kabul +KBV,Krabi +UTP,UTP | Pattaya | utapao +KCZ,Kochi Perfecture | kochi prefecture | kochi perfacture +KDU,Skardu +KIS,Kisumu +KLH,Kolhapur +KMG,Kunming +KMK,Makabana +KRK,Krakow +KRT,Khartoum +KTU,Kota +KUD,Kudat +KUN,Kaunas +LBS,Labasa +LGK,Langkawi +LHE,Lahore +LOS,Lagos +LTU,Latur +LUN,Lusaka +MBA,Mombasa +MED,Al Madinah | Madina +MFR,Medford +MEL,Melbourne | tullamarine +MLE,Male | Maldives +MPM,Maputo +MSP,Minneapolis +MUC,Munich +MUX,Multan +MYQ,Mysore +MZU,Muzaffarpur +NWA,Moheli +ODS,Odessa +ONT,Ontario +PAB,Bilaspur +PEK,Beijing | china +PGH,Pantnagar +PKR,Pokhara +PNH,Phnom Penh | Penh | phnom | Cambodia +PRG,Prague +PSK,Dublin +PTY,Panama City +QOH,Kiev +RAB,Rabaul +RAS,Rasht +RBE,Ratanakiri +REC,Recife +REN,Orenburg +REW,Rewa +RGN,Yangon +RIX,Riga +RJA,Rajahmundry +SAO,Sao Paulo All Airports +SAW,Sabiha Gokcen +SEZ,Mahe Island | Seychelles +SGN,Ho Chi Minh City +SSH,Sharm El Sheikh +STR,Stuttgart +SUA,Stuart +SXV,Salem +SZB,Sultan Abdul Aziz Shah +TBS,Tbilisi +TCO,Tumaco +TEI,Tezu +THR,Tehran +TIF,Taif +TIP,Tripoli +TJV,Thanjavur +TNI,Satna +VNO,Vilnius +WAW,Warsaw | poland +WNZ,Wenzhou +WRO,Wroclaw +WRY,Westray +WUH,Wuhan +XFW,Hamburg +XMN,Xiamen +YBW,Calgary +YIW,Yiwu +YVR,Vancouver +ZAG,Zagreb +ZRH,Zurich +KUU,Kullu|Manali| Kullu manali | Bhuntar +DMM,Ad Dammam | Dammam +DMS,Dammam-Sabtco Bus St +EIS,Terrance B. Lettsome International Airport | Beef Island| British Virgin Islands| bvi +CAH,Vietnam | Ca Mau | mau +AMH,Arba Minch +PSA,Pisa|Italy +BSB,Brasilia | Presidente Juscelino Kubitschek| +SBP,San Luis Obispo USA | SLO +RMF,Marsa Alam International Egypt | alam +TSN,Tianjin Binhai In | Tianjin +TLV,Ben Gurion In | Israel | Tel Aviv +AAN,Al Ain +JNU,Boundary Bay| Juneau +KGI,Kalgoorlie| Australia +SLI,Solwezi| Zambia +RDM,Roberts Field | Redmond +BRD,Brainerd Lakes Regional| UK +RTM,Rotterdam The Hague | Rotterdam Zestienhoven +LRD,Laredo International +PNP,Popondetta | Girua +ROK,Rockhampton +CPH,Copenhagen +OGL,Ogle +HBT,King Khaled Military City | KMC +CDP,Cuddapah | kadapa +MAO,Eduardo Gomes | Manaus +OSL,Oslo +BRU,Brussel|Brussels|Brusel|Brussal|Brusal +SAG,Shirdi|sirdi|sherdi +HGH,Hangzhou +BCN,Barcelona|barselona|barcalona +LIS,Lisbon|portugal|lisban|pourtugal +MAD,madrid|spain|maidrid +JSA,Jaisalmer | Jaiselmer | JSA +AAB,Arrabury +AAC,Al Arish +AAD,Ad-Dabbah +AAE,Annaba +AAF,Apalachicola +AAG,Arapoti +AAI,Arraias +AAJ,Awaradam +AAK,Aranuka +AAL,Aalborg +AAO,Anaco +AAQ,Anapa +AAR,Aarhus +AAS,Apalapsili +AAT,Altay +AAV,Surallah +AAW,Abbottabad +AAX,Araxa +AAY,Al Ghaydah +ABA,Abakan +ABC,Albacete +ABD,Abadan +ABF,Abaiang +ABH,Alpha +ABI,Abilene +ABJ,Abidjan +ABK,Kabri Dar +ABL,Ambler +ABM,"Bamaga, Queensland" +ABN,Albina +ABO,Aboisso +ABP,Atkamba +ABQ,Albuquerque +ABS,Abu Simbel +ABT,Al Baha |Al Aqiq +ABU,Atambua +ABV,Abuja +ABW,Abau +ABX,Albury +ABZ,Aberdeen +ACA,Acapulco +ACB,Bellaire +ACD,Acandi +ACE,Arrecife +ACH,Altenrhein +ACI,Alderney +ACJ,Anuradhapura +ACL,Aguaclara +ACN,Ciudad Acuna +ACO,Ascona +ACP,Sahand +ACR,Araracuara +ACS,Achinsk +ACT,Waco +ACU,Achutupo +ACV,Arcata | Eureka +ACX,Xingyi +ACY,Atlantic City +ACZ,Zabol +ADA,Adana +ADB,Izmir | Adnan Menderes +ADC,Andakombe +ADD,Addis Ababa +ADE,Aden +ADF,Adiyaman +ADG,Adrian +ADH,Aldan +ADI,Arandis +ADK,Adak Island +ADL,Adelaide +ADN,Andes +ADO,Andamooka +ADQ,Kodiak +ADS,Addison +ADU,Ardabil +ADV,Andover +ADW,Camp Springs +ADZ,San Andres Island +AEA,Abemama Atoll +AED,Aleneva +AEG,Aek Godang +AEH,Abecher +AEI,Algeciras +AEK,Aseki +AEL,Albert Lea +AEO,Aioun El Atrouss +AER,Adler/Sochi +AES,Aalesund +AET,Allakaket +AEU,Abu Musa +AEX,"Alexandria, LA" +AEY,Akureyri +AFD,Port Alfred +AFI,Amalfi +AFL,Alta Floresta +AFN,Jaffrey +AFO,Afton +AFR,Afore +AFS,Zarafshan +AFT,Afutara +AFY,Afyon +AFZ,Sabzevar +AGD,Anggi +AGF,Agen +AGG,Angoram +AGH,Angelholm | Helsingborg +AGI,Wageningen +AGJ,Aguni +AGK,Kagua +AGL,Wanigela +AGM,Tasiilaq +AGN,Angoon +AGO,Magnolia +AGP,Malaga +AGQ,Agrinion +AGS,Augusta +AGT,Ciudad Del Este +AGU,Aguascalientes +AGV,Acarigua +AGW,Agnew +AGY,Argyle Downs +AGZ,Aggeneys +AHA,Okinawa +AHC,Herlong +AHF,Arapahoe +AHH,Amery +AHI,Amahai +AHL,Aishalton +AHO,Alghero +AHS,Ahuas +AHT,Amchitka +AHU,Al Hoceima +AHY,Ambatolahy +AHZ,Alpe D Huez +AIA,Alliance +AIB,Anita Bay +AIC,"Airok, Ailinglaplap" +AID,Anderson +AIE,Aiome +AIF,Assis +AIG,Yalinga +AIH,Aiambak +AII,Alisabieh +AIK,Aiken +AIL,Ailigandi +AIM,Ailuk Island +AIN,Wainwright +AIO,Atlantic +AIP,Ailinglapalap Island +AIS,Arorae Island +AIT,Aitutaki +AIU,Atiu Island +AIV,"Aliceville, AL" +AIZ,Kaiser | Lake Ozark +AJA,Ajaccio +AJF,Sakaka Al Jouf +AJJ,Akjoujt +AJK,Araak +AJN,Anjouan +AJO,Aljouf +AJR,Arvidsjaur +AJS,Abreojos +AJU,Aracaju +AJY,Agades +AKB,Atka +AKC,Akron/Canton +AKE,Akieni +AKF,Kufrah +AKG,Anguganak +AKH,Al Kharj +AKI,Akiak +AKJ,Asahikawa +AKK,Akhiok +AKL,Auckland +AKM,Zakouma +AKN,King Salmon +AKO,"Akron, CO" +AKP,Anaktuvuk +AKQ,Astraksetra +AKR,Akure +AKT,Akrotiri +AKV,Akulivik +AKW,Aghajari +AKX,Aktyubinsk +AKY,Sittwe +ALB,Albany +ALC,Alicante +ALE,Alpine +ALF,Alta +ALG,Algiers +ALJ,Alexander Bay +ALK,Asela +ALM,Alamogordo +ALN,Alton +ALO,Waterloo +ALP,Aleppo +ALQ,Alegrete +ALS,Alamosa +ALT,Alenquer +ALU,Alula +ALV,Andorra La Vella +ALX,"Alexander City, AL" +ALZ,Alitak +AMA,"Amarillo, TX" +AMB,Ambilobe +AME,Alto Molocue +AMG,Amboin +AMJ,Almenara +AML,Puerto Armuellas +AMN,Alma +AMP,Ampanihy +AMQ,Ambon +AMU,Amanab +AMV,Amderma +AMW,Ames +AMX,Ammaroo +AMY,Ambatomainty +AMZ,Ardmore +ANA,Anaheim +ANB,"Anniston, AL" +ANC,Anchorage +ANE,Angers +ANF,Antofagasta +ANG,Angouleme +ANH,Anuha Island Resort +ANI,Aniak +ANJ,Zanaga +ANL,Andulo +ANM,Antalaha +ANN,Annette Island +ANO,Angoche +ANP,Annapolis +ANQ,Angola +ANR,Antwerp +ANS,Andahuaylas +ANT,St Anton +ANU,St. John's +ANV,Anvik +ANW,Ainsworth +ANX,Andenes +ANZ,Angus Downs +AOB,Annanberg +AOC,Altenburg +AOD,Abou Deia +AOE,Eskisehir | Anadolu +AOG,Anshan +AOH,Lima +AOI,Ancona +AOJ,Aomori +AOK,Karpathos +AOL,Paso De Los Libres +AOR,Alor Setar +AOS,Amook +AOT,Aosta +AOU,Attopeu +APB,Apolo +APC,Napa +APL,Nampula +APN,Alpena +APO,Apartado +APP,Asapa +APQ,Arapiraca +APR,April River +APS,Anapolis +APT,Jasper +APU,Apucarana +APV,Apple Valley +APW,Apia +APX,Arapongas +APY,Alto Parnaiba +APZ,Zapala +AQA,Araraquara +AQB,Quiche +AQG,Anqing +AQI,Qaisumah +AQJ,Aqaba +AQM,Ariquemes +AQP,Arequipa +AQS,Saqani +AQY,Alyeska +ARA,New Iberia +ARB,"Ann Arbor, MI" +ARC,Arctic Village +ARD,Alor Island +ARF,Acaricuara +ARG,Walnut Ridge +ARH,Arkhangelsk +ARI,Arica +ARJ,Arso +ARK,Arusha +ARM,Armidale +ARO,Arboletas +ARP,Aragip +ARQ,Arauquita +ARR,Alto Rio Senguerr +ARS,Aragarcas +ART,Watertown +ARU,Aracatuba +ARV,Minocqua +ARX,"Neptune, NJ" +ARY,Ararat +ASA,Assab +ASB,Ashgabat +ASC,Ascension +ASD,Andros Town +ASE,Aspen +ASF,Astrakhan +ASG,Ashburton +ASH,"Nashua, NH" +ASJ,Amami O Shima +ASK,Yamoussoukro +ASM,Asmara +ASN,Talladega +ASO,Asosa +ASP,Alice Springs +ASR,Kayseri +AST,Astoria +ASU,Asuncion +ASV,Amboseli +ASW,Aswan +ASX,Ashland +ASY,Ashley +ASZ,Asirim +ATD,Atoifi +ATE,Antlers +ATF,Ambato +ATH,Athens +ATI,Artigas +ATJ,Antsirabe +ATK,Atqasuk +ATL,Atlanta +ATN,Namatanai +ATS,Artesia +ATT,Atmautluak +ATU,Attu Island +ATW,Appleton +ATX,Atbasar +AUA,Aruba +AUB,Itauba +AUC,Arauca +AUD,Augustus Downs +AUE,Abu Rudeis +AUF,Auxerre +AUI,Aua Island +AUJ,Ambunti +AUK,Alakanuk +AUL,Aur Island +AUP,Agaun +AUQ,Atuona +AUS,Austin +AUT,Atauro +AUU,Aurukun Mission +AUY,Aneityum +AVA,An Shun +AVB,Aviano +AVF,Avoriaz +AVG,Auvergne +AVI,Ciego De Avila +AVK,Arvaikheer +AVL,Fletcher +AVN,Avignon +AVO,Avon Park +AVP,Wilkes-Barre +AVV,Geelong +AWD,Aniwa +AWE,Alowe +AWH,Awareh +AWM,West Memphis +AWN,Alton Downs +AWP,Austral Downs +AXA,Anguilla +AXB,Alexandria Bay +AXC,Aramac +AXD,Alexandroupolis +AXE,Xanxere +AXG,Algona +AXM,Armenia +AXP,Spring Point +AXR,Arutua +AXV,Wapakoneta +AXX,Angel Fire +AYA,Ayapel +AYD,Alroy Downs +AYE,Fort Devens +AYG,Yaguara +AYH,Alconbury +AYK,Arkalyk +AYL,Anthony Lagoon +AYN,Anyang +AYP,Ayacucho +AYQ,Ayers Rock +AYS,Waycross +AYT,Antalya +AYU,Aiyura +AYW,Ayawasi +AYZ,Amityville +AZD,Yazd +AZG,Apatzingan +AZN,Andizhan +AZO,Kalamazoo +AZR,Adrar +AZS,El Catey +AZT,Zapatoca +AZZ,Ambriz +BAA,Bialla +BAF,Westfield +BAH,Manama | Bahrain +BAQ,Barranquilla +BAU,Bauru +BAV,Baotou +BAW,Biawonque +BAX,Barnaul +BAZ,Barbelos +BBD,Brady +BBE,Big Bell +BBG,Butaritari +BBH,Barth +BBJ,Bitburg +BBK,Kasane +BBL,Babolsar +BBN,Bario +BBO,Berbera +BBP,Bembridge +BBR,Basse Terre +BBS,Yateley +BBT,Berberati +BBU,Bucharest +BBV,Bereby +BBW,Broken Bow +BBX,Blue Bell +BBY,Bambari +BBZ,Zambezi +BCB,Blacksburg +BCC,Bear Creek +BCE,Bryce +BCF,Bouca +BCG,Bemichi +BCH,Baucau +BCI,Barcaldine +BCJ,Baca Grande +BCK,Bolwarra +BCL,Barra Colorado +BCM,Bacau +BCO,Jinka +BCQ,Brack +BCR,Boca Do Acre +BCS,Belle Chasse +BCT,Boca Raton +BCU,Bauchi +BCV,Belmopan +BCW,Benguera Island +BCX,Beloreck +BCY,Bulchi +BDA,Bermuda +BDB,Bundaberg +BDC,Barra Do Corda +BDD,Badu Island +BDE,Baudette +BDG,Blanding +BDH,Bandar Lengeh +BDI,Bird Island +BDJ,Banjarmasin +BDK,Bondoukou +BDL,"Windsor Locks, CT | Windsor Locks | Windsor" +BDM,Bandirma +BDN,Badin +BDP,Bhadrapur +BDR,Bridgeport +BDS,Brindisi +BDT,Gbadolite +BDU,Bardufoss +BDW,Bedford Downs +BDX,Broadus +BDY,Bandon +BDZ,Baindoung +BEF,Bluefields +BEH,Benton Harbor +BEI,Beica +BEJ,Tanjung Redep +BEM,Bossembele +BEQ,Bury St Edmunds +BEU,Bedourie +BEW,Beira +BEX,Benson +BEZ,Beru +BFA,Bahia Negra +BFB,Blue Fox Bay +BFE,Bielefeld +BFF,Scottsbluff +BFG,Bullfrog Basin +BFL,Bakersfield +BFO,Buffalo Range +BFP,Beaver Falls +BFQ,Bahia Pinas +BFR,Bedford +BFS,Belfast +BFT,Beaufort +BFU,Bengbu +BFV,Buri Ram +BFW,Sidi Belabbes +BFX,Bafoussam +BGA,Bucaramanga +BGB,Booue +BGC,Braganca +BGD,Borger +BGE,Bainbridge +BGF,Bangui +BGG,Bongouanou +BGH,Boghe +BGI,Bridgetown +BGJ,Borgarfjordur Eystri +BGK,Big Creek +BGL,Baglung +BGM,"Binghamton, NY" +BGN,Brueggen +BGO,Bergen +BGP,Bongo +BGQ,Big Lake +BGS,Big Spring +BGT,"Bagdad, AZ" +BGU,Bangassou +BGV,Bento Goncalves +BGW,Baghdad +BGY,Bergamo +BGZ,Braga +BHA,Bahia De Caraquez +BHB,Bar Harbor +BHC,Bhurban +BHE,Blenheim +BHF,Bahia Cupica +BHG,Brus Laguna +BHI,Bahia Blanca +BHK,Bukhara +BHL,Bahia Angeles +BHN,Beihan +BHP,Bhojpur +BHQ,Broken Hill +BHR,Bharatpur +BHS,Bathurst +BHT,Brighton Downs +BHV,Bahawalpur +BHX,Birmingham +BHY,Beihai +BHZ,Belo Horizonte All Airports | Minas Gerais +BIA,Bastia +BIB,Baidoa +BIH,Bishop +BIJ,Biliau +BIM,Bimini +BIP,Bulimba +BIQ,Biarritz +BIR,Biratnagar +BIS,Bismarck +BIU,Bildudalur +BIV,Bria +BIW,Billiluna +BIX,Biloxi +BIY,Bisho +BJA,Bejaia +BJB,Bojnord +BJD,Bakkafjordur +BJF,Batsfjord +BJG,Bolaang +BJH,Bajhang +BJI,Bemidji +BJJ,Wooster +BJK,Benjina +BJL,Banjul +BJM,Bujumbura +BJN,Bajone +BJO,Bermejo +BJR,Bahar Dar +BJT,Bentota River +BJU,Bajura +BJV,Milas +BJW,Bajawa +BJY,Belgrade +BJZ,Badajoz +BKD,Breckenridge +BKE,Baker +BKH,Kekaha +BKI,Kota-Kinabalu | Kota Kinabalu +BKJ,Boke +BKM,Bakalalan +BKN,Birni Nkoni +BKO,Bamako +BKP,Barkly Downs +BKQ,Blackall +BKS,Bengkulu +BKT,Blackstone +BKW,Beckley +BKY,Bukavu +BKZ,Bukoba +BLB,Balboa +BLD,Boulder City +BLG,Belaga +BLH,Blythe +BLI,Bellingham +BLK,Blackpool +BLL,Billund +BLM,Belmar - Farmingdale +BLN,Benalla +BLP,Bellavista +BLQ,Bologna +BLS,Bollon +BLT,Blackwater +BLU,Blue Canyon +BLV,Belleville +BLW,Waimanalo +BLX,Belluno +BLY,Belmullet +BLZ,Blantyre +BMD,Belo +BMF,Bakouma +BMJ,Baramita +BMK,Borkum +BMM,Bitam +BMN,Bamerny +BMO,Bhamo +BMP,Brampton Island +BMQ,Bamburi +BMR,Baltrum Island +BMS,Brumado +BMV,Banmethuot +BMX,Big Mountain +BNA,"Nashville, TN" +BNE,Brisbane +BNF,Baranof +BNG,Banning +BNI,Benin City +BNK,Ballina +BNL,"Barnwell, SC" +BNM,Bodinumu +BNN,Bronnoysund +BNQ,Baganga +BNR,Banfora +BNS,Barinas +BNU,Blumenau +BNX,Banja Luka +BNY,Bellona +BOC,Bocas Del Toro +BOD,Bordeaux +BOE,Boundji +BOG,Bogota | El Dorado +BOH,Bournemouth +BOJ,Bourgas +BOL,Bally Kelly +BON,Kralendijk +BOR,Belfort +BOS,Boston +BOU,Bourges +BOV,Boang +BOW,Bartow +BOZ,Bozoum +BPA,Bethpage +BPB,Boridi +BPC,Bamenda +BPD,Bapi +BPE,Bagan +BPF,Batuna +BPG,Barra Do Garcas +BPH,Bislig +BPI,Big Piney +BPK,Biangabip +BPN,Balikpapan +BPS,Porto Seguro +BPT,Beaumont +BPU,Beppu +BPX,Bangda +BPY,Besalampy +BQA,Baler +BQB,Bussellton +BQE,Bubaque +BQH,Biggin Hill +BQI,Bagani +BQK,Brunswick | Thalman +BQL,Boulia +BQN,Aguadilla +BQO,Bouna +BQS,Blagoveschensk +BQU,Bequia +BQW,Balgo Hills +BRC,San Carlos DeBariloche +BRG,Whitesburg +BRH,Brahman +BRK,Bourke +BRL,Burlington +BRM,Barquisimeto +BRN,Berne +BRP,Biaru +BRQ,Brno +BRR,Barra +BRS,Bristol +BRT,Bathurst Island +BRV,Bremerhaven +BRX,Barahona +BRY,"Bardstown, KY" +BRZ,Borotou +BSA,Bossaso +BSC,Bahia Solano +BSD,Baoshan +BSE,Sematan +BSF,Pohakuloa +BSH,Brighton +BSI,Blairsville +BSJ,Bairnsdale +BSK,Biskra +BSL,Mulhouse/basel +BSM,Bishe-kola +BSN,Bossangoa +BSP,Bensbach +BSQ,Bisbee +BSR,Basra +BSS,Balsas +BSU,Basankusu +BSV,Besakoa +BSW,Boswell Bay +BSX,Bassein +BSY,Bardera +BSZ,Bartletts +BTB,Betou +BTC,Batticaloa +BTD,Brunette Downs +BTE,Bonthe +BTF,Bountiful +BTG,Batangafo +BTI,Barter Island +BTJ,Banda Aceh +BTK,Bratsk +BTL,Battle Creek +BTM,"Butte, (MT)" +BTN,Bennettsville +BTO,Botopasie +BTQ,Butare +BTR,Baton Rouge +BTS,Bratislava +BTT,Bettles +BTU,Bintulu +BTW,Batu Licin +BTX,Betoota +BTY,Beatty +BUB,Burwell +BUC,Burketown +BUD,Budapest +BUE,Buenos Aires All Airports +BUF,"Buffalo, NY" +BUH,Bucharest All Airports +BUI,Bokondini +BUJ,Boussaada +BUK,Albuq +BUL,Bulolo +BUN,Buenaventura +BUO,Burao +BUP,Bhatinda |Bathinda +BUQ,Bulawayo +BUR,Burbank +BUV,Bella Union +BUW,Baubau +BUZ,Bushehr +BVB,Boa Vista +BVC,Boa Vista +BVD,Beaver Inlet +BVE,Brive-La-Gaillarde +BVG,Berlevag +BVH,Vilhena +BVI,"Birdsville, Queensland" +BVK,Huacaraje +BVL,Baures +BVM,Belmonte +BVO,Bartlesville +BVP,Bolovip +BVR,Brava +BVS,Breves +BVU,Beluga +BVW,Batavia Downs +BVX,Batesville +BVY,Beverly +BVZ,Beverley Springs +BWA,Bhairawa +BWB,Barrow Island +BWC,Brawley +BWD,Brownwood +BWE,Braunschweig +BWF,Barrow-In-Furness +BWG,Bowling Green +BWH,Butterworth +BWI,"Baltimore, MD" +BWL,Blackwell +BWM,Bowman +BWN,Bandar Seri Begawan +BWO,Balakovo +BWP,Bewani +BWQ,Brewarrina +BWS,Blaine +BWT,Burnie +BWY,Woodbridge +BXA,Bogalusa +BXC,Boxborough +BXE,Bakel +BXF,Belburn +BXG,Bendigo +BXH,Balhash +BXI,Boundiali +BXJ,Burundai +BXK,Buckeye +BXL,Blue Lagoon +BXO,Buochs +BXS,Borrego Springs +BXT,Bontang +BXV,Breiddalsvik +BXX,Borama +BXZ,Bunsil +BYA,Boundary +BYC,Yacuiba +BYD,Beidah +BYH,"Blytheville, AR" +BYI,Rupert +BYK,Bouake +BYL,Bella Yella +BYM,Bayamo +BYN,Bayankhongor +BYO,Bonito +BYQ,Bunyu +BYR,Laeso Island +BYS,Fort Irwin +BYT,Bantry +BYW,Blakely Island +BYX,Baniyala +BZB,Bazaruto Island +BZC,Buzios +BZD,Balranald +BZE,Belize City +BZG,Bydgoszcz +BZH,Bumi Hills +BZI,Balikesir +BZK,Briansk +BZL,Barisal +BZM,Bergen Op Zoom +BZN,Bozeman +BZO,Bolzano +BZP,Bizant +BZR,Beziers +BZT,Brazoria +BZV,Brazzaville +BZY,Beltsy +CAA,Catacamas +CAC,Cascavel +CAD,Cadillac +CAE,"Columbia, SC" +CAF,Carauari +CAG,Cagliari +CAI,Cairo +CAJ,Canaima +CAK,"Akron/Canton, OH" +CAQ,Caucasia +CAS,Casablanca +CAU,Caruaru +CAV,Cazombo +CAX,Carlisle +CAY,Cayenne +CAZ,Cobar +CBA,Corner Bay +CBB,Cochabamba +CBC,Cherrabun +CBE,Cumberland +CBF,Council Bluffs +CBG,Cambridge +CBH,Bechar +CBI,Cape Barren Island +CBJ,Cabo Rojo +CBK,Colby +CBL,Ciudad Bolivar +CBN,Cirebon +CBO,Cotabato +CBQ,Calabar +CBR,Canberra +CBS,Cabimas +CBT,Catumbela +CBV,Coban +CBW,Campo Mourao +CBX,Condobolin +CBY,Canobie +CBZ,Cabin Creek +CCA,Fort Chaffee +CCB,"Upland, CA" +CCC,Cayo Coco +CCE,St Martin +CCF,Carcassonne +CCG,Crane +CCH,Chile Chico +CCI,Concordia +CCK,Cocos Islands +CCL,Chinchilla +CCM,Criciuma +CCN,Chakcharan +CCO,Carimagua +CCP,Concepcion +CCQ,Cachoeira +CCR,Concord +CCS,Caracas +CCT,Colonia Catriel +CCV,Craig Cove +CCW,Cowell +CCX,Caceres +CCZ,Chub Cay +CDA,Cooinda +CDC,Cedar City +CDD,Cauquira +CDE,Caledonia +CDI,Cachoeiro Itapemirim +CDJ,Conceicao Do Araguaia +CDK,Cedar Key +CDO,Cradock +CDQ,Croydon +CDR,Chadron +CDU,Camden +CDV,Cordova +CDW,"Caldwell, NJ" +CDY,Cagayan De Sulu +CDZ,Cadiz +CEB,Cebu +CEC,Crescent City +CED,Ceduna +CEE,Cherepovets +CEF,"Chicopee, MA" +CEG,Chester +CEH,Chelinda +CEI,Chiang Rai +CEJ,Chernigov +CEK,Chelyabinsk +CEN,Ciudad Obregon +CEQ,Cannes +CER,Cherbourg +CES,Cessnock +CEU,Clemson +CEV,Connersville +CEW,Crestview +CEZ,Cortez +CFB,Cabo Frio +CFC,Cacador +CFF,Cafunfo +CFG,Cienfuegos +CFH,Clifton Hills +CFI,Camfield +CFK,"Chefornak, AK" +CFN,Carrickfinn +CFO,Confreza +CFP,Carpentaria Downs +CFS,Coffs Harbour +CFT,Clifton +CFU,Kerkyra +CFV,Coffeyville +CGB,Cuiaba +CGC,Cape Gloucester +CGG,Casiguran +CGI,Cape Girardeau +CGJ,Chingola +CGM,Camiguin +CGQ,Changchun +CGR,Campo Grande +CGT,Chinguitti +CGU,Ciudad Guayana +CGV,Caiguna +CGY,Cagayan De Oro +CGZ,Casa Grande +CHA,"Chattanooga,TN" +CHB,Chilas +CHC,Christchurch +CHD,Mesa +CHE,Caherciveen +CHF,Jinhae +CHG,Chaoyang +CHH,Chachapoyas +CHI,Chicago All Airports +CHJ,Chipinge +CHK,Chickasha +CHL,Challis +CHM,Chimbote +CHN,Jeonju +CHO,Charlottesville +CHQ,Chania +CHR,Chateauroux +CHS,"Charleston, SC" +CHT,Chatham Island +CHV,Chaves +CHW,Jiuquan +CHX,Changuinola +CHY,Choiseul Bay +CHZ,Chiloquin +CIA,Rome +CIB,Catalina Island +CIC,Chico +CIE,Collie +CIF,Chifeng +CIH,Changzhi +CIJ,Cobija +CIK,Chalkyitsik +CIM,Cimitarra +CIP,Chipata +CIQ,Chiquimula +CIS,Canton Island +CIT,Shimkent +CIV,Chomley +CIW,Canouan Island +CIX,Chiclayo +CIY,Comiso +CIZ,Coari +CJA,Cajamarca +CJC,Calama +CJD,Candilejas +CJH,Chilko Lake +CJI,Ciudad Real +CJJ,Cheongju +CJL,Chitral +CJM,Chumphon +CJN,El Cajon +CJS,Ciudad Juarez +CJT,Comitan +CKB,Clarksburg +CKC,Cherkassy +CKD,Crooked Creek +CKG,Chongqing +CKH,Chokurdah +CKI,Croker Island +CKL,Chkalovsky +CKM,"Clarksdale, MS" +CKN,Crookston +CKO,Cornelio Procopio +CKR,Crane Island +CKS,Carajas +CKT,Sarakhs +CKU,Cordova +CKV,"Clarksville, TN" +CKY,Conakry +CKZ,Canakkale +CLA,Comilla +CLB,Castlebar +CLD,"Carlsbad, CA" +CLG,Coalinga +CLI,Clintonville +CLJ,Cluj-Napoca +CLK,Clinton +CLM,Port Angeles +CLN,Carolina +CLP,Clarks Point +CLQ,Colima +CLR,Calipatria +CLS,Chehalis +CLV,Caldas Novas +CLX,Clorinda +CLY,Calvi +CLZ,Calabozo +CMA,Cunnamulla +CMC,Camocim +CMD,Cootamundra +CME,Ciudad Del Carmen +CMF,Chambery +CMG,Corumba +CMH,Columbus +CMI,Champaign +CMJ,Chi Mei +CMK,Club Makokola +CML,Camooweal +CMM,Carmelita +CMN,Casablanca +CMO,Obbia +CMP,Santana Do Araguaia +CMQ,Clermont +CMR,Colmar +CMS,Scusciuban +CMT,Cameta +CMU,Kundiawa +CMV,Coromandel +CMW,Camaguey +CMX,Hancock +CMY,Sparta +CNA,Cananea +CNB,Coonamble +CNC,Coconut Island +CND,Constanta +CNE,Canon City +CNG,Cognac +CNH,Claremont +CNI,Changhai +CNJ,Cloncurry +CNL,Sindal +CNM,Carlsbad +CNN,Chulman +CNO,Chino +CNP,Neerlerit Inaat +CNQ,Corrientes +CNR,Chanaral +CNU,Chanute +CNV,Canavieiras +CNZ,Cangamba +COB,Coolibah +COF,Cocoa +COG,Condoto +COJ,Coonabarabran +COQ,Choibalsan +COR,Cordoba +CPA,Cape Palmas +CPB,Capurgana +CPC,San Martin DeLos Andes +CPD,Coober Pedy +CPE,Campeche +CPG,Carmen De Patagones +CPI,Cape Orford +CPL,Chaparral +CPM,"Compton, CA" +CPN,Cape Rodney +CPO,Copiapo +CPQ,Campinas +CPR,"Casper, WY" +CPU,Cururupu +CPV,Campina Grande +CPX,Culebra +CQA,Canarana +CQD,Shahre-kord +CQF,Calais +CQP,Cape Flattery +CQS,Costa Marques +CQT,Caquetania +CRA,Craiova +CRB,Collarenebri +CRC,Cartago +CRD,Comodoro Rivadavia +CRF,Carnot +CRH,Cherribah +CRI,Crooked Island +CRJ,Coorabie +CRK,Angeles City +CRM,Catarman +CRN,Cromarty +CRO,Corcoran +CRP,"Corpus Christi, TX" +CRQ,Caravelas +CRR,Ceres +CRS,Corsicana +CRT,Crossett +CRU,Carriacou Is +CRV,Crotone +CRX,Corinth +CRZ,Turkmenabad +CSA,Isle Of Colonsay +CSB,Caransebes +CSC,Canas +CSD,Cresswell Downs +CSE,Crested Butte +CSF,Creil +CSH,Solovetsky +CSJ,Cape St Jacques +CSK,Cap Skirring +CSO,Cochstedt +CSP,Cape Spencer +CSQ,Creston +CSR,Casuarito +CSS,Cassilandia +CSV,Crossville +CSW,Colorado do Oeste +CSX,Changsha +CSZ,Coronel Suarez +CTA,Catania +CTE,Carti +CTF,Coatepeque +CTG,Cartagena +CTH,Coatesville +CTI,Cuito Cuanavale +CTK,Canton +CTL,Charleville +CTM,Chetumal +CTN,Cooktown +CTO,Calverton +CTP,Carutapera +CTQ,Santa Vitoria +CTR,Cattle Creek +CTS,Sapporo +CTT,Le Castellet +CTW,Cottonwood +CTU,Chengdu +CTX,Cortland +CUA,Ciudad Constitucion +CUC,Cucuta +CUF,Cuneo +CUG,Cudal +CUI,Currillo +CUJ,Culion +CUK,Caye Caulker +CUL,Culiacan +CUN,Cancun +CUO,Caruru +CUR,Curacao +CUU,Chihuahua +CUV,Casigua +CUW,Cube Cove +CVB,Chungribu +CVC,Cleve +CVE,Covenas +CVF,Courchevel +CVG,"Covington, KY | Cincinnati" +CVH,Caviahue +CVI,Caleta Olivia +CVJ,Cuernavaca +CVL,Cape Vogel +CVM,Ciudad Victoria +CVN,Clovis +CVQ,Carnarvon +CVR,Culver City +CVT,Coventry +CVU,Corvo Island +CWA,Wausau +CWB,Curitiba +CWC,Chernovtsy +CWG,Callaway Gardens +CWL,Cardiff +CWP,Campbellpore +CWR,Cowarie +CWS,Center Island +CWT,Cowra +CWW,Corowa +CXA,Caicara Del Orinoco +CXC,Chitina +CXF,Coldfoot +CXJ,Caxias Do Sul +CXL,Calexico +CXN,Candala +CXO,Conroe +CXP,Cilacap +CXR,Nha Trang +CXT,Charters Towers +CXY,Cat Cays +CYB,Cayman Brac Is +CYE,Crystal Lake +CYF,Chefornak +CYG,Corryong +CYI,Chiayi +CYL,Coyoles +CYP,Calbayog +CYR,Colonia +CYS,Cheyenne +CYT,Yakataga +CYX,Cherskiy +CYZ,Cauayan +CZB,Cruz Alta +CZC,Copper Centre +CZF,Cape Romanzof +CZH,Corozal +CZJ,Corazon De Jesus +CZK,Cascade Locks +CZL,Constantine +CZM,Cozumel +CZN,Chisana +CZO,Chistochina +CZP,Cape Pole +CZS,Cruzeiro Do Sul +CZT,Carrizo Springs +CZW,Czestochowa +CZX,Changzhou +CZZ,Campo +DAA,Fort Belvoir +DAD,Da Nang +DAF,Daup +DAG,Daggett +DAH,Dathina +DAI,Darjeeling +DAJ,Dauan Island +DAK,Dakhla Oasis +DAL,Dallas Love Field +DAN,Danville +DAP,Darchula +DAS,Great Bear Lake +DAX,Daxian +DAZ,Darwaz +DBA,Dalbandin +DBB,Dabaa City +DBM,Debra Marcos +DBO,Dubbo +DBP,Debepare +DBQ,Dubuque +DBS,Dubois +DBT,Debra Tabor +DBU,Dambula +DBY,Dalby +DCF,Roseau +DCI,Decimomannu +DCK,Dahl Creek +DCM,Castres +DCR,Decatur +DDC,Dodge City +DDG,Dandong +DDI,Daydream Is +DDM,Dodoima +DDP,Dorado +DEA,Dera Ghazi Khan +DEB,Debrecen +DEF,Dezful +DEH,Decorah +DEI,Denis Island +DEM,Dembidollo +DEN,Denver +DEP,Deparizo +DES,Desroches +DEZ,Deirezzor +DFI,Defiance +DFP,Drumduff +DFW,"Dallas, TX" +DGA,Dangriga +DGC,Degahbur +DGD,Dalgaranga +DGE,Mudgee +DGG,Daugo +DGK,Dugong +DGM,Dongguan +DGN,Dahlgren +DGP,Daugavpils +DGR,Dargaville +DGT,Dumaguete +DGU,Dedougou +DHA,Dhahran +DHD,Durham Downs +DHI,Dhangarhi +DHL,Dhala +DHN,Dothan +DHR,Den Helder +DHT,Dalhart +DIJ,Dijon +DIK,Dickinson +DIM,Dimbokro +DIO,Diomede Island +DIP,Diapaga +DIQ,Divinopolis +DIR,Dire Dawa +DJA,Djougou +DJB,Jambi +DJE,Djerba +DJG,Djanet +DJJ,Jayapura +DJM,Djambala +DJN,Delta Junction +DJO,Daloa +DJU,Djupivogur +DKI,Dunk Island +DKK,Dunkirk +DKR,Dakar +DKS,Dikson +DKV,Docker River +DLA,Douala +DLB,Dalbertis +DLC,Dalian +DLD,Geilo +DLG,Dillingham +DLH,Duluth +DLK,Dulkaninna +DLM,Dalaman +DLN,Dillon +DLO,Dolomi +DLP,Disneyland Paris +DLS,The Dalles +DLU,Dali City +DLV,Delissaville +DLY,Dillons Bay +DLZ,Dalanzadgad +DMA,Tucson +DMB,Zhambyl +DMD,Doomadgee +DMN,Deming +DMO,Sedalia +DMR,Dhamar +DMT,Diamantino +DNA,Okinawa +DNB,Dunbar +DNC,Danane +DNF,Derna +DNG,Doongan +DNH,Dunhuang +DNI,Wad Medani +DNK,Dnepropetrovsk +DNL,"Augusta, GA" +DNM,Denham +DNN,Dalton +DNO,Dianopolis +DNQ,Deniliquin +DNR,Dinard +DNS,Denison +DNU,Dinangat +DNX,Dinder +DNZ,Denizli +DOC,Dornoch +DOD,Dodoma +DOE,Djoemoe +DOF,Dora Bay +DOK,Donetsk +DOL,Deauville +DOM,Dominica +DOU,Dourados +DOV,"Dover-Cheswold, DE" +DOX,Dongara +DOY,Dongying +DPE,Dieppe +DPG,Dugway +DPK,Deer Park +DPL,Dipolog +DPO,Devonport +DPU,Dumpu +DRA,Mercury +DRC,Dirico +DRD,Dorunda Station +DRE,Drummond Island +DRF,Drift River +DRG,Deering +DRI,De Ridder +DRJ,Drietabbetje +DRN,Dirranbandi +DRO,Durango +DRR,Durrie +DRS,Dresden +DRT,Del Rio +DRU,Drummond +DRW,Darwin +DRY,Drysdale River +DSA,Doncaster/Sheffield +DSC,Dschang +DSD,La Desirade +DSE,Dessie +DSG,Dilasag +DSI,Destin +DSK,Dera Ismail Khan +DSM,"Des Moines, IA" +DSN,Dongsheng +DSV,Dansville +DTA,Delta +DTD,Datadawai +DTM,Dortmund +DTN,"Shreveport, LA" +DTR,Decatur Island +DTW,Detroit Metropolitan Airport | Detroit | Fort Worth +DUA,Durant +DUB,Dublin +DUD,Dunedin +DUF,"Corolla, NC" +DUJ,Du Bois +DUK,Dukuduk +DUM,Dumai +DUN,Dundas +DUQ,Duncan +DUR,Durban +DUS,Dusseldorf +DUT,Dutch Harbor +DVK,Diavik +DVL,Devils Lake +DVN,Davenport +DVP,Davenport Downs +DVR,Daly River +DVT,Phoenix +DWA,Dwangwa +DWB,Soalala +DWD,Dawadmi +DWF,Dayton +DXA,Deux Alpes +DXD,Dixie +DXR,"Danbury, CT" +DYA,Dysart +DYG,Dayong +DYL,Doylestown +DYM,Diamantina Lakes +DYR,Anadyr +DYU,Dushanbe +DYW,Daly Waters +DZA,Dzaoudzi +DZI,Codazzi +DZN,Zhezkazgan +DZO,Durazno +EAA,Eagle +EAB,Abbse +EAL,Kwajalein Atoll +EAM,Nejran +EAN,Wheatland +EAS,San Sebastian +EAU,"Eau Claire, WI" +EBA,Elba Island +EBD,El Obeid +EBG,El Bagre +EBJ,Esbjerg +EBL,Erbil +EBM,El Borma +EBN,Ebadon +EBS,Webster City +EBU,St Etienne +EBW,Ebolowa +ECA,East Tawas +ECG,"Elizabeth City, NC" +ECH,Echuca +ECN,Lefkosa +ECO,El Encanto +ECR,El Charco +EDA,Edna Bay +EDB,Eldebba +EDD,Erldunda +EDE,Edenton +EDG,Edgewood +EDM,La Roche +EDO,Edremit/korfez +EDQ,Erandique +EDR,Edward River +EDW,Edwards AFB +EEN,Keene +EFB,Eight Fathom Bight +EFG,Efogi +EFL,Kefalonia +EFO,East Fork +EGA,Engati +EGC,Bergerac +EGL,Neghelli +EGN,Geneina +EGP,Eagle Pass +EGS,Egilsstadir +EGV,Eagle River +EGX,Egegik +EHL,El Bolson +EHM,Cape Newenham +EHT,East Hartford +EIB,Eisenach +EIE,Eniseysk +EIH,Einasleigh +EIN,Eindhoven +EIY,Ein Yahav +EJA,Barrancabermeja +EJH,Wedjh +EJT,Mili Atoll +EKB,Ekibastuz +EKD,Elkedra +EKE,Ekereku +EKI,Elkhart +EKN,Elkins +EKO,"Elko, NV" +EKT,Eskilstuna +EKX,Elizabethtown +ELA,Eagle Lake +ELB,El Banco +ELC,Elcho Island +ELE,El Real +ELG,El Golea +ELH,North Eleuthera +ELJ,El Recreo +ELK,Elk City +ELL,Ellisras +ELM,"Corning, NY" +ELN,Ellensburg +ELO,Eldorado +ELP,El Paso +ELQ,Buraidah +ELR,Elelim +ELS,East London +ELT,Tour Sinai City +ELU,El Oued +ELV,Elfin Cove +ELW,Ellamar +ELX,El Tigre +ELZ,Wellsville +EMA,Derby +EMD,Emerald +EME,Emden +EMG,Empangeni +EMI,Emirau +EMK,Emmonak +EML,Luzern +EMM,Kemerer +EMP,Emporia +EMS,Embessa +EMT,El Monte +EMX,El Maiten +EMY,El Minya +ENA,Kenai +ENB,Eneabba West +ENF,Enontekio +ENH,Enshi +ENI,El Nido +ENJ,El Naranjo +ENK,Enniskillen +ENN,Nenana +ENO,Encarnacion +ENQ,Coronel E Soto Cano AB +ENS,Enschede +ENU,Enugu +ENV,Wendover +ENW,Kenosha +EOK,Keokuk +EOS,Neosho +EOZ,Elorza +EPA,El Palomar +EPG,Weeping Water +EPH,Ephrata +EPK,Episkopi +EPL,Epinal +EPN,Epena +EPR,Esperance +EPT,Eliptamin +EPU,Parnu +EQS,Esquel +ERA,Erigavo +ERB,Ernabella +ERC,Erzincan +ERD,Berdyansk +ERF,Erfurt +ERH,Er-Rachidia +ERM,Erechim +ERN,Eirunepe +ERO,Eldred Rock +ERR,Errol +ERT,Erdenet +ERU,Erume +ERV,"Kerrville, TX" +ERZ,Erzurum +ESC,Escanaba +ESD,Eastsound +ESE,Ensenada +ESG,Mariscal Estigarribia +ESH,Shoreham By Sea +ESI,Espinosa +ESL,Elista +ESM,Esmeraldas +ESN,Easton +ESO,Espanola +ESP,East Stroudsburg +ESR,El Salvador +ESS,Essen +EST,Estherville +ESU,Essaouira +ETB,West Bend +ETD,Etadunna +ETE,Genda Wuha +ETH,Eilat +ETN,Eastland +EUC,Eucla +EUF,Eufaula +EUG,Eugene +EUM,Neumuenster +EUN,Laayoune +EUO,Paratebueno +EUQ,Antique +EUX,St Eustatius +EVA,Evadale +EVD,Eva Downs +EVH,Evans Head +EVM,Eveleth +EVN,Yerevan +EVV,"Evansville, IN" +EVW,Evanston +EVX,Evreux +EWB,New Bedford +EWD,Wildman Lake +EWI,Enarotali +EWN,New Bern +EWR,Newark +EWY,Newbury +EXM,Exmouth Gulf +EYL,Yelimane +EYP,El Yopal +EYR,Yerington +EYS,Eliye Springs +EYW,Key West +EZS,Elazig +FAA,Faranah +FAF,Fort Eustis +FAG,Fagurholsmyri +FAI,Fairbanks +FAJ,Fajardo +FAK,False Island +FAS,Faskrudsfjordur +FAY,Fayetteville +FBE,Francisco Beltrao +FBL,Faribault +FBM,Lubumbashi +FBR,Fort Bridger +FBY,Fairbury +FCA,"Kalispell, MT" +FCB,Ficksburg +FCH,Fresno +FCN,Cuxhaven +FCS,Colorado Springs +FCY,Forrest City +FDE,Forde +FDF,Fort De France +FDH,Friedrichshafen +FDK,Frederick +FDU,Bandundu +FDY,Findlay +FEA,Fetlar +FEC,Feira De Santana +FEG,Fergana +FEJ,Feijo +FEK,Ferkessedougou +FEL,Fuerstenfeldbruck +FER,Fergusons Gulf +FET,Fremont +FEW,Cheyenne +FFA,Kill Devil Hills +FFD,Fairford +FFL,Fairfield +FFM,Fergus Falls +FFT,"Frankfort, KY" +FFU,Futaleufu +FGD,Fderik +FGL,Fox Glacier +FGR,Fuengirola +FGU,Fangatau +FHU,Sierra Vista +FHZ,Fakahina +FIC,Fire Cove +FID,Fishers Island +FIE,Fair Isle +FIG,Fria +FIK,Finke +FIN,Finschhafen +FIV,Five Finger Coast Guard Heliport +FIZ,Fitzroy Crossing +FJR,Al-fujairah +FKB,Karlsruhe/Baden Baden +FKH,Fakenham +FKI,Kisangani +FKJ,Fukui +FKL,Franklin +FKS,Fukushima +FLA,Florencia +FLB,Floriano +FLC,Falls Creek +FLF,Flensburg +FLG,Grand Canyon | pulliam field +FLH,Flotta +FLI,Flateyri +FLJ,Falls Bay +FLL,Fort Lauderdale | Hollywood +FLM,Filadelfia +FLN,Florianopolis +FLP,Flippin +FLR,Florence +FLS,Flinders Island +FLV,Fort Leavenworth +FLW,Flores Island +FLX,Fallon +FMA,Formosa +FMC,Five Mile +FME,Fort Meade +FMG,Flamingo +FMH,Falmouth +FMI,Kalemie +FMM,Memmingen +FMN,Farmington +FMO,Muenster/Osnabrueck +FNA,Freetown +FNB,Neubrandenburg +FNC,Funchal +FNG,Fada Ngourma +FNH,Fincha +FNJ,Pyongyang +FNK,Fin Creek +FNL,Fort Collins/Loveland +FNR,Funter Bay +FNT,Flint +FOA,Foula +FOB,Fort Bragg +FOC,Fuzhou +FOE,"Topeka, KS" +FOK,Westhampton +FOM,Foumban +FON,Fortuna +FOT,Forster +FOU,Fougamou +FOY,Foya +FPO,Freeport +FPR,Fort Pierce +FPY,Perry +FRC,Franca +FRD,Friday Harbor +FRG,Farmingdale +FRH,French Lick +FRJ,Frejus +FRL,Forli +FRM,Fairmont +FRN,Fort Richardson +FRP,Fresh Water Bay +FRQ,Feramin +FRR,"Front Royal, (VA)" +FRS,Flores +FRT,Frutillar +FRW,Francistown +FRY,Fryeburg +FRZ,Fritzlar +FSC,Figari +FSD,Sioux Falls +FSI,Fort Sill +FSK,Fort Scott +FSL,Fossil Downs +FSM,Fort Smith +FSN,Fort Sheridan +FSP,St Pierre +FSS,Forres +FST,Fort Stockton +FSU,Fort Sumner +FTA,Futuna Island +FTE,El Calafate +FTI,Fitiuta +FTK,Fort Knox +FTL,Fortuna Ledge +FTU,Fort Dauphin +FTX,Owando +FUB,Fulleborn +FUE,Puerto del Rosario +FUG,Fuyang +FUJ,Fukue +FUO,Fuoshan +FUT,Futuna Island +FVL,Flora Valley +FVR,Forrest River +FWA,Fort Wayne +FWM,Fort William +FXM,Flaxman Island +FXO,Cuamba +FXY,Forest City +FYT,Faya +FYU,Fort Yukon +SVO,Moscow +GAA,Guamal +GAB,Gabbs +GAC,Gracias +GAD,Gadsden +GAF,Gafsa +GAH,Gayndah +GAJ,Yamagata +GAK,Gakona +GAN,Gan Island +GAP,Gusap +GAW,Gangaw +GAX,Gamba +GAZ,Guasopa +GBA,Big Bay +GBB,Gara Djebilet +GBC,Gasuke +GBD,Great Bend +GBE,Gaborone +GBF,Negarbo +GBG,Galesburg +GBH,Galbraith Lake +GBI,Grand Bahama +GBJ,Marie Galante +GBK,Gbangbatok +GBL,Goulburn Island +GBM,Garbaharey +GBN,San Giovanni Rotondo +GBP,Gamboola +GBQ,Muharraq +GBR,Great Barrington +GBS,Port Fitzroy +GBT,Gorgan +GBU,Khashm El Girba +GBV,Gibb River +GBZ,Great Barrier Island +GCA,Guacamaya +GCH,Gachsaran +GCI,Guernsey +GCK,"Garden City, KS" +GCM,Georgetown +GCV,Gravatai +GDA,Gounda +GDD,Gordon Downs +GDE,Gode/Iddidole +GDG,Magdagachi +GDH,"Golden Horn Lodge, Alaska" +GDI,Gordil +GDL,Guadalajara +GDM,Gardner +GDO,Guasdualito +GDP,Guadalupe +GDQ,Gondar +GDT,Grand Turk Is +GDV,Glendive +GDW,Gladwin +GDX,Magadan +GDZ,Gelendzik +GEC,Gecitkale +GEG,Spokane +GEI,Green Islands +GEK,Ganes Creek +GER,Nueva Gerona +GES,General Santos +GEV,Gallivare +GEX,Geelong +GEY,Greybull +GFB,Togiak Fish +GFD,Greenfield +GFE,Grenfell +GFF,Griffith +GFK,Grand Forks +GFL,Glens Falls +GFN,Grafton +GFO,Bartica +GFR,Granville +GFY,Grootfontein +GGC,Lumbala +GGD,Gregory Downs +GGG,Kilgore +GGL,Gilgal +GGN,Gagnoa +GGO,Guiglo +GGR,Garoe +GGS,Gobernador Gregores +GGT,George Town +GHA,Ghardaia +GHB,Governors Harbour +GHC,Great Harbour +GHD,Ghimbi +GHE,Garachine +GHF,Giebelstadt +GHK,Gush Katif +GHM,Centerville +GHN,Guanghan +GHU,Gualeguaychu +GIB,Gibraltar +GIC,Boigu Island +GIF,Winter Haven +GII,Siguiri +GIL,Gilgit +GIM,Miele Mimbale +GIS,Gisborne +GIU,Sigiriya +GIY,Giyani +GJA,Guanaja +GJL,Jijel +GJM,Guajara-Mirim +GJR,Gjogur +GJT,Grand Junction +GKA,Goroka +GKE,Geilenkirchen +GKH,Gorkha +GKL,Great Keppel Island +GKN,Gulkana +GKO,Kongoboumba +GKT,Gatlinburg +GLA,Glasgow +GLC,Geladi +GLD,Goodland +GLF,Golfito +GLG,Glengyle +GLI,Glen Innes +GLK,Galcaio +GLM,Glenormiston +GLN,Goulimime +GLO,Gloucester +GLP,Gulgubip +GLQ,Glennallen +GLR,Gaylord +GLS,Galveston +GLT,Gladstone +GLV,Golovin +GLX,Galela +GLY,Goldsworthy +GMA,Gemena +GMC,Guerima +GMI,Gasmata Island +GMM,Gamboma +GMN,Greymouth +GMR,Gambier Is +GMS,Guimaraes +GMT,Granite Mountain +GMV,Monument Valley Gldngs +GMY,Rheindahlen +GMZ,San Sebas De La Gomera +GNB,Grenoble +GND,St. Georges +GNI,Green Island +GNM,Guanambi +GNN,Ghinnir +GNS,Gunungsitoli +GNU,Goodnews Bay +GNV,Gainesville +GNZ,Ghanzi +GOA,Genova | Genoa +GOE,Gonalia +GOJ,Nizhniy Novgorod +GOK,Guthrie +GON,New London +GOO,Goondiwindi +GOQ,Golmud +GOS,Gosford +GOU,Garoua +GOY,Gal Oya | Ampara +GOZ,Gorna Oriahovitsa +GPB,Guarapuava +GPL,Guapiles +GPN,Garden Point +GPO,General Pico +GPS,Galapagos Is +GPT,Gulfport +GQJ,Machrihanish +GQQ,Galion +GRA,Gamarra +GRB,Green Bay +GRC,Grand Cess +GRF,Tacoma +GRH,Garuahi +GRI,"Grand Island, NE" +GRJ,George +GRK,"Fort Hood, TX" +GRM,Grand Marais +GRO,Gerona +GRQ,Groningen +GRR,"Grand Rapids, MI" +GRS,Grosseto +GRV,Groznyj +GRW,Graciosa Island +GRX,Granada +GRY,Grimsey +GSA,Long Pasia +GSB,Goldsboro +GSC,Gascoyne Junction +GSE,Gothenburg +GSH,Goshen +GSI,Guadalcanal +GSL,Taltheilei Narrows +GSM,Gheshm +GSN,Mount Gunson +GSO,"Greensboro, NC" +GSP,Greenville +GSQ,Shark Elowainat +GSS,Sabi Sabi +GSU,Gedaref +GSY,Grimsby +GTA,Gatokae +GTC,Green Turtle +GTE,Groote Eylandt +GTF,Great Falls +GTI,Guettin +GTK,Sungei Tekai +GTN,Mount Cook +GTO,Gorontalo +GTY,Gettysburg +GUB,Guerrero Negro +GUC,Gunnison +GUE,Guriaso +GUF,Gulf Shores +GUG,Guari +GUH,Gunnedah +GUI,Guiria +GUJ,Guaratingueta +GUO,Gualaco +GUQ,Guanare +GUS,"Peru, Indiana" +GUU,Grundarfjordur +GUV,Mougulu +GUW,Atyrau +GUZ,Guarapari +GVI,Green River +GVP,Greenvale +GVR,Governador Valadares +GVW,Grandview +GWN,Gnarowein +GWO,Greenwood +GWS,Glenwood Springs +GWT,Westerland +GWV,Glendale +GWY,Galway +GXF,Seiyun +GXG,Negage +GXQ,Coyhaique +GXX,Yagoua +GXY,Greeley +GYA,Guayaramerin +GYE,Guayaquil +GYI,Gisenyi +GYN,Goiania +GYP,Gympie +GYS,Guang Yuan +GYY,"Gary, IN" +GZT,Gaziantep +GZW,Ghazvin +HAC,Hachijo Jima +HAE,Havasupai +HAJ,Hanover +HAU,Haugesund +HAW,Haverfordwest +HAZ,Hatzfeldthaven +HBC,Hanus Bay +HBH,Hobart Bay +HBI,Harbour Island +HBR,"Hobart, OK" +HCB,Shoal Cove +HCC,Hudson +HCN,Hengchun +HCQ,Halls Creek +HCR,Holy Cross +HDA,Hidden Falls +HDB,Heidelberg +HDE,Holdrege +HDF,Heringsdorf +HDM,Hamadan +HDN,Hayden +HDR,Havadarya +HDS,Hoedspruit +HDY,Hat Yai +HEB,Henzada +HED,Herendeen +HEK,Heihe +HEL,Vantaa +HEO,Haelogo +HET,Hohhot +HEV,Huelva +HEZ,Natchez +HFA,Haifa +HFD,Hartford All Airports +HFE,Luogang +HFF,Hoffman +HFN,Hornafjordur +HFS,Hagfors +HFT,Hammerfest +HGA,Hargeisa +HGD,Hughenden +HGI,Higlieg +HGN,Mae Hong Son +HGO,Korhogo +HGR,Hagerstown +HGU,Mount Hagen +HGZ,Hogatza +HHE,Hachinohe +HHH,Hilton Head +HHI,Wahiawa +HHQ,Hua Hin +HHR,Hawthorne +HHZ,Hikueru +HIB,Chisholm +HIG,Highbury +HIH,Hook Island +HIJ,Hiroshima +HIL,Shillavo +HIO,Hillsboro +HIX,Hiva Oa +HJJ,Zhi Jiang +HJT,Khujirt +HKA,Blytheville +HKB,Healy Lake +HKD,Hakodate +HKK,Hokitika +HKN,Hoskins +HKV,Haskovo +HKY,Hickory +HLA,Lanseria +HLC,Hill City +HLF,Hultsfred +HLH,Ulanhot +HLI,Hollister +HLL,Hillside +HLM,Holland +HLS,St Helens +HLU,Houailou +HLV,Helenvale +HLW,Hluhluwe +HLY,Holyhead +HMA,Khanty-mansiysk +HME,Hassi Messaoud +HMG,Hermannsburg +HMJ,Khmelnitskiy +HMO,Hermosillo +HMS,Homeshore AK +HMV,Hemavan +HNA,Hanamaki +HNB,Huntingburg +HNC,Hatteras +HNE,Tahneta Pass Lodge +HNG,Hienghene +HNI,Heiweni +HNK,Hinchinbrook Island +HNL,Honolulu +HNN,Honinabi +HNO,Hercegnovi +HNY,Hengyang +HOC,Komako +HOG,Holguin +HOH,Hohenems +HOI,Hao Island +HOK,Hooker Creek +HOL,Holikachu +HOS,Chos Malal +HOV,Orsta-Volda +HOY,Hoy Island +HPB,Hooper Bay +HPH,Haiphong +HPN,White Plains +HPY,Baytown +HQM,Hoquiam +HRA,Mansehra +HRC,Zhairem +HRG,Hurghada +HRJ,Chaurjhari +HRK,Kharkov +HRL,Harlingen +HRN,Heron Island +HRO,Harrison +HRR,Herrera +HRS,Harrismith +HRT,Harrogate +HRY,Henbury +HRZ,Horizontina +HSH,Henderson +HSK,Huesca +HSM,Horsham +HSN,Zhoushan +HSP,Hot Springs +HSS,Hissar +HSV,"Huntsville, AL" +HSZ,Hsinchu +HTB,Terre-de-Bas +HTF,Hatfield +HTG,Hatanga +HTI,Hamilton Island +HTL,Houghton +HTM,Khatgal +HTO,East Hampton | Hampton +HTR,Hateruma +HTS,Huntington +HTU,Hopetoun +HTW,Chesapeake/Huntington Wv +HTZ,Hato Corozal +HUB,Humbert River +HUC,Humacao +HUD,Humboldt +HUF,Terre Haute +HUG,Huehuetenango +HUH,Huahine +HUK,Hukuntsi +HUL,Houlton +HUN,Hualien +HUS,Hughes +HUU,Huanuco +HUV,Hudiksvall +HUX,Huatulco +HUY,Humberside +HUZ,Huizhou +HVA,Analalava +HVB,Hervey Bay +HVK,Holmavik +HVN,New Haven +HVS,Hartsville +HWA,Hawabango +HWI,Hawk Inlet +HWK,Hawker +HWN,Hwange Nat Park +HWO,Hollywood +HYA,Hyannis +HYC,High Wycombe +HYF,Hayfields +HYG,Hydaburg +HYL,Hollis +HYN,Huangyan +HYR,Hayward +HYV,Hyvinkaa +HZB,Hazebrouck +HZG,Hanzhong +HZH,Liping City +HZK,Husavik +HZL,Hazleton +HZV,Hazyview +IAA,Igarka +IAD,Washington +IAG,Niagara Falls +IAH,Houston +IAN,Kiana +IAQ,Bahregan +IAR,Yaroslavl +IBA,Ibadan +IBE,Ibague +IBI,Iboki +IBL,Indigo Bay Lodge +IBP,Iberia +IBZ,Ibiza +ICA,Icabaru +ICK,Nieuw Nickerie +ICL,Clarinda +ICO,Sicogon Island +ICR,Nicaro +ICT,Wichita +ICY,Icy Bay +IDA,Idaho Falls +IDC,Ila Da Chilonzuene +IDF,Idiofa +IDG,Ida Grove +IDI,"Indiana, PA" +IDK,Indulkana +IDN,Indagen +IDO,Santa Isabel Do Morro +IEG,Zielona Gora +IEJ,Iejima +IES,Riesa +IFA,Iowa Falls +IFF,Iffley +IFJ,Isafjordur +IFL,Innisfail +IFN,Isfahan +IFO,Ivano-Frankovsk +IFP,Bullhead City +IGA,Inagua +IGB,Ingeniero Jacobacci +IGE,Iguela +IGG,Igiugig +IGH,Ingham +IGL,Izmir +IGM,Kingman +IGN,Iligan +IGO,Chigorodo +IGR,Iguazu +IGS,Ingolstadt-manching +IGU,Iguassu Falls +IHA,Niihama +IHC,Inhaca +IHN,Qishn +IHO,Ihosy +IHR,Iran Shahr +IIA,Galloway +IIL,Ilaam +IIS,Nissan Island +IJK,Izhevsk +IKB,Wilkesboro +IKK,Kankakee +IKO,Nikolski +IKP,Inkerman +IKS,Tiksi +IKT,Irkutsk +ILA,Illaga +ILB,Ilha Solteira +ILE,Killeen +ILF,Ilford +ILH,Illisheim +ILI,Iliamna +ILM,Wilmington +ILO,Iloilo +ILP,Ile Des Pins +ILR,Ilorin +ILU,Kilaguni +ILZ,Zilina +IMB,Imbaimadai +IMD,Imonda +IMG,Inhaminga +IMI,Ine Island +IMK,Simikot +IMM,Immokalee +IMN,Imane +IMO,Zemio +IMT,Iron Mountain +IMZ,Nimroz +INC,Yinchuan +INE,Chinde +INF,In Guezzam +ING,Lago Argentino +INH,Inhambane +INL,International Falls +INM,Innamincka +INO,Inongo +INQ,Inisheer +INS,Indian Springs +INU,Nauru Island +INV,Inverness +INW,"Winslow, AZ" +INX,Inanwatan +INY,Inyati +IOA,Ioannina +ION,Impfondo +IOR,Inishmore +IOS,Ilheus +IOU,Ile Ouen +IOW,"Iowa City, IA" +IPG,Ipiranga +IPI,Ipiales +IPN,Ipatinga +IPT,Williamsport +IPU,Ipiau +IPW,Ipswich +IQM,Qiemo +IQN,Qingyang +IQQ,Iquique +IQT,Iquitos +IRA,Kirakira +IRD,Ishurdi +IRE,Irece +IRG,Lockhart River +IRI,Iringa +IRJ,La Rioja +IRK,Kirksville +IRN,Iriona +IRO,Birao +IRP,Isiro +IRS,Sturgis +ISA,Mount Isa +ISB,Islamabad +ISE,Isparta +ISG,Ishigaki +ISH,Ischia +ISJ,Isla Mujeres +ISL,Isabel Pass +ISN,Williston +ISO,Kinston +ISP,Islip | long island +ISQ,Manistique +ISS,Wiscasset +IST,Istanbul +ISW,Wisconsin Rapids +ITA,Itacoatiara +ITB,Itaituba +ITE,Itubera +ITH,Ithaca +ITI,Itambacuri +ITK,Itokama +ITM,Osaka All Airports +ITN,Itabuna +ITP,Itaperuna +ITQ,Itaqui +ITR,Itumbiara +IUE,Niue Island +IUM,Summit Lake +IVA,Ambanja +IVC,Invercargill +IVG,Berane +IVH,Ivishak +IVL,Ivalo +IVO,Chivolo +IVR,Inverell +IVW,Inverway +IWA,Ivanova +IWD,Ironwood +IWJ,Iwami +IWO,Iwo Jima Vol +IXN,Khowai +IXQ,Kamalpur +IXT,Pasighat +IYK,Inyokern +IZO,Izumo +IZT,Ixtepec +JAF,Jaffna +JAH,Aubagne +JAK,Jacmel +JAP,Punta Renes +JAQ,Jacquinot Bay +JAV,Ilulissat +JAX,"Jacksonville, FL" +JBK,Berkeley +JBR,Jonesboro +JBS,Pleasanton +JBT,Bethel +JCB,Joacaba +JCH,Qasigiannguit +JCI,"Olathe, KS" +JCK,Julia Creek +JCM,Jacobina +JCN,Incheon +JCO,Comino +JCR,Jacareacanga +JCU,Ceuta +JCY,Johnson +JDA,John Day +JDF,Juiz De Fora +JDN,Jordan +JDO,Juazeiro Do Norte +JDY,Downey +JDZ,Jingdezhen +JEF,"Jefferson City, MO" +JEG,Aasiaat | Ausiait +JEM,Emeryville +JEQ,Jequie +JFK,New York | nyc +JFM,Fremantle +JFR,Paamiut +JGB,Jagdalpur +JGE,Geoje +JGN,Jiayuguan +JGO,Qeqertarsuaq +JGR,Groennedal +JHB,Johor Bahru +JHG,Jinghong +JHM,Lahaina +JHQ,Shute Harbour +JHS,Sisimiut +JIA,Juina +JIB,Djibouti +JIJ,Jijiga +JIK,Ikaria Island +JIP,Jipijapa +JIU,Jiujiang +JJI,Juanjui +JJN,Jinjiang +JJU,Qaqortoq +JKG,Jonkoping +JKH,Chios +JKR,Janakpur +JKT,Jakarta +JLA,Cooper Lodge +JLB,Long Beach +JLD,Landskrona +JLH,Arlington Heights +JLN,"Joplin, MO" +JLP,Juan Les Pins +JLS,Jales +JMB,Jamba +JMC,"Sausalito, CA" +JMH,Schaumburg +JMK,Mikonos +JMO,Jomsom +JMS,Jamestown +JNG,Jining +JNI,Junin +JNN,Nanortalik +JNS,Narsaq +JNX,Naxos +JNZ,Jinzhou +JOH,Port Saint Johns +JOI,Joinville +JOM,Njombe +JOP,Josephstaal +JOT,Joliet +JPA,Joao Pessoa +JPD,Pasadena +JPR,Ji-Parana +JQA,Qaarsut +JQE,Jaque +JRK,Arsuk +JRN,Juruena +JRO,Kilimanjaro +JRS,Jerusalem +JSD,"Stratford, CT" +JSH,Sitia +JSI,Skiathos +JSM,Jose De San Martin +JSO,Sodertalje +JSR,Jessore +JSS,Spetsai Island +JST,Johnstown +JSU,Maniitsoq +JSY,Syros Island +JTO,Thousand Oaks +JTR,Santorini (Thira) +JTY,Astypalaia Island +JUA,Juara +JUI,Juist +JUR,Jurien Bay +JUV,Upernavik +JUZ,Juzhou +JVA,Ankavandra +JVI,Manville +JVL,Janesville +JWA,Jwaneng +JWN,Zanjan +JYR,Jiroft +JYV,Jyvaskyla +JZH,Song Pan +KAC,Kameshli +KAD,Kaduna +KAF,Karato +KAG,Gangneung +KAJ,Kajaani +KAM,Kamaran Is +KAO,Kuusamo +KAP,Kapanga +KAQ,Kamulai +KAS,Karasburg +KAV,Kavanayen +KAW,Kawthaung +KAX,Kalbarri +KAY,Wakaya Island +KBA,Kabala +KBB,Kirkimbie +KBD,Kimberley Downs +KBE,Bell Island +KBF,Karubaga +KBG,Kabalega Falls +KBH,Kalat +KBI,Kribi +KBJ,Kings Canyon +KBK,Klag Bay +KBM,Kabwum +KBN,Kabinda +KBO,Kabalo +KBQ,Kasungu +KBR,Kota Bharu +KBT,Kaben +KBU,Kotabaru +KBW,Chignik +KBX,Kambuaya +KBY,Streaky Bay +KBZ,Kaikoura +KCB,Kasikasima +KCC,Coffman Cove +KCD,Kamur +KCE,Collinsville +KCF,Kadanwari +KCH,Kuching +KCJ,Komaio +KCM,Kahramanmaras +KCN,Chernofski +KCO,Kocaeli +KCP,Kamenets-podolskiy +KCR,Colorado Creek +KCS,Kings Creek Station +KCT,Koggala +KCU,Masindi +KDA,Kolda +KDB,Kambalda +KDD,Khuzdar +KDE,Koroba +KDF,Kouba +KDG,Kardjali +KDH,Kandahar +KDI,Kendari +KDL,Kardla +KDM,Kaadedhdhoo +KDN,Ndende +KDO,Kadhdhoo +KDP,Kandep +KDQ,Kamberatoro +KDR,Kandrian +KDT,Kamphangsaen +KDV,Kandavu +KDY,Mahaweli +KDZ,Katugastota +KED,Kaedi +KEF,Reykjavik +KEG,Keglsugl +KEH,Kenmore Air Harbor +KEJ,Kemerovo +KEK,Ekwok +KEO,Odienne +KEQ,Kebar +KET,Keng Tung +KEU,Kelly Bar +KEV,Kuorevesi +KEW,Keewaywin +KEX,Kanabea +KFA,Kiffa +KFS,Kastamonu +KGA,Kananga +KGB,Konge +KGC,Kingscote +KGD,Kaliningrad +KGE,Kagau +KGF,Karaganda +KGG,Kedougou +KGH,Yongai +KGJ,Karonga +KGK,New Koliganek +KGL,Kigali +KGO,Kirovograd +KGP,Kogalym +KGR,Kulgera +KGU,Keningau +KGX,Grayling +KGY,"Kingaroy, Queensland" +KGZ,Glacier Creek +KHC,Kerch +KHD,Khorramabad +KHH,Kaohsiung +KHJ,Kauhajoki +KHK,Khark Island +KHL,Khulna +KHM,Khamti +KHN,Nanchang +KHO,Khoka Moya +KHR,Kharkhorin +KHU,Kremenchug +KHV,Khabarovsk +KHW,Khwai River Lodge +KHZ,Kauehi +KIE,Kieta +KIF,Kingfisher Lake +KIG,Koinghaas +KIH,Kish Island +KII,Kibuli +KIJ,Niigata +KIO,Kili Island +KIR,Farranfore +KIV,Chisinau +KIY,Kilwa +KIZ,Kikinonda +KJA,Krasnojarsk +KJK,Kortrijk +KJP,Kerama +KJU,Kamiraba +KKA,Koyuk +KKB,Kitoi Bay +KKC,Khon Kaen +KKD,Kokoda +KKE,Kerikeri +KKF,Kagvik Creek +KKG,Konawaruk +KKH,Kongiganak +KKI,Akiachak +KKJ,Kita Kyushu +KKK,Kalakaket +KKL,Karluk Lake +KKM,Lop Buri +KKN,Kirkenes +KKO,Kaikohe +KKR,Kaukura Atoll +KKT,Kentland +KKW,Kikwit +KKX,Kikaiga Shima +KKY,Kilkenny +KKZ,Koh Kong +KLB,Kalabo +KLC,Kaolack +KLD,Kalinin +KLE,Kaele +KLF,Kaluga +KLG,Kalskag +KLI,Kota Koli +KLK,Kalokol +KLL,Levelock +KLM,Kalaleh +KLN,Larsen Bay +KLO,Kalibo +KLP,Kelp Bay +KLQ,Keluang +KLR,Kalmar +KLS,Kelso +KLT,Kaiserslautern +KLU,Klagenfurt +KLV,Karlovy Vary +KLW,Klawock +KLX,Kalamata +KLY,Kalima +KLZ,Kleinzee +KMB,Koinambe +KMD,Mandji +KME,Kamembe +KMH,Kuruman +KMI,Miyazaki +KMJ,Kumamoto +KML,Kamileroi +KMM,Kimam +KMO,Manokotak +KMQ,Komatsu +KMR,Karimui +KMS,Kumasi +KMT,Kampot +KMU,Kismayu +KMV,Kalemyo +KMW,Kostroma +KMX,Khamis Mushait +KMY,Moser Bay +KMZ,Kaoma +KNA,Vina del Mar +KND,Kindu +KNE,Kanainj +KNF,Kings Lynn +KNG,Kaimana +KNH,Kinmen +KNI,Katanning +KNJ,Kindamba +KNK,Kakhonak +KNL,Kelanoa +KNM,Kaniama +KNO,Knokke/Het Zoute +KNP,Capanda +KNS,"King Island, Tasmania" +KNV,Knights Inlet +KNW,New Stuyahok +KNX,Kununurra +KNY,Kinoosao +KNZ,Kenieba +KOB,Koutaba +KOC,Koumac +KOD,Kotabangun +KOE,Kupang +KOF,Komatipoort +KOG,Khong +KOH,Koolatah +KOI,Orkney Island +KOJ,Kagoshima +KOK,Kokkola | Pietarsaari | Kokkola-Pietarsaari +KOL,Koumala +KOM,Komo-Manda +KON,Kontum +KOO,Kongolo +KOP,Nakhon Phanom +KOQ,Koethen +KOR,Kokoro +KOS,Sihanoukville +KOT,Kotlik +KOU,Koulamoutou +KOV,Kokshetau +KOW,Ganzhou +KOX,Kokonao +KOY,Olga Bay +KOZ,Ouzinkie +KPA,Kopiago +KPB,Point Baker +KPC,Port Clarence +KPD,King Of Prussia +KPE,Yapsiei +KPF,Kondubol +KPG,Kurupung +KPH,Pauloff Harbor +KPI,Kapit +KPK,Parks +KPL,Kapal +KPM,Kompiam +KPN,Kipnuk +KPO,Pohang +KPP,Kalpowar +KPR,Port Williams +KPS,Kempsey +KPV,Perryville +KPY,Port Bailey +KQA,Akutan +KRA,Kerang +KRB,Karumba +KRC,Kerinci +KRD,Kurundi +KRE,Kirundo +KRF,Kramfors +KRG,Karasabai +KRI,Kikori +KRJ,Karawari +KRM,Karanambo +KRN,Kiruna +KRO,Kurgan +KRP,Karup +KRQ,Kramatorsk +KRR,Krasnodar +KRS,Kristiansand +KRU,Kerau +KRV,Kerio Valley +KRW,Turkmenbashi +KRY,Karamay +KSA,Kosrae +KSB,Kasanombe +KSD,Karlstad +KSE,Kasese +KSF,Kassel +KSG,Kisengan +KSH,Kermanshah +KSI,Kissidougou +KSJ,Kasos Island +KSK,Karlskoga +KSL,Kassala +KSM,Saint Marys +KSN,Kostanay +KSO,Kastoria +KSP,Kosipe +KSQ,Karshi +KSR,Sandy River +KSS,Sikasso +KST,Kosti +KSU,Kristiansund +KSW,Kiryat Shmona +KSX,Yasuru +KSZ,Kotlas +KTA,Karratha +KTB,Thorne Bay +KTC,Katiola +KTD,Kitadaito +KTE,Kerteh +KTF,Takaka +KTG,Ketapang +KTH,Tikchik +KTI,Kratie +KTK,Kanua +KTL,Kitale +KTN,Ketchikan +KTT,Kittila +KTV,Kamarata +KTW,Katowice +KTX,Koutiala +KTY,Katukurunda +KTZ,Kwun Tong +KUA,Kuantan +KUC,Kuria +KUE,Kukundu +KUF,Samara +KUG,Kubin Island +KUH,Kushiro +KUI,Kawau Island +KUJ,Kushimoto +KUK,Kasigluk +KUL,Kuala Lumpur | Kualalumpur | Malaysia | kaulampur +KUM,Yakushima +KUO,Kuopio +KUP,Kupiano +KUR,Kuran-O-Munjan +KUS,Kulusuk +KUT,Kutaisi +KUV,Gunsan +KUW,Kugururok River +KUX,Kuyol +KUY,Kamusi +KUZ,Gunsan AB +KVA,Kavala +KVB,Skovde +KVC,King Cove +KVD,Gyandzha +KVE,Kitava +KVG,Kavieng +KVK,Kirovsk +KVL,Kivalina +KVU,Korolevu +KWA,Kwajalein +KWB,Karimunjawa +KWD,Kawadjia +KWE,Guiyang +KWG,Krivoy Rog +KWH,Khwahan +KWJ,Gwangju +KWK,Kwigillingok +KWL,Guilin +KWM,Kowanyama +KWN,Quinhagak +KWO,Kawito +KWR,Kwai Harbour +KWS,Kwailabesi +KWT,Kwethluk +KWU,Mansion House +KWV,Kurwina +KWX,Kiwai Island +KWY,Kiwayu +KWZ,Kolwezi +KXE,Klerksdorp +KXF,Koro Island +KXK,Komsomolsk Na Amure +KXR,Karoola +KXU,Katiu +KYA,Konya +KYI,Yalata Mission +KYK,Karluk +KYP,Kyaukpyu +KYS,Kayes +KYT,Kyauktaw +KYU,Koyukuk +KYX,Yalumet +KYZ,Kyzyl +KZB,Zachar Bay +KZC,Kompong-Chhna +KZD,Krakor +KZF,Kaintiba +KZG,Kitzingen +KZH,Kizhuyak +KZI,Kozani +KZK,Kompong Thom +KZN,Kazan +KZO,Kzyl-Orda +KZS,Kastelorizo +LAH,Labuha +LAM,Los Alamos +LAQ,Beida +LAR,Laramie +LAS,Las Vegas +LAX,Los Angeles +LAZ,Bom Jesus Da Lapa +LBB,Lubbock +LBD,Khudzhand +LBE,Latrobe +LBF,North Platte +LBJ,Labuan Bajo +LBK,Liboi +LBL,Liberal +LBM,Luabo +LBN,Lake Baringo +LBO,Lusambo +LBP,Long Banga +LBQ,Lambarene +LBR,Labrea +LBT,Lumberton +LBU,Labuan +LBV,Libreville +LBX,Lubang +LBY,La Baule-Escoublac +LBZ,Lukapa +LCA,Larnaca +LCB,Pontes e Lacerda +LCC,Lecce +LCD,Louis Trichardt +LCE,La Ceiba +LCF,Rio Dulce +LCG,La Coruna +LCH,Lake Charles +LCI,Laconia +LCL,La Coloma +LCM,La Cumbre +LCN,Balcanoona +LCO,Lague +LCP,Loncopue +LCR,La Chorrera +LCS,Las Canas +LCV,Lucca +LCX,Longyan +LCY,London City +LDA,Malda +LDB,Londrina +LDC,Lindeman Island +LDE,Lourdes/Tarbes +LDG,Leshukonskoye +LDH,Lord Howe Island +LDJ,Linden +LDK,Lidkoping +LDM,Ludington +LDN,Lamidanda +LDO,Ladouanie +LDU,Lahad Datu +LDV,Landivisiau +LDW,Lansdowne +LDX,St Laurent du Maroni +LDZ,Londolozi +LEC,Lencois +LEJ,Leipzig-halle +LEP,Leopoldina +LEQ,Lands End +LEX,Lexington | Blue Grass +LER,Leinster +LEU,Seu De Urgel +LEZ,La Esperanza +LFB,Lumbo +LFK,"Lufkin, TX" +LFM,Lamerd +LFN,Louisburg +LFO,Kelafo/Callaf +LFP,Lakefield +LGC,La Grange +LGE,Lake Gregory +LGG,Liege +LGH,Leigh Creek +LGL,Long Lellang +LGM,Laiagam +LGN,Linga Linga +LGO,Langeoog +LGP,Legazpi +LGQ,Lago Agrio +LGS,Malargue +LGT,Las Gaviotas +LGW,Gatwick +LGX,Lugh Ganane +LGY,Lagunillas +LGZ,Leguizamo +LHB,Lost Harbor +LHG,Lightning Ridge +LHK,Guanghua +LHN,Lishan +LHU,Caprivi +LHV,Lock Haven +LHW,Lanzhou +LIA,Liangping +LIB,Limbunya +LIG,Limoges +LIH,Kauai Island +LIK,Likiep Island +LIQ,Lisala +LIR,Liberia +LIW,Loikaw +LIY,Hinesville +LJG,Lijiang City +LJN,Lake Jackson +LJU,Ljubljana +LKA,Larantuka +LKB,Lakeba +LKC,Lekana +LKD,Lakeland Downs +LKG,Lokichoggio +LKH,Long Akah +LKK,Kulik Lake +LKL,Lakselv +LKN,Leknes +LKP,Lake Placid +LKR,Las Khoreh +LKS,Lakeside +LKT,Lakota +LKU,Lake Rudolf +LKV,Lakeview +LKY,Lake Manyara +LLA,Lulea +LLE,Malelane +LLF,LingLing +LLG,Chillagoe +LLH,Las Limas +LLM,Long Lama +LLN,Kelila +LLP,Linda Downs +LLS,Las Lomitas +LLT,Lilydale +LLU,Alluitsup Paa +LLW,Lilongwe +LLX,Lyndonville +LMA,Lake Minchumina +LMB,Salima +LMD,Los Menucos +LMG,Lamassa +LMH,Limon +LML,Lae Island +LMM,Los Mochis +LMN,Limbang +LMO,Lossiemouth +LMP,Lampedusa +LMQ,Marsa Brega +LMR,Lime Acres +LMT,Klamath Falls +LMX,Lopez De Micay +LMY,Lake Murray +LNB,Lamen Bay +LNC,Lengbati +LND,Lander +LNF,Munbil +LNH,Lake Nash +LNJ,Lincang +LNK,"Lincoln, NE" +LNM,Langimar +LNN,Willoughby +LNO,Leonora +LNR,Lone Rock +LNS,Lancaster +LNV,Lihir Island +LNX,Smolensk +LNY,Lanai City +LOA,Lorraine +LOI,Lontras +LOM,Lagos De Moreno +LOQ,Lobatse +LOX,Los Tablones +LPA,Las Palmas +LPB,La Paz +LPC,Lompoc +LPD,La Pedrera +LPE,La Primavera +LPG,La Plata +LPH,Lochgilphead +LPI,Linkoping +LPJ,Pijiguaos +LPK,Lipetsk +LPL,Liverpool +LPM,Lamap +LPN,Leron Plains +LPO,Laporte +LPP,Lappeenranta +LPQ,Luang Prabang +LPS,Lopez Island +LPT,Lampang +LPU,Long Apung +LPW,Little Port Walter +LPX,Liepaja +LPY,Le Puy +LQK,Pickens +LQM,Puerto Leguizamo +LQN,Qala Nau +LRB,Leribe +LRC,Laarbruch +LRE,Longreach +LRG,Lora Lai +LRH,La Rochelle +LRI,Lorica +LRJ,Lemars +LRK,"Lincoln Rock, AK" +LRL,Niamtougou +LRM,La Romana +LRO,Lathrop +LRQ,Laurie River +LRS,Leros +LRT,Lorient +LRU,"Las Cruces, NM" +LRV,Los Roques +LSA,Losuia +LSB,Lordsburg +LSC,La Serena +LSD,"Lexington, KY" +LSE,La Crosse +LSH,Lashio +LSI,Shetland Islands +LSL,Los Chiles +LSM,Long Semado +LSN,Los Banos +LSO,Les Sables +LSP,Las Piedras +LSR,Lost River +LSS,Terre-de-Haut +LST,Launceston +LSU,Long Sukang +LSW,Lhoksumawe +LSX,Lhok Sukon +LSY,Lismore +LSZ,Mali Losinj +LTA,Tzaneen +LTD,Ghadames +LTF,Leitre +LTG,Langtang +LTH,Lathrop Wells +LTI,Altai +LTK,Latakia +LTL,Lastourville +LTM,Lethem +LTO,Loreto +LTP,Lyndhurst +LTQ,Le Touquet +LTR,Letterkenny +LTV,Lotusvale +LTW,Leonardtown +LTX,Latacunga +LUA,Lukla +LUB,Lumid Pau +LUC,Laucala Is +LUE,Lucenec +LUG,Lugano | Agno +LUJ,Lusikisiki +LUO,Luena +LUP,Kalaupapa +LUQ,San Luis +LUR,Cape Lisburne +LUW,Luwuk +LUX,luxembourg +LUY,Lushoto +LUZ,Lushan +LVB,Livramento +LVD,Lime Village +LVI,Livingstone +LVK,Livermore +LVM,Livingston +LVO,Laverton +LVP,Lavan +LWA,Lwbak +LWB,Lewisburg +LWC,Lawrence +LWE,Lewoleba +LWH,Lawn Hill +LWN,Gyoumri +LWO,Lviv | lvov +LWR,Leeuwarden +LWS,Lewiston +LWT,Lewistown +LWY,Lawas +LXA,Gonggar +LXG,Luang Namtha +LXI,Linxi +LXN,Lexington +LXS,Limnos +LXU,Lukulu +LXV,Leadville +LYA,Luoyang +LYB,Little Cayman +LYE,Lyneham +LYG,Lianyungang +LYH,"Lynchburg, VA" +LYI,Linyi +LYP,Faisalabad +LYR,Longyearbyen +LYS,Lyon +LYT,Lady Elliot Island +LZC,Lazaro Cardenas +LZH,Liuzhou +LZI,Luozi +LZM,Luzamba +LZN,Nangan +LZO,Luzhou +LZR,Lizard Island +LZU,Lawrenceville +MAB,Maraba +MAG,Madang +MAJ,Majuro +MBB,Marble Bar +MBC,Mbigou +MBD,Mmabatho +MBE,Monbetsu +MBG,Mobridge +MBH,Maryborough +MBI,Mbeya +MBJ,Montego Bay +MBK,Matupa +MBL,Manistee +MBM,Mkambati +MBN,Mt Barnett +MBO,Mamburao +MBP,Moyobamba +MBQ,Mbarara +MBR,Mbout +MBS,Saginaw +MBT,Masbate +MBU,Mbambanakira +MBW,Mentone +MBX,Maribor +MBY,Moberly +MBZ,Maues +MCB,Mccomb +MCD,Mackinac Island +MCF,MacDill +MCG,Mcgrath +MCH,Machala +MCI,Kansas City +MCJ,Maicao +MCL,Mt Mckinley +MCM,Monte Carlo +MCN,Macon +MCO,Orlando +MCP,Macapa +MCQ,Miskolc +MCR,Melchor De Menco +MCS,Monte Caseros +MCU,Montlucon +MCV,Mcarthur River +MCW,"Mason City, IA" +MCX,Makhachkala +MCY,Sunshine Coast +MCZ,Maceio +MDB,Melinda +MDC,Manado +MDD,Midland +MDE,Medellin | Jose Maria +MDG,Mudanjiang +MDH,Carbondale +MDI,Makurdi +MDK,Mbandaka +MDL,Mandalay +MDM,Munduku +MDO,Middleton Island +MDP,Mindiptana +MDQ,Mar Del Plata +MDR,Medfra +MDS,Middle Caicos +MDT,"Harrisburg, PA" +MDV,Medouneu +MDX,Mercedes +MDY,Midway Island +MDZ,Mendoza +MEO,Manteo +MEP,Mersing +MEQ,Meulaboh +MER,"Atwater, CA" +MES,Medan +MEU,Monte Dourado +MEV,Minden +MEX,Mexico City +MEZ,Messina +MFB,Monfort +MFC,Mafeteng +MFD,Mansfield +MFE,"Mc Allen, TX" +MFF,Moanda +MFG,Muzaffarabad +MFH,Mesquite +MFI,Marshfield +MFJ,Moala +MFK,Matsu +MFL,Mount Full Stop +MFN,Milford Sound +MFO,Manguna +MFP,Manners Creek +MFQ,Maradi +MFS,Miraflores +MFT,Machu Picchu +MFU,Mfuwe +MFV,"Melfa, VA" +MFX,Meribel +MFZ,Mesalia +MGA,Managua +MGB,Mount Gambier +MGC,Michigan City +MGD,Magdalena +MGE,Marietta +MGF,Maringa +MGG,Margarima +MGH,Margate +MGI,"Matagorda Island, TX" +MGK,Mong Ton +MGL,Moenchengladbach +MGM,Montgomery +MGN,Magangue +MGQ,Mogadishu +MGR,Moultrie +MGS,Mangaia Island +MGT,Milingimbi +MGU,Manaung +MGV,Margaret River Station +MGW,Morgantown +MGX,Moabi +MGZ,Myeik +MHC,Macmahon Camp 4 +MHD,Mashad +MHE,Mitchell +MHF,Morichal +MHG,Mannheim +MHH,Marsh Harbour +MHI,Musha +MHJ,Misrak Gashamo +MHK,Manhattan +MHM,Minchumina +MHN,Mullen +MHO,Mount House +MHQ,Mariehamn +MHS,Mount Shasta +MHT,"Manchester, NH" +MHU,Mount Hotham +MHV,Mojave +MHW,Monteagudo +MHX,Manihiki Island +MHZ,Mildenhall +MIG,Mian Yang +MIH,Mitchell Plateau +MIJ,Mili Island +MIL,Milan All Aiports +MIP,Mitspeh Ramon +MIR,Monastir +MIS,Misima Island +MIT,Shafter +MIU,Maiduguri +MIV,Millville +MIW,Marshalltown +MIY,Mittiebah +MIZ,Mainoru +MJB,Mejit Island +MJD,Mohenjodaro +MJE,Majkin +MJF,Mosjoen +MJG,Mayajigua +MJI,Mitiga +MJK,Monkey Mia +MJL,Mouila +MJM,Mbuji Mayi +MJN,Majunga +MJO,Mount Etjo Lodge +MJP,Manjimup +MJR,Miramar +MJS,Maganja Da Costa +MJT,Mytilene +MJU,Mamuju +MJV,Murcia +MJW,Mahenye +MJX,Toms River +MJY,Mangunjaya +MJZ,Mirnyj +MKA,Marianske Lazne +MKB,Mekambo +MKE,Milwaukee +MKG,Muskegon +MKH,Mokhotlong +MKJ,Makoua +MKK,Hoolehua +MKM,Mukah +MKN,Malekolon +MKO,Muskogee +MKP,Makemo +MKQ,Merauke +MKR,Meekatharra +MKS,Mekane Selam +MKT,Mankato +MKU,Makokou +MKV,Mt Cavenagh +MKW,Manokwari +MKX,Mukalla +MKY,Mackay +MKZ,Malacca +MLA,Gudja +MLC,Mc Alester +MLF,Milford +MLG,Malang +MLH,Basel Mulhouse Freiburg +MLI,Moline +MLJ,Milledgeville +MLL,Marshall +MLM,Morelia +MLN,Melilla +MLO,Milos +MLP,Malabang +MLQ,Malalaua +MLR,Millicent +MLS,Miles City +MLT,Millinocket +MLU,Monroe +MLV,Merluna +MLW,Monrovia +MLX,Malatya +MLY,Manley Hot Springs +MMB,Memanbetsu +MMC,Ciudad Mante +MMD,Minami Daito +MME,"Teesside, Durham" +MMF,Mamfe +MMG,Mount Magnet +MMH,Mammoth Lakes +MMJ,Matsumoto +MMK,Murmansk +MMP,Mompos +MMQ,Mbala +MMU,Morristown +MMX,Malmo | sturup +MMY,Miyako Jima +MMZ,Maimana +MNA,Melangguane +MND,Medina +MNE,Mungeranie +MNF,Mana Island +MNG,Maningrida +MNH,Minneriya +MNI,Gerald's Park +MNJ,Mananjary +MNK,Maiana +MNM,Menominee +MNO,Manono +MNR,Mongu +MNT,Minto +MNU,Maulmyine +MNV,Mountain Valley +MNX,Manicore +MNZ,"Manassas, VA" +MOE,Momeik +MOF,Maumere +MOJ,Moengo +MOQ,Morondava +MOU,Mountain Village +MOX,Morris +MOZ,Moorea +MPA,Mpacha +MPD,Mirpur Khas +MPF,Mapoda +MPG,Makini +MPH,Caticlan +MPI,Mamitupo +MPJ,Morrilton +MPK,Mokpo +MPL,Montpellier +MPN,Mount Pleasant +MPO,Mt Pocono +MPP,Mulatupo +MPR,Mcpherson +MPU,Mapua +MPV,"Montpelier, VT" +MPW,"Mariupol, MN" +MPX,Miyanmin +MPY,Maripasoula +MQA,Mandora +MQB,Macomb +MQC,Miquelon +MQD,Maquinchao +MQE,Marqua +MQF,Magnitogorsk +MQG,Midgard +MQH,Minacu +MQK,San Matias +MQL,Mildura +MQM,Mardin +MQO,Malam +MQQ,Moundou +MQR,Mosquera +MQS,Mustique Island +MQT,Marquette +MQU,Mariquita +MQV,Mostaganem +MQX,Makale +MQY,Smyrna +MQZ,Margaret River +MRA,Misurata +MRB,Martinsburg +MRD,Merida +MRG,Mareeba +MRJ,Marcala +MRK,Marco Island +MRL,Miners Lake +MRM,Manare +MRN,Morganton +MRQ,Marinduque +MRR,Macara +MRT,Moroak +MRV,Mineralnye Vody +MRW,Maribo +MRX,Bandar Mahshahr +MSA,Muskrat Dam +MSD,Mt Pleasant +MSE,Manston +MSF,Mount Swan +MSG,Matsaile +MSH,Masirah +MSI,Masalembo +MSJ,Misawa +MSK,Mastic Point +MSM,Masi Manimba +MSN,Madison +MSO,Missoula +MSQ,Minsk +MSS,Massena +MST,Maastricht | Aachen +MSU,Maseru +MSV,Monticello +MSW,Massawa +MSX,Mossendjo +MSY,New Orleans +MSZ,Namibe +MTB,Monte Libano +MTC,Mt Clemens +MTD,Mt Sandford +MTE,Monte Alegre +MTF,Mizan Teferi +MTG,Mato Grosso +MTI,Mosteiros +MTJ,Montrose +MTK,Makin Island +MTL,Maitland +MTM,Metlakatla +MTT,Minatitlan +MTU,Montepuez +MTW,Manitowoc +MTY,Monterrey +MTZ,Masada +MUD,Mueda +MUE,Kamuela +MUH,Mersa Matruh +MUK,Mauke Island +MUN,Maturin +MUP,Mulga Park +MUQ,Muccan +MUS,Marcus Island +MUT,Muscatine +MUU,Mount Union +MUY,Mouyondzi +MUZ,Musoma +MVA,Myvatn +MVB,Franceville +MVC,Monroeville +MVE,"Montevideo, MN" +MVF,Mossoro +MVG,Mevang +MVH,Macksville +MVI,Manetai +MVJ,Mandeville +MVK,Mulka +MVM,"Kayenta, AZ" +MVN,Mt Vernon +MVQ,Mogilev +MVR,Maroua +MVS,Mucuri +MVT,Mataiva +MVU,Musgrave +MVV,Megeve +MVW,Mount Vernon +MVX,Minvoul +MVZ,Masvingo +MWA,Marion +MWB,Morawa +MWD,Mianwali +MWE,Merowe +MWF,Maewo +MWG,Marawaka +MWH,Moses Lake +MWI,Maramuni +MWJ,Matthews Ridge +MWK,Matak +MWL,Mineral Wells +MWM,"Windom, MN" +MWN,Mwadui +MWO,"Middletown, Ohio" +MWP,Mountain +MWQ,Magwe +MWR,Motswari +MWS,Mount Wilson +MWT,Moolawatana +MWU,Mussau +MWV,Mundulkiri +MWY,Miranda Downs +MWZ,Mwanza +MXB,Masamba +MXE,Maxton +MXG,Marlborough +MXK,Mindik +MXL,Mexicali +MXM,Morombe +MXN,Morlaix +MXQ,Mitchell River +MXR,Mirgorod +MXS,Maota Savaii Is +MXT,Maintirano +MXU,Mullewa +MXW,Mandalgobi +MXY,Mccarthy +MXZ,Meixian +MYB,Mayoumba +MYC,Maracay +MYD,Malindi +MYE,Miyake Jima +MYG,Mayaguana +MYI,Murray Island +MYJ,Matsuyama +MYM,Monkey Mountain +MYR,Myrtle Beach +MYT,Myitkyina +MYU,Mekoryuk +MYV,Marysville +MYW,Mtwara +MYX,Menyamya +MZA,Muzaffarnagar +MZB,Mocimboa Praia +MZC,Mitzic +MZD,Mendez +MZE,Manatee +MZF,Mzamba +MZG,Makung +MZH,Merzifon +MZI,Mopti +MZJ,Marana +MZK,Marakei +MZL,Manizales +MZP,Motueka +MZQ,Mkuze +MZR,Mazar-i-sharif +MZS,Mostyn +MZT,Mazatlan +MZV,"Mulu, Sarawak" +MZW,Mechria +MZY,Mossel Bay +NAA,Narrabri +NAC,Naracoorte +NAD,Macanal +NAE,Natitingou +NAF,Banaina +NAJ,Nakhichevan +NAK,Nakhon Ratchasima +NAL,Nalchik +NAO,Nanchong +NAP,Napoli | Naples +NAQ,Qaanaaq +NAS,Nassau +NAU,Napuka Island +NAV,Nevsehir +NAW,Narathiwat +NAX,Barbers Point +NAZ,Star Habour +NBA,Nambaiyufa +NBB,Barrancominas +NBC,Naberevnye Chelny +NBH,Nambucca Heads +NBL,San Blas +NBO,Nairobi +NBR,Nambour +NBU,Glenview +NBV,Cana Brava +NBW,Guantanamo +NBX,Nabire +NCA,North Caicos +NCG,Paloma Grande +NCH,Nachingwea +NCI,Necocli +NCL,Newcastle +NCN,New Chenega +NCO,Quonset Point +NCT,Nicoya +NCU,Nukus +NCY,Annecy +NDA,Bandanaira +NDB,Nouadhibou +NDE,Mandera +NDF,Ndalatandos +NDG,Qiqihar +NDI,Namudi +NDJ,Ndjamena +NDK,Namdrik Island +NDL,Ndele +NDN,Nadunumu +NDO,La Palma Del Condado +NDR,Nador +NDS,Sandstone +NDV,"Anacostia, DC" +NDZ,Nordholz-Spieka +NEA,Glynco +NEC,Necochea +NEF,Neftekamsk +NEG,Negril +NEJ,Nejjo +NEK,Nekemt +NEN,Whitehouse +NEU,Sam Neua +NEV,Nevis +NFG,Nefteyugansk +NFR,Nafoora +NGB,Ningbo +NGD,Anegada +NGE,Ngaoundere +NGI,Ngau Island +NGL,Ngala +NGM,Agana +NGN,Nargana +NGR,Ningerum +NGS,Nagasaki +NGV,Ngiva +NGX,Manang +NGZ,Alameda +NHD,Minhad AB +NHF,New Halfa +NHK,"Patuxent River, MD" +NHS,Nushki +NHT,Northolt +NHV,Nuku Hiva +NIB,Nikolai +NIE,Niblack +NIG,Nikunau +NIM,Niamey +NIR,Beeville +NIS,Simberi Island +NIX,Nioro +NJA,Atsugi +NJC,Nizhnevartovsk +NJK,"El Centro, CA" +NKA,Nkan +NKB,Noonkanbah +NKC,Nouakchott +NKD,Sinak +NKG,Nanking | Nanjing +NKI,Naukiti +NKL,Nkolo +NKM,Nagoya +NKN,Nankina +NKO,Ankokoambo +NKS,Nkongsamba +NKU,Nkaus +NKV,"Nichen Cove, AK" +NKY,Nkayi +NLC,"Lemoore, CA" +NLD,Nuevo Laredo +NLF,Darnley Island +NLG,Nelson Lagoon +NLK,Norfolk Island +NLL,Nullagine +NLP,Nelspruit +NLS,Nicholson +NLU,Santa Lucia +NLV,Nikolaev +NMA,Namangan +NME,Nightmute +NMN,Nomane +NMR,Nappa Merry +NMS,Namsang +NMT,Namtu +NNA,Kenitra +NND,Nangade +NNG,Nanning +NNI,Namutoni +NNK,Naknek +NNL,Nondalton +NNM,Naryan-Mar +NNU,Nanuque +NNX,Nunukan +NNY,Nanyang +NOA,Nowra +NOB,Nosara Beach +NOE,Norddeich +NOG,Nogales +NOI,Novorossijsk +NOJ,Nojabrxsk +NOK,Nova Xavantina +NOL,Nakolik River +NOR,Nordfjordur +NOU,Noumea +NOZ,Novokuznetsk +NPE,Napier/Hastings +NPH,Nephi +NPL,New Plymouth +NPO,Nangapinoh +NPP,Napperby +NPU,San Pedro Uraba +NQA,"Millington, TN" +NQI,Kingsville +NQL,Niquelandia +NQN,Neuquen +NQT,Nottingham +NQU,Nuqui +NQY,Newquay +NRA,Narrandera +NRB,Mayport +NRC,Crows Landing +NRD,Norderney +NRG,Narrogin +NRK,Norrkoping +NRL,North Ronaldsay +NSI,Yaounde +NSM,Norseman +NSP,Sangley Point +NST,Nakhon Si Thammarat +NSV,Noosaville +NTA,Natadola +NTB,Notodden +NTC,Santa Carolina +NTD,"Port Hueneme, CA" +NTE,Nantes +NTG,Nantong +NTI,Bintuni +NTM,Miracema Do Norte +NTN,Normanton +NTO,Santo Antao +NTQ,Wajima +NTT,Niuatoputapu +NTX,Natuna Ranai +NUB,Numbulwar +NUF,Hatton +NUG,Nuguria +NUH,Nunchia +NUI,Nuiqsut +NUK,Nukutavake +NUP,Nunapitchuk +NUQ,Mountain View +NUR,Nullarbor +NUS,Norsup +NUU,Nakuru +NUX,Novy Urengoy +NVA,Neiva +NVD,Nevada +NVG,Nueva Guinea +NVI,Navoi +NVK,Narvik +NVP,Aripuana +NVT,Navegantes +NWI,Norwich +NWP,Argentia +NWT,Nowata +NXX,Willow Grove +NYG,Quantico +NYI,Sunyani +NYK,Nanyuki +NYU,Nyaung-u +NZA,Nzagi +NZE,Nzerekore +NZH,Manzhouli +NZW,South Weymouth +OAK,Oakland +OAL,Cacoal +OAM,Oamaru +OAR,"Marina, CA" +OAX,Oaxaca +OBD,Obano +OBE,Okeechobee +OBF,Oberpfaffenhofen +OBI,Obidos +OBL,Zoersel +OBM,Morobe +OBS,Aubenas +OBU,Kobuk +OCA,Ocean Reef +OCF,Ocala +OCH,"Nacogdoches, TX" +OCJ,Ocho Rios +ODB,Cordoba +ODH,Odiham +ODJ,Ouanda Djalle +ODL,Cordillo Downs +ODN,Long Seridan +ODR,Ord River +ODW,Oak Harbor +OEA,Vincennes +OEC,Ocussi +OEM,Paloemeu +OEO,Osceola +OER,Ornskoldsvik +OES,San Antonio Oeste +OFI,Ouango Fitini +OFJ,Olafsfjordur +OGA,Ogallala +OGB,Orangeburg +OGD,Ogden +OGE,Ogeranang +OGG,"Maui, HI" +OGN,Yonaguni Jima +OGO,Abengourou +OGR,Bongor +OGS,Ogdensburg +OGV,Ongava Game Reserve +OGX,Ouargla +OGZ,Vladikavkaz +OHA,Ohakea +OHC,Northeast Cape +OHD,Ohrid +OHI,Oshakati +OHO,Okhotsk +OHR,Wyk Auf Foehr +OHT,Kohat +OIA,Ourilandia +OIM,Oshima +OIR,Okushiri +OKB,Orchid Beach +OKC,Oklahoma City +OKE,Okino Erabu +OKF,Okaukuejo +OKG,Okoyo +OKH,Oakham +OKI,Oki Island +OKJ,Okayama | Okayama-shi +OKK,Kokomo +OKL,Oksibil +OKM,Okmulgee +OKN,Okondja +OKP,Oksapmin +OKR,Yorke Island +OKT,Oktiabrskij +OKU,Mokuti Lodge +OLB,Olbia +OLD,Old Town +OLF,Wolf Point +OLH,Old Harbor +OLI,Olafsvik +OLJ,Olpoi +OLK,Fuerte Olimpo +OLM,Olympia +OLN,Colonia Sarmiento +OLO,Olomouc +OLP,Olympic Dam +OLQ,Olsobip +OLS,Nogales +OLV,Olive Branch +OMA,Omaha +OMB,Omboue +OMC,Ormoc +OMD,Oranjemund +OMF,Mafraq +OMG,Omega +OMH,Urmieh +OMI,Omidieh +OMJ,Omura +OML,Omkalai +OMM,Marmul +OMN,Osmanabad +OMO,Mostar +OMR,Oradea +OMY,Oddor Meanche +ONA,Winona +ONB,Ononge +OND,Ondangwa +ONG,Mornington +ONH,Oneonta +ONI,Moanamani +ONJ,Odate Noshiro +ONL,Oneill +ONM,Socorro +ONN,Onion Bay +ONP,Newport +ONQ,Zonguldak +ONR,Monkira +ONS,Onslow +ONY,Olney +OOA,Oskaloosa +OOK,Toksook Bay +OOL,Gold Coast +OOR,Mooraberree +OPA,Kopasker +OPI,Oenpelli +OPL,Opelousas +OPS,Sinop +OPU,Balimo +OPW,Opuwa +ORB,Orebro +ORC,Orocue +ORE,Orleans +ORF,Norfolk +ORH,Worcester +ORI,Port Lions +ORJ,Orinduik +ORM,Northampton +ORP,Orapa +ORQ,Norwalk +ORR,Yorketown +ORS,Orpheus Island Resort +ORT,Northway +ORU,Oruro +ORV,Noorvik +ORW,Ormara +ORX,Oriximina +ORZ,Orange Walk +OSB,Osage Beach +OSC,Oscoda +OSD,Ostersund +OSG,Ossima +OSH,Oshkosh +OSI,Osijek +OSK,Oskarshamn +OSM,Mosul +OSO,Sulaimaniyah +OSP,Slupsk +OSR,Ostrava +OST,Ostend +OSX,Kosciusko +OSZ,Koszalin +OTD,Contadora +OTH,North Bend +OTI,"Pitu, Morotai Island" +OTJ,Otjiwarongo +OTL,Boutilimit +OTM,Ottumwa +OTN,Oaktown +OTS,Anacortes +OTV,Ontong Java +OTZ,Kotzebue +OUA,Ouagadougou +OUD,Oujda +OUE,Ouesso +OUG,Ouahigouya +OUH,Oudtshoorn +OUK,Outer Skerries +OUM,Oum Hadjer +OUN,Norman +OUS,Ourinhos +OUU,Ouanga +OUZ,Zouerate +OVB,Novosibirsk +OVD,Oviedo/Aviles +OVE,Oroville +OVG,Overberg +OVL,Ovalle +OVR,Olavarria +OWA,Owatonna +OWB,Owensboro +OWD,Norwood +OWE,Owendo +OWK,Norridgewock +OXB,Bissau +OXF,Oxford | Oxfordshire +OXO,Orientos +OXR,Ventura +OYK,Oiapoque +OYL,Moyale +OYN,Ouyen +OYP,St Georges de lOyapock +OYS,Yosemite Ntl Park +OZC,Ozamis City +OZH,Zaporozhye +OZI,Bobadilla +OZU,Montilla +OZZ,Ouarzazate +PAE,Everett +PAF,Pakuba +PAG,Pagadian +PAH,"Paducah, KY" +PAJ,Para Chinar +PAL,Palanquero +PAP,Port Au Prince +PAQ,Palmer +PAS,Paros +PAV,Paulo Afonso +PAW,Pambwa +PAZ,Poza Rica +PBA,Barrow +PBB,Paranaiba +PBC,Puebla Atlixco +PBE,Puerto Berrio +PBF,Pine Bluff +PBG,Plattsburgh +PBI,West Palm Beach +PBJ,Paama +PBK,Pack Creek +PBL,Puerto Cabello +PBM,Paramaribo +PBN,Porto Amboim +PBO,Paraburdoo +PBP,Punta Islita +PBQ,Pimenta Bueno +PBR,Puerto Barrios +PBS,Patong Beach +PBT,Puerto Leda +PBU,Putao +PBV,Porto Dos Gauchos +PBW,Palibelo +PBX,Porto Alegre Do Norte +PBY,Peppers Palm Bay +PBZ,Plettenberg Bay +PCA,Portage Creek +PCD,Prairie Du Chien +PCE,Painter Creek +PCG,Paso Caballos +PCJ,Puerto La Victoria +PCK,Porcupine Creek +PCL,Pucallpa +PCM,Playa Del Carmen +PCN,Picton +PCP,Principe +PCQ,Phongsaly +PCR,Puerto Carreno +PCT,Princeton +PCU,Picayune +PCV,Punta Chivato +PDB,Pedro Bay +PDD,Ponta de Ouro +PDE,Pandie Pandie +PDG,Padang +PDI,Pindiu +PDL,"Ponta Delgada, Azores" +PDN,Parndana +PDO,Pendopo +PDP,Maldonado +PDR,Presidente Dutra +PDS,Piedras Negras +PDT,Pendleton +PDU,Paysandu +PDV,Plovdiv +PDX,"Portland, OR" +PDZ,Pedernales +PEA,Penneshaw +PEB,Pebane +PEC,Pelican +PED,Pardubice +PEF,Peenemuende +PEH,Pehuajo +PEJ,Peschiei +PEL,Pelaneng +PEM,Puerto Maldonado +PEN,Penang +PEP,Peppimenarti +PEQ,Pecos City +PER,Perth +PES,Petrozavodsk +PEU,Puerto Lempira +PEW,Peshawar +PEX,Pechora +PEY,Penong +PEZ,Penza +PFC,"Pacific City, OH" +PFJ,Patreksfjordur +PFO,Paphos +PFQ,Parsabad +PFR,Ilebo +PGB,Pangoa +PGD,Punta Gorda +PGE,Yegepa +PGF,Perpignan +PGI,Chitato +PGK,Pangkalpinang +PGL,Pascagoula +PGM,Port Graham +PGN,Pangia +PGO,Pagosa Springs +PGR,Paragould +PGS,Peach Springs +PGX,Perigueux +PHA,Phan Rang +PHB,Parnaiba +PHC,Port Harcourt +PHE,Port Hedland +PHG,Port Harcourt +PHH,Phan Thiet +PHI,Pinheiro +PHJ,Port Hunter +PHK,Pahokee +PHL,Philadelphia +PHM,Boeblingen +PHR,Pacific Harbor +PHS,Phitsanulok +PHU,Phu Vinh +PHW,Phalaborwa +PHY,Phetchabun +PHZ,Phi Phi Island +PIB,"Hattiesburg/Laurel, MS" +PIC,Pine Cay +PIF,Pingtung +PIG,Pitinga +PIH,Pocatello +PIK,"Prestwick, South Ayrshire" +PIM,Pine Mountain +PIO,Pisco +PIP,Pilot Point +PIQ,Pipillipai +PIR,Pierre +PIS,Poitiers +PIT,"Pittsburgh, PA" +PIU,Piura +PIV,Pirapora +PIW,Pikwitonei +PIX,Pico Island +PIZ,Point Lay +PJA,Pajala +PJB,Payson +PJC,Pedro Juan Caballero +PJG,Panjgur +PJM,Puerto Jimenez +PJS,Port San Juan +PJZ,Puerto Juarez +PKA,Napaskiak +PKB,Parkersburg +PKC,Petropavlovsk-Kamchats +PKD,Park Rapids +PKE,Parkes +PKF,Park Falls +PKG,Pangkor +PKH,Porto Kheli +PKJ,Playa Grande +PKK,Pakokku +PKL,Pakatoa Island +PKM,Port Kaituma +PKN,Pangkalanbuun +PKO,Parakou +PKP,Puka Puka +PKS,Paksane +PKT,Port Keats +PKU,Pekanbaru +PKV,Pskov +PKW,Selebi-Phikwe +PKY,Palangkaraya +PKZ,Pakse +PLA,Planadas +PLC,Planeta Rica +PLD,Playa Samara +PLE,Paiela +PLG,La Plagne +PLJ,Placencia +PLK,Branson/point Lookout +PLL,Manaus +PLM,Palembang +PLN,Pellston +PLO,Port Lincoln +PLP,La Palma +PLQ,Klaipeda/Palanga +PLR,Pell City +PLT,Plato +PLV,Poltava +PLX,Semipalatinsk +PMA,Pemba +PMB,Pembina +PMC,Puerto Montt +PMD,"Palmdale, CA" +PMF,Parma +PMG,Ponta Pora +PMI,Palma Mallorca +PMK,Palm Island +PML,Port Moller +PMM,Phanom Sarakham +PMN,Pumani +PMO,Palermo +PMP,Pimaga +PMQ,Perito Moreno +PMR,Palmerston North +PMS,Palmyra +PMT,Paramakotoi +PMU,Paimiut +PMV,Porlamar +PMW,Palmas +PMY,Puerto Madryn +PMZ,Palmar +PNA,Pamplona +PNB,Porto Nacional +PNC,Ponca City +PNI,Pohnpei +PNJ,Peng Lai +PNK,Pontianak +PNL,Pantelleria +PNO,Pinotepa Nacional +PNR,Pointe Noire +PNS,Pensacola +PNT,Puerto Natales +PNU,Panguitch +PNV,Panevezys +PNX,Sherman-Denison +PNZ,Petrolina +POA,Porto Alegre +POC,La Verne +POE,Fort Polk +POF,Poplar Bluff +POG,Port Gentil +POH,Pocahontas +POI,Potosi +POJ,Patos De Minas +POL,Pemba +POM,Port Moresby +PON,Poptun +POO,Pocos De Caldas +POQ,Polk Inlet +POS,Port Of Spain +POU,Poughkeepsie +POV,Presov +POW,Portoroz +POY,Powell +POZ,Poznan +PPA,Pampa +PPB,Presidente Prudente +PPC,Prospect Creek +PPE,Puerto Penasco +PPF,Parsons +PPG,Pago Pago +PPH,Peraitepuy +PPI,Port Pirie +PPJ,Pulau Panjang +PPK,Petropavlovsk +PPL,Phaplu +PPM,Pompano Beach +PPN,Popayan +PPO,Powell Point +PPP,Proserpine +PPQ,Paraparaumu +PPR,Pasir Pangarayan +PPS,Puerto Princesa +PPV,Port Protection +PPW,Papa Westray +PPY,Pouso Alegre +PPZ,Puerto Paez +PQC,Phu Quoc +PQI,Presque Isle +PQM,Palenque +PQQ,Port Macquarie +PQS,Pilot Station +PQT,Qeqertaq +PRA,Parana +PRB,Paso Robles +PRC,Prescott +PRD,Pardoo +PRF,Port Johnson +PRH,Phrae +PRI,Praslin Island +PRK,Prieska +PRL,Port Oceanic +PRM,Portimao +PRP,Propriano +PRQ,Pres. Roque Saenz Pena +PRR,Paruima +PRS,Parasi +PRT,Point Retreat +PRV,Prerov +PRW,Prentice +PRY,Pretoria +PRZ,Prineville +PSB,Bellefonte +PSC,"Pasco, WA" +PSD,Port Said +PSE,Ponce +PSF,Pittsfield +PSG,"Petersburg, AK" +PSH,St Peter +PSI,Pasni +PSM,"Portsmouth, NH" +PSN,"Palestine, TX" +PSO,Pasto +PSP,Palm Springs +PSR,Pescara +PSS,Posadas +PST,Preston +PSU,Putussibau +PSV,Papa Stour +PSW,Passos +PSX,Palacios +PSY,Port Stanley +PSZ,Puerto Suarez +PTA,Port Alsworth +PTC,Port Alice +PTD,Port Alexander +PTE,Port Stephens +PTF,Malololailai +PTG,Polokwane +PTH,Port Heiden +PTI,Port Douglas +PTK,Pontiac +PTL,Port Armstrong +PTM,Palmarito +PTN,Patterson +PTO,Pato Branco +PTP,Pointe-a-pitre +PTQ,Porto de Moz +PTR,Pleasant Harbour +PTS,Pittsburg +PTT,Pratt +PTU,Platinum +PTV,Porterville +PTW,Pottstown +PTX,Pitalito +PTZ,Pastaza +PUA,Puas +PUB,Pueblo +PUD,Puerto Deseado +PUE,Puerto Obaldia +PUH,Pochutla +PUI,Pureni +PUJ,Higuey +PUK,Pukarua +PUL,Poulsbo +PUO,Prudhoe Bay +PUQ,Punta Arenas +PUR,Puerto Rico +PUS,Busan +PUU,Puerto Asis +PUV,Poum +PUW,Pullman +PUX,Puerto Varas +PUZ,Puerto Cabezas +PVA,Providencia +PVC,Provincetown +PVD,Providence +PVE,El Porvenir +PVF,Placerville +PVH,Porto Velho +PVI,Paranavai +PVK,Preveza/Lefkas +PVN,Pleven +PVO,Portoviejo +PVR,Puerto Vallarta +PVS,Provideniya +PVW,Plainview +PVX,Provedenia +PVY,Pope Vanoy +PVZ,Painesville +PWD,Plentywood +PWE,Pevek +PWL,Purwokerto +PWN,Pitts Town +PWO,Pweto +PWQ,Pavlodar +PWR,Port Walter +PWT,Bremerton +PXL,Polacca +PXM,Puerto Escondido +PXO,Porto Santo +PXR,Surin +PXS,Puerto De Santa Maria +PXU,Pleiku +PYA,Puerto Boyaca +PYB,Jeypore +PYC,Playon Chico +PYE,Penrhyn Island +PYH,Puerto Ayacucho +PYJ,Polyarnyj +PYL,Perry Island +PYN,Payan +PYO,Putumayo +PYR,Pyrgos +PYV,Yaviza +PZA,Paz De Ariporo +PZB,Pietermaritzburg +PZE,Penzance +PZI,Pan Zhi Hua +PZL,Phinda +PZO,Puerto Ordaz +PZU,Port Sudan +PZY,Piestany +QBC,"Bella Coola, BC" +QCE,Copper Mountain +QCU,Akunnaaq +QDM,Shek Mum +QFI,Iginniarfik +QFQ,Maloy +QHU,Husum +QJE,Kitsissuarsuit +QJI,Ikamiut +QJV,Skagen Z7 +QKS,Keystone +QLX,Lauterach +QMK,Niaqornaarsuk +QMM,Marina Di Massa +QMQ,Murzuq +QMV,Montvale +QPW,Kangaatsiaq +QQS,Britrail Rail Zone S +QRO,Queretaro +QRY,Ikerasaarsuk +QUB,Ubari +QUP,Saqqaq +QVL,Victoria Island +QVY,Kouvola +QWP,Winter Park +RAA,Rakanda +RAG,Raglan +RAH,Rafha +RAK,Marrakech +RAL,Riverside +RAO,Ribeirao Preto +RAR,Rarotonga +RAU,Rangpur +RAV,Cravo Norte +RAY,Rothesay +RAZ,Rawala Kot +RBA,Rabat +RBB,Borba +RBC,Robinvale +RBF,Big Bear +RBG,Roseburg +RBH,Brooks Lodge +RBJ,Rebun +RBK,Rancho +RBL,Red Bluff +RBM,Straubing +RBN,Fort Jefferson +RBO,Robore +RBP,Rabaraba +RBQ,Rurrenabaque +RBR,Rio Branco +RBS,Orbost +RBT,Marsabit +RBU,Roebourne +RBV,Ramata +RBW,Walterboro +RCA,Rapid City +RCB,Richards Bay +RCE,Roche Harbor +RCH,Riohacha +RCK,Rockdale +RCL,Redcliffe +RCN,American River +RCO,Rochefort +RCP,Cinder River +RCQ,Reconquista +RCT,Reed City +RCU,Rio Cuarto +RDA,Rockhampton Downs +RDC,Redencao +RDE,Merdey +RDG,Reading +RDN,Redang +RDR,Red River +RDS,Rincon de los Sauces +RDT,Richard Toll +RDU,Raleigh-durham +RDZ,Rodez +REA,Reao +REB,Rechlin +REG,Reggio Calabria +REH,Rehoboth Beach +REL,Trelew +REP,Siem Reap +RER,Retalhuleu +RES,Resistencia +REX,Reynosa +REY,Reyes +REZ,Resende +RFA,Rafai +RFD,"Rockford, IL" +RFG,Refugio +RFN,Raufarhofn +RFP,Raiatea +RFR,Rio Frio +RFS,Rosita +RGA,Rio Grande +RGE,Porgera +RGH,Balurghat +RGI,Rangiroa +RGL,Rio Gallegos +RGR,Ranger +RGT,Rengat +RHA,Reykholar +RHD,Rio Hondo +RHE,Reims +RHG,Ruhengeri +RHI,Rhinelander +RHL,Roy Hill +RHO,Rhodes +RHP,Ramechhap +RIB,Riberalta +RIC,Richmond +RIE,Rice Lake +RIF,Richfield +RIJ,Rioja +RIK,Carrillo +RIL,Rifle +RIM,Rodriguez De Mendoza +RIN,Ringi Cove +RIO,Rio De Janeiro All Airports +RIS,Rishiri +RIT,Rio Tigre +RIW,"Riverton, WY" +RIY,Riyan Mukalla +RIZ,Rio Alzucar +RJB,Rajbiraj +RJH,Rajshahi +RJI,Rajouri +RJK,Rijeka +RJL,Logrono +RJN,Rafsanjan +RKC,Yreka +RKD,Rockland +RKH,Rock Hill +RKI,Rokot +RKO,Sipora +RKP,Rockport +RKR,Poteau +RKS,Rock Springs +RKT,Ras Al Khaimah +RKU,Yule Island +RKW,Rockwood +RKY,Rokeby +RLA,Rolla +RLD,Richland +RLG,Rostock-laage +RLO,Merlo +RLP,Rosella Plains +RLT,Arlit +RLU,Bornite +RMB,Buraimi +RMD,Ramagundam +RMI,Rimini +RMK,Renmark +RMN,Rumginae +RMP,Rampart +RMQ,Taichung +RMS,Ramstein +RNB,Ronneby +RNC,Mcminnville +RNE,Roanne +RNG,Rangely +RNI,Corn Island +RNJ,Yoronjima +RNL,Rennell +RNO,"Reno, NV" +RNP,Rongelap Island +RNS,Rennes +RNT,"Renton, WA" +RNU,Ranau +RNZ,Rensselaer +ROA,Roanoke +ROC,"Rochester, NY" +ROD,Robertson +ROH,Robinhood +ROI,Roi Et +ROL,Roosevelt +ROO,Rondonopolis +ROR,Koror +ROT,Rotorua +ROU,Rousse +ROV,Rostov +ROW,Roswell +RPA,Rolpa +RPB,Roper Bar +RPM,Ngukurr +RPN,Rosh Pina +RPV,Roper Valley +RRA,Ronda +RRE,Marree +RRI,Barora +RRK,Rourkela +RRL,Merrill +RRN,Serra Norte +RRS,Roros +RRT,Warroad +RRV,Robinson River +RSA,Santa Rosa +RSB,Roseberth +RSD,Rock Sound +RSG,Serra Pelada +RSH,Russian Mission +RSI,Rio Sidra +RSK,Ransiki +RSL,Russell +RSN,Ruston +RSP,Raspberry Strait +RSU,Yeosu +RSW,Fort Myers +RSX,Rouses Point +RTA,Rotuma Island +RTB,Roatan +RTC,Ratnagiri +RTD,Rotunda +RTE,Marguerite Bay +RTG,Ruteng +RTL,Spirit Lake +RTN,Raton +RTP,Rutland Plains +RTS,Rottnest Island +RTW,Saratov +RTY,Merty +RUF,Yuruf +RUG,Rugao +RUI,Ruidoso +RUP,Rupsi +RUR,Rurutu +RUS,Marau Sound +RUT,Rutland +RUV,Rubelsanto +RUY,Copan +RVA,Farafangana +RVC,Rivercess +RVD,Rio Verde +RVE,Saravena +RVK,Roervik +RVN,Rovaniemi +RVO,Reivilo +RVT,Ravensthorpe +RVV,Rairua +RVY,Rivera +RWB,Rowan Bay +RWF,Redwood Falls +RWI,"Rocky Mount," +RWL,Rawlins +RWN,Rovno +RWS,Sumare +RXA,Raudha +RXS,Roxas City +RYB,Rybinsk +RYK,Rahim Yar Khan +RYN,Royan +RYO,Rio Turbio +RZE,Rzeszow +RZN,Ryazan +RZP,Taytay Sandoval +RZR,Ramsar +RZS,Sawan +SAA,Saratoga +SAF,Santa Fe +SAJ,Sirajganj +SAK,Saudarkrokur +SAL,San Salvador +SAN,San Diego +SAQ,San Andros +SAS,Salton City +SAV,Savannah +SAX,Sambu +SAZ,Sasstown +SBA,"Santa Barbara, CA" +SBB,Santa Barbara de Barinas +SBC,Selbang +SBD,San Bernardino +SBE,Suabi +SBF,Sardeh Band +SBG,Sabang +SBH,St Barthelemy +SBI,Koundara +SBJ,Sao Mateus +SBK,Tremuson +SBM,Sheboygan +SBN,South Bend +SBR,Saibai Island +SBS,Steamboat Springs +SBU,Springbok +SBX,Shelby +SBY,Salisbury-Ocean City +SBZ,Sibiu +SCA,Santa Catalina +SCB,Scribner +SCC,Prudhoe Bay/Deadhorse +SCD,Sulaco +SCG,Spring Creek +SCH,"Schenectady, NY" +SCI,San Cristobal +SCJ,Smith Cove +SCK,Stockton +SCL,Santiago +SCM,Scammon Bay +SCN,Saarbruecken +SCO,Aktau +SCP,St Crepin +SCQ,Santiago De Compostela +SCR,Scranton +SCT,Socotra +SCV,Suceava +SCW,Syktyvkar +SDB,Saldanha Bay +SDC,Sandcreek +SDD,Lubango +SDE,Santiago Del Estero +SDF,"Louisville, KY" +SDG,Sanandaj +SDI,Saidor +SDJ,Sendai +SDK,Sandakan +SDL,Sundsvall +SDN,Sandane +SDO,Ryotsu Sado Is +SDP,Sand Point +SDQ,Santo Domingo +SDR,Santander +SDS,Sado Shima +SDT,Saidu Sharif +SDX,Sedona +SEB,Sebha +SEF,"Sebring, Fl" +SEG,Selinsgrove +SEH,Senggeh +SEI,Senhor Do Bonfim +SEJ,Seydisfjordur +SEK,Ksar Es Souk +SEM,Selma +SEN,Southend +SEO,Seguela +SEQ,Sungai Pakning +SER,Seymour +SEU,Seronera +SEV,Severodoneck +SEY,Selibaby +SFB,Sanford +SFC,St Francois +SFH,San Felipe +SFJ,Kangerlussuaq +SFK,Soure +SFL,Sao Filipe +SFP,Surfers Paradise +SFQ,Sanliurfa +SFR,"San Fernando, CA" +SFT,Skelleftea +SFU,Safia +SFV,Santa Fe Do Sul +SFX,San Felix +SFZ,"Pawtucket, RI" +SGA,Sheghnan +SGB,Singaua +SGC,Surgut +SGD,Sonderborg +SGE,Siegen +SGF,Springfield +SGG,Simanggang +SGI,Sargodha +SGJ,Sagarai +SGK,Sangapi +SGL,Cavite City +SGO,St George +SGP,Shay Gap +SGQ,Sanggata +SGS,Sanga Sanga +SGT,"Stuttgart, AR" +SGU,Saint George +SGV,Sierra Grande +SGW,Saginaw Bay +SGX,Songea +SGY,Skagway +SGZ,Songkhla +SHB,Nakashibetsu +SHC,Indaselassie +SHD,Staunton +SHF,Shanhaiguan +SHG,Shungnak +SHH,Shishmaref +SHI,Shimojishima +SHK,Sehonghong +SHM,Shirahama +SHN,Shelton +SHO,Sokcho +SHQ,Southport +SHR,Sheridan +SHU,Smith Point +SHV,Shreveport +SHW,Sharurah +SHX,Shageluk +SHZ,Seshutes +SIB,Sibiti +SIE,Sines +SIH,Silgadi Doti +SII,Sidi Ifni +SIJ,Siglufjordur +SIK,Sikeston +SIO,Smithton +SIQ,Singkep +SIU,Siuna +SIV,Sullivan +SIW,Sibisa +SIY,Montague +SIZ,Sissano +SJB,San Joaquin +SJC,San Jose +SJD,Los Cabos +SJF,St John Island +SJG,San Pedro Jagua +SJJ,Sarajevo +SJK,Sao Jose Dos Campos +SJL,Sao Gabriel +SJN,"St Johns, AZ" +SJO,Juan Santamaria | San Juanillo | San Juan +SJP,Sao Jose Do Rio Preto +SJQ,Sesheke +SJT,San Angelo +SJV,San Javier +SJW,Shijiazhuang +SJX,Sartaneja +SJY,Seinajoki +SJZ,Sao Jorge Island +SKB,"Basseterre, St. Kitts Island" +SKD,Samarkand +SKE,Skien +SKG,Thessaloniki +SKH,Surkhet +SKJ,Sitkinak Island +SKK,Shaktoolik +SKL,Isle Of Skye +SKM,Skeldon +SKN,Stokmarknes +SKO,Sokoto +SKP,Skopje +SKQ,Sekakes +SKR,Shakiso +SKS,Vojens +SKT,Sialkot +SKU,Skiros +SKV,Santa Katarina +SKW,Skwentna +SKX,Saransk +SLB,Storm Lake +SLC,"Salt Lake City, UT" +SLD,Sliac +SLF,Sulayel +SLG,Siloam Springs +SLJ,Chandler +SLK,Saranac Lake +SLL,Salalah +SLM,Salamanca +SLP,San Luis Potosi +SLQ,Sleetmute +SLR,Sulphur Springs +SLS,Silistra +SLT,Salida +SLU,Castries +SLW,Saltillo +SLX,Salt Cay +SMB,Cerro Sombrero +SME,Somerset +SMF,"Sacramento, CA" +SMH,Sapmanga +SMK,St Michael +SML,Stella Maris +SMM,Semporna +SMN,Salmon +SMO,Santa Monica +SMQ,Sampit +SMR,Santa Marta +SMS,Sainte Marie +SMT,Sun Moon Lake +SMU,Sheep Mountain +SMV,St Moritz +SMX,Santa Maria +SMY,Simenti +SMZ,Stoelmans Eiland +SNA,"Santa Ana, CA" +SNB,Snake Bay +SNC,Salinas +SNE,Sao Nicolau +SNG,San Ignacio De Velasco +SNH,Stanthorpe +SNI,Sinoe +SNJ,San Julian +SNK,Snyder +SNL,Shawnee +SNN,Shannon +SNO,Sakon Nakhon +SNP,Saint Paul Island +SNQ,San Quintin +SNR,St Nazaire +SNT,Sabana De Torres +SNU,Santa Clara +SNV,Santa Elena +SNW,Thandwe +SNX,Sabana De Mar +SOA,Soc Trang +SOC,Solo City +SOD,Sorocaba +SOE,Souanke +SOG,Sogndal +SOH,Solita +SOI,South Molle Island +SOJ,Sorkjosen +SOK,Semongkong +SOL,Solomon +SOM,San Tome +SOO,Soderhamn +SOP,Southern Pines +SOQ,Sorong +SOR,Al Thaurah +SOT,Sodankyla +SOU,Eastleigh near Southampton +SOV,Seldovia +SOW,"Show Low, AZ" +SOX,Sogamoso +SOY,Stronsay +SOZ,Solenzara +SPB,St Thomas Island +SPE,Sepulot +SPF,Spearfish +SPM,Spangdahlem +SPN,Saipan +SPP,Menongue +SPR,San Pedro +SPS,Wichita Falls +SPT,Sipitang +SPV,Sepik Plains +SPW,Spencer +SPZ,Springdale +SQA,Santa Ynez +SQC,Southern Cross +SQE,San Luis De Pale +SQF,Solano +SQG,Sintang +SQI,Sterling Rockfalls +SQJ,Shehdi +SQK,Sidi Barani +SQL,San Carlos +SQN,Sanana +SQO,Storuman +SQP,Starcke +SQQ,Siauliai +SQR,Soroako +SQS,San Ignacio +SQT,Samarai Island +SQU,Saposoa +SQV,Sequim +SQW,Skive +SQX,Sao Miguel do Oeste +SQY,Sao Lourenco Do Sul +SQZ,Scampton +SRC,Searcy +SRD,San Ramon +SRF,San Rafael +SRG,Semarang +SRI,Samarinda +SRJ,San Borja +SRK,Sierra Leone +SRM,Sandringham +SRN,Strahan +SRO,Santana Ramos +SRP,Stord +SRQ,"Sarasota, FL" +SRR,Stradbroke Island +SRS,San Marcos +SRT,Soroti +SRV,Stony River +SRW,Salisbury +SSA,"Salvador, Bahia" +SSE,Sholapur +SSG,Malabo +SSJ,Sandnessjoen +SSK,Sturt Creek +SSO,Sao Lourenco +SSP,Silver Plains +SSQ,La Sarre +SSS,Siassi +SST,Santa Teresita +SSU,White Sulphur Springs +SSV,Siasi +SSW,Stuart Island +SSX,Samsun/carsamba +SSZ,Santos +STA,Skjern +STC,Saint Cloud +STE,Stevens Point +STF,Stephen Island +STG,St George Island +STH,Strathmore +STJ,St Joseph +STK,Sterling +STL,St Louis +STM,Santarem +STO,Stockholm +STP,St Paul +STT,"Charlotte Amalie, St Thomas" +STW,Stavropol +STX,St Croix Island +STY,Salto +STZ,Santa Terezinha +SUB,Surabaya +SUC,Sundance +SUD,Stroud +SUE,Sturgeon Bay +SUF,Lamezia-terme +SUG,Surigao +SUI,Sukhumi +SUJ,Satu Mare +SUK,Samcheok +SUO,Sun River +SUP,Sumenep +SUQ,Sucua +SUR,Summer Beaver +SUT,Sumbawanga +SUW,Superior +SUX,Sioux City +SUY,Sudureyri +SUZ,Suria +SVA,Savoonga +SVB,Sambava +SVC,Silver City +SVD,St Vincent +SVE,Susanville +SVG,Stavanger +SVH,Statesville +SVI,San Vicente +SVJ,Svolvaer +SVK,Silver Creek +SVL,Savonlinna +SVP,Kuito +SVQ,Sevilla +SVR,Svay Rieng +SVS,Stevens Village +SVT,Savuti +SVU,Savusavu +SVW,Sparrevohn +SVX,Ekaterinburg +SWA,Shantou +SWB,Shaw River +SWC,Stawell +SWD,Seward +SWE,Siwea +SWF,Newburgh +SWG,Satwag +SWH,Swan Hill +SWI,Swindon +SWJ,South West Bay +SWL,Spanish Wells +SWM,Suia-Missu +SWN,Sahiwal +SWO,Stillwater +SWP,Swakopmund +SWQ,Sumbawa +SWR,Silur +SWS,Swansea +SWT,Strzhewoi +SWU,Suwon +SWV,Shikarpur +SWX,Shakawe +SWY,Sitiawan +SXA,Sialum +SXB,Strasbourg +SXD,Sophia Antipolis +SXG,Senanga +SXH,Sehulea +SXI,Sirri Island +SXJ,Shanshan +SXK,Saumlaki +SXL,Sligo +SXM,"Philipsburg, St. Maarten" +SXN,Suapan +SXO,Sao Felix Do Araguaia +SXP,Sheldon Point +SXQ,Soldotna +SXS,Sahabat 16 +SXT,Taman Negara +SXU,Soddu +SXW,Sauren +SXX,Sao Felix Do Xingu +SYA,Shemya +SYB,Seal Bay +SYC,Shiringayoc +SYE,Sadah +SYF,Silva Bay +SYG,Svalbard +SYH,Syangboche +SYI,Shelbyville +SYJ,Sirjan +SYK,Stykkisholmur +SYL,San Miguel +SYM,Simao +SYN,Stanton +SYO,Shonai +SYR,Syracuse +SYS,Suncheon +SYT,Saint Yan +SYU,Sue Island +SYW,Sehwen Sharif +SYY,Stornoway +SYZ,Shiraz +SZE,Semera +SZG,Salzburg +SZH,Senipah +SZI,Zaisan +SZJ,Siguanea +SZK,Skukuza +SZM,Sesriem +SZO,Shanzhou +SZP,Santa Paula +SZQ,Saenz Pena +SZR,Stara Zagora +SZS,Stewart Island +SZU,Segou +SZV,Suzhou +SZW,Schwerin +SZX,Shenzhen +SZY,Szymany +SZZ,Szczecin +TAA,Tarapaina +TAC,Tacloban +TAD,Trinidad +TAE,Daegu +TAM,Tampico +TAO,Qingdao +TAQ,Tarcoola +TAS,Tashkent +TAW,Tacuarembo +TAZ,Dashoguz +TBA,Tabibuga +TBB,Tuy Hoa +TBC,Tuba City +TBD,Timbiqui +TBE,Timbunke +TBF,Tabiteuea North +TBG,Tabubil +TBI,The Bight +TBJ,Tabarka +TBK,Timber Creek +TBL,Tableland +TBM,Tumbang Samba +TBN,Fort Leonard Wood +TBO,Tabora +TBP,Tumbes +TBQ,Tarabo +TBT,Tabatinga +TBW,Tambov +TBY,Tsabong +TBZ,Tabriz +TCA,Tennant Creek +TCB,"Treasure Cay, Ibaco Islands" +TCC,Tucumcari +TCD,Tarapaca +TCE,Tulcea +TCG,Tacheng +TCH,Tchibanga +TCJ,Torembi +TCK,Tinboli +TCL,"Tuscaloosa, AL" +TCN,Tehuacan +TCS,Truth Or Consequences +TCT,Takotna +TCU,Thaba Nchu +TCW,Tocumwal +TCX,Tabas +TDB,Tetabedi +TDG,Tandag +TDJ,Tadjoura +TDK,Taldy-Kurgan +TDL,Tandil +TDS,Sasereme +TDT,Tanda Tula +TDV,Tanandava | Antanandava +TDW,Amarillo +TEB,Teterboro +TEC,Telemaco Borba +TEF,Telfer +TEK,Tatitlek +TEO,Terapo +TEP,Teptep +TEQ,Tekirdag +TER,Terceira Island +TES,Tessenei +TEU,Te Anau +TEW,Tohid +TEX,Telluride +TFB,Tifalmin +TFC,Taormina +TFL,Teofilo Otoni +TFM,Telefomin +TFR,Ramadan +TFS,Tenerife +TFT,Taftan +TFY,Tarfaya +TGB,Tagbita +TGD,Podgorica +TGE,Tuskegee +TGF,Tignes +TGG,Kuala Terengganu +TGH,Tongoa +TGI,Tingo Maria +TGL,Tagula +TGM,Tirgu Mures +TGN,Traralgon +TGO,Tongliao +TGQ,Tangara da Serra +TGR,Touggourt +TGS,Chokwe +TGU,Tegucigalpa +TGV,Targovishte +TGX,Tingrela +TGZ,Tuxtla Gutierrez +THB,Thaba-Tseka +THC,Tchien +THG,Thangool +THH,Taharoa +THL,Tachilek +THO,Thorshofn +THP,Thermopolis +THY,Thohoyandou +THZ,Tahoua +TIC,Tinak Island +TID,Tiaret +TIG,Tingwon +TIH,Tikehau Atoll +TII,Tirinkot +TIJ,Tijuana +TIQ,Tinian +TIU,Timaru +TIV,Tivat +TIX,Titusville +TIY,Tidjikja +TJA,Tarija +TJB,Tanjung Balai +TJC,Ticantiki +TJG,Tanjung Warukin +TJH,Toyooka +TJM,Tyumen +TJN,Takume +TJQ,Tanjung Pandan +TJS,Tanjung Selor +TKA,Talkeetna +TKB,Tekadu +TKD,Takoradi +TKF,"Truckee, CA" +TKG,Bandar Lampung +TKH,Takhli +TKI,Tokeen +TKL,Taku Lodge +TKN,Tokunoshima +TKO,Tlokoeng +TKP,Takapoto +TKQ,Kigoma +TKR,Thakurgaon +TKS,Tokushima +TKU,Turku +TKV,Tatakoto +TKX,Takaroa +TKY,Turkey Creek +TKZ,Tokoroa +TLB,Tarbela +TLC,Toluca +TLD,Tuli Block +TLE,Tulear +TLF,Telida +TLG,Tulagi Island +TLH,Tallahassee +TLI,Tolitoli +TLJ,Tatalina +TLL,Tallinn +TLM,Tlemcen +TLN,Hyeres +TLP,Tumolbil +TLR,"Tulare, CA" +TLS,Toulouse +TLT,Tuluksak +TLW,Talasea +TLZ,Catalao +TMA,"Tifton, GA" +TMC,Tambolaka +TMD,Timbedra +TMG,Tomanggong +TMH,Tanahmerah +TMI,Tumling Tar +TMJ,Termez +TML,Tamale +TMM,Tamatave +TMN,Tamana Island +TMO,Tumeremo +TMP,Tampere +TMQ,Tambao +TMR,Tamanrasset +TMS,Sao Tome Is +TMT,Trombetas +TMU,Tambor +TMW,Tamworth +TMX,Timimoun +TMZ,Thames +TNA,Jinan +TNB,Tanah Grogot +TNE,Tanegashima +TNF,Toussus-Le-Noble +TNG,Tangier +TNH,Tonghua +TNJ,Tanjung Pinang +TNK,Tununak +TNL,Ternopol +TNM,Teniente R. Marsh Martin +TNN,Tainan +TNO,Tamarindo +TNQ,Teraina +TNR,Antananarivo +TNS,Tungsten +TNU,Newton +TNV,Tabuaeran +TNX,Stung Treng +TNZ,Tosontsengel +TOA,Torrance +TOB,Tobruk +TOC,Toccoa +TOF,Tomsk +TOG,Togiak Village +TOQ,Tocopilla +TOS,Tromso +TOU,Touho +TOV,Tortola +TOX,Tobolsk +TOZ,Touba +TPA,Tampa +TPC,Tarapoa +TPE,Taipei +TPG,Taiping +TPH,Tonopah +TPI,Tapini +TPJ,Taplejung +TPK,Tapaktuan +TPN,Tiputini +TPP,Tarapoto +TPQ,Tepic +TPS,Trapani +TPT,Tapeta +TPX,Tupai +TQN,Taluqan +TQR,San Domino Island +TQS,Tres Esquinas +TRA,Taramajima +TRB,Turbo +TRC,Torreon +TRD,Trondheim +TRF,Torp +TRG,Tauranga +TRH,Trona +TRI,Blountville +TRJ,Tarakbits +TRK,Tarakan +TRL,Terrell +TRQ,Tarauaca +TRR,Trincomalee +TRS,Trieste +TRT,Tremonton +TRU,Trujillo +TRW,Tarawa +TRX,Trenton +TSA,Taipei City +TSB,Tsumeb +TSC,Taisha +TSD,Tshipise +TSE,Astana +TSF,Treviso +TSG,Tanacross +TSH,Tshikapa +TSI,Tsili Tsili +TSJ,Tsushima +TSK,Taskul +TSL,Tamuin +TSO,Isles Of Scilly +TSP,"Tehachapi, CA" +TSQ,Torres +TSR,Timisoara +TST,Trang +TSU,Tabiteuea South +TSV,Townsville +TSW,Tsewi +TSX,Tanjung Santan +TSY,Tasikmalaya +TSZ,Tsetserleg +TTB,Tortoli +TTC,Taltal +TTD,Troutdale +TTE,Ternate +TTG,Tartagal +TTH,Thumrait +TTI,Tetiaroa Is +TTJ,Tottori +TTL,Turtle Island +TTM,Tablon De Tamara +TTN,"Trenton, NJ" +TTO,Britton +TTQ,Tortuquero +TTR,Tana Toraja +TTS,Tsaratanana +TTT,Taitung +TTU,Tetuan +TUA,Tulcan +TUC,Tucuman +TUD,Tambacounda +TUG,Tuguegarao +TUH,Tullahoma +TUI,Turaif +TUK,Turbat +TUU,Tabuk +TUV,Tucupita +TUW,Tubala +TUZ,Tucuma +TVA,Morafenobe +TVC,Traverse City +TVF,Thief River Falls +TVI,Thomasville +TVL,South Lake Tahoe +TVU,Taveuni +TWA,Twin Hills +TWB,Toowoomba +TWD,Port Townsend +TWF,"Twin Falls, ID" +TWN,Tewantin +TWP,Torwood +TWT,Tawitawi +TWU,Tawau +TXF,Teixeira de Freitas +TXK,Texarkana +TXM,Teminabuan +TXN,Tunxi +TXR,Tanbar +TXU,Tabou +TYB,Tibooburra +TYD,Tynda +TYE,Tyonek +TYF,Torsby +TYG,Thylungra +TYL,Talara +TYM,Staniel Cay +TYN,Taiyuan +TYO,Tokyo All Airports +TYR,Tyler +TYS,Knoxville +TYT,Treinta-y-Tres +TYZ,Taylor +TZL,Tuzla +TZM,Tizimin +TZN,South Andros +TZX,Trabzon +UAC,San Luis Rio Colorado +UAE,Mount Aue +UAK,Narsarsuaq +UAM,"Andersen, Mariana Island" +UAS,Samburu +UAX,Uaxactun +UBA,Uberaba +UBB,Mabuiag Island +UBP,Ubon Ratchathni +UBT,Ubatuba +UBU,Kalumburu +UCA,Utica +UCE,Eunice +UCK,Lutsk +UCN,Buchanan +UCT,Ukhta +UDI,Uberlandia +UDJ,Uzhgorod +UDN,Udine +UDO,Udomxay +UEL,Quelimane +UEO,Kumejima +UER,Puertollano +UES,Waukesha +UET,Quetta +UGA,Bulgan +UGC,Urgench +UGI,Uganik +UGN,Waukegan +UGS,Ugashik +UGT,Umnugobitour +UGU,Zugapa +UHE,Uherske Hradiste +UHF,Upper Heyford +UIB,Quibdo +UIH,Qui Nhon +UII,Utila +UIK,Ust-Ilimsk +UIL,Quillayute +UIN,Quincy +UIO,Quito +UIP,Quimper +UIQ,Quine Hill +UIR,Quirindi +UIT,Jaluit Island +UJE,Ujae Island +UKA,Ukunda +UKB,Kobe +UKI,Ukiah +UKK,Ust-kamenogorsk +UKN,Waukon +UKR,Mukeiras +UKS,Sevastopol +UKT,Quakertown +UKX,Ust-Kut +UKY,Kyoto +ULD,Ulundi +ULG,Ulgit +ULI,Ulithi +ULM,New Ulm +ULN,Ulaanbaatar +ULO,Ulaangom +ULP,Quilpie +ULQ,Tulua +ULS,Mulatos +ULX,Ulusaba +ULY,Ulyanovsk +ULZ,Uliastai +UMA,Punta De Maisi +UMB,Umnak Island +UMD,Uummannaq +UMI,Quincemil +UMM,Summit +UMR,Woomera +UMT,Umiat +UMU,Umuarama +UNC,Unguia +UND,Kunduz +UNE,Qachas Nek +UNG,Kiunga +UNI,Union Island +UNK,Unalakleet +UNN,Ranong +UNR,Underkhaan +UNT,Unst Shetland Is +UNU,"Juneau, WI" +UON,Muong Sai +UOS,Sewanee +UPA,Punta Alegre +UPB,Havana +UPC,Puerto La Cruz +UPF,Pforheim +UPG,Ujung Pandang +UPL,Upala +UPN,Uruapan +UPP,Upolu Point +UPR,Upiara +UPV,Upavon +UQE,Queen +URA,Uralsk +URB,Urubupunga +URC,Urumqi +URD,Burg Feuerstein +URE,Kuressaare +URG,Uruguaiana +URM,Uriman +URN,Urgoon +URO,Rouen +URR,Urrao +URS,Kursk +URU,Uroubi +URY,Gurayat +URZ,Uruzgan +USH,Ushuaia +USI,Mabaruma +USK,Usinsk +USM,Koh Samui +USN,Ulsan +USO,Usino +UST,St Augustine +USU,Busuanga +UTA,Mutare +UTB,Muttaburra +UTC,Utrecht +UTD,Nutwood Downs +UTH,Udon Thani +UTK,Utirik Island +UTL,Torremolinos +UTN,Upington +UTO,Utopia Creek +UTR,Uttaradit +UTT,Umtata +UTU,Ustupo +UUA,Bugulma +UUD,Ulan-ude +UUK,Kuparuk +UUN,Baruun-Urt +UUS,Yuzhno-Sakhalinsk +UUU,Manumu +UVA,Uvalde +UVE,Ouvea +UVF,St Lucia +UVL,Kharga +UYL,Nyala +UYN,Yulin +UZH,Unayzah +UZU,Curuzu Cuatia +VAA,Vaasa +VAB,Yavarate +VAC,Varrelbusch +VAF,Valence +VAG,Varginha +VAH,Vallegrande +VAK,Chevak +VAO,Suavanao +VAU,Vatukoula +VAW,Vardoe +VBS,Brescia +VBV,Vanuabalavu +VBY,Visby +VCE,Venice +VCF,Valcheta +VCH,Vichadero +VCL,Tamky +VCR,Carora +VCS,Con Dao +VCV,"Victorville, CA" +VDB,Fagernes +VDC,Vitoria Da Conquista +VDE,Valverde +VDI,Vidalia +VDM,Viedma +VDP,Valle De Pascua +VDR,Villa Dolores +VDS,Vadso +VDZ,Valdez +VEJ,Vejle +VEL,"Vernal, UT" +VEV,Barakoma +VEX,Tioga +VEY,Vestmannaeyjar +VFA,Victoria Falls +VGD,Vologda +VGG,Vangrieng +VGO,Vigo +VGS,General Villegas +VGZ,Villagarzon +VHC,Saurimo +VHM,Vilhelmina +VHN,Van Horn +VHY,Vichy +VHZ,Vahitahi +VIB,Villa Constitucion +VIC,Vicenza +VID,Vidin +VIE,Vienna +VIF,Vieste +VIG,El Vigia +VIK,Kavik +VIL,Dakhla +VIQ,Viqueque +VIX,Vitoria +VJQ,Gurue +VKG,Rach Gia +VKS,Vicksburg +VKT,Vorkuta +VKW,West Kavik +VLA,Vandalia +VLD,Valdosta +VLE,Valle +VLG,Villa Gesell +VLI,Port Vila +VLK,Volgodonsk +VLL,Valladolid +VLM,Villamontes +VLN,Valencia +VLO,Vallejo +VLP,Vila Rica +VLR,Vallenar +VLS,Valesdir +VLU,Velikiye Luki +VLV,Valera +VME,Villa Mercedes +VMI,Vallemi +VMU,Baimuru +VNA,Saravane +VND,Vangaindrano +VNE,Vannes +VNG,Viengxay +VNR,Vanrook +VNX,Vilanculos +VOG,Volgograd +VOH,Vohemar +VOI,Voinjama +VOK,Camp Douglas +VOT,Votuporanga +VOZ,Voronezh +VPE,Ongiva +VPN,Vopnafjordur +VPS,"Valparaiso, FL" +VPY,Chimoio +VQS,Vieques +VRA,Varadero +VRB,Vero Beach +VRC,Virac +VRE,Vredendal +VRK,Joroinen +VRL,Vila Real +VRN,Verona +VRO,Matanzas +VRS,Versailles +VRU,Vryburg +VRY,Vaeroy +VSA,Villahermosa +VSE,Viseu +VSG,Lugansk +VSO,Phuoclong +VTB,Vitebsk +VTE,Vientiane +VTF,Vatulele +VTG,Vung Tau +VTL,Vittel +VTN,Valentine +VTU,Las Tunas +VUP,Valledupar +VUS,Velikij Ustyug +VUU,Mvuu Camp +VVB,Mahanoro +VVC,Villavicencio +VVK,Vastervik +VVO,Vladivostok +VVZ,Illizi +VXC,Lichinga +VXE,Sao Vicente +VYD,Vryheid +WAA,Wales +WAB,Wabag +WAD,Andriamena +WAE,Wadi Ad Dawasir +WAG,Wanganui +WAH,Wahpeton +WAJ,Wawoi Falls +WAK,Ankazoabo +WAL,Chincoteague +WAM,Ambatondrazaka +WAN,Waverney +WAQ,Antsalova +WAT,Waterford +WAU,Wauchope +WAV,Wave Hill +WAY,Waynesburg +WAZ,Warwick +WBA,Wahai +WBB,Stebbins +WBC,Wapolu +WBD,Befandriana +WBE,Bealanana +WBG,Schleswig-jagel +WBM,Wapenamanda +WBN,Woburn +WBO,Beroroha +WBQ,Beaver +WBR,Big Rapids +WCA,Castro +WCH,Chaiten +WCR,Chandalar +WDH,Windhoek +WDI,Wondai +WDN,Waldron Island +WDR,Winder +WEA,Weatherford +WEF,Weifang +WEH,Weihai +WEL,Welkom +WEM,West Malling +WEX,Wexford +WFI,Fianarantsoa +WFK,Frenchville +WGB,Bahawalnagar +WGC,Warangal +WGE,Walgett +WGN,Waitangi +WGO,Winchester +WGP,Waingapu +WGT,Wangaratta +WGU,Wagau +WGY,Wagny +WHF,Wadi Halfa +WHK,Whakatane +WIE,Wiesbaden +WIK,Surfdale +WIO,Wilcannia +WIR,Wairoa +WJR,Wajir +WJU,WonJu +WKA,Wanaka +WKB,Warracknabeal +WKI,Hwange +WKJ,Wakkanai +WKK,Aleknagik +WKL,Waikoloa +WKN,Wakunai +WLA,Wallal +WLB,Labouchere Bay +WLC,Walcha +WLD,Winfield +WLG,Wellington +WLH,Walaha +WLK,Selawik +WLL,Wollogorang +WLM,Waltham +WLS,Wallis Island +WLW,Willows +WMA,Mandritsara +WMB,Warrnambool +WMC,Winnemucca +WMD,Mandabe +WME,Mount Keith +WMH,Mountain Home +WMK,Meyers Chuck +WML,Malaimbandy +WMN,Maroantsetra +WMO,White Mountain +WMP,Mampikony +WMR,Mananara +WMV,Madirovalo +WMX,Wamena +WNA,Napakiak +WNC,Tuxekan Island +WND,Windarra +WNN,Wunnummin Lake +WNR,Windorah +WNS,Nawabshah +WNU,Wanuma +WOA,Wonenara +WOB,Suttonheath +WOD,Wood River +WOE,Woensdrecht +WOG,Woodgreen +WOI,Wologissi +WOK,Wonken +WOR,Ankorefo +WPA,Puerto Aisen +WPB,Port Berge +WPC,Pincher Creek +WPK,Wrotham Park +WPL,Powell Lake +WPM,Wipim +WPO,Paonia +WPR,Porvenir +WPU,Puerto Williams +WRA,Warder +WRE,Whangarei +WRG,Wrangell +WRH,Wrench Creek +WRI,"Wrightstown, New Jersey" +WRL,"Worland, WY" +WRW,Warrawagine +WRZ,Wirawila +WSA,Wasua +WSB,Steamboat Bay +WSD,White Sands +WSF,Sarichef +WSN,South Naknek +WSO,Washabo +WSP,Waspam +WSR,Wasior +WST,Westerly +WSX,Westsound +WSY,Airlie Beach +WSZ,Westport +WTA,Tambohorano +WTD,West End +WTE,Wotje Island +WTK,Noatak +WTL,Tuntutuliak +WTN,Waddington +WTO,Wotho Island +WTP,Woitape +WTR,White River +WTS,Tsiroanomandidy +WTT,Wantoat +WTZ,Whitianga +WUD,Wudinna +WUK,Hammersmith +WUM,Wasum +WUN,Wiluna +WUS,Wuyishan +WUV,Wuvulu Is +WUZ,Wuzhou +WVB,Walvis Bay +WVI,Watsonville +WVK,Manakara +WVL,Waterville +WVN,Wilhelmshaven +WWA,Wasilla +WWD,Wildwood +WWG,Al Koude +WWI,Woodie Woodie +WWK,Wewak +WWP,Whale Pass +WWR,Woodward +WWT,Newtok +WWY,West Wyalong +WXN,Wanxian +WYA,Whyalla +WYE,Yengema +WYN,Wyndham +WYS,West Yellowstone +XAL,Alamos +XAP,Chapeco +XAR,Aribinda +XAY,Xayabury +XBB,Blubber Bay +XBE,Bearskin Lake +XBG,Bogande +XBJ,Birjand +XBL,Buno Bedelle +XBN,Biniguni +XBO,Boulsa +XBR,Brockville +XBW,Killineq +XCL,Cluff Lake +XCM,Chatham +XCN,Coron +XCO,Colac +XCR,Chalons Sur Marne +XDB,Lille +XDE,Diebougou +XDJ,Djibo +XEN,Xingcheng +XEO,Oqatsut +XEQ,Tasiuasaq +XES,Lake Geneva +XFN,Xiangfan +XGA,Gaoua +XGL,Granville Lake +XGN,Xangongo +XGR,Kangiqsualujjuaq +XGZ,Bregenz +XHJ,Aix La Chapelle +XIC,Xichang +XIE,Xienglom +XIG,Xinguara +XIH,Khan Al Baghdadi +XIJ,Ahmed Al Jaber +XIL,Xilinhot +XIN,Xingning +XIQ,Ilimanaq +XJD,Al Udeid +XJM,Mangla +XJS,Kitzbuehl +XKA,Kantchari +XKC,Sandnes +XKH,Xieng Khouang +XKO,Kemano +XKS,Kasabonika +XLB,Lac Brochet +XLF,Leaf Bay +XLO,Long Xuyen +XLW,Lemwerder +XMA,Maramag +XMC,Mallacoota +XMG,Mahendranagar +XMH,Manihi +XMI,Masasi +XML,Minlaton +XMP,Macmillan Pass +XMS,Macas +XMY,Yam Island +XNG,Quang Ngai +XNH,Nasiriyah +XNN,Xining +XNT,Xingtai +XNU,Nouna +XPK,Pukatawagan +XPL,Comayagua +XPP,Poplar River +XPQ,Port Klang +XPR,Pine Ridge +XPU,West Kuparuk +XPZ,Saint Tropez +XQP,Pavones +XQU,Qualicum +XQV,Baqubah +XRF,Marseille +XRR,Ross River +XRY,Jerez De La Frontera +XSC,South Caicos +XSE,Sebba +XSI,South Indian Lake +XSO,Siocon +XTG,Thargomindah +XTL,"Tadoule Lake, MB" +XTM,Ramadi +XTO,Taroom +XTV,Tikrit +XUV,Storekvina +XUW,Storen +XUZ,Xuzhou +XVL,Vinh Long +XWP,Hassleholm +XWQ,Enkoping +XWZ,Nykoping +XXA,Alvesta +XXK,Katrineholm +XXU,Hedemora +XYA,Yandina +XYB,Borlange | Falun +XYC,Herrljunga +XYM,Falkenberg +XYN,Kristinehamn +XYO,Karlshamn +XYP,Avesta Krylbo +XYR,Yellow River +XYU,Solvesborg +XZA,Zabre +YAB,Arctic Bay +YAC,Cat Lake +YAD,Moose Lake +YAF,Asbestos Hill +YAG,Fort Frances +YAH,Lagrande 4 +YAI,Chillan +YAJ,Lyall Harbour +YAM,Sault Ste Marie +YAN,Yangambi +YAP,"Yap, Caroline Islands" +YAQ,Maple Bay +YAT,Attawapiskat +YAU,Kattiniq +YAV,Miners Bay +YAX,Angling Lake +YAZ,"Tofino, BC" +YBB,Kugaaruk +YBC,Baie Comeau +YBD,New Westminster +YBE,Uranium City +YBF,Bamfield +YBG,Bagotville +YBH,Bull Harbour +YBI,Black Tickle +YBJ,Baie Johan Beetz +YBK,Baker Lake +YBL,Campbell River +YBM,Bronson Creek +YBN,Borden +YBO,Bobquinn Lake +YBP,Yibin +YBQ,Telegraph Harbour +YBR,Brandon +YBS,Opapamiska Lake +YBT,Brochet +YBV,Berens River +YBX,Blanc Sablon +YBY,"Bonnyville, AB" +YCA,Courtenay +YCB,Cambridge Bay +YCC,Cornwall +YCD,Nanaimo +YCE,Centralia +YCF,Cortes Bay +YCG,Castlegar +YCH,Miramichi +YCI,Caribou Island +YCJ,Cape St James +YCK,Colville Lake +YCM,St Catharines +YCN,Cochrane +YCO,Kugluktuk/Coppermine +YCQ,Chetwynd +YCR,Cross Lake +YCS,Chesterfield Inlet +YCT,Coronation +YCU,Yun Cheng +YCV,Cartierville +YCW,Chilliwack +YCX,Gagetown +YCY,Clyde River +YCZ,Fairmont Hot Springs +YDA,Dawson City +YDB,Burwash Landings +YDC,Drayton Valley +YDE,Paradise River +YDF,Deer Lake +YDG,Digby +YDH,Daniels Harbour +YDI,Davis Inlet +YDJ,Hatchet Lake +YDK,Main Duck Island +YDL,Dease Lake +YDN,Dauphin +YDO,Dolbeau +YDQ,Dawson Creek +YDR,Broadview +YDS,Desolation Sound +YDU,Kasba Lake +YDV,Bloodvein +YDW,Obre Lake +YDX,Doc Creek +YEC,Yecheon +YEG,Edmonton +YEI,Bursa +YEK,Arviat +YEL,Elliot Lake +YEM,Manitowaning +YEN,Estevan +YEO,Yeovilton +YEQ,Yenkis +YER,Fort Severn +YEV,Inuvik +YFA,Fort Albany +YFB,Iqaluit +YFC,Fredericton +YFE,Forestville +YFG,Fontanges +YFH,Fort Hope +YFJ,Snare Lake +YFL,Fort Reliance +YFO,Flin Flon +YFR,Fort Resolution +YFS,Fort Simpson +YFX,Fox Harbour (St Lewis) +YGA,Gagnon +YGB,Gillies Bay +YGC,Grande Cache +YGE,Gorge Harbor +YGG,Ganges Harbor +YGH,Fort Good Hope +YGJ,Yonago +YGK,Kingston +YGL,La Grande +YGM,Gimli +YGN,Greenway Sound +YGO,Gods Narrows +YGQ,Geraldton +YGR,Iles De La Madeleine +YGS,Germansen +YGT,Igloolik +YGV,Havre St Pierre +YGW,Kuujjuarapik +YGX,Gillam +YGY,Deception +YGZ,Grise Fiord +YHA,Port Hope Simpson +YHB,Hudson Bay +YHC,Hakai Pass +YHD,Dryden +YHI,Holman +YHK,Gjoa Haven +YHM,Hamilton +YHN,Hornepayne +YHO,Hopedale +YHP,Poplar Hill +YHR,Chevery +YHS,Sechelt +YHT,Haines Junction +YHY,Hay River +YHZ,"Halifax, NS" +YIB,Atikokan +YIF,Pakuashipi +YIG,Big Bay Marina +YIH,Yichang +YIK,Ivujivik +YIN,Yining +YIO,Pond Inlet +YIV,Island Lk/Garden Hill +YJF,Fort Liard +YJN,St Jean +YJO,Johnny Mountain +YJP,Jasper-hinton +YJT,Stephenville +YKA,Kamloops +YKC,Collins Bay +YKD,Kincardine +YKE,Knee Lake +YKF,Kitchener/Waterloo +YKG,Kangirsuk +YKI,Kennosao Lake +YKJ,Key Lake +YKK,Kitkatla +YKL,Schefferville +YKM,Yakima +YKN,Yankton +YKQ,Waskaganish +YKS,Yakutsk +YKT,Klemtu +YKU,Chisasibi +YKX,Kirkland Lake +YKY,Kindersley +YLA,Langara +YLB,Lac Biche +YLC,Kimmirut/Lake Harbour +YLD,Chapleau +YLE,Wha Ti/Lac La Martre +YLF,LaForges +YLG,Yalgoo +YLH,Lansdowne House +YLI,Ylivieska +YLJ,Meadow Lake +YLL,"Lloydminster, AB" +YLM,Clinton Creek +YLN,Yilan +YLO,Shilo +YLP,Mingan +YLQ,La Tuque +YLR,Leaf Rapids +YLS,Lebel-Sur-Quevillon +YLW,"Kelowna, BC" +YLX,Long Point +YLY,Langley +YMB,Merritt +YMC,Maricourt Airstrip +YMD,Mould Bay +YME,Matane +YMF,Montagne Harbor +YMG,Manitouwadge +YMI,Minaki +YMJ,Moose Jaw +YML,"Murray Bay, NT" +YMM,Fort Mcmurray +YMN,Makkovik +YMO,"Moosonee, ON" +YMP,Port McNeil +YMR,Merry Island +YMS,Yurimaguas +YMT,Chibougamau +YMW,Maniwaki +YNA,Natashquan +YNB,Yanbu +YNC,Wemindji +YNE,Norway House +YNF,Corner Brook +YNG,Youngstown +YNI,Nitchequon +YNK,Nootka Sound +YNL,"Points North Landing, Saskatchewan" +YNM,Matagami +YNN,Yandicoogina +YNO,"North Spirit Lake, ON" +YNP,Natuashish +YNR,"Arnes, MB" +YNS,Nemiscau +YNT,Yantai +YNY,Yangyang +YNZ,Yancheng +YOC,Old Crow +YOD,Cold Lake +YOH,Oxford House +YOK,Yokohama +YOP,Rainbow Lake +YOS,Owen Sound +YOT,Yotvata +YOW,Ottawa +YOY,Valcartier +YPA,"Prince Albert, SK" +YPB,Port Alberni +YPC,Paulatuk +YPD,Parry Sound +YPE,Peace River +YPF,Esquimalt +YPG,Portage La Prairie +YPH,Inukjuak +YPI,Port Simpson +YPJ,Aupaluk +YPL,Pickle Lake +YPM,Pikangikum +YPN,Port Menier +YPO,Peawanuck +YPP,Pine Point +YPQ,Peterborough +YPR,Prince Rupert +YPS,Port Hawkesbury +YPT,Pender Harbor +YPW,Powell River +YPX,Povungnituk +YPY,Fort Chipewyan +YPZ,Burns Lake +YQA,Muskoka +YQB,Quebec +YQC,Quaqtaq +YQE,Kimberley +YQF,Red Deer +YQG,Windsor +YQH,Watson Lake +YQI,"Yarmouth, NS" +YQK,Kenora +YQL,Lethbridge +YQM,Moncton +YQN,Nakina +YQQ,Comox +YQR,"Regina, Saskatchewan" +YQS,St Thomas +YQT,Thunder Bay +YQU,Grande Prairie +YQV,Yorkton +YQW,North Battleford +YQX,Gander +YQZ,Quesnel +YRA,Rae Lakes +YRB,Resolute +YRD,Dean River +YRE,Resolution Island +YRF,Cartwright +YRG,Rigolet +YRI,Riviere Du Loup +YRJ,Roberval +YRL,Red Lake +YRM,Rocky Mountain House +YRN,Owekeno Village +YRQ,Trois-Rivieres +YRS,Red Sucker Lake +YRT,"Rankin Inlet, NT" +YRV,Revelstoke +YSA,Sable Island +YSB,Sudbury +YSC,Sherbrooke +YSD,Suffield +YSE,Squamish +YSF,Stony Rapids +YSG,Lutselke/Snowdrift +YSH,Smith Falls +YSI,Sans Souci +YSJ,Saint John +YSK,Sanikiluaq +YSL,St Leonard +YSN,Salmon Arm +YSO,Postville +YSQ,Spring Island +YSR,Nanisivik +YSS,Slate Island +YST,Ste Therese Point +YSU,Summerside +YSV,Saglek +YSX,Shearwater +YSY,Sachs Harbour +YSZ,Squirrel Cove +YTA,Pembroke +YTB,Hartley Bay +YTC,Sturdee +YTD,Thicket Portage +YTE,Cape Dorset +YTG,Sullivan Bay +YTH,Thompson +YTI,Triple Island +YTJ,Terrace Bay +YTK,Tulugak +YTL,Big Trout +YTM,Mont Tremblant +YTN,Riviere Au Tonnerre +YTP,Tofino +YTQ,Tasiujuaq +YTS,"Timmins, ON" +YTT,"Tisdale, sk" +YTX,Telegraph Creek +YUA,Yuanmou +YUB,Tuktoyaktuk +YUD,Umiujaq +YUE,Yuendumu +YUL,Montreal +YUT,Repulse Bay +YUX,Hall Beach +YVA,Moroni +YVB,Bonaventure +YVC,La Ronge +YVE,Vernon B. C. +YVG,Vermilion +YVM,Qikiqtarjuaq +YVP,Kuujjuaq +YVQ,Norman Wells +YVT,Buffalo Narrows +YVV,"Wiarton, ON" +YWA,Petawawa +YWB,Kangiqsujuaq +YWG,Winnipeg +YWJ,Deline +YWK,Wabush +YWL,Williams Lake +YWM,Williams Harbour +YWN,Winisk +YWO,Lupin +YWP,Webequie +YWQ,Chute-Des-Passes +YWS,Whistler +YWY,Wrigley +YXC,Cranbrook +YXE,Saskatoon +YXF,Snake River +YXH,Medicine Hat +YXI,Killaloe +YXJ,Fort St John +YXK,Rimouski +YXL,Sioux Lookout +YXN,Whale Cove +YXP,Pangnirtung +YXQ,Beaver Creek +YXR,Earlton +YXS,Prince George +YXT,"Terrace, BC" +YXX,Abbotsford +YXY,"Whitehorse, Yukon" +YYA,Big Bay Yacht Club +YYB,North Bay +YYC,"Calgary, AB" +YYD,Smithers +YYE,Fort Nelson +YYF,Penticton +YYG,Charlottetown +YYH,Taloyoak +YYI,Rivers +YYJ,Victoria +YYL,Lynn Lake +YYN,Swift Current +YYQ,"Churchill, Manitoba" +YYR,Goose Bay +YYT,"St. John's, NL" +YYU,Kapuskasing +YYW,Armstrong +YYY,Mont Joli +YZA,Ashcroft +YZC,Beatton River +YZF,Yellowknife +YZG,Salluit +YZH,Slave Lake +YZM,Buchans +YZP,Sandspit +YZR,Sarnia +YZS,Coral Harbour +YZT,Port Hardy +YZU,Whitecourt +YZW,Teslin +ZAH,Zahedan +ZAJ,Zaranj +ZAK,Chiusa/Klausen +ZAL,Valdivia +ZAM,Zamboanga +ZAS,Shunde +ZAT,Zhaotong +ZAZ,Zaragoza +ZBD,Jiang Men +ZBE,Zabreh +ZBK,Zabljak +ZBL,Biloela +ZBM,Bromont +ZBN,Bozen +ZBO,Bowen +ZBR,Chah-Bahar +ZBU,Aarhus Limo +ZBY,Sayaboury +ZBZ,Xin Hui +ZCA,Tai Shan +ZCD,Bamberg +ZCL,Zacatecas +ZCO,Temuco +ZCP,Foshan +ZDM,Ramallah +ZEC,Secunda +ZEF,Nanhai +ZEG,Senggo +ZEM,East Main +ZEQ,Dewsbury +ZFB,Old Fort Bay +ZFD,Fond Du Lac +ZFL,South Trout Lake +ZFM,Fort Mcpherson +ZFN,Tulita/Fort Norman +ZFW,Fairview +ZGD,Groton +ZGE,Goerlitz +ZGI,Gods River +ZGL,South Galway +ZGM,Ngoma +ZGN,Zhongshan +ZGR,Little Grand Rapids +ZGS,Gethsemani +ZGW,Greifswald +ZGZ,Fictitious Point/AA2 +ZHA,Zhanjiang +ZHM,Shamshernagar +ZHP,High Prairie +ZHZ,Halle +ZIE,Vulcano +ZIH,Ixtapa |Zihuatanejo +ZIY,Lianhuashan +ZJE,Panarea +ZJG,Jenpeg +ZJJ,Procida +ZJK,Chek Lap Kok +ZJN,Swan River +ZJS,Jena +ZJT,Tanjung Pelepas +ZJX,Stromboli +ZJY,Ponza +ZKB,Kasaba Bay +ZKE,Kaschechewan +ZKG,Kegaska +ZKL,Steenkool +ZKM,Sette Cama +ZKP,Kasompe +ZLG,El Gouera +ZLO,Manzanillo +ZLT,La Tabatiere +ZLW,Pasir Gudang +ZMM,Zamora +ZMO,Modena +ZMR,Meran +ZMT,Masset +ZMY,Huangpu +ZNE,Newman +ZNG,Negginan +ZNU,"Namu, BC" +ZNZ,Zanzibar +ZOF,Ocean Falls +ZOS,Osorno +ZPB,Sachigo Lake +ZPC,Pucon +ZPH,Zephyrhills +ZPO,Pine House +ZQN,Queenstown +ZQS,Queen Charlotte Is +ZRC,San Pedro de Alcantara +ZRI,Serui +ZRJ,Round Lake +ZRM,Sarmi +ZRR,Fiumicino +ZSE,St Pierre dela Reunion +ZSJ,Sandy Lake +ZSS,Sassandra +ZST,Stewart +ZSU,Dessau +ZTA,Tureira +ZTB,Tete-a-La Baleine +ZTF,Westchester County +ZTH,Zakinthos +ZTI,Humen +ZTM,Shamattawa +ZTR,Zhitomir +ZTS,Tahsis +ZTT,Cottbus +ZTZ,Chemnitz +ZUC,Ignace +ZUD,Ancud +ZUE,Zuenoula +ZUH,Zhuhai +ZUL,Zilfi +ZUM,Churchill Falls +ZVA,Miandrivazo +ZVG,Springvale +ZVK,Savannakhet +ZWL,Wollaston Lake +ZYB,SNCB Rail Network +ZYI,Zunyi +ZYL,Sylhet +ZYN,Nimes +ZZU,Mzuzu +ZZV,Zanesville \ No newline at end of file diff --git a/datastore/elastic_search/query.py b/datastore/elastic_search/query.py index a013b0b99..0e16de1d8 100644 --- a/datastore/elastic_search/query.py +++ b/datastore/elastic_search/query.py @@ -386,7 +386,7 @@ def _generate_es_search_dictionary(entity_name, text, fuzziness_threshold, langu 'bool': { 'must': must_terms, 'should': [], - 'minimum_number_should_match': 1 + 'minimum_should_match': 1 } } } diff --git a/docs/api_call.md b/docs/api_call.md index b1c8066d1..10ea71641 100644 --- a/docs/api_call.md +++ b/docs/api_call.md @@ -1,845 +1,718 @@ +## API Documentation -# API calls +Chatbot_ner designed to extract essential entities or information like date, time, numbers, texts (city, organisation name) from textual data. These APIs are built keeping in mind to plug it in for conversational AI applications. -[TOC] +Following are the different entity types we currently support. -## List of entity types +| Entity Type | Description | Examples | +| ------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| [Time](#1-time) | Detects time in various formats from given text. | tomorrow morning at 5, рдХрд▓ рд╕реБрдмрд╣ рел рдмрдЬреЗ, kal subah 5 baje | +| [Date](#2-date) | Detects date in various formats from given text. | 28-12-2096, 09th Nov 2014, Tomorrow, next monday, agle somvar, рдЕрдЧрд▓реЗ рд╕реЛрдорд╡рд╛рд░ | +| [Number](#3-number) | Detects number from the text. | 50 rs per person, рел рдХрд┐рд▓реЛ рдЪрд╛рд╡рд▓, рдореБрдЭреЗ рдПрдХ рд▓реАрдЯрд░ рдСрдЗрд▓ рдЪрд╛рд╣рд┐рдП | +| [Phone number](#4-phone-number) | Detects phone numbers in given text. | +919222222222 | +| [Email](#5-email) | Detects email addresses in given text. | abc.123@gmail.com | +| [Text](#6-text) | Detect custom entities in text string using full text search in Datastore or based on contextual model | **pizza**, **рдореБрдВрдмрдИ** | +| [PNR-Number](#7-pnr-number) | Detect PNR (serial) codes in given text. | My flight PNR is **4SGX3E** | +| [Regex](#8-regex) | Detect entities using custom regex patterns | My flight PNR is **4SGX3E**
Please apply **CASH20** coupon code | -Following are the list of different entity types along with its API call: -### text -- This functionality calls the TextDetection class to detect textual entities. +### API Parameters -- Example: +Following are the list of parameters accepted by APIs used for detection: - - Example 1: +1. **message**: Message on which detection logic needs to run. It is an unstructured text from which entity needs to be extracted. For example, *"I want to order pizza"*. + +2. **entity_name**: Name of the entity. This parameter primarily defines the key of the output dictionary. - - ```python - message='i want to order chinese from mainland china and pizza from domminos' - entity_name='restaurant' - structured_value=None - fallback_value=None - bot_message=None - ``` - - - *Python:* - ```python - from ner_v1.chatbot.entity_detection import get_text - output = get_text(message=message, entity_name=entity_name, structured_value=structured_value, fallback_value=fallback_value, bot_message=bot_message) - print output - ``` - The above can also be done from within the Docker container's shell. Setup is in docker.md file. - - - *CURL command:* - ```shell - URL='localhost' - PORT=8081 - ``` - - ```shell - curl -i 'http://'$URL':'$PORT'/v1/text/?message=i%20want%20to%20order%20chinese%20from%20%20mainland%20china%20and%20pizza%20from%20domminos&entity_name=restaurant&structured_value=&fallback_value=None&bot_message=' - ``` - - - *CURL Output:* - - ```json - { - "data": [ - { - "detection": "message", - "original_text": "mainland china", - "entity_value": { - "value": "Mainland China" - } - }, - { - "detection": "message", - "original_text": "dominos", - "entity_value": { - "value": "Domino's Pizza" - } - } - ] - } - ``` - - - Example 2: - - - ```python - message = 'i wanted to watch movie' - entity_name = 'movie' - structured_value = 'inferno' - fallback_value = None - bot_message = None - ``` - - - *Python:* - - ```python - from ner_v1.chatbot.entity_detection import get_text - output = get_text(message=message, entity_name=entity_name, structured_value=structured_value, fallback_value=fallback_value, bot_message=bot_message) - print output - ``` - - - *CURL command:* - - ```shell - URL='localhost' - PORT=8081 - ``` - - ```shell - curl -i 'http://'$URL':'$PORT'/v1/text/?message=i%20wanted%20to%20watch%20movie&entity_name=movie&structured_value=inferno&fallback_value=None&bot_message=' - ``` - - - *CURL Output*: - - - тАЛ - - ```json - { - "data": [ - { - "detection": "structure_value_verified", - "original_text": "inferno", - "entity_value": { - "value": "Inferno" - } - } - ] - } - ``` - - - тАЛ - - -### phone_number - -- This functionality calls the PhoneDetector class to detect textual entities. - -- Example: - - - Example 1: - - - ```python - message = 'my contact number is 9049961794' - entity_name = 'phone_number' - structured_value = None - fallback_value = None - bot_message = None - ``` - - - *Python:* - - ```python - from ner_v1.chatbot.entity_detection import get_phone_number - output = get_phone_number(message=message, entity_name=entity_name, structured_value=structured_value, fallback_value=fallback_value, bot_message=bot_message) - print output - ``` - - - *CURL command:* - - ```shell - URL='localhost' - PORT=8081 - ``` - - ```shell - curl -i 'http://'$URL':'$PORT'/v1/phone_number/?message=my%20contact%20number%20is%209049961794&entity_name=phone_number&structured_value=&fallback_value=None&bot_message=' - ``` - - - *CURL Output:* - - ```json - { - "data": [ - { - "detection": "message", - "original_text": "9049961794", - "entity_value": { - "value": "9049961794" - } - } - ] - } - ``` - - - Example 2: - - - ```python - message = 'Please call me' - entity_name = 'phone_number' - structured_value = None - fallback_value = '9049961794' - bot_message = None - ``` - - - *Python:* - - ```python - from ner_v1.chatbot.entity_detection import get_phone_number - output = get_phone_number(message=message, entity_name=entity_name, structured_value=structured_value, fallback_value=fallback_value, bot_message=bot_message) - print output - ``` - - - *CURL command:* - - ```shell - URL='localhost' - PORT=8081 - ``` - - тАЛ - - ```shell - curl -i 'http://'$URL':'$PORT'/v1/phone_number/?message=Please%20call%20me&entity_name=phone_number&structured_value=&fallback_value=9049961794&bot_message=' - ``` - - - *CURL Output:* - - ```json - { - "data": [ - { - "detection": "fallback_value", - "original_text": "9049961794", - "entity_value": { - "value": "9049961794" - } - } - ] - } - ``` - -### email - -- This functionality calls the EmailDetector class to detect email ids. - -- Example: - - - Example 1: - - - ```python - message = 'my email id is apurv.nagvenkar@gmail.com' - entity_name = 'email' - structured_value = None - fallback_value = None - bot_message = None - ``` - - - *Python:* - - ```python - from ner_v1.chatbot.entity_detection import get_email - output = get_email(message=message, entity_name=entity_name, structured_value=structured_value,fallback_value=fallback_value, bot_message=bot_message) - print output - ``` - - - *CURL command:* - - ```shell - URL='localhost' - PORT=8081 - ``` - - ```shell - curl -i 'http://'$URL':'$PORT'/v1/email/?message=my%20email%20id%20is%20apurv.nagvenkar%40gmail.com&entity_name=email&structured_value=&fallback_value=&bot_message=' - ``` - - - *CURL Output:* - - ```json - { - "data": [ - { - "detection": "message", - "original_text": "apurv.nagvenkar@gmail.com", - "entity_value": { - "value": "apurv.nagvenkar@gmail.com" - } - } - ] - } - ``` - - - Example 2: - - - ```python - message = 'send me to my email' - entity_name = 'email' - structured_value = None - fallback_value = 'apurv.nagvenkar@gmail.com' - bot_message = None - ``` - - - *Python:* - - ```python - from ner_v1.chatbot.entity_detection import get_email - output = get_email(message=message, entity_name=entity_name, structured_value=structured_value,fallback_value=fallback_value, bot_message=bot_message) - print output - ``` - - - *CURL command:* - - ```shell - URL='localhost' - PORT=8081 - ``` - - ```shell - curl -i 'http://'$URL':'$PORT'/v1/email/?message=send%20me%20to%20my%20email&entity_name=email&structured_value=&fallback_value=apurv.nagvenkar@gmail.com&bot_message=' - ``` - - - *CURL Output:* - - ```json - { - "data": [ - { - "detection": "fallback_value", - "original_text": "apurv.nagvenkar@gmail.com", - "entity_value": { - "value": "apurv.nagvenkar@gmail.com" - } - } - ] - } - ``` - -### city - -- This functionality calls the CityDetector class to detect cities along with its attributes. - -- Example: - - - Example 1: - - - ```python - message = 'i want to go to mummbai' - entity_name = 'city' - structured_value = None - fallback_value = None - bot_message = None - ``` - - - *Python:* - - ```python - from ner_v1.chatbot.entity_detection import get_city - output = get_city(message=message, entity_name=entity_name, structured_value=structured_value,fallback_value=fallback_value,bot_message=bot_message) - print output - ``` - - - *CURL command:* - - ```shell - URL='localhost' - PORT=8081 - ``` - - ```shell - curl -i 'http://'$URL':'$PORT'/v1/city/?message=i%20want%20to%20go%20to%20mummbai&entity_name=city&structured_value=&fallback_value=&bot_message=' - ``` - - - *CURL Output:* - - ```json - { - "data": [ - { - "detection": "message", - "original_text": "mummbai", - "entity_value": { - "to": true, - "via": false, - "from": false, - "value": "Mumbai", - "normal": false - } - } - ] - } - ``` - - - Example 2: - - - ```python - message = "I want to book a flight from delhhi to mumbai" - entity_name = 'city' - structured_value = None - fallback_value = None - bot_message = None - ``` - - - *Python:* - - ```python - from ner_v1.chatbot.entity_detection import get_city - output = get_city(message=message, entity_name=entity_name, structured_value=structured_value,fallback_value=fallback_value,bot_message=bot_message) - print output - ``` - - - CURL command:* - - ```shell - URL='localhost' - PORT=8081 - ``` - - ```shell - curl -i 'http://'$URL':'$PORT'/v1/city/?message=I%20want%20to%20book%20a%20flight%20from%20delhhi%20to%20mumbai&entity_name=city&structured_value=&fallback_value=&bot_message=' - ``` - - - *CURL Output:* - - ```json - { - "data": [ - { - "detection": "message", - "original_text": "delhhi", - "entity_value": { - "to": false, - "via": false, - "from": true, - "value": "New Delhi", - "normal": false - } - }, - { - "detection": "message", - "original_text": "mumbai", - "entity_value": { - "to": true, - "via": false, - "from": false, - "value": "Mumbai", - "normal": false - } - } - ] - } - ``` - - - Example 3: - - - ```python - message = "mummbai" - entity_name = 'city' - structured_value = None - fallback_value = None - bot_message = "Please help me departure city?" - ``` - - - *CURL command:* - - ```shell - URL='localhost' - PORT=8081 - ``` - - ```shell - curl -i 'http://'$URL':'$PORT'/v1/city/?message=mummbai&entity_name=city&structured_value=&fallback_value=&bot_message=Please%20help%20me%20departure%20city%3F' - ``` - - - *CURL Output:* - - ```json - { - "data": [ - { - "detection": "message", - "original_text": "mummbai", - "entity_value": { - "to": false, - "via": false, - "from": true, - "value": "Mumbai", - "normal": false - } - } - ] - } - ``` - -### pnr - -- This functionality calls the PNRDetector class to detect pnr. - -- Example: - -- - Example 1: - - - ```python - message = 'check my pnr status for 2141215305.' - entity_name = 'train_pnr' - structured_value = None - fallback_value = None - bot_message = None - ``` - - - *Python:* - - ```python - from ner_v1.chatbot.entity_detection import get_pnr - output = get_pnr(message=message, entity_name=entity_name,structured_value=structured_value,fallback_value=fallback_value, bot_message=bot_message) - print output - ``` - - - *CURL command:* - - ```shell - URL='localhost' - PORT=8081 - ``` - - ```shell - curl -i 'http://'$URL':'$PORT'/v1/pnr/?message=check%20my%20pnr%20status%20for%202141215305.&entity_name=pnr&structured_value=&fallback_value=&bot_message=' - ``` - - - *CURL Output:* - - ```json - { - "data": [ - { - "detection": "message", - "original_text": "2141215305", - "entity_value": { - "value": "2141215305" - } - } - ] - } - ``` - -### number - -- This functionality calls the NumberDetector class to detect numerals. - -- Example: - - - Example 1: - - - ```python - message = "I want to purchase 30 units of mobile and 40 units of Television" - entity_name = 'number_of_unit' - structured_value = None - fallback_value = None - bot_message = None - min_digit = 1 - max_digit = 2 - ``` - - - *Python:* - - ```python - from ner_v1.chatbot.entity_detection import get_number - output = get_number(message=message, entity_name=entity_name, structured_value=structured_value, fallback_value=fallback_value, bot_message=bot_message, min_digit=min_digit, max_digit=max_digit) - print output - ``` - - - *CURL command:* - - ```shell - URL='localhost' - PORT=8081 - ``` - - ```shell - curl -i 'http://'$URL':'$PORT'/v1/number/?message=I%20want%20to%20purchase%2030%20units%20of%20mobile%20and%2040%20units%20of%20Television&entity_name=number_of_unit&structured_value=&fallback_value=&bot_message=&min_number_digits=1&max_number_digits=2' - ``` - - - *CURL Output:* - - ```json - { - "data": [ - { - "detection": "message", - "original_text": "30", - "entity_value": { - "value": "30" - } - }, - { - "detection": "message", - "original_text": "40", - "entity_value": { - "value": "40" - } - } - ] - } - ``` + For example, in Text detection logic the entity name is based on dictionary name of entities we need to detect. - - Example 2: + - For detecting: + - *cuisine* entity_name will be *"cuisine"* + - *dish* entity_name will be *"dish"* - - ```python - message = "I want to reserve a table for 3 people" - entity_name = 'number_of_people' - structured_value = None - fallback_value = None - bot_message = None - min_digit = 1 - max_digit = 2 - ``` + For other entities like `date` or `time` `entity_name`, detection logic works solely on their entity_types. - - *Python:* +3. **structured_value** (optional): It is a value which is obtained from the structured text. For example, UI elements like form, payload, etc. See below image for reference used for detecting test name from form key `Test name` - ```python - from ner_v1.chatbot.entity_detection import get_number - output = get_number(message=message, entity_name=entity_name, structured_value=structured_value, fallback_value=fallback_value, bot_message=bot_message, min_digit=min_digit, max_digit=max_digit) - print output - ``` + ![form](images/form.png) - - *CURL command:* +4. **fallback_value** (optional): It is a fallback value. If the detection logic fails to detect any value either from *structured_value* or *message* then we return a *fallback_value* passed in request as an output. - ```shell - URL='localhost' - PORT=8081 - ``` + For example, if user says *"Nearby ATMs"*. In this example user has not provided any information about his location in the chat but, we can pass a *fallback_value* that will contain its location that can be obtained from its profile or third party apis (like geopy, etc). - ```shell - curl -i 'http://'$URL':'$PORT'/v1/number/?message=I%20want%20to%20reserve%20a%20table%20for%203%20people&entity_name=number_of_people&structured_value=&fallback_value=&bot_message=&min_number_digits=1&max_number_digits=2' - ``` +5. **source_language**: It is the language in which user message is passed. We have to pass ISO 639-1 code of the language here. - - *CURL Output:* +6. **bot_message** (optional): previous message from a bot/agent. This is an important parameter, many times the entity value relies on the message from the bot/agent i.e. what is bot saying? or asking? - ```json - { - "data": [ - { - "detection": "message", - "original_text": "for 3 people", - "entity_value": { - "value": "3" - } - } - ] - } - ``` + For example, bot might ask for departure date to book a flight and user might reply with a date. Now, it is difficult to disambiguate whether its departure date or arrival date unless, we know what bot is asking for? -### time + ``` + bot: Please help me with date of departure? + user: 23rd March + ``` -- This functionality calls the TimeDetector class to detect time. +### **Output Format** -- Example: +The output of entities detected will be stored in a list of dictionary containing the following structure: - - Example 1: +``` +[ + { + "entity_value": entity_value, + "detection": detection_method, + "original_text": original_text + }, +] +``` - - Use the **timezone** parameter to pass your current timezone to time detection +Consider the following example for detailed explanation: - - ```python - message = "John arrived at the bus stop at 13:50 hrs, expecting the bus to be there in 15 mins. \ - But the bus was scheduled for 12:30 pm" - entity_name = 'time' - structured_value = None - fallback_value = None - bot_message = None - timezone = 'UTC' - ``` +``` +"I want to order two litre pepsi." +``` - - *Python:* +- entity_value: This will store the value of entity (i.e entity value) that is detected. The output will be in dictionary format. For example, `{"value": "2", "unit": "quantity"}`. +- detection: This indicates how the entity was detected. Possibles values are + - *message* : If entity get detected from message key. + - *structured value*: If entity get detected from structured value. + - *fallback value*: If entity get detected from fallback value. +- original_text: This store the part of the text that gets detected as an entity. For example, `two`. - ```python - from ner_v1.chatbot.entity_detection import get_time - output = get_time(message=message, entity_name=entity_name, structured_value=structured_value, fallback_value=fallback_value, bot_message=bot_message, timezone=timezone) - print output - ``` +```json +Example 1: +input: +message = u'I want to order 2 burgers from mainland china at 3 pm ' +entity_name = 'restaurant' +structured_value = None +structured_value_verification = 0 +fallback_value = None +bot_message = None - - CURL command:* +output: +[ + { + "detection": "message", + "original_text": "2", + "entity_value": { "value": "2", "unit": null}, + "language": "en" + }, + { + "detection": "message", + "original_text": "3 pm", + "entity_value": { "mm": 0, "hh": 3, "nn": "pm"}, + "language": "en" + } +] - ```shell - URL='localhost' - PORT=8081 - ``` +Example 2: +// If today is 19th feb +input: +message = u'I have my maths exam next Saturday.' +entity_name = 'date' +structured_value = None +structured_value_verification = 0 +fallback_value = None +bot_message = None - ```shell - curl -i 'http://'$URL':'$PORT'/v1/time/?message=John%20arrived%20at%20the%20bus%20stop%20at%2013%3A50%20hrs%2C%20expecting%20the%20bus%20to%20be%20there%20in%2015%20mins.%20But%20the%20bus%20was%20scheduled%20for%2012%3A30%20pm&entity_name=time&structured_value=&fallback_value=&bot_message=&timezone=UTC' - ``` +output:[ +{ + "detection": "message", + "original_text": "inferno", + "entity_value": {"value": {"mm":03, "yy": 2019, "dd": 02, "type": "date"}}, + "language": "en" + }, +] +``` - - *CURL Output:* +### - ```json - { - "data": [ - { +### Installing Chatbot NER: + +Please, have a look at [installation steps](https://github.com/hellohaptik/chatbot_ner/blob/master/docs/install.md) guide to install Chatbot NER on your system. + +After following above steps, you can test the APIs either using django shell or by making curl get request. + +To get into django shell you need to execute the below commands. + +1. To get inside container, first run`docker exec -it bash` +2. Then, inside main project directory run `python manage.py shell` + +Below are the APIs example for each of the entity types mentioned above. + +### 1. Time + +The Time detector module has the capability to detect time from text in multiple languages. It can detect time in 12/24 hr format and also detect text with time difference specified. for example - wake me up `after 10 mins`. + +Currently time detection support has been provided in different languages - `English`, `Hindi`, `Marathi`, `Bengali`, `Gujrati`, `Tamil`. It also supports latin script of given languages. + +> To add support for new languages or to add custom patterns in particular language please go through the Time Detector readme [here](https://github.com/hellohaptik/chatbot_ner/blob/develop/ner_v2/detectors/temporal/time/README.md) + +*Note - This module has been updated to v2 version of chatbot_ner.* + +**API Example**: + +- ***Example 1: Detect time from English text which contains time mentions in 24 hours format, 12 hours format and relative time format*** + + - *Django Shell* + + ```python + message = u"John arrived at the bus stop at 13:50 hrs, expecting the bus to be there in 15 mins. But the bus was scheduled for 12:30 pm" + entity_name = 'time' + structured_value = None + fallback_value = None + bot_message = None + timezone = 'UTC' + source_language='en' + + from ner_v2.detectors.temporal.time.time_detection import TimeDetector + detector = TimeDetector(entity_name=entity_name, language=source_language, + timezone=timezone) + output = detector.detect(message=message, entity_name=entity_name, + structured_value=structured_value, + fallback_value=fallback_value) + print(output) + ``` + + - *CURL command* + + ```bash + URL='localhost' + PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v2/time/?message=John%20arrived%20at%20the%20bus%20stop%20at%2013%3A50%20hrs%2C%20expecting%20the%20bus%20to%20be%20there%20in%2015%20mins.%20But%20the%20bus%20was%20scheduled%20for%2012%3A30%20pm&entity_name=time&structured_value=&fallback_value=&bot_message=&timezone=UTC&source_language=en' + ``` + + > **Output**: + + ```json + {"data": [ + { "detection": "message", "original_text": "12:30 pm", - "entity_value": { - "mm": 30, - "hh": 12, - "nn": "pm" - } - }, - { + "entity_value": { "mm": 30, "hh": 12, "nn": "pm"}, + "language": "en" + }, + { "detection": "message", "original_text": "in 15 mins", - "entity_value": { - "mm": "15", - "hh": 0, - "nn": "df" - } - }, - { + "entity_value": { "mm": "15", "hh": 0, "nn": "df" }, + "language": "en" + }, + { "detection": "message", "original_text": "13:50", - "entity_value": { - "mm": 50, - "hh": 13, - "nn": "hrs" - } - } - ] - } - ``` -### time_with_range + "entity_value": {"mm": 50, "hh": 13, "nn": "hrs"}, + "language": "en" + }]} + ``` + + + +- ***Example 2: Detect time[Hindi] from text containing 24 hrs, 12 hrs and time difference text format*** + + - *Django Shell* + + ```python + message = u"рд░рд╛рдЬреВ рдХрд╛ рдмрд╕ резрей:релреж рдХреЛ рдмрд╕ рд╕реНрдЯреЙрдк рд╕реЗ рдирд┐рдХрд▓рд╛ рдФрд░ резрел рдорд┐рдирдЯ рдореЗрдВ рдпрд╣рд╛рдБ рдкрд╣реБрдВрдЪ рдЬрд╛рдПрдЧрд╛ рдФрд░ рдЧреЛрд╡рд╛ рдХреЛ рд╢рд╛рдо рдореЗрдВ рдмрд╛рд░рд╣ рдмрдЬрдХрд░ рейреж рдорд┐рдирдЯ рдкреИрд░ рдкрд╣реБрдВрдЪреЗрдЧрд╛" + entity_name = 'time' + structured_value = None + fallback_value = None + bot_message = None + timezone = 'UTC' + source_language='hi' + + from ner_v2.detectors.temporal.time.time_detection import TimeDetector + detector = TimeDetector(entity_name=entity_name, language=source_language, + timezone=timezone) + output = detector.detect(message=message, entity_name=entity_name, + structured_value=structured_value, + fallback_value=fallback_value) + print(output) + ``` + + - *CURL command* + + ```bash + URL='localhost' + PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v2/time/?message=рд░рд╛рдЬреВ%20рдХрд╛%20рдмрд╕%20резрей:релреж%20рдХреЛ%20рдмрд╕%20рд╕реНрдЯреЙрдк%20рд╕реЗ%20рдирд┐рдХрд▓рд╛%20рдФрд░%20резрел%20рдорд┐рдирдЯ%20рдореЗрдВ%20рдпрд╣рд╛рдБ%20рдкрд╣реБрдВрдЪ%20рдЬрд╛рдПрдЧрд╛%20рдФрд░%20рдЧреЛрд╡рд╛%20рдХреЛ%20рд╢рд╛рдо%20рдореЗрдВ%20рдмрд╛рд░рд╣%20рдмрдЬрдХрд░%20рейреж%20рдорд┐рдирдЯ%20рдкреИрд░%20рдкрд╣реБрдВрдЪреЗрдЧрд╛&entity_name=time&structured_value=&fallback_value=&bot_message=&timezone=UTC&source_language=en' + + ``` + + > **Output**: + + ```json + {"data": [ + { + "detection": "message", + "original_text": "резрей:релреж", + "entity_value": { "mm": 1, "hh": 50,"nn": "hr"}, + "language": "hi" + }, + { + "detection": "message", + "original_text": "резрел рдорд┐рдирдЯ рдореЗрдВ", + "entity_value": {"mm": "15", "hh": 0, "nn": "df"}, + "language": "hi" + }, + { + "detection": "message", + "original_text": "рд╢рд╛рдо рдореЗрдВ рдмрд╛рд░рд╣ рдмрдЬрдХрд░ рейреж рдорд┐рдирдЯ", + "entity_value": { "mm": 30, "hh": 12, "nn": "pm"}, + "language": "hi" + }] + } + + ``` + + + +### 2. Date + +The Date detector module has the capability to detect various form of dates from text in multiple languages. It can detect date from following patterns: + +1. **Day month year format** - 12 feb 2018, 2nd Jan 2019, 12/11/2019, 12-jan-2019 +2. **Day month** - 12 feb, 12/12 +3. **Weekday reference** - Comming monday, next sunday +4. **Reference day month** - 2nd of next month, 2nd sunday of coming month +5. **Current day reference** - tomorrow, yesterday, day after tomorrow + + Currently date detection support has been provided in different languages - `English`, `Hindi`, `Marathi`, `Bengali`, `Gujrati`, `Tamil`. It also supports latin script of given languages. + +> To add support for new languages or to add custom patterns in particular language please go through the Date Detector readme [here](https://github.com/hellohaptik/chatbot_ner/blob/develop/ner_v2/detectors/temporal/date/README.md) + +*Note - This module has been updated to v2 version of chatbot_ner* + +**API Examples:** + +- ***Example 1: Detecting day month format date [English] from user message*** + + Use the **timezone** parameter to pass your current timezone to date detection + + - *Django Shell:* + + ```python + message = u"set me reminder on 23rd december" + entity_name = 'date' + structured_value = None + fallback_value = None + bot_message = None + timezone='UTC' + source_language='en' + past_date_referenced=False # flag to check if the date reference lies in past or future. For Example - In hindi "Kal"corresonds to both tomorrow and yesterday. So this flag will determines actual referenced date. + + from ner_v2.detectors.temporal.date.date_detection import DateAdvanceDetector + detector = DateAdvanceDetector(entity_name=entity_name, language=source_language, + timezone=timezone, + past_date_referenced=past_date_referenced) + output = detector.detect(message=message, entity_name=entity_name, + structured_value=structured_value, + fallback_value=fallback_value) + print(output) + + ``` + + - *CURL:* + + ```shell + URL='localhost' + PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v1/date/?message=set%20me%20reminder%20on%2023rd%20december&entity_name=date&structured_value=&fallback_value=&bot_message=%timezone=UTC&source_language=en&past_date_referenced=false' + + ``` + + > **Output:** + + ```json + {"data": [ + { + "detection": "message", + "original_text": "23rd december", + "entity_value": { "end_range": false, "from": false, "normal": true, "to": + false, "start_range": false, + "value": {"mm": 12, "yy": 2017, "dd": 23, "type": "date"} + }, + "language": "en" + }]} + + ``` + +- ***Example 2: Detecting referenced date [Hindi] from user message*** + + Use the **timezone** parameter to pass your current timezone to date detection + + - *Django Shell:* + + ```python + message = u"рдореБрдЭреЗ рдХрд▓ рд╕реБрдмрд╣ рел рдмрдЬреЗ рдЙрдард╛ рджреЗрдирд╛" + entity_name = 'date' + structured_value = None + fallback_value = None + bot_message = None + timezone='UTC' + source_language='hi' + past_date_referenced=False + + from ner_v2.detectors.temporal.date.date_detection import DateAdvanceDetector + detector = DateAdvanceDetector(entity_name=entity_name,language=source_language, + timezone=timezone, + past_date_referenced=past_date_referenced) + output = detector.detect(message=message, entity_name=entity_name, + structured_value=structured_value, + fallback_value=fallback_value) + print(output) + + ``` + + - *CURL:* + + ```shell + URL='localhost' + PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v2/date/?message=рдореБрдЭреЗ%20рдХрд▓%20рд╕реБрдмрд╣%20рел%20рдмрдЬреЗ%20рдЙрдард╛%20рджреЗрдирд╛&entity_name=date&structured_value=&fallback_value=&bot_message=%timezone=UTC&source_language=en&past_date_referenced=false' + + ``` + + > **Output:** + + ```json + /* Assuming today's date is 12th feb 2019*/ + {"data": [ + { + "detection": "message", + "original_text": "рдХрд▓", + "entity_value": { "end_range": false, "from": false, "normal": true, "to": + false, "start_range": false, + "value": {"mm": 02, "yy": 2019, "dd": 13, "type": "date"} + }, + "language": "en" + }]} + + ``` + +- ***Example 3: Detecting referenced weekday [Hindi] from user message*** + + Use the **timezone** parameter to pass your current timezone to date detection + + - *Django Shell:* + + ```python + message = u"рдЖрдиреЗ рд╡рд╛рд▓реЗ рд╕реЛрдорд╡рд╛рд░ рдХреЛ рдореЗрд░рд╛ рдореИрдереНрд╕ рдХрд╛ рдПрдЧреНрдЬрд╛рдо рд╣реИ" + entity_name = 'date' + structured_value = None + fallback_value = None + bot_message = None + timezone='UTC' + source_language='hi' + past_date_referenced=False + + from ner_v2.detectors.temporal.date.date_detection import DateAdvanceDetector + detector = DateAdvanceDetector(entity_name=entity_name,language=source_language, + timezone=timezone, + past_date_referenced=past_date_referenced) + output = detector.detect(message=message, entity_name=entity_name, + structured_value=structured_value, + fallback_value=fallback_value) + print(output) + + ``` + + - *CURL:* + + ```shell + URL='localhost' + PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v2/date/?message=рдЖрдиреЗ%20рд╡рд╛рд▓реЗ%20рд╕реЛрдорд╡рд╛рд░%20рдХреЛ%20рдореЗрд░рд╛%20рдореИрдереНрд╕%20рдХрд╛%20рдПрдЧреНрдЬрд╛рдо%20рд╣реИ&entity_name=date&structured_value=&fallback_value=&bot_message=%timezone=UTC&source_language=en&past_date_referenced=false' + + ``` + + > **Output:** + + ```json + /* Assuming today's date is 12th feb 2019*/ + {"data": [ + { + "detection": "message", + "original_text": "рдХрд▓", + "entity_value": { "end_range": false, "from": false, "normal": true, "to": + false, "start_range": false, + "value": {"mm": 02, "yy": 2019, "dd": 18, "type": "date"} + }, + "language": "en" + }]} + + ``` -- This functionality calls the TimeDetector class to detect time with range. +### 3. Number -- Example: +The Number detector module has the capability to detect number or number word from text in multiple languages. The detector supports an additional feature of detecting units along with number if given in text. For example - for a given text `5 kg`, this module will return `5` as detected value and `kg` as detected unit. It also has the capability to detect only certain type of numbers like currency or temperature type numbers by specifying the unit type. - - Example 1: +You can find the current supported unit_types in english [here](https://github.com/hellohaptik/chatbot_ner/blob/develop/ner_v2/detectors/numeral/number/en/data/units.csv) - - Use the **timezone** parameter to pass your current timezone to time detection +Currently number detection support has been provided for 6 different languages - `English`, `Hindi`, `Marathi`, `Bengali`, `Gujrati`, `Tamil`. It also supports latin script of given languages. - - ```python - message = 'Set a drink water reminder for tomorrow from 7:00 AM to 6:00 PM' - entity_name = 'time_with_range' - structured_value = None - fallback_value = None - bot_message = None - timezone = 'UTC' - ``` +> To add support for new languages or to add custom patterns in particular language please go through the Number Detector readme [here](https://github.com/hellohaptik/chatbot_ner/blob/develop/ner_v2/detectors/numeral/number/README.md) - - *Python:* +*Note - This module has been updated to v2 version of chatbot_ner.* - ```python - from ner_v1.chatbot.entity_detection import get_time_with_range - output = get_time_with_range(message=message, entity_name=entity_name, structured_value=structured_value, fallback_value=fallback_value, bot_message=bot_message, timezone=timezone) - print output - ``` +**API Example**: - - CURL command:* +- ***Example 1: Detecting number[English] without unit in message*** - ```shell - URL='localhost' - PORT=8081 - ``` + - *Django Shell* - ```shell - curl -i 'http://'$URL':'$PORT'/v1/time_with_range/?message=Set+a+drink+water+reminder+for+tomorrow+from+7%3A00+AM+to+6%3A00+PM&entity_name=time_with_range&structured_value=&fallback_value=&bot_message=&timezone=UTC' - ``` + ```python + # For a sample query with following parameters + message=u"i want to purchase 30 units of mobile abd 40 units of telivision" + entity_name='number' + structured_value=None + fallback_value=None + bot_message=None + min_number_digits=1 # minimum number of digit + max_number_digits=6 # maximum number of digit + source_language='en' # here language will be ISO 639-1 code + unit_type=None # this restrict the number detector to detect particular number type only. + + from ner_v2.detector.number.number.number_detection import NumberDetector + detector = NumberDetector(entity_name=entity_name, language=source_language, + unit_type=None) + detector.set_min_max_digits(min_digit=min_number_digits, max_digit=max_number_digits) + output = detector.detect(message=message,structured_value=structured_value, + fallback_value=fallback_value, bot_message=bot_message) + print(output) + ``` - - *CURL Output:* + - *CURL command:* - ```json - { - "data": [ - { - "detection": "message", - "original_text": "7:00 am to 6:00 pm", - "entity_value": { - "mm": 0, - "hh": 7, - "range": "start", - "nn": "am", - "time_type": null - }, + ```shell + URL='localhost' + PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v2/number/?message=I%20want%20to%20purchase%2030%20units%20of%20mobile%20and%2040%20units%20of%20Television&entity_name=number_of_unit&structured_value=&fallback_value=&bot_message=&min_number_digits=1&max_number_digits=2&source_language=en&unit_type=' + ``` + + > **Output:** + + ```json + {"data": [ + { + "detection": "message", + "original_text": "30", + "entity_value": { "value": "30", "unit": null}, "language": "en" - }, - { + }, + { + "detection": "message", + "original_text": "40", + "entity_value": { "value": "40", "unit": null}, + "language": "en" + }] + } + ``` + +- ***Example 2: Detecting number[Hindi] without unit in message*** + + - *Django Shell* + + ```python + # For a sample query with following parameters + message=u"рдореБрдЭреЗ рейреж рдХрд┐рд▓реЛ рдЖрдЯрд╛ рдФрд░ рджреЛ рд╣рдЬрд╛рд░ рдХрд╛ рдЪреАрдиреА рджреЗрдирд╛ " + entity_name='number' + structured_value=None + fallback_value=None + bot_message=None + min_number_digits=1 # minimum number of digit + max_number_digits=6 # maximum number of digit + source_language='hi' # here language will be ISO 639-1 code + unit_type="weight" # this restrict the number detector to detect only weight type number entity + + from ner_v2.detector.number.number.number_detection import NumberDetector + detector = NumberDetector(entity_name=entity_name, language=source_language, + unit_type=None) + detector.set_min_max_digits(min_digit=min_number_digits, max_digit=max_number_digits) + output = detector.detect(message=message,structured_value=structured_value, + fallback_value=fallback_value, bot_message=bot_message) + print(output) + + ``` + + - *CURL command:* + + ```shell + URL='localhost' + PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v2/number/?рдореБрдЭреЗ%20рейреж%20рдХрд┐рд▓реЛ%20рдЖрдЯрд╛%20рдФрд░%20рджреЛ%20рд╣рдЬрд╛рд░%20рдХ%20%20рдЪреАрдиреА%20рджреЗрдирд╛ &entity_name=number_of_unit&structured_value=&fallback_value=&bot_message=&min_number_digits=1&max_number_digits=2&source_language=en&unit_type=' + + ``` + + > **Output:** + + ```json + {"data": [ + { + "detection": "message", + "original_text": "рейреж рдХрд┐рд▓реЛ", + "entity_value": { "value": "рейреж", "unit": "kg"}, + "language": "hi" + }] + } + + ``` + +- ***Example 3: Detecting number[Hindi in latin script] without unit in message*** + + - *Django Shell* + + ```python + # For a sample query with following parameters + message=u"mujhe 30 kilo aata aur 2 hajaar ka chini dena aur teen sau ka chawal" + entity_name='number' + structured_value=None + fallback_value=None + bot_message=None + min_number_digits=1 # minimum number of digit + max_number_digits=6 # maximum number of digit + source_language='hi' # here language will be ISO 639-1 code + unit_type=None # this restrict the number detector to detect particular number type only. + + from ner_v2.detector.number.number.number_detection import NumberDetector + detector = NumberDetector(entity_name=entity_name, language=source_language, + unit_type=None) + detector.set_min_max_digits(min_digit=min_number_digits, + max_digit=max_number_digits) + output = detector.detect(message=message,structured_value=structured_value, + fallback_value=fallback_value, + bot_message=bot_message) + print(output) + + ``` + + - *CURL command:* + + ```shell + URL='localhost' + PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v2/number/?mujhe%2030%20kilo%20aata%20aur%202%20hajaar%20ka%20chini%20dena%20aur%20 teen%20sau%20ka%20chawal&entity_name=number_of_unit&structured_value=&fallback_value=&bot_message=&min_number_digits=1&max_number_digits=2&source_language=en&unit_type=' + + ``` + + > **Output:** + + ```json + {"data": [ + { + "detection": "message", + "original_text": "30", + "entity_value": { "value": "30", "unit": null}, + "language": "hi" + }, + { + "detection": "message", + "original_text": "2 hajaar", + "entity_value": { "value": "2000", "unit": null}, + "language": "hi" + }, + { "detection": "message", - "original_text": "7:00 am to 6:00 pm", + "original_text": "teen sau", + "entity_value": { "value": "300", "unit": null}, + "language": "hi" + } + ]} + + ``` + + + +- ***Example 4: Detecting number[English] with unit in message*** + + - *Django Shell* + + ```python + # For a sample query with following parameters + message=u"i want more than Rupees 20k and 10 pendrive" + entity_name='number' + structured_value=None + fallback_value=None + bot_message=None + min_number_digits=1 + max_number_digits=6 + source_language='en' # here language will be ISO 639-1 code + unit_type='currency' # this restrict the number detector to detect particular number type only. + + from ner_v2.detector.number.number.number_detection import NumberDetector + detector = NumberDetector(entity_name=entity_name, language=source_language, + unit_type=None) + detector.set_min_max_digits(min_digit=min_number_digits, max_digit=max_number_digits) + output = detector.detect(message=message,structured_value=structured_value, + fallback_value=fallback_value, bot_message=bot_message) + print(output) + + ``` + + - *CURL command:* + + ```shell + URL='localhost' + PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v2/number/?message=i%20want%20more%20than%20Rupees%2020k%20and%2010%20pendrive&entity_name=number_of_unit&structured_value=&fallback_value=&bot_message=&min_number_digits=1&max_number_digits=2&source_language=en&unit_type=currency' + + ``` + + > **Output:** + + ```json + {"data": [ + { + "detection": "message", + "original_text": "Rupees 20k", "entity_value": { - "mm": 0, - "hh": 6, - "range": "end", - "nn": "pm", - "time_type": null - }, + "value": "20000", + "unit": "rupees" + }, "language": "en" - } - ] - } - ``` + }] + } + /* here 40 is not detected as unit_type is specified as currency, Hence it only detect numbers having currencies value in unit */ + + ``` -### date + ### 4. Phone number -- This functionality calls the DateDetector class to detect date. + The Phone Number Detector has the capability to detect phone numbers from within the given text. The detector has the ability to handle multilanguage text. Additionally, this detector is scaled to handle domestic as well as international phone numbers. -- Example: + *This module has been updated to v2 version of chatbot_ner and is language agnostic.* - - Example 1: + **API Examples:** - - Use the **timezone** parameter to pass your current timezone to date detection - - - ```python - message = "set me reminder on 23rd december" - entity_name = 'date' - structured_value = None - fallback_value = None - bot_message = None - timezone='UTC' - ``` + - **Example 1: *Detecting phone number from message*** - - *Python:* + - *Django Shell:* ```python - from ner_v1.chatbot.entity_detection import get_date - output = get_date(message=message, entity_name=entity_name, structured_value=structured_value, fallback_value=fallback_value,bot_message=bot_message, timezone=timezone) - print output - ``` - - - CURL command:* - - ```shell - URL='localhost' - PORT=8081 - ``` - - ```shell - curl -i 'http://'$URL':'$PORT'/v1/date/?message=set%20me%20reminder%20on%2023rd%20december&entity_name=date&structured_value=&fallback_value=&bot_message=%timezone=UTC' - ``` - - - *CURL Output:* - - ```json - { - "data": [ - { - "detection": "message", - "original_text": "23rd december", - "entity_value": { - "end_range": false, - "from": false, - "normal": true, - "value": { - "mm": 12, - "yy": 2017, - "dd": 23, - "type": "date" - }, - "to": false, - "start_range": false - } - } - ] - } - ``` - - - Example 2: - - - ```python - message = "set me reminder day after tomorrow" - entity_name = 'date' + message = u'send a message on 91 9820334455' + entity_name = 'phone_number' structured_value = None fallback_value = None bot_message = None - timezone='UTC' + source_langauge='en' # here language will be ISO 639-1 code + + from ner_v2.detectors.pattern.phone_number.phone_number_detection import PhoneDetector + detector = PhoneDetector(language=source_langauge, entity_name=entity_name) + output = detector.detect(message=message, entity_name=entity_name, + structured_value=structured_value, + fallback_value=fallback_value, + bot_message=bot_message,language=source_language) + print(output) + ``` - *CURL command:* @@ -847,60 +720,45 @@ Following are the list of different entity types along with its API call: ```shell URL='localhost' PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v2/phone_number/?message=my%20contact%20number%20is%209049961794&entity_name=phone_number&structured_value=&fallback_value=&bot_message=&source_language=en' + ``` - ```shell - curl -i 'http://'$URL':'$PORT'/v1/date/?message=set%20me%20reminder%20day%20after%20tomorrow&entity_name=date&structured_value=&fallback_value=&bot_message=&timezone=UTC' - ``` - - - *CURL Output:* + > **Output **: ```json - { - "data": [ - { + {"data": [ + { "detection": "message", - "original_text": "day after tomorrow", - "entity_value": { - "end_range": false, - "from": false, - "normal": true, - "value": { - "mm": 8, - "yy": 2017, - "dd": 24, - "type": "day_after" - }, - "to": false, - "start_range": false - } - } - ] - } + "original_text": "9049961794", + "entity_value": { "value": "9049961794"}, + "language": "en" + }] + } + ``` -### budget - -- This functionality calls the BudgetDetector class to detect budget. + - **Example 2: *Detecting phone number (hindi) from message*** -- Example: + - *Django Shell:* - - Example 1: - - - ```python - message = "shirts between 2000 to 3000" - entity_name = 'budget' + ```python + message = u'рдореЗрд░рд╛ рдореЛрдмрд╛рдЗрд▓ рдирдВрдмрд░ рд╣реИ репреорепрезрепреорепреоренрез' + entity_name = 'phone_number' structured_value = None fallback_value = None bot_message = None - ``` - - - *Python:* - - ```python - from ner_v1.chatbot.entity_detection import get_budget - output = get_budget(message=message, entity_name=entity_name, structured_value=structured_value,fallback_value=fallback_value, bot_message=bot_message) - print output + source_langauge='hi' # here language will be ISO 639-1 code + + from ner_v2.detectors.pattern.phone_number.phone_number_detection import PhoneDetector + detector = PhoneDetector(language=source_langauge, entity_name=entity_name) + output = detector.detect(message=message, entity_name=entity_name, + structured_value=structured_value, + fallback_value=fallback_value, + bot_message=bot_message,language=source_language) + print(output) + ``` - *CURL command:* @@ -908,53 +766,45 @@ Following are the list of different entity types along with its API call: ```shell URL='localhost' PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v2/phone_number/?message=рдореЗрд░рд╛%20рдореЛрдмрд╛рдЗрд▓%20рдирдВрдмрд░%20рд╣реИ%20репреорепрезрепреорепреоренрезentity_name=phone_number&structured_value=&fallback_value=&bot_message=&source_language=en' + ``` - ```shell - curl -i 'http://'$URL':'$PORT'/v1/budget/?message=shirts%20between%202000%20to%203000&entity_name=budget&structured_value=&fallback_value=&bot_message=' - ``` - - - *CURL Output:* + > **Output **: ```json - { - "data": [ + {"data": [ { - "detection": "message", - "original_text": "2000 to 3000", - "entity_value": { - "max_budget": 3000, - "type": "normal_budget", - "min_budget": 2000 - } - } - ] + "detection": "message", + "original_text": "репреорепрезрепреорепреоренрез", + "entity_value": { "value": "981117971"}, + "language": "hi" + }] } + ``` -### shopping_size - -- This functionality calls the ShoppingSizeDetector class to detect cloth size. For example, Large, small, 34, etc. + - Example 2: *Detecting phone number from fallback value*** -- Example: + - *Django Shell:* - - Example 1: - - - ```python - - message = "I want to buy Large shirt and jeans of 36 waist" - entity_name = 'shopping_clothes_size' + ```python + message = u'Please call me' + entity_name = 'phone_number' structured_value = None - fallback_value = None + fallback_value = '9049961794' bot_message = None - ``` - - - *Python:* - - ```python - from ner_v1.chatbot.entity_detection import get_shopping_size - output = get_shopping_size(message=message, entity_name=entity_name, structured_value=structured_value, fallback_value=fallback_value, bot_message=bot_message) - print output + source_langauge='en' + + from ner_v2.detectors.pattern.phone_number.phone_number_detection import PhoneDetector + detector = PhoneDetector(language=source_langauge, entity_name=entity_name) + output = detector.detect(message=message, entity_name=entity_name, + structured_value=structured_value, + fallback_value=fallback_value, + bot_message=bot_message,language=source_language) + print(output) + ``` - *CURL command:* @@ -962,58 +812,50 @@ Following are the list of different entity types along with its API call: ```shell URL='localhost' PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v2/phone_number/?message=Please%20call%20me&entity_name=phone_number&structured_value=&fallback_value=9049961794&bot_message=&source_language=en' + ``` - ```shell - curl -i 'http://'$URL':'$PORT'/v1/shopping_size/?message=I%20want%20to%20buy%20Large%20shirt%20and%20jeans%20of%2036%20waist&entity_name=shopping_clothes_size&structured_value=&fallback_value=&bot_message=' - ``` - - - *CURL Output:* + > **Output **: ```json - { - "data": [ - { - "detection": "message", - "original_text": "large", - "entity_value": { - "value": "L" - } - }, + {"data": [ { - "detection": "message", - "original_text": "36", - "entity_value": { - "value": "36" - } - } - ] + "detection": "fallback_value", + "original_text": "9049961794", + "entity_value": {"value": "9049961794"}, + "language": "en" + }] } + ``` -### passenger_count + -- This functionality calls the PassengerDetector class to detect passenger count. + ### 5. Email -- Example: + The Email Detector has the capability to detect emails within the given text. - - Example 1: + **API Example:** - - ```python + - **Example 1: *Detecting emails from message*** - message = 'Can you please help me to book tickets for 3 people' - entity_name = 'no_of_adults' + - *Django Shell:* + + ```python + message = u'my email id is amans.rlx@gmail.com' + entity_name = 'email' structured_value = None fallback_value = None bot_message = None - ``` - - - *Python:* - - ```python - from ner_v1.chatbot.entity_detection import get_passenger_count - output = get_passenger_count(message=message, entity_name=entity_name, structured_value=structured_value, fallback_value=fallback_value, bot_message=bot_message) - print output + + from ner_v1.chatbot.entity_detection import get_email + output = get_email(message=message,entity_name=entity_name, + structured_value=structured_value, + fallback_value=fallback_value, bot_message=bot_message) + print(output) + ``` - *CURL command:* @@ -1021,52 +863,40 @@ Following are the list of different entity types along with its API call: ```shell URL='localhost' PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v1/email/?message=my%20email%20id%20is%20amans.rlx%40gmail.com&entity_name=email&structured_value=&fallback_value=&bot_message=' + ``` - ```shell - curl -i 'http://'$URL':'$PORT'/v1/passenger_count/?message=Can+you+please+help+me+to+book+tickets+for+3+people&entity_name=no_of_adults&structured_value=&fallback_value=&bot_message=' - ``` - - - *CURL Output:* + > **Output ** ```json - { - "data": [ + {"data": [ { - "detection": "message", - "original_text": "3", - "entity_value": { - "value": "3" - }, - "language": "en" - } - ] + "detection": "message", + "original_text": "amans.rlx@gmail.com", + "entity_value": {"value": "amans.rlx@gmail.com"} + }] } + ``` -### location + - ***Example 2: Detecting email from fallback value*** -- This functionality calls the TextDetector class to detect location. + - *Django Shell:* -- Example: - - - Example 1: - - - ```python - - message = 'atm in andheri west' - entity_name = 'locality_list' + ```python + message = u'send this me to my email' + entity_name = 'email' structured_value = None - fallback_value = None + fallback_value = 'amans.rlx@gmail.com' bot_message = None - ``` - - - *Python:* - - ```python - from ner_v1.chatbot.entity_detection import get_location - output = get_location(message=message, entity_name=entity_name, structured_value=structured_value, fallback_value=fallback_value, bot_message=bot_message) - print output + + from ner_v1.chatbot.entity_detection import get_email + output = get_email(message=message,entity_name=entity_name, + structured_value=structured_value, + fallback_value=fallback_value, bot_message=bot_message) + print(output) ``` - *CURL command:* @@ -1074,279 +904,233 @@ Following are the list of different entity types along with its API call: ```shell URL='localhost' PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v1/email/?message=send%20me%20to%20my%20email&entity_name=email&structured_value=&fallback_value=amans.rlx@gmail.com&bot_message=' + ``` - ```shell - curl -i 'http://'$URL':'$PORT'/v1/location/?message=atm+in+andheri+west&entity_name=locality_list&structured_value=&fallback_value=&bot_message=' - ``` - - - *CURL Output:* + > **Output ** ```json - { - "data": [ + {"data": [ { - "detection": "message", - "original_text": "andheri west", - "entity_value": { - "value": "Andheri West" - }, - "language": "en" - } - ] + "detection": "fallback_value", + "original_text": "abc.123@gmail.com", + "entity_value": {"value": "abc.123@gmail.com"} + }] } ``` -### person_name - -- This functionality calls the NameDetector class to detect Name entities. - -- Examples: - - - Example 1: - - - ```python - message = 'my name is yash doshi' - entity_name = 'person_name' - structured_value = None - fallback_value = 'Guest' - bot_message = 'what is your name ?' - ``` - - - *Python:* - - ```python - from ner_v1.chatbot.entity_detection import get_person_name - output = get_person_name(message=message, entity_name=entity_name, structured_value=structured_value, fallback_value=fallback_value, bot_message=bot_message) - print output - ``` - - - *CURL command:* - - ```python - URL='localhost' - PORT=8081 - ``` + - ```shell - curl -i 'http://'$URL':'$PORT'/v1/person_name/?message=my%20name%20is%yash%20doshi&entity_name=person_name&structured_value=&fallback_value=Guest&bot_message=what%20is%your%20name%20?' - ``` +### 6. Text - - *CURL Output:* +The Text Detector has the capability to detect custom text entity within the given text. This detector is language agnostic - ```python - { - "data": [ - { - "detection": "message", - "original_text": "yash doshi", - "entity_value": { - "first_name": "yash", - "last_name": "doshi", - "middle_name": null - - } - } - ] - } - ``` +> To create new text type entities, follow the steps from [here](https://github.com/hellohaptik/chatbot_ner/blob/develop/docs/adding_entities.md). - - Example 2: +**API Examples:** - - ```python - message = '' - entity_name = 'person_name' - structured_value = None - fallback_value = 'sagar nimesh dedhia' - bot_message = 'what is your name ?' - ``` +- **Example 1: *Detecting text entity from message*** - - *Python:* + - *Django Shell:* - ```python - from ner_v1.chatbot.entity_detection import get_person_name - output = get_person_name(message=message, entity_name=entity_name, structured_value=structured_value, fallback_value=fallback_value, bot_message=bot_message) - print output - ``` + ```python + message=u'i want to order chinese from mainland china and pizza from dominos' + entity_name='restaurant' # here detection NER will search for values in dictionary 'restaurant' + structured_value=None + fallback_value=None + bot_message=None + source_language='en' + + from ner_v1.chatbot.entity_detection import get_text + output = get_text(message=message, entity_name=entity_name, + structured_value=structured_value, + fallback_value=fallback_value, + bot_message=bot_message,language=source_language) + print(output) + + ``` - - *CURL command:* + The above can also be done from within the Docker container's shell. Setup is in docker.md file. - ```python - URL='localhost' - PORT=8081 - ``` + - *CURL command:* - ```shell - curl -i 'http://'$URL':'$PORT'/v1/person_name/?message=&entity_name=person_name&structured_value=&fallback_value=sagar%20nimesh%20dedhia&bot_message=what%20is%your%20name%20?' - ``` + ```shell + URL='localhost' + PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v1/text/?message=i%20want%20to%20order%20chinese%20from%20%20mainland%20china%20and%20pizza%20from%20domminos&entity_name=restaurant&structured_value=&fallback_value=&bot_message=&source_language=en' + + ``` - - *CURL Output:* + > **Output **: - ```python - { - "data": [ - { - "detection": "fallback_value", - "original_text": "sagar nimesh dedhia", - "entity_value": { - "first_name": "sagar" - "last_name": "dedhia" - "middle_name": "nimesh" - } - } - ] - } - ``` + ```json + {"data": [ + { + "detection": "message", + "original_text": "mainland china", + "entity_value": {"value": "Mainland China"}, + "language": "en" + }, + { + "detection": "message", + "original_text": "dominos", + "entity_value": { "value": "Domino's Pizza"}, + "language": "en" + }] + } + + ``` + + + +- **Example 2: *Detecting text entity from structured value*** + + - *Django Shell:* + + ```python + message = u'рдореЗрд░реЗ рд▓рд┐рдП рдХреИрдм рдмреБрдХ рдХрд░ рджреАрдЬрд┐рдпреЗ' + entity_name = 'city' + structured_value = 'рдореБрдВрдмрдИ' + fallback_value = None + bot_message = None + source_langauge='hi' + + from ner_v1.chatbot.entity_detection import get_text + output = get_text(message=message, entity_name=entity_name, + structured_value=structured_value, + fallback_value=fallback_value, + bot_message=bot_message,langauge=source_language) + print(output) + + ``` + + - *CURL command:* + + ```shell + URL='localhost' + PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v1/text/?message=рдореЗрд░реЗ рд▓рд┐рдП рдХреИрдм рдмреБрдХ рдХрд░ рджреАрдЬрд┐рдпреЗ&entity_name=movie&structured_value=рдореБрдВрдмрдИ&fallback_value=&bot_message=&source_language=en' + + ``` + + > **Output **: + + ```json + {"data": [ + { + "detection": "structure_value_verified", + "original_text": "mumbai", + "entity_value": {"value": "Mumbai"}, + "language":"hi" + }] + } + + ``` -### regex -- This functionality calls the RegexDetector class to detect entities that abide by the specified regex. - > IMPORTANT NOTE: - > - > 1. The regex pattern provided must be escaped if you are not passing in a raw string (marked by 'r' in Python) - > 2. Errors in compiling the provided pattern are not handled and will result in an exception - > 3. chatbot_ner also uses re.UNICODE flag by default for detection. This can be overridden by using re_flags argument in the constructor - > 4. If you are using groups, only 0th group will be returned. Sub grouping is not supported at the moment -- Examples: +### 7. PNR Number - - Example 1: +The PNR Detector has the capability to detect Train/ Flight PNR number within the given text. - - ```python - message = '123456 is my otp' - entity_name = 'regex_test_otp' - structured_value = None - fallback_value = None - bot_message = 'enter the otp' - regex = '\\d{4,6}' - ``` +**API Examples**: - - *Python:* +- ***Example 1: Detecting 10 digit Train PNR number from text*** - ```python - from ner_v1.chatbot.entity_detection import get_regex - output = get_regex(message=message,entity_name=entity_name, structured_value=structured_value,fallback_value=fallback_value,bot_message=bot_message, pattern=regex) - print output - ``` + - *Django Shell* - - *CURL command:* + ```python + message = 'check my pnr status for 2141215305' + entity_name = 'train_pnr' + structured_value = None + fallback_value = None + bot_message = None + + from ner_v1.chatbot.entity_detection import get_pnr + output = get_pnr(message=message, entity_name=entity_name, + structured_value=structured_value, + fallback_value=fallback_value, bot_message=bot_message) + print(output) + + ``` - ```python - URL='localhost' - PORT=8081 - ``` + - *CURL command:* - ```shell - curl -i 'http://'$URL':'$PORT'/v1/regex/?message=123456%20is%20my%otp&entity_name=regex&structured_value=&fallback_value=&bot_message=enter%20the%otp%20®ex=\d{4,6}' - ``` + ```bash + URL='localhost' + PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v1/pnr/?message=check%20my%20pnr%20status%20for%202141215305.&entity_name=pnr&structured_value=&fallback_value=&bot_message=' + ``` - - *CURL Output:* + > **Output**: - ```python - { - "data": [ - { + ```json + {"data": [ + { "detection": "message", - "original_text": "123456", - "entity_value": "123456" - } - ] - } - ``` + "original_text": "2141215305", + "entity_value": { "value": "2141215305"} + }] + } + ``` - тАЛ + -## Data Tagging +### 8. Regex -- This functionality tags the message with the entity name and also identifies the entity values. +Detect entities that match by the specified pattern. If you are not familiar with regex, please see http://www.rexegg.com/regex-quickstart.html -- Example: +*IMPORTANT NOTES* - - Example 1: +- *The regex pattern provided must be escaped if you are not passing in a raw string (marked by 'r' in Python)* +- *Errors in compiling the provided pattern are not handled and will result in an exception* +- *chatbot_ner also uses re.UNICODE flag by default for detection. This can be overridden by using re_flags argument in the constructor* +- *If you are using groups, only 0th group will be returned. Sub grouping is not supported at the moment* - - ```python - entities = ['date','time','restaurant'] - message = "Reserve me a table today at 6:30pm at Mainland China and on Monday at 7:00pm at Barbeque Nation" - ``` +**API Examples**: - - *CURL command:* +- ***Example 1: Detecting 4-6 digit number using regex*** - ```shell - URL='localhost' - PORT=8081 - ``` + - *Django Shell:* - ```shell - curl -i 'http://'$URL':'$PORT'/v1/ner/?entities=\[%22date%22,%22time%22,%22restaurant%22\]&message=Reserve%20me%20a%20table%20today%20at%206:30pm%20at%20Mainland%20China%20and%20on%20Monday%20at%207:00pm%20at%20Barbeque%20Nation' - ``` + ```python + message = 'please apply AMAZON30 coupon code to my cart' + entity_name = 'regex_coupon_code' + structured_value = None + fallback_value = None + bot_message = 'Enter the coupon code' + regex = '[A-Z]+\d{2,6}' + + from ner_v1.chatbot.entity_detection import get_regex + output = get_regex(message=message,entity_name=entity_name, + structured_value=structured_value, + fallback_value=fallback_value,bot_message=bot_message, + pattern=regex) + print(output) + ``` - - *CURL Output:* + - *CURL command:* - ```json - { - "data": { - "tag": "reserve me a table __date__ at __time__ at __restaurant__ and on __date__ at __time__ at __restaurant__", - "entity_data": { - "date": [ - { - "detection": "message", - "original_text": "monday", - "entity_value": { - "mm": 3, - "yy": 2017, - "dd": 27, - "type": "day_within_one_week" - } - }, - { - "detection": "message", - "original_text": "today", - "entity_value": { - "mm": 3, - "yy": 2017, - "dd": 21, - "type": "today" - } - } - ], - "time": [ - { - "detection": "message", - "original_text": "6:30pm", - "entity_value": { - "mm": 30, - "hh": 6, - "nn": "pm" - } - }, - { - "detection": "message", - "original_text": "7:00pm", - "entity_value": { - "mm": 0, - "hh": 7, - "nn": "pm" - } - } - ], - "restaurant": [ - { - "detection": "message", - "original_text": "barbeque nation", - "entity_value": { - "value": "Barbeque Nation" - } - }, - { - "detection": "message", - "original_text": "mainland china", - "entity_value": { - "value": "Mainland China" - } - } - ] - } - } - } - ``` + ```bash + URL='localhost' + PORT=8081 + + curl -i 'http://'$URL':'$PORT'/v1/regex/?message=please%20apply%20AMAZON30%20coupon%20code%20to my%20cart&entity_name=regex&structured_value=&fallback_value=&bot_message=enter%20the%otp%20®ex=\d{4,6}' + ``` + > **Output:** + + ```json + {"data": [ + { + "detection": "message", + "original_text": "AMAZON30", + "entity_value": "AMAZON30" + }] + } + ``` diff --git a/docs/code_style_guide.md b/docs/code_style_guide.md new file mode 100644 index 000000000..0432c25e7 --- /dev/null +++ b/docs/code_style_guide.md @@ -0,0 +1,353 @@ +### Python Code Style Guide for chatbot_ner + +**Why follow a style guide ?** + +- To keep the coding style consistent across the whole repo +- Make it more readable and maintainable. +- Ensure that others can work with the code you write +- Avoid opinionated agruments about the cosmetic quality of code and documentation in code reviews + +Since the project has been running for quite a long time without any code analysis checks, there are inconsistencies +everywhere. And since we can't fix everything at once, moving forward we would want to fix such issues part by part +as and when we make changes to said parts. + +**General Instructions:** + +- Read the guidelines and externals links presented in this document. +- Keep revisiting them from time to time. +- Update this document if you find something useful not mentioned here and educate other contributors. +- Even though we are going to setup CI, set up the mentioned tools locally to run before you commit. +- If some piece of code is within the scope of your change and it doesn't follow the style guide, refactor it. +- Finally, all this is to ensure code quality without compromising functionality. With that being said, all messages + generated by tools are warnings and should be treated as such. It is good practice to address them but dangerous + to get too hung up on them. + +----------- + +### Style Guide + +We want to closely follow [Google's Python styleguide](https://google.github.io/styleguide/pyguide.html) +with few exceptions that will be mentioned here. Although Google's styleguide provides good advice, is quite extensive and could possibly have some rules that might be hard to adhere to in our case. Such rules can be discussed for exemption later and if found troublesome can be changed. + +#### Exceptions/Additions to Google's Python styleguide + +##### 2.20 Py 2/3 cross compatibility + +- Take some effort to ensure code compatibility between Python 2.6.x and 3.x+ . Follow section 2.20, + use future and six libraries to write cross compatible code. Note, we can drop this compatibility, + once we finish porting to Py3. + + Handy guide: http://python-future.org/compatible_idioms.html + +##### 3.2 Line length + +Maximum line length is *119 characters*. + +##### 3.8 Code documentation + +We want to follow Google's doc format as mentioned in section [3.8](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings). More examples of such documentation style can be found at + +- https://www.sphinx-doc.org/en/master/usage/extensions/example_google.html#example-google +- https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html + +Adding types to arguments in docstrings can get difficult with complex types. There are some open questions on how +to mention member types for containers like lists, dict, tuple, etc. The sphinx guidelines don't elaborate much on this. +There are many ways we can go + +```python +# Consider some function like +def do_something(texts, attrs, ids=None): + pass + +# Format 1: Specifying member types +texts (list(str or unicode)): list of strings or unicode literals +attrs (tuple(int, str, float) or None): tuple with three members - int, str, float +ids (dict(str, int) or None, optional): dict mapping str to int. Defaults to None + +# Format 2: Not specifying member types and explaining in the explanation part +texts (list): list containing str or unicode literals +attrs (tuple or None): tuple containing + int: integer + str: string + float: float +ids (dict or None, optional): dict with str keys and int values. Defaults to None + +# Format 3: Using PEP 484 +texts (List[Union[str, unicode]]): list of strings or unicode literals +attrs (Optional[Tuple[int, str, float]]): tuple with three members - int, str, float +ids (Optional[Dict[str, int]], optional): dict mapping str to int. Defaults to None +``` + +Note that 1st and 3rd are compact and understood by IDEs like PyCharm but harder to read. +2nd format is easier to read but would need more explaning about the types in explanation part. +3rd style is defined by PEP 484, it is much more consistent and already has a detailed guideline +on how to write complex types. + +Notice it uses `Optional[]` which indicates this argument can take `None` value; +`Union[]` where members can be multiple types; +whereas 1st format needs the use of `or` to mention multiple types explicitly. +The `, optional` part indicates if the argument is optional (default) argument for the function +and is present in all three formats. It is different from `Optional[]`. +Also note that `List, Union, Tuple, Dict` all are in title case. These are defined in `typing` module + +It is highly recommended that you go through +[Type Annotation cheat sheet for Python 2](https://mypy.readthedocs.io/en/latest/cheat_sheet.html) +to understand how 3rd format's type annotation works. +We would recommend you follow Format 2 plus adding type annotations with `typing`. + +##### 3.10 Strings + +Use double quotes `"` for string literals so it becomes easy to copy to other formats (like JSON, C++, Java). It is +okay to use sinngle quote to to avoid the need to `\\` escape within the string + +--- + +### Some other documents to read + +- https://docs.python-guide.org/writing/style/ - From the Hitchhiker's Guide to Python highlights + some good practices that are a subset of the above guideline. +- [Haptik's Python best practices](haptik_python_best_practices.md) - Haptik's internal best practices document, + again a subset of above guideline, shows some examples of what to do and what not to do. + +--- + +### Tools + +We will use [flake8](http://flake8.pycqa.org/en/latest/), [pylint](http://pylint.pycqa.org/en/latest/), +and optionally [mypy](https://mypy.readthedocs.io/en/latest/python2.html) (encouraged but not required) + +> Note: Our CI does not run pylint because it is too verbose. However, we would still recommend running it locally + +1. **Running flake8** + + flake8 checks for pep8 compatibility + + ```shell + flake8 --max-line-length=119 + ``` + Here is a sample run on `datastore` package + + ``` + flake8 --max-line-length=119 datastore/ + ``` + + ``` + datastore/__init__.py:1:1: F401 'datastore.DataStore' imported but unused + datastore/__init__.py:1:1: F401 'datastore.DataStore' imported but unused + datastore/exceptions.py:73:1: E302 expected 2 blank lines, found 1 + datastore/exceptions.py:73:1: F811 redefinition of unused 'EngineNotImplementedException' from line 22 + datastore/exceptions.py:84:1: F811 redefinition of unused 'IndexForTransferException' from line 44 + datastore/exceptions.py:94:1: F811 redefinition of unused 'AliasForTransferException' from line 54 + datastore/datastore.py:93:121: E501 line too long (126 > 119 characters) + datastore/datastore.py:94:121: E501 line too long (131 > 119 characters) + datastore/elastic_search/__init__.py:1:1: F401 'connect' imported but unused + datastore/elastic_search/__init__.py:2:1: F401 'create' imported but unused + datastore/elastic_search/__init__.py:3:1: F401 'populate' imported but unused + datastore/elastic_search/__init__.py:4:1: F401 'query' imported but unused + datastore/elastic_search/__init__.py:5:1: F401 'transfer' imported but unused + datastore/elastic_search/__init__.py:5:16: W292 no newline at end of file + datastore/elastic_search/populate.py:4:1: F403 'from ..utils import *' used; unable to detect undefined names + datastore/elastic_search/populate.py:29:21: F405 'get_files_from_directory' may be undefined, or defined from star imports: ..utils + datastore/elastic_search/populate.py:31:29: F405 'os' may be undefined, or defined from star imports: ..utils + datastore/elastic_search/populate.py:61:21: F405 'get_files_from_directory' may be undefined, or defined from star imports: ..utils + datastore/elastic_search/populate.py:63:29: F405 'os' may be undefined, or defined from star imports: ..utils + datastore/elastic_search/populate.py:90:24: F405 'defaultdict' may be undefined, or defined from star imports: ..utils + datastore/elastic_search/populate.py:92:22: F405 'read_csv' may be undefined, or defined from star imports: ..utils + datastore/elastic_search/populate.py:179:22: F405 'os' may be undefined, or defined from star imports: ..utils + datastore/elastic_search/populate.py:180:22: F405 'os' may be undefined, or defined from star imports: ..utils + datastore/elastic_search/populate.py:191:50: F405 'remove_duplicate_data' may be undefined, or defined from star imports: ..utils + datastore/elastic_search/populate.py:193:8: F405 'os' may be undefined, or defined from star imports: ..utils + datastore/elastic_search/populate.py:193:42: F405 'os' may be undefined, or defined from star imports: ..utils + datastore/elastic_search/populate.py:194:9: F405 'os' may be undefined, or defined from star imports: ..utils + datastore/elastic_search/populate.py:263:121: E501 line too long (124 > 119 characters) + datastore/elastic_search/populate.py:267:121: E501 line too long (127 > 119 characters) + datastore/elastic_search/populate.py:297:121: E501 line too long (136 > 119 characters) + ``` + + As you see it caught redefinitions so some exceptions that were missed in Code review, `*` import, too long lines, + `os` import being used from another import. All of this could be easily fixed. + + **Usually we would want to fix most flake8 reported issues, unless there are some strong reasons to ignore + some of them** + +2. **Running pylint just for Python 2 and 3 compatibility checks** + + Before we run the pylint check for all possible checks, we would want to fix code compatibility issues first as + more often than not, there are very few issues and once fixed it is unlikely, they pop up again. + + To get all compatibility issues, run + + ```shell + pylint --rcfile=~/chatbot_ner/.pylintrc --py3k -f parseable -r n + ``` + + It is advised to **run it only on changed files**. + + **Usually we would want to fix most compatibility reported issues, + unless there are some strong reasons to ignore some of them** + +3. **Running pylint** + + pylint checks code for pep8 compatibility plus code complexity and code smell issues. + + ```shell + pylint --rcfile=~/chatbot_ner/.pylintrc -f parseable -r n + ``` + + Note you might need to adjust the `тАФrcfile` path depending on where you are running the command from. + Always use the `.pylintrc` provided in the repo. That way we can ensure everyone is using the same config + + Once you start using pylint, you would see that it's **brutal** with your code analysis, + so it is advised to **run it only on changed files**. Remember that even if pylint is too picky and strict + there is often useful advice for readability and code style in pylint's output. Not all issues need to be strictly + resolved but considering them would help. It is recommended to read + [pylint's tutorial](http://pylint.pycqa.org/en/latest/tutorial.html). + + Here is an example run on `datastore` package + + ```shell + cd chatbot_ner/ + pylint --rcfile=.pylintrc -f parseable -r n datastore/ + ``` + + ``` + Using config file ~/chatbot_ner/.pylintrc + ************* Module datastore + datastore/__init__.py:1: [C0111(missing-docstring), ] Missing module docstring + datastore/__init__.py:1: [W0403(relative-import), ] Relative import 'datastore', should be 'datastore.datastore' + ************* Module datastore.constants + datastore/constants.py:1: [C0111(missing-docstring), ] Missing module docstring + datastore/constants.py:2: [C0411(wrong-import-order), ] standard import "import os" should be placed before "import elasticsearch" + ************* Module datastore.utils + datastore/utils.py:1: [C0111(missing-docstring), ] Missing module docstring + ************* Module datastore.exceptions + datastore/exceptions.py:1: [C0111(missing-docstring), ] Missing module docstring + ... + datastore/exceptions.py:185: [W0231(super-init-not-called), DeleteIndexFromAliasException.__init__] __init__ method from base class 'Exception' is not called + ************* Module datastore.datastore + datastore/datastore.py:341: [W0511(fixme), ] TODO: repopulate code for crf index missing + datastore/datastore.py:93: [C0301(line-too-long), ] Line too long (126/119) + datastore/datastore.py:94: [C0301(line-too-long), ] Line too long (131/119) + datastore/datastore.py:1: [C0111(missing-docstring), ] Missing module docstring + datastore/datastore.py:3: [W0403(relative-import), ] Relative import 'elastic_search', should be 'datastore.elastic_search' + datastore/datastore.py:457: [W1201(logging-not-lazy), DataStore.get_crf_data_for_entity_name] Specify string format arguments as logging function parameters + datastore/datastore.py:475: [W1201(logging-not-lazy), DataStore.get_crf_data_for_entity_name] Specify string format arguments as logging function parameters + ************* Module datastore.commands.populate_datastore + datastore/commands/populate_datastore.py:1: [C0111(missing-docstring), ] Missing module docstring + datastore/commands/populate_datastore.py:8: [C0111(missing-docstring), Command] Missing class docstring + datastore/commands/populate_datastore.py:51: [E1101(no-member), Command.handle] Instance of 'Style' has no 'ERROR' member + ************* Module datastore.commands.delete_entity_data_datastore + datastore/commands/delete_entity_data_datastore.py:1: [C0111(missing-docstring), ] Missing module docstring + datastore/commands/delete_entity_data_datastore.py:5: [C0111(missing-docstring), Command] Missing class docstring + datastore/commands/delete_entity_data_datastore.py:22: [E1101(no-member), Command.handle] Instance of 'Style' has no 'ERROR' member + ************* Module datastore.commands.delete_datastore + datastore/commands/delete_datastore.py:1: [C0111(missing-docstring), ] Missing module docstring + datastore/commands/delete_datastore.py:5: [C0111(missing-docstring), Command] Missing class docstring + ************* Module datastore.commands.repopulate_datastore + datastore/commands/repopulate_datastore.py:1: [C0111(missing-docstring), ] Missing module docstring + datastore/commands/repopulate_datastore.py:8: [C0111(missing-docstring), Command] Missing class docstring + datastore/commands/repopulate_datastore.py:53: [E1101(no-member), Command.handle] Instance of 'Style' has no 'ERROR' member + ************* Module datastore.commands.create_datastore + datastore/commands/create_datastore.py:1: [C0111(missing-docstring), ] Missing module docstring + datastore/commands/create_datastore.py:5: [C0111(missing-docstring), Command] Missing class docstring + ************* Module datastore.elastic_search.create + datastore/elastic_search/create.py:1: [C0111(missing-docstring), ] Missing module docstring + datastore/elastic_search/create.py:1: [W0403(relative-import), ] Relative import 'utils', should be 'datastore.elastic_search.utils' + datastore/elastic_search/create.py:26: [W0703(broad-except), delete_index] Catching too general exception Exception + datastore/elastic_search/create.py:91: [W0703(broad-except), _create_index] Catching too general exception Exception + ************* Module datastore.elastic_search.query + datastore/elastic_search/query.py:286: [W1401(anomalous-backslash-in-string), ] Anomalous backslash in string: '\s'. String constant might be missing an r prefix. + datastore/elastic_search/query.py:1: [C0111(missing-docstring), ] Missing module docstring + datastore/elastic_search/query.py:50: [R0913(too-many-arguments), full_text_query] Too many arguments (7/5) + datastore/elastic_search/query.py:2: [C0411(wrong-import-order), ] standard import "import re" should be placed before "from six import string_types" + datastore/elastic_search/query.py:3: [C0411(wrong-import-order), ] standard import "import collections" should be placed before "from six import string_types" + datastore/elastic_search/query.py:6: [C0411(wrong-import-order), ] first party import "from external_api.constants import SENTENCE_LIST, ENTITY_LIST" should be placed before "from ..constants import ELASTICSEARCH_SEARCH_SIZE, ELASTICSEARCH_VERSION_MAJOR, ELASTICSEARCH_VERSION_MINOR" + datastore/elastic_search/query.py:7: [C0411(wrong-import-order), ] first party import "from language_utilities.constant import ENGLISH_LANG" should be placed before "from ..constants import ELASTICSEARCH_SEARCH_SIZE, ELASTICSEARCH_VERSION_MAJOR, ELASTICSEARCH_VERSION_MINOR" + ************* Module datastore.elastic_search.connect + datastore/elastic_search/connect.py:1: [C0111(missing-docstring), ] Missing module docstring + ************* Module datastore.elastic_search.__init__ + datastore/elastic_search/__init__.py:5: [C0304(missing-final-newline), ] Final newline missing + ************* Module datastore.elastic_search + datastore/elastic_search/__init__.py:1: [C0111(missing-docstring), ] Missing module docstring + ... + datastore/elastic_search/__init__.py:5: [W0403(relative-import), ] Relative import 'transfer', should be 'datastore.elastic_search.transfer' + ************* Module datastore.elastic_search.transfer + datastore/elastic_search/transfer.py:276: [W0511(fixme), ] TODO - this works differently from other connects, picks scheme from the full URL + datastore/elastic_search/transfer.py:207: [C0325(superfluous-parens), ] Unnecessary parens after 'while' keyword + datastore/elastic_search/transfer.py:1: [C0111(missing-docstring), ] Missing module docstring + datastore/elastic_search/transfer.py:192: [W1201(logging-not-lazy), ESTransfer.check_if_index_exits] Specify string format arguments as logging function parameters + datastore/elastic_search/transfer.py:247: [R0201(no-self-use), ESTransfer._generate_update_json] Method could be a function + datastore/elastic_search/transfer.py:464: [W0102(dangerous-default-value), ESTransfer.transfer_specific_entities] Dangerous default value [] as argument + datastore/elastic_search/transfer.py:471: [W1201(logging-not-lazy), ESTransfer.transfer_specific_entities] Specify string format arguments as logging function parameters + datastore/elastic_search/transfer.py:477: [W1201(logging-not-lazy), ESTransfer.transfer_specific_entities] Specify string format arguments as logging function parameters + datastore/elastic_search/transfer.py:480: [W1201(logging-not-lazy), ESTransfer.transfer_specific_entities] Specify string format arguments as logging function parameters + datastore/elastic_search/transfer.py:484: [W1201(logging-not-lazy), ESTransfer.transfer_specific_entities] Specify string format arguments as logging function parameters + datastore/elastic_search/transfer.py:492: [W1201(logging-not-lazy), ESTransfer.transfer_specific_entities] Specify string format arguments as logging function parameters + datastore/elastic_search/transfer.py:2: [C0411(wrong-import-order), ] standard import "import json" should be placed before "import requests" + ************* Module datastore.elastic_search.utils + datastore/elastic_search/utils.py:1: [C0111(missing-docstring), ] Missing module docstring + ************* Module datastore.elastic_search.populate + datastore/elastic_search/populate.py:114: [C0301(line-too-long), ] Line too long (120/119) + datastore/elastic_search/populate.py:154: [C0330(bad-continuation), ] Wrong continued indentation (remove 1 space). + } + |^ + datastore/elastic_search/populate.py:220: [C0330(bad-continuation), ] Wrong continued indentation (remove 1 space). + } + |^ + datastore/elastic_search/populate.py:263: [C0301(line-too-long), ] Line too long (124/119) + datastore/elastic_search/populate.py:267: [C0301(line-too-long), ] Line too long (127/119) + datastore/elastic_search/populate.py:297: [C0301(line-too-long), ] Line too long (136/119) + datastore/elastic_search/populate.py:332: [C0330(bad-continuation), ] Wrong continued indentation (remove 1 space). + } + |^ + datastore/elastic_search/populate.py:1: [C0111(missing-docstring), ] Missing module docstring + datastore/elastic_search/populate.py:4: [W0401(wildcard-import), ] Wildcard import utils + datastore/elastic_search/populate.py:10: [R0913(too-many-arguments), create_all_dictionary_data] Too many arguments (6/5) + datastore/elastic_search/populate.py:42: [R0913(too-many-arguments), recreate_all_dictionary_data] Too many arguments (6/5) + datastore/elastic_search/populate.py:105: [W0703(broad-except), get_variants_dictionary_value_from_key] Catching too general exception Exception + datastore/elastic_search/populate.py:101: [W0703(broad-except), get_variants_dictionary_value_from_key] Catching too general exception Exception + datastore/elastic_search/populate.py:74: [W0613(unused-argument), get_variants_dictionary_value_from_key] Unused argument 'kwargs' + ... + datastore/elastic_search/populate.py:4: [W0614(unused-wildcard-import), ] Unused import csv from wildcard import + datastore/elastic_search/populate.py:5: [C0411(wrong-import-order), ] first party import "from language_utilities.constant import ENGLISH_LANG" should be placed before "from ..constants import ELASTICSEARCH_BULK_HELPER_MESSAGE_SIZE, ELASTICSEARCH_SEARCH_SIZE" + datastore/elastic_search/populate.py:1: [R0801(duplicate-code), ] Similar lines in 2 files + ==datastore.commands.populate_datastore:11 + ==datastore.commands.repopulate_datastore:13 + ... + Your code has been rated at 8.30/10 + ``` + + As you see it warns about missing documentation, non standard naming conventions, indentation mistakes, long lines, + import errors, too many arguments, catching general exception etc. The output is quite verbose + and not always perfect. For example - we use dynamic imports in some places which pylint can't understand. + In such cases it makes sense to ignore such messages. But some errors like `*` imports, indentation mistakes, + long lines, too many arguments, relative imports provide good signals to refactor those parts. + + **We do not aim to achieve a 10/10 score from pylint** + +> You can use tools like [yapf](https://github.com/google/yapf) or [autopep8](https://github.com/hhatto/autopep8) or + Pycharm plugins to fix lint errors or fix them manually. + In the end all that matters is fixing them. + +4. **Running mypy** + + MyPy helps checking type annotations in code according to [PEP 484](https://www.python.org/dev/peps/pep-0484/). + Since we are still using Py 2.x, we cannot use mypy type annotations as we can in Python 3.5+. + Only option to annotate is to do so via inline comments. + MyPy docs do a good job of explaining how to install, annotate and use it. + However, note that running mypy needs Python 3. + Adding type annotations is encouraged however we are not enforcing it. + We would highly encourage you to read mypy docs. Some handy pages: + + - [Introduction](https://mypy.readthedocs.io/en/latest/introduction.html) + - [Use with existing codebase](https://mypy.readthedocs.io/en/latest/existing_code.html) + - [Type Checking for Python2](https://mypy.readthedocs.io/en/latest/python2.html) + - [Type Annotation cheat sheet for Python 2](https://mypy.readthedocs.io/en/latest/cheat_sheet.html) + + Running mypy + + ```shell + mypy + ``` + + тАЛ \ No newline at end of file diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 000000000..0ecca47e5 --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,49 @@ +### Steps for writing code and Raise a PR: + +1. Fork the repo by going to https://github.com/hellohaptik/chatbot_ner.git and doing the below: + ![Fork-1](images/Fork-1.png) + + Above will open a prompt like this: + ![Fork-2](images/Fork-2.png) + + Click on your username or organization you own. + +2. So, now you have forked the chatbot_ner repository as shown below: + ![Fork-3](images/Fork-3.png) + + Lets see what you need to do next: + + 1. Clone your new forked repository on your machine, for me it would be something like: + git clone https://github.com/ranvijayj/chatbot_ner.git + + 2. Remember, chatbot_ner follows GitFlow so all changes unless a hot fix go to develop first. + + 3. Checkout to new branch + git checkout -b branch_name + + Note: branch_name to be replace with the branch name you want. Ideally it should be the name of the feature and the change e.g.: language_support_hindi + + 4. Make code changes. Follow pointer number 5 for code style docs. + git commit -am"This change will add hindi language support etc. " + git push origin branch_name + + +3. Create a pull request against the hellohaptik chatbot_ner repository. While creating the PR take care of the following things as shown below: + ![Create PR](images/Create-PR.png) + + Add Title, Description, Labels, and Milestone if you're working on any mentioned in the repository milestones. + + **List of appropriate labels**: + new-feature + bug-fixes + documentation + enhancement + needs-migration + packages-updated + miscellaneous + +4. You're done. Just wait for the PR checks to pass as shown below: + ![PR-Checks](images/PR-Checks.png) One of the admins will approve your PR and merge it. + +5. You can follow this link to checkout basic coding +[guidelines](https://github.com/hellohaptik/chatbot_ner/tree/develop/docs/code_style_guide.md) diff --git a/docs/haptik_python_best_practices.md b/docs/haptik_python_best_practices.md new file mode 100644 index 000000000..14df2010d --- /dev/null +++ b/docs/haptik_python_best_practices.md @@ -0,0 +1,367 @@ +# Whitespace +* Use spaces instead of tabs for indentation. +* Use four spaces for each level of syntactically significant indenting. +* Lines should be 120 characters in length or less. +* Continuations of long expressions onto additional lines should be indented by four extra spaces from their normal indentation level. +* In a file, functions and classes should be separated by two blank lines. +* Don't put spaces around + * List indexes + * Function calls + * Keyword argument assignments +* Put one space + * Before and after variable assignments. + * After colon separating `key: value` in dictonary. + * After comma separating items in list, dict, tuple. + +# Naming +* Functions, variables, and attributes should be in `lowercase_underscore` format. +* Protected instance attributes should be in `_leading_underscore` format. +* Private instance attributes should be in `__double_leading_underscore` +format. +* Classes and exceptions should be in `CapitalizedWord` format. +* Module-level constants should be in `ALL_CAPS` format. +* Instance methods in classes should use `self` as the name of the first parameter (which refers to the object). +* Class methods should use `cls` as the name of the first parameter (which refers to the class). + +# Expressions and Statements +* Don't check for empty values (like [] or '') by checking the length +`if len(somelist) == 0)`. Use `if not somelist` and assume empty values implicitly evaluate to False. +* The same thing goes for non-empty values (like [1] or 'hello'). The statement `if somelist` is implicitly True for non-empty values. +* If you want to check if a value is None. Use `if var is None`. Do not do `if not var`.it will return True even if var value is 0. +* Always put import statements at the top of a file. +* Never user `import *`. +* Imports should be in sections in the following order: standard library modules, thirdparty modules, your own modules. + +```python +# Standard library modules +import datetime +import sys + +# Thirdparty modules +from django.core.cache import caches +from django.db.models import Q + +# App imports +from ner_v2.detectors.numeral.number import number_detection + +``` + +* Python's syntax makes it all too easy to write single-line expressions that are overly complicated and difficult to read. Move complex expressions into helper functions, especially if you need to use the same logic repeatedly. +* Prefer using List comprehensions instead of map and filter. Its easier to read as they don't require extra lambda expressions. +```python +# list comprehension +even_squares = [x**2 for x in a if x % 2 == 0] + +# map and filter +even_squares = list(map(lambda x: x**2, filter(lambda x: x % 2 == 0, a))) +``` +* Dictonary also support comprehension expressions +```python +names = ['James', 'Jack', 'Alley'] +names_len = {a: len(a) for a in names } +``` +* List comprehensions with more than two expressions are very difficult to read and should be avoided. +* List comprehensions can cause problems for large inputs by using too much +memory. Use Generator expressions to avoid memory issues by producing outputs one at a time as an iterator. + +```python +# List comprehension +values = [len(x) for x in open('/tmp/my_file.txt')] + +# Generator expression +it = (len(x) for x in open('/tmp/my_file.txt')) +print next(it) +``` + +# Functions +* Use None to specify dynamic default parameters. Default argument values are evaluated only once per module load, which usually happens when a program starts up. + +```python +# Do not do this +def log(message, when=datetime.now()): + print('%s: %s' % (when, message)) + +log('Hi') +sleep(1) +log('Hello') + +>> +2017-11-15 21:10:10.371432: Hi +2017-11-15 21:10:10.371432: Hello + +# Do this +def log(message, when=None): + when = datetime.now() if when is None else when + print('%s: %s' % (when, message)) + +log('Hi') +sleep(1) +log('Hello') + +>> +2017-11-15 21:10:10.371432: Hi +2017-11-15 21:10:11.371432: Hello +``` + +* Using None for default argument values is especially important when the arguments are `mutable` i.e dict or list. + +```python +def decode(data, default={}): + try: + return json.loads(data) + except ValueError: + return default + +foo = decode('bad data') +foo['stuff'] = 5 +bar = decode('also bad') +bar['meep'] = 1 +print('Foo:', foo) +print('Bar:', bar) + +>> +Foo: {'stuff': 5, 'meep': 1} # Expected Foo: {'stuff': 5} +Bar: {'stuff': 5, 'meep': 1} # Expected Bar: {'meep': 1} +``` +You'd expect two different dictionaries, each with a single key and value. But modifying one seems to also modify the other as they are using same dictionary object. + +```python +def decode(data, default=None): + if default is None: + default = {} + try: + return json.loads(data) + except ValueError: + return default + +foo = decode('bad data') +foo['stuff'] = 5 +bar = decode('also bad') +bar['meep'] = 1 +print('Foo:', foo) +print('Bar:', bar) +>>> +Foo: {'stuff': 5} +Bar: {'meep': 1} +``` + +* You can enforce clarity in function call using keyword arguments. +```python +def send_automated_reply(msg, should_type, send_athena): + # create msg + if should_type: + # send typing indicator + + if send_athena: + # send msg to athena + +send_automated_reply(msg, True, False) +``` +The problem is that it's easy to confuse the position of the two Boolean arguments that control sending typing indicator and sending msg to athena. This can easily cause bugs that are hard to trackdown. To avoid this condition we should use keyword arguments. + +```python +def send_automated_reply(msg, should_type=True, send_athena=True): + # create msg + if should_type: + # send typing indicator + + if send_athena: + # send msg to athena + +send_automated_reply(msg, should_type=True, send_athena=False) +``` + +# Non Pythonic vs Pythonic +* Use range function to loop over a series of numbers +```python +# Non Pythonic +for i in [0, 1, 2, 3, 4, 5]: + print i*i + +# Pythonic +for i in xrange(0, 6): # python 2 + print i*i + +for i in range(0, 6): # python 3 + print i*i +``` + +* Looping over a collection +```python +# Non Pythonic +names = ['james', 'jack', 'alex', 'martin'] +# Forward looping +for i in range(len(names)): + print names[i] +# Reverse looping +for i in range(len(names)-1, -1, -1): + print names[i] +# Print indeces with names +for i in range(len(names)): + print i, '--->', names[i] + +# Pythonic +names = ['james', 'jack', 'alex', 'martin'] +# Forward looping +for name in names: + print name +# Reverse looping of names +for name in reversed(names): + print name +# Print indeces with names +for i, name in enumerate(names): + print i, '---->', name +``` +* looping over two collections together +```python +names = ['james', 'jack', 'alex', 'martin'] +ages = [23, 34, 54] + +# Non pythonic +n = min(len(names), len(ages)) +for i in range(n): + print names[i], '--->', ages[i] + +# Pythonic +for name, age in zip(names, ages): + print name, '---->', age +``` +* Use named tuples instead of tuples +```python +# Non Pythonic +colour_heuristic = (170, 0.1, 0.6) +if colour_heuristic[1] > 0.5: + print 'that is too bright' +if colour_heuristic[2] > 0.5: + print 'wow this is light' + +# Pythonic +from collections import namedtuple + +colour = namedtuple('Colour', ['hue', 'saturation', 'luminosity']) +colour_heuristic = colour(170, 0.1, 0.6) + +if colour_heuristic.saturation > 0.5: + print 'that is too bright' +if colour_heuristic.luminosity > 0.5: + print 'wow this is light' +``` +* Use properties instead of getters methods +```python +# Non Pythonic +class NetworkElement(object): + def get_name(): + return self.name + def get_ipaddr(): + return self.ip_addr +ne = NetworkElement() +network_name = ne.get_name() +ip_addr = ne.get_ipaddr() +create_connection(network_name, ip_addr) + +# Pythonic +class NetworkElement(object): + @property + def name(): + return self.name + @property + def ip_addr(): + return self.ip_addr + +ne = NetworkElement() +create_connection(ne.name, ne.ip_addr) +``` +* Use `defaultdict` to assign default values for keys in dict + +```python +names = ['jack', 'alex', 'martin', 'ruby', 'alex'] + +# Non Pythonic +name_count = {} +for name in names: + if name not in name_count: + name_count[name] = 0 + name_count[name] += 1 + +# Pythonic +name_count = defaultdict(int) +for name in names: + name_count[name] += 1 +``` +* Unpacking of sequence +```python +# Non Pythonic +p = 'Jack', 23, 'jack@gmail.com' +name = p[0] +age = p[1] +email = p[2] + +# Pythonic +name, age, email = 'Jack', 23, 'jack@gmail.com' +``` +* use `join()` for concatenation of string + +```python + +# Non pythonic +names = ['jack', 'alex', 'martin', 'ruby', 'alex'] +s = '' +for name in names: + s += ', ' + name + +# Pythonic +s = ', '.join(names) +``` + +* Use `Deque` for updating sequence. Deques are a generalization of stacks and queues. Deques have O(1) speed for appendleft() and popleft() while lists have O(n) performance for insert(0, value) and pop(0). + +```python +# Non Pythonic +names = ['jack', 'alex', 'martin', 'ruby', 'alex'] +del names[0] +names.pop[0] +names.insert(0, 'mark') + +# Pythonic +from collections import deque +names = deque(['jack', 'alex', 'martin', 'ruby', 'alex']) +del names[0] +names.popleft(0) +names.appendleft('mark') +``` + +* Factor-out your setup logic and teardown logic with context managers. You can write your custom context manager using `__enter__()` and `__exit__()` functions. [Read more](https://jeffknupp.com/blog/2016/03/07/python-with-context-managers/) + +```python +# Non Pythonic +f = open('data.txt') +try: + data = f.read() +finally: + f.close() + +# Pythonic +with open('data.txt') as f: + data = f.read() +``` + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/Create-PR.png b/docs/images/Create-PR.png new file mode 100644 index 000000000..d9ead9d12 Binary files /dev/null and b/docs/images/Create-PR.png differ diff --git a/docs/images/Fork-1.png b/docs/images/Fork-1.png new file mode 100644 index 000000000..e724303eb Binary files /dev/null and b/docs/images/Fork-1.png differ diff --git a/docs/images/Fork-2.png b/docs/images/Fork-2.png new file mode 100644 index 000000000..f11934391 Binary files /dev/null and b/docs/images/Fork-2.png differ diff --git a/docs/images/Fork-3.png b/docs/images/Fork-3.png new file mode 100644 index 000000000..0a5fbc3d5 Binary files /dev/null and b/docs/images/Fork-3.png differ diff --git a/docs/images/PR-Checks.png b/docs/images/PR-Checks.png new file mode 100644 index 000000000..5136b2eb7 Binary files /dev/null and b/docs/images/PR-Checks.png differ diff --git a/docs/images/date_contribution_example.png b/docs/images/date_contribution_example.png new file mode 100644 index 000000000..a13049ec7 Binary files /dev/null and b/docs/images/date_contribution_example.png differ diff --git a/docs/images/form.png b/docs/images/form.png new file mode 100644 index 000000000..95694c7d8 Binary files /dev/null and b/docs/images/form.png differ diff --git a/external_api/api.py b/external_api/api.py index 3be5bafe1..b5dcc7b39 100644 --- a/external_api/api.py +++ b/external_api/api.py @@ -324,3 +324,19 @@ def entity_data_view(request, entity_name): else: raise APIHandlerException("{0} is not allowed.".format(request.method)) + + +@external_api_response_wrapper +def read_unique_values_for_text_entity(request, entity_name): + """ + API call to View unique values for text entity. + """ + if request.method == 'GET': + try: + return dictionary_utils.get_entity_unique_values(entity_name=entity_name) + except (DataStoreSettingsImproperlyConfiguredException, + EngineNotImplementedException, + EngineConnectionException, FetchIndexForAliasException) as error_message: + raise APIHandlerException(str(error_message)) + else: + raise APIHandlerException("{0} is not allowed.".format(request.method)) diff --git a/ner_v1/chatbot/entity_detection.py b/ner_v1/chatbot/entity_detection.py index a5dec349e..311066e5d 100644 --- a/ner_v1/chatbot/entity_detection.py +++ b/ner_v1/chatbot/entity_detection.py @@ -514,22 +514,28 @@ def get_person_name(message, entity_name, structured_value, fallback_value, bot_ [{'detection': 'message', 'original_text': 'yash doshi', 'entity_value': {'first_name': yash, 'middle_name': None, 'last_name': doshi}}] """ + # TODO refactor NameDetector to make this easy to read and use name_detection = NameDetector(entity_name=entity_name, language=language) - if structured_value: - entity_list, original_text_list = name_detection.detect_entity(text=structured_value) - if entity_list: - return output_entity_dict_list(entity_list, original_text_list, FROM_STRUCTURE_VALUE_VERIFIED) - else: - return output_entity_dict_list([structured_value], [structured_value], FROM_STRUCTURE_VALUE_NOT_VERIFIED) - else: - entity_list, original_text_list = name_detection.detect_entity(text=message, bot_message=bot_message) - if entity_list: - return output_entity_dict_list(entity_list, original_text_list, FROM_MESSAGE) - elif fallback_value: - fallback_entity_value, fallback_original_value = NameDetector.get_format_name(fallback_value.split()) - return output_entity_dict_list(entity_value_list=[fallback_entity_value[0]], - original_text_list=[fallback_original_value[0]], - detection_method=FROM_FALLBACK_VALUE) + text, detection_method, fallback_text, fallback_method = (structured_value, + FROM_STRUCTURE_VALUE_VERIFIED, + structured_value, + FROM_STRUCTURE_VALUE_NOT_VERIFIED) + if not structured_value: + text, detection_method, fallback_text, fallback_method = (message, + FROM_MESSAGE, + fallback_value, + FROM_FALLBACK_VALUE) + entity_list, original_text_list = [], [] + + if text: + entity_list, original_text_list = name_detection.detect_entity(text=text, bot_message=bot_message) + + if not entity_list and fallback_text: + entity_list, original_text_list = NameDetector.get_format_name(fallback_text.split()) + detection_method = fallback_method + + if entity_list and original_text_list: + return output_entity_dict_list(entity_list, original_text_list, detection_method) return None diff --git a/ner_v1/detectors/textual/name/hindi_const.py b/ner_v1/detectors/textual/name/hindi_const.py index 65907bd5e..7651d42ff 100644 --- a/ner_v1/detectors/textual/name/hindi_const.py +++ b/ner_v1/detectors/textual/name/hindi_const.py @@ -1,303 +1,336 @@ # coding=utf-8 HINDI_BADWORDS = [u'рдмрдХрд░ рдЫреЛрдбрд╝', -u'рдмрд╛рд╣реЗрдВ рдЫреЛрдбрд╝', - u'рдмрд╛рд╣реЗрдВ рдХреЗ рд▓реЙрдб', - u'рдмрд╛рд╣реЗрдВ рдХреЗ рдЯрдХреНрдХреЗ', - u'рдмрдХрд▓рдВрдб', - u'рдмреЗрдЯреА рдЫреЛрдбрд╝', - u'рднрдврд╝рд╛рд╡рд╛', - u'рднрджреНрд╡реЗ рдХрд╛ рдЕрд╡рд▓рдЯ', - u'рднрд╛рдИ рдЫреЛрдбрд╝', - u'рднрд╛рдВрдб рдЦрд╝реМ', - u'рднреЛрдВрд╕рд░реА рд╡рд╛рд▓рд╛', - u'рднреВрдЯреНрдиреА рдХрд╛', - u'рднреЛрд╕рдж рдЫреЛрдбрд╝', - u'рднреЛрд╕рджреАрдХреЗ', - u'рдмрд░ рдХреА рдЪрдЯрдиреА', - u'рдЪреНрдЫреЗрдж', - u'рдЫреНрд╣реЛрд▓рд╛ рдлреБрджрдХрдирд╛', - u'рдЫрд┐рдирд╛рд▓', - u'рдЫреЛрдбрд╝реЗрд▓рд╛', - u'рдЫреЛрджреНрд░рд╛', - u'рдЫреЛрдбрд╝реВ рднрдЧрдд', - u'рдЫреЛрдбрд╝реВ', - u'рдЪреВрдЫреАреА', - u'рдЫреВрдЯ рдХрд╛ рдмрд╛рд▓', - u'рдЫреВрдЯ рдХреЗ рднреВрдд', - u'рдЫреВрдЯ рдорд╛рд░рдиреА рдХрд╛', - u'рдЪреВрддрд┐рдпрд╛', - u'рдЪреБрджрд╛рдИ рдЦрд╛рдирд╛', - u'рдЪреБрдбрд╝рд╛рди рдЫреБрдбрд╝рд╛', - u'рдЫреВрдЯ рдХрд╛ рдкреБрдЬрд╛рд░реА', - u'рдЫреВрдЯ рдХреЗ рдврдХреНрдХрди', - u'рдЫреВрдЯ рдХреЗ рдЧреБрд▓рд╛рдо', - u'рдЫреВрдЯ рдорд╛рд░реА рдХреЗ', - u'рдЫреВрдЯ рдорд╛рд░реАрдХреЗ', - u'рдЫреВрдЯ', - u'рдЪреВрдЯрд╛рди', - u'рдХреБрдВрдЯрдорд╛рдорд╛', - u'рдЧрд╛рдВрдж рдХрд╛ рдорд╛рдЦрди', - u'рдЧрд╛рдВрдж рдореИрдВ рдбрдВрдбрд╛', - u'рдЧрд╛рдВрдж рдореИрдВ рдХреАрд░рд╛', - u'рдЧрд╛рдВрдж рдореИрдВ рд▓рд╛**рдЖрди', - u'рдЧрд╛рдВрдж рдорд░реМ', - u'рдЧрд╛рдВрдж', - u'рдЧрд╛рдВрдбреНрдлрд╛рдЯ', - u'рдЧрд╛рдВрджрдорд╛рд╕реНрддреА', - u'рдЧрд╛рдиреНрдбреВ', - u'рд╣рд░рд╛рдо рдЬрд╝рд╛рджрд╛', - u'рд╣рд░рд╛рдореА', - u'рд╣рд┐рдЬрдбрд╝реЗ', - u'рдЭрд╛рдБрдд рдХреЗ рдкрд┐рд╕реНрд╕реВ', - u'рдЭрд▓реНрд▓рд╛', - u'рдЭрд╛рдВрдЯ рдЪрд╛рддреБ', - u'рдЭрд╛рдВрдЯ рдХреЗ рдмрд╛рд▓', - u'рдХрдбрд╝рдХ рдорд╛рд▓', - u'рдХрдореАрдирд╛', - u'рдХреБрддреНрддреЗ рдХрд╛ рдЕрд╡рд▓рдЯ', - u'рдХреБрддреНрддреЗ рдХрд╛ рдмреАрдЬ', - u'рдХреБрдЯреНрдЯрд┐рдпрд╛', - u'рд▓реЙрдбрд╛, рд▓рдВрдб', - u'рд▓рд╡рдВрдбрд░', - u'рд│рд╡реНрдб', - u'рд▓рд╡рджреЗ рдХреЗ рдмрд╛рд▓', - u'рд▓рдВрдб', - u'рд▓рдВрдб рдЪреВрд╕реВ', - u'рдорд╛ рдЪреВрдбрд╝реА', - u'рдлреБрджрдзрд┐', - u'рд░рд╛рдВрдбреА рдмрд╛рдЬреЗрд░', - u'рд░реБрдВрдбреА рдХрд╛ рдмрдЪрд╛', - u'рд░реБрдВрдбреА рдХреЗ рдЯрдЯреНрдЯреА рдкреЗ рдмрд┐рдпрддрдиреЗ рд╡рд╛рд▓рд╛ рдордЦреА', - u'рд░реБрдВрдбреА рдЦрд╛рдирд╛', - u'рд░реБрдВрдбреА рдХреА рдмрдЪреА', -u'рдорджрд░рдЪреЛрдбрд╝', - u'рднреЛрд╕рджреАрдХреЗ', - u'рднреЗрдВ рдЫреЛрдбрд╝', - u'рдмреЗрдЯреА рдЫреЛрдбрд╝', - u'рднрдврд╝рд╛рд╡рд╛', - u'рдЫреЛрдбрд╝реВ', - u'рдЪреВрддрд┐рдпрд╛', - u'рдЧрд╛рдВрдж', - u'рдЧрд╛рдиреНрдбреВ', - u'рдЧрдврд╝рд╛, рдмрдХрд▓рдВрдб', - u'рд▓реЙрдбрд╛, рд▓рдВрдб', - u'рд╣рд┐рдпрд┐рд░рд╛', - u'рдХреБрдЯреНрдЯрд┐рдпрд╛', - u'рдкрд╛рдж', - u'рд░рдВрдбреА', - u'рд╕рд╛рд▓рд╛ рдХреБрддреНрддрд╛', - u'рд╕рд╛рд▓реА рдХреБрдЯреНрдЯреА', - u'рдЯрдЯреНрдЯреА', - u'рдХрдореАрдирд╛', - u'рдЫреВрдЯ рдХреЗ рдкрд╕реАрдиреЗ рдореЗрдВ рддрд▓реЗ рд╣реБрдП рднрдЬрд┐рдП', - u'рдЫреВрдЯ рдХреЗ рдврдХреНрдХрди', - u'рдЫреВрдЯ рдХреЗ рдЧреБрд▓рд╛рдо', - u'рдЪреВрддрд┐рдпрд╛ рдХрд╛ рднреЗрдЬрд╛ рдШрд╛рд╕ рдЦрд╛рдиреЗ рдЧрдпрд╛ рд╣реИ', - u'рдЫреВрдЯ рдорд╛рд░рдиреА рдХрд╛', - u'рдЫреВрдЯ рдХрд╛ рдмрд╛рд▓', - u'рдЫрд┐рдкрдХрд▓реА рдХреЗ рдЭрд╛рдЯ рдХреЗ рдмрд╛рд▓', - u'рдЫрд┐рдкрдХрд▓реА рдХреЗ рдЭрд╛рдЯ рдХреЗ рдкрд╕реАрдиреЗ', - u'рдЫрд┐рдкрдХрд▓реА рдХреЗ рдЧрд╛рдВрдж рдХреЗ рдкрд╕реАрдиреЗ', - u'рдЫрд┐рдкрдХрд▓реА рдХреЗ рдЫреВрдЯ рдХреЗ рдкрд╕реАрдиреЗ', - u'рдЫрд┐рдкрдХрд▓реА рдХреА рднреАрдЧреА рдЫреВрдЯ', - u'рдЫрд┐рдирд╛рд▓ рдХреЗ рдЧрджреНрджреЗ рдХреЗ рдирд┐рдкрд▓ рдХреЗ рдмрд╛рд▓ рдХреЗ рдЬреВрди', - u'рдЪреБрд▓реНрд▓реВ рднрд░ рдореВрда рдореЗрдВ рдбреВрдм рдорд╛рд░', - u'рдХреБрдВрдЯрдорд╛рдорд╛', - u'рдЪреНрдЫреЗрдж', - u'рдЕрдкрдиреА рдЧрд╛рдВрдж рдореЗрдВ рдореБрддрд┐ рдбрд╛рд▓', - u'рдЕрдкрдиреА рд▓рдВрдб рдЪреВрд╕', - u'рдЕрдкрдиреА рдорд╛ рдХреЛ рдЬрд╛ рдЪреВрд╕', - u'рднреЗрдВ рдХреЗ рд▓реЙрдб', - u'рднреЗрдВ рдХреЗ рдЯрдХреНрдХреЗ: рдЧреЛ рдЖрдВрдб рд╕рдХ рдпреБрд╡рд░ рд╕рд┐рд╕реНрдЯрд░тАЩрд╕ рдмреЙрд▓реН', - u'рдЕрдмрд▓рд╛ рдирд╛рд░реА рддреЗрд░рд╛ рдмреБрдмрд▓реЗ рднрд╛рд░реА', - u'рднреЛрдВрд╕рд░реА', - u'рднрджреНрд╡реЗ рдХрд╛ рдЕрд╡рд▓рдЯ', - u'рднреИрдВрд╕ рдХреА рдФрд▓рд╛рдж', - u'рдмреБрджреНрдзрд╛ рдЦреВрд╕рдЯ', - u'рдмреЛрд▓ рддреЗрд░реА рдЧрдВрдж рдХреИрд╕реЗ рдорд╛рд░реВ', - u'рдмрд░ рдХреА рдЪрдЯрдиреА', - u'рдЪреБрдирдиреА', - u'рдЫрд┐рдирд╛рд▓', - u'рдЪреБрджрд╛рдИ рдЦрд╛рдирд╛', - u'рдЪреБрдбрд╝рд╛рди рдЫреБрдбрд╝рд╛', - u'рдЫреВрдЯ рдХрд╛ рдкреБрдЬрд╛рд░реА', - u'рдЫреВрдЯ рдХрд╛ рднреВрдд', - u'рдЧрд╛рдВрдж рдХрд╛ рдорд╛рдЦрди', - u'рдЧрд╛рдВрдж рдореИрдВ рд▓рд╛рд╖рд╕рди', - u'рдЧрд╛рдВрдж'] + u'рдмрд╛рд╣реЗрдВ рдЫреЛрдбрд╝', + u'рдмрд╛рд╣реЗрдВ рдХреЗ рд▓реЙрдб', + u'рдмрд╛рд╣реЗрдВ рдХреЗ рдЯрдХреНрдХреЗ', + u'рдмрдХрд▓рдВрдб', + u'рдмреЗрдЯреА рдЫреЛрдбрд╝', + u'рднрдврд╝рд╛рд╡рд╛', + u'рднрджреНрд╡реЗ рдХрд╛ рдЕрд╡рд▓рдЯ', + u'рднрд╛рдИ рдЫреЛрдбрд╝', + u'рднрд╛рдВрдб рдЦрд╝реМ', + u'рднреЛрдВрд╕рд░реА рд╡рд╛рд▓рд╛', + u'рднреВрдЯреНрдиреА рдХрд╛', + u'рднреЛрд╕рдж рдЫреЛрдбрд╝', + u'рднреЛрд╕рджреАрдХреЗ', + u'рдмрд░ рдХреА рдЪрдЯрдиреА', + u'рдЪреНрдЫреЗрдж', + u'рдЫреНрд╣реЛрд▓рд╛ рдлреБрджрдХрдирд╛', + u'рдЫрд┐рдирд╛рд▓', + u'рдЫреЛрдбрд╝реЗрд▓рд╛', + u'рдЫреЛрджреНрд░рд╛', + u'рдЫреЛрдбрд╝реВ рднрдЧрдд', + u'рдЫреЛрдбрд╝реВ', + u'рдЪреВрдЫреАреА', + u'рдЫреВрдЯ рдХрд╛ рдмрд╛рд▓', + u'рдЫреВрдЯ рдХреЗ рднреВрдд', + u'рдЫреВрдЯ рдорд╛рд░рдиреА рдХрд╛', + u'рдЪреВрддрд┐рдпрд╛', + u'рдЪреБрджрд╛рдИ рдЦрд╛рдирд╛', + u'рдЪреБрдбрд╝рд╛рди рдЫреБрдбрд╝рд╛', + u'рдЫреВрдЯ рдХрд╛ рдкреБрдЬрд╛рд░реА', + u'рдЫреВрдЯ рдХреЗ рдврдХреНрдХрди', + u'рдЫреВрдЯ рдХреЗ рдЧреБрд▓рд╛рдо', + u'рдЫреВрдЯ рдорд╛рд░реА рдХреЗ', + u'рдЫреВрдЯ рдорд╛рд░реАрдХреЗ', + u'рдЫреВрдЯ', + u'рдЪреВрдЯрд╛рди', + u'рдХреБрдВрдЯрдорд╛рдорд╛', + u'рдЧрд╛рдВрдж рдХрд╛ рдорд╛рдЦрди', + u'рдЧрд╛рдВрдж рдореИрдВ рдбрдВрдбрд╛', + u'рдЧрд╛рдВрдж рдореИрдВ рдХреАрд░рд╛', + u'рдЧрд╛рдВрдж рдореИрдВ рд▓рд╛**рдЖрди', + u'рдЧрд╛рдВрдж рдорд░реМ', + u'рдЧрд╛рдВрдж', + u'рдЧрд╛рдВрдбреНрдлрд╛рдЯ', + u'рдЧрд╛рдВрджрдорд╛рд╕реНрддреА', + u'рдЧрд╛рдиреНрдбреВ', + u'рд╣рд░рд╛рдо рдЬрд╝рд╛рджрд╛', + u'рд╣рд░рд╛рдореА', + u'рд╣рд┐рдЬрдбрд╝реЗ', + u'рдЭрд╛рдБрдд рдХреЗ рдкрд┐рд╕реНрд╕реВ', + u'рдЭрд▓реНрд▓рд╛', + u'рдЭрд╛рдВрдЯ рдЪрд╛рддреБ', + u'рдЭрд╛рдВрдЯ рдХреЗ рдмрд╛рд▓', + u'рдХрдбрд╝рдХ рдорд╛рд▓', + u'рдХрдореАрдирд╛', + u'рдХреБрддреНрддреЗ рдХрд╛ рдЕрд╡рд▓рдЯ', + u'рдХреБрддреНрддреЗ рдХрд╛ рдмреАрдЬ', + u'рдХреБрдЯреНрдЯрд┐рдпрд╛', + u'рд▓реЙрдбрд╛, рд▓рдВрдб', + u'рд▓рд╡рдВрдбрд░', + u'рд│рд╡реНрдб', + u'рд▓рд╡рджреЗ рдХреЗ рдмрд╛рд▓', + u'рд▓рдВрдб', + u'рд▓рдВрдб рдЪреВрд╕реВ', + u'рдорд╛ рдЪреВрдбрд╝реА', + u'рдлреБрджрдзрд┐', + u'рд░рд╛рдВрдбреА рдмрд╛рдЬреЗрд░', + u'рд░реБрдВрдбреА рдХрд╛ рдмрдЪрд╛', + u'рд░реБрдВрдбреА рдХреЗ рдЯрдЯреНрдЯреА рдкреЗ рдмрд┐рдпрддрдиреЗ рд╡рд╛рд▓рд╛ рдордЦреА', + u'рд░реБрдВрдбреА рдЦрд╛рдирд╛', + u'рд░реБрдВрдбреА рдХреА рдмрдЪреА', + u'рдорджрд░рдЪреЛрдбрд╝', + u'рднреЛрд╕рджреАрдХреЗ', + u'рднреЗрдВ рдЫреЛрдбрд╝', + u'рдмреЗрдЯреА рдЫреЛрдбрд╝', + u'рднрдврд╝рд╛рд╡рд╛', + u'рдЫреЛрдбрд╝реВ', + u'рдЪреВрддрд┐рдпрд╛', + u'рдЧрд╛рдВрдж', + u'рдЧрд╛рдиреНрдбреВ', + u'рдЧрдврд╝рд╛, рдмрдХрд▓рдВрдб', + u'рд▓реЙрдбрд╛, рд▓рдВрдб', + u'рд╣рд┐рдпрд┐рд░рд╛', + u'рдХреБрдЯреНрдЯрд┐рдпрд╛', + u'рдкрд╛рдж', + u'рд░рдВрдбреА', + u'рд╕рд╛рд▓рд╛ рдХреБрддреНрддрд╛', + u'рд╕рд╛рд▓реА рдХреБрдЯреНрдЯреА', + u'рдЯрдЯреНрдЯреА', + u'рдХрдореАрдирд╛', + u'рдЫреВрдЯ рдХреЗ рдкрд╕реАрдиреЗ рдореЗрдВ рддрд▓реЗ рд╣реБрдП рднрдЬрд┐рдП', + u'рдЫреВрдЯ рдХреЗ рдврдХреНрдХрди', + u'рдЫреВрдЯ рдХреЗ рдЧреБрд▓рд╛рдо', + u'рдЪреВрддрд┐рдпрд╛ рдХрд╛ рднреЗрдЬрд╛ рдШрд╛рд╕ рдЦрд╛рдиреЗ рдЧрдпрд╛ рд╣реИ', + u'рдЫреВрдЯ рдорд╛рд░рдиреА рдХрд╛', + u'рдЫреВрдЯ рдХрд╛ рдмрд╛рд▓', + u'рдЫрд┐рдкрдХрд▓реА рдХреЗ рдЭрд╛рдЯ рдХреЗ рдмрд╛рд▓', + u'рдЫрд┐рдкрдХрд▓реА рдХреЗ рдЭрд╛рдЯ рдХреЗ рдкрд╕реАрдиреЗ', + u'рдЫрд┐рдкрдХрд▓реА рдХреЗ рдЧрд╛рдВрдж рдХреЗ рдкрд╕реАрдиреЗ', + u'рдЫрд┐рдкрдХрд▓реА рдХреЗ рдЫреВрдЯ рдХреЗ рдкрд╕реАрдиреЗ', + u'рдЫрд┐рдкрдХрд▓реА рдХреА рднреАрдЧреА рдЫреВрдЯ', + u'рдЫрд┐рдирд╛рд▓ рдХреЗ рдЧрджреНрджреЗ рдХреЗ рдирд┐рдкрд▓ рдХреЗ рдмрд╛рд▓ рдХреЗ рдЬреВрди', + u'рдЪреБрд▓реНрд▓реВ рднрд░ рдореВрда рдореЗрдВ рдбреВрдм рдорд╛рд░', + u'рдХреБрдВрдЯрдорд╛рдорд╛', + u'рдЪреНрдЫреЗрдж', + u'рдЕрдкрдиреА рдЧрд╛рдВрдж рдореЗрдВ рдореБрддрд┐ рдбрд╛рд▓', + u'рдЕрдкрдиреА рд▓рдВрдб рдЪреВрд╕', + u'рдЕрдкрдиреА рдорд╛ рдХреЛ рдЬрд╛ рдЪреВрд╕', + u'рднреЗрдВ рдХреЗ рд▓реЙрдб', + u'рднреЗрдВ рдХреЗ рдЯрдХреНрдХреЗ: рдЧреЛ рдЖрдВрдб рд╕рдХ рдпреБрд╡рд░ рд╕рд┐рд╕реНрдЯрд░тАЩрд╕ рдмреЙрд▓реН', + u'рдЕрдмрд▓рд╛ рдирд╛рд░реА рддреЗрд░рд╛ рдмреБрдмрд▓реЗ рднрд╛рд░реА', + u'рднреЛрдВрд╕рд░реА', + u'рднрджреНрд╡реЗ рдХрд╛ рдЕрд╡рд▓рдЯ', + u'рднреИрдВрд╕ рдХреА рдФрд▓рд╛рдж', + u'рдмреБрджреНрдзрд╛ рдЦреВрд╕рдЯ', + u'рдмреЛрд▓ рддреЗрд░реА рдЧрдВрдж рдХреИрд╕реЗ рдорд╛рд░реВ', + u'рдмрд░ рдХреА рдЪрдЯрдиреА', + u'рдЪреБрдирдиреА', + u'рдЫрд┐рдирд╛рд▓', + u'рдЪреБрджрд╛рдИ рдЦрд╛рдирд╛', + u'рдЪреБрдбрд╝рд╛рди рдЫреБрдбрд╝рд╛', + u'рдЫреВрдЯ рдХрд╛ рдкреБрдЬрд╛рд░реА', + u'рдЫреВрдЯ рдХрд╛ рднреВрдд', + u'рдЧрд╛рдВрдж рдХрд╛ рдорд╛рдЦрди', + u'рдЧрд╛рдВрдж рдореИрдВ рд▓рд╛рд╖рд╕рди', + u'рдЧрд╛рдВрдж'] HINDI_STOPWORDS = [u'рдЕрдд', - u'рдЕрдкрдирд╛', - u'рдЕрдкрдиреА', - u'рдЕрдкрдиреЗ', - u'рдЕрднреА', - u'рдЕрдВрджрд░', - u'рдЖрджрд┐', - u'рдЖрдк', - u'рдЗрддреНрдпрд╛рджрд┐', - u'рдЗрди ', - u'рдЗрдирдХрд╛', - u'рдЗрдиреНрд╣реАрдВ', - u'рдЗрдиреНрд╣реЗрдВ', - u'рдЗрдиреНрд╣реЛрдВ', - u'рдЗрд╕', - u'рдЗрд╕рдХрд╛', - u'рдЗрд╕рдХреА', - u'рдЗрд╕рдХреЗ', - u'рдЗрд╕рдореЗрдВ', - u'рдЗрд╕реА', - u'рдЗрд╕реЗ', - u'рдЙрди', - u'рдЙрдирдХрд╛', - u'рдЙрдирдХреА', - u'рдЙрдирдХреЗ', - u'рдЙрдирдХреЛ', - u'рдЙрдиреНрд╣реАрдВ', - u'рдЙрдиреНрд╣реЗрдВ', - u'рдЙрдиреНрд╣реЛрдВ', - u'рдЙрд╕', - u'рдЙрд╕рдХреЗ', - u'рдЙрд╕реА', - u'рдЙрд╕реЗ', - u'рдПрдХ', - u'рдПрд╡рдВ', - u'рдПрд╕', - u'рдРрд╕реЗ', - u'рдФрд░', - u'рдХрдИ', - u'рдХрд░', - u'рдХрд░рддрд╛', - u'рдХрд░рддреЗ', - u'рдХрд░рдирд╛', -u'рдХрд░рдиреЗ', - u'рдХрд░реЗрдВ', - u'рдХрд╣рддреЗ', - u'рдХрд╣рд╛', - u'рдХрд╛', - u'рдХрд╛реЮреА', - u'рдХрд┐', - u'рдХрд┐рддрдирд╛', - u'рдХрд┐рдиреНрд╣реЗрдВ', - u'рдХрд┐рдиреНрд╣реЛрдВ', - u'рдХрд┐рдпрд╛', - u'рдХрд┐рд░', - u'рдХрд┐рд╕', - u'рдХрд┐рд╕реА', - u'рдХрд┐рд╕реЗ', - u'рдХреА', - u'рдХреБрдЫ', - u'рдХреБрд▓', - u'рдХреЗ', - u'рдХреЛ', - u'рдХреЛрдИ', - u'рдХреМрди', - u'рдХреМрдирд╕рд╛', - u'рдЧрдпрд╛', - u'рдШрд░', - u'рдЬрдм', - u'рдЬрд╣рд╛рдБ', - u'рдЬрд╛', - u'рдЬрд┐рддрдирд╛', - u'рдЬрд┐рди', - u'рдЬрд┐рдиреНрд╣реЗрдВ', - u'рдЬрд┐рдиреНрд╣реЛрдВ', - u'рдЬрд┐рд╕', - u'рдЬрд┐рд╕реЗ', - u'рдЬреАрдзрд░', - u'рдЬреИрд╕рд╛', - u'рдЬреИрд╕реЗ', - u'рдЬреЛ', - u'рддрдХ', - u'рддрдм', - u'рддрд░рд╣', - u'рддрд┐рди', - u'рддрд┐рдиреНрд╣реЗрдВ', - u'рддрд┐рдиреНрд╣реЛрдВ', - u'рддрд┐рд╕', - u'рддрд┐рд╕реЗ', - u'рддреЛ', - u'рдерд╛', - u'рдереА', - u'рдереЗ', - u'рджрдмрд╛рд░рд╛', - u'рджрд┐рдпрд╛', - u'рджреБрд╕рд░рд╛', - u'рджреВрд╕рд░реЗ', - u'рджреЛ', - u'рджреНрд╡рд╛рд░рд╛', - u'рди', - u'рдирдХреЗ', - u'рдирд╣реАрдВ', - u'рдирд╛', - u'рдирд┐рд╣рд╛рдпрдд', - u'рдиреАрдЪреЗ', - u'рдиреЗ', - u'рдкрд░', - u'рдкрд╣рд▓реЗ', - u'рдкреВрд░рд╛', - u'рдкреЗ', - u'рдлрд┐рд░', - u'рдмрдиреА', - u'рдмрд╣реА', - u'рдмрд╣реБрдд', - u'рдмрд╛рдж', - u'рдмрд╛рд▓рд╛', - u'рдмрд┐рд▓рдХреБрд▓', - u'рднреА', - u'рднреАрддрд░', - u'рдордЧрд░', - u'рдорд╛рдиреЛ', - u'рдореЗ', - u'рдореЗрдВ', - u'рдпрджрд┐', - u'рдпрд╣', - u'рдпрд╣рд╛рдБ', - u'рдпрд╣реА', - u'рдпрд╛', - u'рдпрд┐рд╣', - u'рдпреЗ', - u'рд░рдЦреЗрдВ', - u'рд░рд╣рд╛', - u'рд░рд╣реЗ', - u'рд▒реНрд╡рд╛рд╕рд╛', - u'рд▓рд┐рдП', - u'рд▓рд┐рдпреЗ', - u'рд▓реЗрдХрд┐рди', - u'рд╡', - u'рд╡реЪреИрд░рд╣', - u'рд╡рд░реНрдЧ', - u'рд╡рд╣', - u'рд╡рд╣рд╛рдБ', - u'рд╡рд╣реАрдВ', - u'рд╡рд╛рд▓реЗ', - u'рд╡реБрд╣', - u'рд╡реЗ', - u'рд╕рдХрддрд╛', - u'рд╕рдХрддреЗ', - u'рд╕рдмрд╕реЗ', - u'рд╕рднреА', - u'рд╕рд╛рде', - u'рд╕рд╛рдмреБрдд', - u'рд╕рд╛рдн', - u'рд╕рд╛рд░рд╛', - u'рд╕реЗ', - u'рд╕реЛ', - u'рд╕рдВрдЧ', - u'рд╣реА', - u'рд╣реБрдЖ', - u'рд╣реБрдИ', - u'рд╣реБрдП', - u'рд╣реИ', - u'рд╣реИрдВ', - u'рд╣реЛ', - u'рд╣реЛрддрд╛', - u'рд╣реЛрддреА', - u'рд╣реЛрддреЗ', - u'рд╣реЛрдирд╛', - u'рд╣реЛрди', -u'рд╣реВрдБ'] + u'рдЕрдкрдирд╛', + u'рдЕрдкрдиреА', + u'рдЕрдкрдиреЗ', + u'рдЕрднреА', + u'рдЕрдВрджрд░', + u'рдЖрджрд┐', + u'рдЖрдк', + u'рдЗрддреНрдпрд╛рджрд┐', + u'рдЗрди ', + u'рдЗрдирдХрд╛', + u'рдЗрдиреНрд╣реАрдВ', + u'рдЗрдиреНрд╣реЗрдВ', + u'рдЗрдиреНрд╣реЛрдВ', + u'рдЗрд╕', + u'рдЗрд╕рдХрд╛', + u'рдЗрд╕рдХреА', + u'рдЗрд╕рдХреЗ', + u'рдЗрд╕рдореЗрдВ', + u'рдЗрд╕реА', + u'рдЗрд╕реЗ', + u'рдЙрди', + u'рдЙрдирдХрд╛', + u'рдЙрдирдХреА', + u'рдЙрдирдХреЗ', + u'рдЙрдирдХреЛ', + u'рдЙрдиреНрд╣реАрдВ', + u'рдЙрдиреНрд╣реЗрдВ', + u'рдЙрдиреНрд╣реЛрдВ', + u'рдЙрд╕', + u'рдЙрд╕рдХреЗ', + u'рдЙрд╕реА', + u'рдЙрд╕реЗ', + u'рдПрдХ', + u'рдПрд╡рдВ', + u'рдПрд╕', + u'рдРрд╕реЗ', + u'рдФрд░', + u'рдХрдИ', + u'рдХрд░', + u'рдХрд░рддрд╛', + u'рдХрд░рддреЗ', + u'рдХрд░рдирд╛', + u'рдХрд░рдиреЗ', + u'рдХрд░реЗрдВ', + u'рдХрд╣рддреЗ', + u'рдХрд╣рд╛', + u'рдХрд╛', + u'рдХрд╛реЮреА', + u'рдХрд┐', + u'рдХрд┐рддрдирд╛', + u'рдХрд┐рдиреНрд╣реЗрдВ', + u'рдХрд┐рдиреНрд╣реЛрдВ', + u'рдХрд┐рдпрд╛', + u'рдХрд┐рд░', + u'рдХрд┐рд╕', + u'рдХрд┐рд╕реА', + u'рдХрд┐рд╕реЗ', + u'рдХреА', + u'рдХреБрдЫ', + u'рдХреБрд▓', + u'рдХреЗ', + u'рдХреЛ', + u'рдХреЛрдИ', + u'рдХреМрди', + u'рдХреМрдирд╕рд╛', + u'рдЧрдпрд╛', + u'рдШрд░', + u'рдЬрдм', + u'рдЬрд╣рд╛рдБ', + u'рдЬрд╛', + u'рдЬрд┐рддрдирд╛', + u'рдЬрд┐рди', + u'рдЬрд┐рдиреНрд╣реЗрдВ', + u'рдЬрд┐рдиреНрд╣реЛрдВ', + u'рдЬрд┐рд╕', + u'рдЬрд┐рд╕реЗ', + u'рдЬреАрдзрд░', + u'рдЬреИрд╕рд╛', + u'рдЬреИрд╕реЗ', + u'рдЬреЛ', + u'рддрдХ', + u'рддрдм', + u'рддрд░рд╣', + u'рддрд┐рди', + u'рддрд┐рдиреНрд╣реЗрдВ', + u'рддрд┐рдиреНрд╣реЛрдВ', + u'рддрд┐рд╕', + u'рддрд┐рд╕реЗ', + u'рддреЛ', + u'рдерд╛', + u'рдереА', + u'рдереЗ', + u'рджрдмрд╛рд░рд╛', + u'рджрд┐рдпрд╛', + u'рджреБрд╕рд░рд╛', + u'рджреВрд╕рд░реЗ', + u'рджреЛ', + u'рджреНрд╡рд╛рд░рд╛', + u'рди', + u'рдирдХреЗ', + u'рдирд╣реАрдВ', + u'рдирд╛', + u'рдирд┐рд╣рд╛рдпрдд', + u'рдиреАрдЪреЗ', + u'рдиреЗ', + u'рдкрд░', + u'рдкрд╣рд▓реЗ', + u'рдкреВрд░рд╛', + u'рдкреЗ', + u'рдлрд┐рд░', + u'рдмрдиреА', + u'рдмрд╣реА', + u'рдмрд╣реБрдд', + u'рдмрд╛рдж', + u'рдмрд╛рд▓рд╛', + u'рдмрд┐рд▓рдХреБрд▓', + u'рднреА', + u'рднреАрддрд░', + u'рдордЧрд░', + u'рдорд╛рдиреЛ', + u'рдореЗ', + u'рдореЗрдВ', + u'рдпрджрд┐', + u'рдпрд╣', + u'рдпрд╣рд╛рдБ', + u'рдпрд╣реА', + u'рдпрд╛', + u'рдпрд┐рд╣', + u'рдпреЗ', + u'рд░рдЦреЗрдВ', + u'рд░рд╣рд╛', + u'рд░рд╣реЗ', + u'рд▒реНрд╡рд╛рд╕рд╛', + u'рд▓рд┐рдП', + u'рд▓рд┐рдпреЗ', + u'рд▓реЗрдХрд┐рди', + u'рд╡', + u'рд╡реЪреИрд░рд╣', + u'рд╡рд░реНрдЧ', + u'рд╡рд╣', + u'рд╡рд╣рд╛рдБ', + u'рд╡рд╣реАрдВ', + u'рд╡рд╛рд▓реЗ', + u'рд╡реБрд╣', + u'рд╡реЗ', + u'рд╕рдХрддрд╛', + u'рд╕рдХрддреЗ', + u'рд╕рдмрд╕реЗ', + u'рд╕рднреА', + u'рд╕рд╛рде', + u'рд╕рд╛рдмреБрдд', + u'рд╕рд╛рдн', + u'рд╕рд╛рд░рд╛', + u'рд╕реЗ', + u'рд╕реЛ', + u'рд╕рдВрдЧ', + u'рд╣реА', + u'рд╣реБрдЖ', + u'рд╣реБрдИ', + u'рд╣реБрдП', + u'рд╣реИ', + u'рд╣реИрдВ', + u'рд╣реЛ', + u'рд╣реЛрддрд╛', + u'рд╣реЛрддреА', + u'рд╣реЛрддреЗ', + u'рд╣реЛрдирд╛', + u'рд╣реЛрди', + u'рд╣реВрдБ'] HINDI_QUESTIONWORDS = [u'рдХреНрдпрд╛', u'рдХрдм', u'рдХрд╣рд╛', u'рдХреНрдпреЛрдВ', u'рдХреМрди', u'рдХреМрди', u'рдЬрд┐рд╕реЗ', u'рдЬрд┐рд╕рдХрд╛', u'рдХреИрд╕реЗ', u'рдХрд┐рддрдиреЗ'] # Variants in "name" to check for previous context flag NAME_VARIATIONS = ['name', u'рдирд╛рдо'] + +# Common hindi words occuring in context to a name +COMMON_HINDI_WORDS_OCCURING_WITH_NAME = {u"рдореБрдЭреЗ", + u"рд╣рдореЗрдВ", + u"рдореБрдЭрдХреЛ", + u"рд╣рдордХреЛ", + u"рд╣рдореЗ", + u"рд▓реЛрдЧ", + u"рдирд╛рдо", + u"рд╕реЗ", + u"рдХрд╣рддреЗ", + u"рдмреБрд▓рд╛рддреЗ", + u"рдмреБрд▓рд╛рдУ", + u"рдирд╛рдо", + u"рдореИрдВ", + u"рд╣рдо", + u"рдореИ", + u"рдореБрдЭреЗ", + u"рд╣рдореЗрдВ", + u"рдореБрдЭрдХреЛ", + u"рд╣рдордХреЛ", + u"рд╣рдореЗ", + u"рдХрд╣рддреЗ", + u"рдмреБрд▓рд╛рддреЗ", + u"рдмреБрд▓рд╛рдУ", + u"рдореБрдЭреЗ", + u"рдореИрдВ", + u"рдореИ)", + u"рдХрд╣рддреЗ", + u"рдмреБрд▓рд╛рддреЗ", + u"рдмреБрд▓рд╛рдУ", + u"рд╣рдорд╛рд░рд╛", + u"рдореЗрд░рд╛"} diff --git a/ner_v1/detectors/textual/name/name_detection.py b/ner_v1/detectors/textual/name/name_detection.py index e94c439a0..1d9317c05 100644 --- a/ner_v1/detectors/textual/name/name_detection.py +++ b/ner_v1/detectors/textual/name/name_detection.py @@ -1,13 +1,17 @@ # coding=utf-8 import re -from lib.nlp.pos import * -from ner_v1.constant import FIRST_NAME, MIDDLE_NAME, LAST_NAME -from ner_v1.detectors.textual.text.text_detection import TextDetector -from ner_v1.constant import EMOJI_RANGES from language_utilities.constant import ENGLISH_LANG, HINDI_LANG -from ner_v1.detectors.textual.name.hindi_const import \ - HINDI_BADWORDS, HINDI_QUESTIONWORDS, HINDI_STOPWORDS, NAME_VARIATIONS from lib.nlp.const import nltk_tokenizer +from lib.nlp.pos import POS +from ner_v1.constant import EMOJI_RANGES, FIRST_NAME, MIDDLE_NAME, LAST_NAME +from ner_v1.detectors.textual.name.hindi_const import (HINDI_BADWORDS, HINDI_QUESTIONWORDS, + HINDI_STOPWORDS, NAME_VARIATIONS, + COMMON_HINDI_WORDS_OCCURING_WITH_NAME) +from ner_v1.detectors.textual.text.text_detection import TextDetector +import string + +# TODO: Refactor this module for readability and useability. Remove any hacks +# TODO: Make this module python 3 compatible class NameDetector(object): """ @@ -17,7 +21,8 @@ class NameDetector(object): Attributes: text: string to extract entities from - entity_name: string by which the detected person_name entities would be replaced with on calling detect_entity() + entity_name: string by which the detected person_name entities would be replaced with + on calling detect_entity() tagged_text: string with city entities replaced with tag defined by entity_name processed_text: string with detected time entities removed text_detection_object: the object which is used to call the TextDetector @@ -56,9 +61,11 @@ def get_format_name(name_list): ['yash', 'doshi'] Returns: - ({first_name: "yash", middle_name: None, last_name: "modi"}, "yash modi") + ( + [{first_name: "yash", middle_name: None, last_name: "doshi"}], + ["yash modi"] + ) """ - original_text = " ".join(name_list) first_name = name_list[0] @@ -73,7 +80,7 @@ def get_format_name(name_list): return [entity_value], [original_text] - def text_detection_name(self): + def text_detection_name(self, text=None): """ Makes a call to TextDetection and return the person_name detected from the elastic search. Returns: @@ -83,8 +90,9 @@ def text_detection_name(self): ([u'dosh', u'yash'], ['doshi', 'yash']) """ - - return self.text_detection_object.detect_entity(text=self.text) + if text is None: + text = self.text + return self.text_detection_object.detect_entity(text=text) def get_name_using_pos_tagger(self, text): """ @@ -164,7 +172,7 @@ def detect_entity(self, text, bot_message=None): return entity_value, original_text - def detect_english_name(self): + def detect_english_name(self, text=None): """ This method is used to detect English names from the provided text Returns: @@ -178,13 +186,13 @@ def detect_english_name(self): detect_entity_english() >>[{first_name: "yash", middle_name: None, last_name: "modi"}], [ yash modi"] """ - - text_detection_result = self.text_detection_name() - replaced_text = self.replace_detected_text(text_detection_result, text=self.text) + if text is None: + text = self.text + text_detection_result = self.text_detection_name(text) + replaced_text = self.replace_detected_text(text_detection_result, text=text) entity_value, original_text = self.detect_person_name_entity(replaced_text) - if not entity_value: - entity_value, original_text = self.get_name_using_pos_tagger(self.text) + entity_value, original_text = self.get_name_using_pos_tagger(text) return entity_value, original_text @@ -207,6 +215,7 @@ def detect_hindi_name(self): return [], [] text = self.remove_emojis(text=self.text) + text_before_hindi_regex_operations = text regex = re.compile(ur'[^\u0900-\u097F\s]+', re.U) text = regex.sub(string=text, repl='') @@ -216,10 +225,17 @@ def detect_hindi_name(self): if not entity_value: entity_value, original_text = self.get_hindi_names_without_regex(text=text) + # Further check for name, if it might have been written in latin script. + if not entity_value: + english_present_regex = re.compile(ur'[a-zA-Z\s]+', re.U) + if english_present_regex.search(text_before_hindi_regex_operations): + remove_everything_except_english = re.compile(ur'[^a-zA-Z\s]+', re.U) + text_only_english = remove_everything_except_english.sub( + string=text_before_hindi_regex_operations, repl='') + entity_value, original_text = self.detect_english_name(text=text_only_english.strip()) return entity_value, original_text - def replace_detected_text(self, text_detection_result, text): """ Replaces the detected name from text_detection_result by __ @@ -289,12 +305,14 @@ def context_check_botmessage(self, botmessage): Checks if previous botmessage conatins name as a keyword or not Args: botmessage: it consists of the previous botmessage - Example: what is your name ? + + Example: what is your name ? + Returns: True """ - regex_pattern = re.compile(r'[\|\,+\:\?\!\"\(\)!\'\.\%\[\]]+') + regex_pattern = re.compile(r'[{}]+'.format(re.escape(string.punctuation))) botmessage = regex_pattern.sub(r'', botmessage) botmessage = " " + botmessage.lower().strip() + " " @@ -335,30 +353,29 @@ def get_hindi_names_without_regex(self, text): """ This method is used to get detect hindi names without any regex pattern (This method is called only if detection from regex patterns fails) + This method removes common hindi words ocurring in context of name and hindi stop words + COMMON_HINDI_WORDS_OCCURING_WITH_NAME set of hindi words ocurring in context of name Args: text (str): the text from which hindi text has to be detected Returns: person_name (tuple): two dimensional tuple 1. entity_value (list): representing the entity values of names 2. original_text (list): representing the original text detected - - Example: text = u'рдкреНрд░рддрд┐рдХ рд╢реНрд░реАрджрддреНрдд рдЬрдпрд░рд╛рдУ' get_hindi_names_without_regex(text=text) - >> [{first_name: u"рдкреНрд░рддрд┐рдХ", middle_name: u"рд╢реНрд░реАрджрддреНрдд", last_name: u"рдЬрдпрд░рд╛рдУ"}], [ u'рдкреНрд░рддрд┐рдХ рд╢реНрд░реАрджрддреНрдд рдЬрдпрд░рд╛рдУ'] - """ - text = self.replace_stopwords_hindi(text) + text = " ".join([word for word in text.split(" ") if word not in COMMON_HINDI_WORDS_OCCURING_WITH_NAME]) + if not text.strip(): + return [], [] original_text_list = text.strip().split() if len(original_text_list) > 4: original_text_list = [] replaced_text = self.replace_detected_text((original_text_list, original_text_list), text=text) return self.detect_person_name_entity(replaced_text=replaced_text) - def get_hindi_text_from_regex(self, text): """ This method is used to detect hindi names using regexes from the given text diff --git a/ner_v1/detectors/textual/name/tests/test_cases_person_name.csv b/ner_v1/detectors/textual/name/tests/test_cases_person_name.csv index bc5a5a182..94eaa35ee 100644 --- a/ner_v1/detectors/textual/name/tests/test_cases_person_name.csv +++ b/ner_v1/detectors/textual/name/tests/test_cases_person_name.csv @@ -10,4 +10,5 @@ hi,рдореЗрд░рд╛ рдирд╛рдо рдкреНрд░рддрд┐рдХ рд╢реНрд░реАрджрддреНрдд рдЬрдпрд░ hi,рдирд╛рдо рдкреНрд░рддрд┐рдХ рд╢реНрд░реАрджрддреНрдд рдЬрдпрд░рд╛рдУ рд╣реИ,рдкреНрд░рддрд┐рдХ,рд╢реНрд░реАрджрддреНрдд,рдЬрдпрд░рд╛рдУ,рдкреНрд░рддрд┐рдХ рд╢реНрд░реАрджрддреНрдд рдЬрдпрд░рд╛рдУ hi,рдирд╛рдо рдкреНрд░рддрд┐рдХ рдЬрдпрд░рд╛рдУ рд╣реИ,рдкреНрд░рддрд┐рдХ,None,рдЬрдпрд░рд╛рдУ,рдкреНрд░рддрд┐рдХ рдЬрдпрд░рд╛рдУ hi,рдореБрдЭреЗ рдкреНрд░рддрд┐рдХ рдЬрдпрд░рд╛рдУ рдмреБрд▓рд╛рддреЗ рд╣реИ,рдкреНрд░рддрд┐рдХ,None,рдЬрдпрд░рд╛рдУ,рдкреНрд░рддрд┐рдХ рдЬрдпрд░рд╛рдУ -hi,рдкреНрд░рддрд┐рдХ рдЬрдпрд░рд╛рдУ,рдкреНрд░рддрд┐рдХ,None,рдЬрдпрд░рд╛рдУ,рдкреНрд░рддрд┐рдХ рдЬрдпрд░рд╛рдУ \ No newline at end of file +hi,рдкреНрд░рддрд┐рдХ рдЬрдпрд░рд╛рдУ,рдкреНрд░рддрд┐рдХ,None,рдЬрдпрд░рд╛рдУ,рдкреНрд░рддрд┐рдХ рдЬрдпрд░рд╛рдУ +hi,рдореЗрд░рд╛ рдирд╛рдо pratik jayarao рд╣реИ,pratik,None,jayarao,pratik jayarao diff --git a/ner_v2/detectors/numeral/number/README.md b/ner_v2/detectors/numeral/number/README.md index f03b78c6c..ed5f10f42 100644 --- a/ner_v2/detectors/numeral/number/README.md +++ b/ner_v2/detectors/numeral/number/README.md @@ -1,8 +1,10 @@ ## Number Detector -This is the V2 version of Number detector module that will detect number and number word from text in multiple languages. This detector module adds an additional feature of detecting units along with number in text. Example - for a given text "5 kg", this module will return `5` as detected value and `kg` as detected unit. +This is the V2 version of Number detector module that will detect number and number word from text in multiple languages. This detector module adds an additional feature of detecting units along with number in text. Example - for a given text "5 kg", this module will return `5` as detected value and `kg` as detected unit. The module has the capability to detect only certain type of numbers like currency or temperature type numbers by specifying the unit type. - We are currently providing number detection supports in 6 languages, which are +To check all unit type supported by english number detector please go through [unit.csv](https://github.com/hellohaptik/chatbot_ner/blob/develop/ner_v2/detectors/numeral/number/en/data/units.csv) + +We are currently providing number detection supports for 6 different languages, which are - English - Hindi @@ -16,12 +18,16 @@ This is the V2 version of Number detector module that will detect number and num - **Python Shell** ```python - >> from ner_v2.detector.number.number.number_detection import NumberDetector - >> detector = NumberDetector(entity_name='number', language='en', unit_type='currency') # here language will be ISO 639-1 code - >> detector.detect_entity(text= 'I want 4000 rs') - >> {'entity_value': [{'value': '4000', 'unit': 'rupees'}], 'original_text':['4000 rs']} + from ner_v2.detectors.numeral.number.number_detection import NumberDetector + detector = NumberDetector(entity_name='number', language='en', unit_type='currency') # here language will be ISO 639-1 code + detector.detect_entity(text= 'I want 4000 rs') + # Note: if unit type is not given it will only detect 4000, not unit. + ``` - # Notes -> if unit type is not given it will only detect 4000, not unit. + Output + + ```python + {'entity_value': [{'value': '4000', 'unit': 'rupees'}], 'original_text':['4000 rs']} ``` - **Curl Command** @@ -36,59 +42,57 @@ This is the V2 version of Number detector module that will detect number and num # min_number_digits=1 # max_number_digits=6 # source_language='hi' - # language_script='hi' # unit_type=None $ URL='localhost' $ PORT=8081 - $ curl -i 'http://'$URL':'$PORT'/v2/number?message=do%20hajaar%20char%20sau&entity_name=number&structured_value=&fallback_value=&bot_message=&min_number_digits=1&max_number_digits=6&source_language=hi&language_script=hi&unit_type=' - - # Curl output - $ { - "data": [ - { - "detection": "message", - "original_text": "do hajaar chaar sau", - "entity_value": { - "unit": null, - "value": "2400" - }, - "language": "hi" - } - ] - } + $ curl -i 'http://'$URL':'$PORT'/v2/number/message=do%20hajaar%20char%20sau&entity_name=number&structured_value=&fallback_value=&bot_message=&min_number_digits=1&max_number_digits=6&source_language=hi&language_script=hi&unit_type=' ``` +- **Output** + + ```json + { + "data": [ + { + "detection": "message", + "original_text": "do hajaar chaar sau", + "entity_value": { + "unit": null, + "value": "2400" + }, + "language": "hi" + } + ] + } + ``` + + ### Steps to add new language for Number detection In order to add any new language you have to follow below steps: 1. Create a directory with `ISO 639-1` code of that language inside `ner_v2/detectors/numeral/number/`. - 2. Create a directory named `data` inside language_code folder. - 3. Add two files named `numerals_constant.csv`, `units.csv` inside data folder. - Below is the folder structure of same after adding all the files for new language `xy`. - - ```python - |__ner_v2 - |___detectors - |___numeral - |___number - |___xy # <- New language Added - | |___data - | |___numerals_constant.csv - | |___units.csv - | - |__number_detection.py - ``` - - +Below is the folder structure of same after adding all the files for new language `xy`. +```python +|__ner_v2 + |___detectors + |___numeral + |___number + |___xy # <- New language Added + | |___data + | |___numerals_constant.csv + | |___units.csv + | + |___number_detection.py +``` #### GuideLines to create data files @@ -100,7 +104,7 @@ Below is the brief about how to create data files `numerals_constant.csv`, `unit | :----: | :--------------------: | :----: | :---: | | реж | рд╢реВрдиреНрдп\|zero\|sunya | 0 | unit | | рез | рдПрдХ\|ek\|ik | 1 | unit | - | рез.рел | рдбреЗреЭ\|рдвреЗреЬ\|рджреЗреЭ\|dedh\|dhed | 1.5 | unit | + | рез.рел | рдбреЗрдврд╝\|рдвреЗрдбрд╝\|рджреЗрдврд╝\|dedh\|dhed | 1.5 | unit | | резрежреж | рд╕реМ\|sau\|sao | 100 | scale | | резрежрежрежрежреж | рд▓рд╛рдЦ\|lakh\|laakh\|lac | 100000 | scale | @@ -117,7 +121,7 @@ Below is the brief about how to create data files `numerals_constant.csv`, `unit | currency | rupees | rupees \| rupay \| paisa \| paise \| inr \| рд░реВрдкреАрд╕ \| рд░реБрдкрдпрд╛ \| рд░реВрдкрдП\| рдкреИрд╕рд╛\| рдкреИрд╕реЗ\| тВ╣ | | currency | dollar | Dollar \| usd \| рдбреЙрд▓рд░ \| $ | - Here, the 1st column contains the type of unit (E.g. dollars, euros are "currency", centimetre, metre, kilometre are "distance"), 2nd column contains the value of unit which will be returned by number detector and 3rd column contains all the possible variants of that unit value (delimited by pipe┬а`|`) for the language you are adding. (It is recommended to add Romanised versions of the variants you are adding) +Here, the 1st column contains the type of unit (E.g. dollars, euros are "currency", centimetre, metre, kilometre are "distance"), 2nd column contains the value of unit which will be returned by number detector and 3rd column contains all the possible variants of that unit value (delimited by pipe┬а`|`) for the language you are adding. (It is recommended to add Romanised versions of the variants you are adding) #### Guidelines to add new detectors for number apart from builtin ones: @@ -127,22 +131,17 @@ To start with copy the code below ```python import re import os - from ner_v2.constant import LANGUAGE_DATA_DIRECTORY -from ner_v2.detectors.numeral.constant import NUMBER_DETECT_UNIT, NUMBER_DETECT_VALUE +from ner_v2.detectors.numeral.constant import NUMBER_DETECTION_RETURN_DICT_VALUE, NUMBER_DETECTION_RETURN_DICT_UNIT from ner_v2.detectors.numeral.number.standard_number_detector import BaseNumberDetector - class NumberDetector(BaseNumberDetector): data_directory_path = os.path.join((os.path.dirname(os.path.abspath(__file__)).rstrip(os.sep)), LANGUAGE_DATA_DIRECTORY) - def __init__(self, entity_name='number', unit_type=None): super(NumberDetector, self).__init__(entity_name=entity_name, - - data_directory_path=NumberDetector.data_directory_path, + data_directory_path=NumberDetector.data_directory_path, unit_type=unit_type) - ``` Note that the class name must be `NumberDetector` @@ -159,36 +158,34 @@ Next we define a custom detector. For our purposes we will add a detector to det 5. Finally your detector must return a tuple of (number_list, original_list). Ensure that `number_list` and `original_list` are of equal lengths before returning them. ```python - def _custom_detect_number_of_people_format(self, number_list=None, original_list=None): + def _custom_detect_number_of_people_format(self, number_list=None, original_list=None): number_list = number_list or [] original_list = original_list or [] patterns = re.findall(r'\s((fo?r)*\s*([0-9]+)\s*(ppl|people|passengers?|travellers?|persons?|pax|adults?))\s', self.processed_text.lower()) for pattern in patterns: number_list.append({ - NUMBER_DETECT_VALUE: pattern[2], - NUMBER_DETECT_UNIT: 'people' + NUMBER_DETECTION_RETURN_DICT_VALUE: pattern[2], + NUMBER_DETECTION_RETURN_DICT_UNIT: 'people' }) original_list.append(pattern[0]) - return number_list, original_list ``` - Once having defined a custom detector, we now add it to `self.detector_preferences` attribute. You can simply append your custom detectors at the end of this list or you can copy the default ordering from `detectors.numeral.number.standard_number_detector.BaseNumberDetector` and inject your own detectors in between. Below we show an example where we put our custom detector on top to execute it before some builtin detectors. ```python - def __init__(self, entity_name='number', unit_type=None): - super(NumberDetector, self).__init__(entity_name=entity_name, - data_directory_path=NumberDetector.data_directory_path, - unit_type=unit_type) - - self.detector_preferences = [ - self._custom_detect_number_of_people_format, - self._detect_number_from_digit, - self._detect_number_from_numerals - ] +def __init__(self, entity_name='number', unit_type=None): + super(NumberDetector, self).__init__(entity_name=entity_name, + unit_type=unit_type, + data_directory_path=NumberDetector.data_directory_path) + + self.detector_preferences = [ + self._custom_detect_number_of_people_format, + self._detect_number_from_digit, + self._detect_number_from_words + ] ``` Also to run the custom detector only for few set of entities, you can do it by putting a `if` condition to check if given entity_name belong to list, and modify the detector preference only for them. Below is the example where custom detector will run just for `person_count` and `traveller_number` entity. For other entities it will follow the default pattern defined in BaseNumberDetector. @@ -197,18 +194,16 @@ Also to run the custom detector only for few set of entities, you can do it by p def __init__(self, entity_name='number', unit_type=None): super(NumberDetector, self).__init__(entity_name=entity_name, data_directory_path=NumberDetector.data_directory_path, - unit_type=unit_type) + unit_type=unit_type) - if entity name in ['person_count', 'traveller_number']: + if entity_name in ['person_count', 'traveller_number']: self.detector_preferences = [ self._custom_detect_number_of_people_format, self._detect_number_from_digit, - self._detect_number_from_numerals + self._detect_number_from_words ] ``` - - Putting it all together, we have ```python @@ -216,7 +211,7 @@ import re import os from ner_v2.constant import LANGUAGE_DATA_DIRECTORY -from ner_v2.detectors.numeral.constant import NUMBER_DETECT_UNIT, NUMBER_DETECT_VALUE +from ner_v2.detectors.numeral.constant import NUMBER_DETECTION_RETURN_DICT_VALUE, NUMBER_DETECTION_RETURN_DICT_UNIT from ner_v2.detectors.numeral.number.standard_number_detector import BaseNumberDetector @@ -231,11 +226,11 @@ class NumberDetector(BaseNumberDetector): unit_type=unit_type) - if entity name in ['person_count', 'traveller_number']: + if entity_name in ['person_count', 'traveller_number']: self.detector_preferences = [ self._custom_detect_number_of_people_format, self._detect_number_from_digit, - self._detect_number_from_numerals + self._detect_number_from_words ] def _custom_detect_number_of_people_format(self, number_list=None, original_list=None): @@ -245,8 +240,8 @@ class NumberDetector(BaseNumberDetector): self.processed_text.lower()) for pattern in patterns: number_list.append({ - NUMBER_DETECT_VALUE: pattern[2], - NUMBER_DETECT_UNIT: 'people' + NUMBER_DETECTION_RETURN_DICT_VALUE: pattern[2], + NUMBER_DETECTION_RETURN_DICT_UNIT: 'people' }) original_list.append(pattern[0]) diff --git a/ner_v2/detectors/numeral/number/en/data/numerals_constant.csv b/ner_v2/detectors/numeral/number/en/data/numerals_constant.csv index 22edad854..9c9310e69 100644 --- a/ner_v2/detectors/numeral/number/en/data/numerals_constant.csv +++ b/ner_v2/detectors/numeral/number/en/data/numerals_constant.csv @@ -30,5 +30,5 @@ number,name_variants,number_value,number_type 100,hundred,100,scale 1000,Thousand|thousands|k,1000,scale 100000,lakh|lakhs|lac|lacs|l,100000,scale -100000,million|mil|ml|m,1000000,scale +100000,million|mil|m,1000000,scale 10000000,crore|crores|c|cr,10000000,scale diff --git a/ner_v2/detectors/numeral/number/en/data/units.csv b/ner_v2/detectors/numeral/number/en/data/units.csv index 950035e6a..5d9fde06f 100644 --- a/ner_v2/detectors/numeral/number/en/data/units.csv +++ b/ner_v2/detectors/numeral/number/en/data/units.csv @@ -1,3 +1,9 @@ unit_type,unit_value,unit_variants currency,rupees,rupees | rupee | rs | rupya | rupaya | rupaye | rupye | rupay | paisa | paise | inr | тВ╣ currency,dollar,Dollar | usd | $ +package_metric_unit,mg,mg | milligram | milligrams +package_metric_unit,gms,gms | grams | gram +package_metric_unit,kg,kilogram | kilograms | kg +package_metric_unit,ml,ml | milliliter +package_metric_unit,ltr,ltr | litre +package_metric_unit,pcs,pcs \ No newline at end of file diff --git a/ner_v2/detectors/temporal/constant.py b/ner_v2/detectors/temporal/constant.py index a01239fcd..eefa012cc 100644 --- a/ner_v2/detectors/temporal/constant.py +++ b/ner_v2/detectors/temporal/constant.py @@ -54,7 +54,6 @@ TYPE_THIS_DAY = 'day_within_one_week' TYPE_POSSIBLE_DAY = 'possible_day' - # ORIGINAL constants # TYPE_NEXT_DAY = 'next_day' # TYPE_CURRENT_DAY = 'current_day' @@ -73,27 +72,27 @@ TYPE_REPEAT_DAY = 'repeat_day' MONTH_DICT = { - u'1': [u'jan', u'january'], - u'10': [u'october', u'oct'], - u'11': [u'november', u'nov'], - u'12': [u'december', u'dec'], - u'2': [u'february', u'feb'], - u'3': [u'mar', u'march'], - u'4': [u'apr', u'april'], - u'5': [u'may'], - u'6': [u'jun', u'june'], - u'7': [u'july', u'jul'], - u'8': [u'august', u'aug'], - u'9': [u'september', u'sept', u'sep'] + 1: [u'jan', u'january'], + 10: [u'october', u'oct'], + 11: [u'november', u'nov'], + 12: [u'december', u'dec'], + 2: [u'february', u'feb'], + 3: [u'mar', u'march'], + 4: [u'apr', u'april'], + 5: [u'may'], + 6: [u'jun', u'june'], + 7: [u'july', u'jul'], + 8: [u'august', u'aug'], + 9: [u'september', u'sept', u'sep'] } DAY_DICT = { - u'1': [u'sun', u'sunday'], - u'2': [u'mon', u'monday'], - u'3': [u'tuesday', u'tue'], - u'4': [u'wednesday', u'wed'], - u'5': [u'thu', u'thursday', u'thurs', u'thur'], - u'6': [u'fri', u'friday'], - u'7': [u'saturday', u'sat'] + 1: [u'sun', u'sunday'], + 2: [u'mon', u'monday'], + 3: [u'tuesday', u'tue'], + 4: [u'wednesday', u'wed'], + 5: [u'thu', u'thursday', u'thurs', u'thur'], + 6: [u'fri', u'friday'], + 7: [u'saturday', u'sat'] } # CONSTANTS USED FOR DATE DETECTION @@ -127,5 +126,5 @@ '9th': 9, 'tenth': 10, '10th': 10, - 'last': -1 # used to get last week of any month + 'last': -1 # used to get last week of any month } diff --git a/ner_v2/detectors/temporal/date/date_detection.py b/ner_v2/detectors/temporal/date/date_detection.py index 10be4f9bb..3f219d06e 100644 --- a/ner_v2/detectors/temporal/date/date_detection.py +++ b/ner_v2/detectors/temporal/date/date_detection.py @@ -179,63 +179,67 @@ def _detect_range(self): regex_pattern = re.compile(r'\b(([12][0-9]|3[01]|0?[1-9])' r'\s?' r'(?:nd|st|rd|th)?' - r'\s?' - r'(?:to|\-|till)' - r'\s?' + r'(?:(?:\s*\-\s*)|\s+(?:to|till|se)\s+)' r'([12][0-9]|3[01]|0?[1-9])' r'\s?' r'(?:nd|st|rd|th)?' - r'[\ \,]' - r'\s?' - r'(?:of)?' - r'\s?' + r'[\s\,]+' + r'(?:of\s+)?' r'([A-Za-z]+))\b', flags=re.UNICODE) regex_pattern_2 = re.compile(r'\b(([12][0-9]|3[01]|0?[1-9])' r'\s?' r'(?:nd|st|rd|th)?' - r'\s+' + r'[\s\,]+' + r'(?:of\s+)?' r'([A-Za-z]+)' - r'\s+' - r'(?:to|\-|till)' - r'\s+' + r'(?:(?:\s*\-\s*)|\s+(?:to|till|se)\s+)' r'([12][0-9]|3[01]|0?[1-9])' r'\s?' r'(?:nd|st|rd|th)?' - r'\s?' - r'([a-zA-Z]+)?)\b', flags=re.UNICODE) + r'(?:[\s\,]+(?:of\s+)?([A-Za-z]+))?)\b', flags=re.UNICODE) - patterns = regex_pattern.findall(self.processed_text.lower()) - patterns_2 = regex_pattern_2.findall(self.processed_text.lower()) - if patterns: - for pattern in patterns: - date_dicts = self._date_dict_from_text(text=pattern[0]) + dd_to_dd_mmm_matches = regex_pattern.findall(self.processed_text) + dd_mmm_to_dd_matches = regex_pattern_2.findall(self.processed_text) + if dd_to_dd_mmm_matches: + for match in dd_to_dd_mmm_matches: + date_dicts = self._date_dict_from_text(text=match[0]) if len(date_dicts) == 2: date_dicts[0][temporal_constant.DATE_START_RANGE_PROPERTY] = True date_dicts[1][temporal_constant.DATE_END_RANGE_PROPERTY] = True date_dict_list.extend(date_dicts) - elif patterns_2: - for pattern in patterns_2: - date_dicts = self._date_dict_from_text(text=pattern[0]) + elif dd_mmm_to_dd_matches: + for match in dd_mmm_to_dd_matches: + date_dicts = self._date_dict_from_text(text=match[0]) if len(date_dicts) == 2: date_dicts[0][temporal_constant.DATE_START_RANGE_PROPERTY] = True date_dicts[1][temporal_constant.DATE_END_RANGE_PROPERTY] = True date_dict_list.extend(date_dicts) else: - parts = re.split(r'\s+(?:\-|to|se)\s+', self.processed_text.lower()) - if len(parts) > 1: - for start_part, end_part in zip(parts[:-1], parts[1:]): - start_date_list = self._date_dict_from_text(text=start_part, start_range_property=True) - end_date_list = self._date_dict_from_text(text=end_part, end_range_property=True) - if start_date_list and end_date_list: - start_date_list, end_date_list = self._generate_range(start_date_dict=start_date_list[0], - end_date_dict=end_date_list[-1]) - date_dict_list.extend(start_date_list) - date_dict_list.extend(end_date_list) + parts = iter(re.split(r'\s+(?:\-|to|till|se)\s+', self.processed_text)) + _day_of_week_types = [temporal_constant.TYPE_THIS_DAY, temporal_constant.TYPE_NEXT_DAY] + for start_part, end_part in zip(parts, parts): # Consumes 2 items at a time from parts + start_date_list = self._date_dict_from_text(text=start_part, start_range_property=True) + end_date_list = self._date_dict_from_text(text=end_part, end_range_property=True) + if start_date_list and end_date_list: + possible_start_date = start_date_list[0] + possible_end_date = end_date_list[-1] + start_date_type = possible_start_date[temporal_constant.DATE_VALUE]['type'] + end_date_type = possible_end_date[temporal_constant.DATE_VALUE]['type'] + if start_date_type in _day_of_week_types and end_date_type in _day_of_week_types: + start_date_list, end_date_list = self._fix_day_range(start_date_dict=possible_start_date, + end_date_dict=possible_end_date) + else: + # FIXME: Assumes end_date > start_date. Also can return dates in past when date detector + # returns dates in the past + start_date_list = [possible_start_date] + end_date_list = [possible_end_date] + date_dict_list.extend(start_date_list) + date_dict_list.extend(end_date_list) return date_dict_list - def _generate_range(self, start_date_dict, end_date_dict): + def _fix_day_range(self, start_date_dict, end_date_dict): """ If today is between the detected range, generate two day ranges - range for current week and the same range for next week, other wise both start date and end date dicts are returned as only elements of start date list @@ -298,14 +302,15 @@ def _detect_departure_date(self): For departure date the key "From" will be set to True. """ date_dict_list = [] - regex_pattern = re.compile(r'\b((onward date\:|onward date -|departure date|leaving on|starting from|' - r'departing on|departing|going on|for|departs on)\s+(.+))\b', flags=re.UNICODE) - patterns = regex_pattern.findall(self.processed_text.lower()) - - for pattern in patterns: - date_dict_list.extend( - self._date_dict_from_text(text=pattern[2], from_property=True) - ) + regex_pattern = re.compile(r'\b' + r'(?:check(?:\s|\-)?in date (?:is|\:)?|' + r'onward date\s?(?:\:|\-)?|departure date|leaving on|starting from|' + r'departing on|departing|going on|departs on|for)' + r'\s+(.+?)(?:\band|&|(? 1: - for i in range(len(date_dict_list)): - date_dict_list[i][temporal_constant.DATE_NORMAL_PROPERTY] = True + date_dict_list = self._date_dict_from_text(text=self.processed_text) + if date_dict_list: + if len(date_dict_list) > 1: + for i in range(len(date_dict_list)): + date_dict_list[i][temporal_constant.DATE_NORMAL_PROPERTY] = True + else: + if departure_date_flag: + date_dict_list[0][temporal_constant.DATE_FROM_PROPERTY] = True + elif return_date_flag: + date_dict_list[0][temporal_constant.DATE_TO_PROPERTY] = True else: - if departure_date_flag: - date_dict_list[0][temporal_constant.DATE_FROM_PROPERTY] = True - elif return_date_flag: - date_dict_list[0][temporal_constant.DATE_TO_PROPERTY] = True - else: - date_dict_list[0][temporal_constant.DATE_NORMAL_PROPERTY] = True + date_dict_list[0][temporal_constant.DATE_NORMAL_PROPERTY] = True return date_dict_list def _update_processed_text(self, date_dict_list): diff --git a/ner_v2/detectors/temporal/date/en/date_detection.py b/ner_v2/detectors/temporal/date/en/date_detection.py index 8add87f0d..12036b6f0 100644 --- a/ner_v2/detectors/temporal/date/en/date_detection.py +++ b/ner_v2/detectors/temporal/date/en/date_detection.py @@ -8,7 +8,7 @@ from ner_v2.detectors.temporal.constant import TYPE_EXACT, TYPE_EVERYDAY, TYPE_TODAY, TYPE_TOMORROW, TYPE_YESTERDAY, \ TYPE_DAY_AFTER, TYPE_DAY_BEFORE, TYPE_N_DAYS_AFTER, TYPE_NEXT_DAY, TYPE_THIS_DAY, TYPE_POSSIBLE_DAY, WEEKDAYS, \ REPEAT_WEEKDAYS, WEEKENDS, REPEAT_WEEKENDS, TYPE_REPEAT_DAY, MONTH_DICT, DAY_DICT, ORDINALS_MAP -from ner_v2.detectors.temporal.utils import get_weekdays_for_month +from ner_v2.detectors.temporal.utils import get_weekdays_for_month, get_next_date_with_dd, get_previous_date_with_dd class DateDetector(object): @@ -164,8 +164,7 @@ def get_exact_date(self, date_list, original_list): self._update_processed_text(original_list) date_list, original_list = self._date_range_ddth_of_mmm_to_ddth(date_list, original_list) self._update_processed_text(original_list) - date_list, original_list = self._date_range_ddth_to_ddth_of_next_month(date_list, - original_list) + date_list, original_list = self._date_range_ddth_to_ddth_of_next_month(date_list, original_list) self._update_processed_text(original_list) date_list, original_list = self._gregorian_day_with_ordinals_month_year_format(date_list, original_list) self._update_processed_text(original_list) @@ -230,6 +229,8 @@ def get_possible_date(self, date_list=None, original_list=None): self._update_processed_text(original_list) date_list, original_list = self._date_identification_given_day(date_list, original_list) self._update_processed_text(original_list) + # FIXME: This call order causes everyday to be taken away from "everyday except <>" which means + # FIXME: successive calls for everyday_except_weekends and everyday_except_weekdays return wrong results date_list, original_list = self._date_identification_everyday(date_list, original_list, n_days=15) self._update_processed_text(original_list) date_list, original_list = self._date_identification_everyday_except_weekends(date_list, original_list, @@ -289,14 +290,16 @@ def _gregorian_day_month_year_format(self, date_list=None, original_list=None): original_list = [] if date_list is None: date_list = [] - regex_pattern = re.compile(r'\b(([12][0-9]|3[01]|0?[1-9])\s?[/\-\.]\s?(1[0-2]|0?[1-9])\s?[/\-\.]' - r'\s?((?:20|19)?[0-9]{2}))(\s|$)') + regex_pattern = re.compile(r'\b(([12][0-9]|3[01]|0?[1-9])\s?[/\-\.]\s?(1[0-2]|0?[1-9])' + r'(?:\s?[/\-\.]\s?((?:20|19)?[0-9]{2}))?)(?:\s|$)') patterns = regex_pattern.findall(self.processed_text.lower()) for pattern in patterns: original = pattern[0] - dd = pattern[1] - mm = pattern[2] - yy = self.normalize_year(pattern[3]) + dd = int(pattern[1]) + mm = int(pattern[2]) + yy = int(self.normalize_year(pattern[3])) if pattern[3] else self.now_date.year + if not pattern[3] and self.timezone.localize(datetime.datetime(year=yy, month=mm, day=dd)) < self.now_date: + yy += 1 date = { 'dd': int(dd), @@ -493,8 +496,8 @@ def _gregorian_day_with_ordinals_month_year_format(self, date_list=None, origina date_list = [] if original_list is None: original_list = [] - regex_pattern = re.compile(r'\b(([12][0-9]|3[01]|0?[1-9])\s?(?:nd|st|rd|th)?\s?(?:of)?[\s\,]\s?' - r'([A-Za-z]+)[\s\,]\s?((?:20|19)?[0-9]{2}))(\s|$)') + regex_pattern = re.compile(r'\b(([12][0-9]|3[01]|0?[1-9])\s?(?:nd|st|rd|th)?\s?(?:of)?[\s\,\-]\s?' + r'([A-Za-z]+)[\s\,\-]\s?((?:20|19)?[0-9]{2}))(\s|$)') patterns = regex_pattern.findall(self.processed_text.lower()) for pattern in patterns: original = pattern[0].strip() @@ -647,8 +650,8 @@ def _gregorian_month_day_with_ordinals_year_format(self, date_list=None, origina original_list = [] if date_list is None: date_list = [] - regex_pattern = re.compile(r'\b(([A-Za-z]+)[\ \,]\s?([12][0-9]|3[01]|0?[1-9])\s?(?:nd|st|rd|th)?' - r'[\ \,]\s?((?:20|19)?[0-9]{2}))(\s|$)') + regex_pattern = re.compile(r'\b(([A-Za-z]+)[\ \,\-]\s?([12][0-9]|3[01]|0?[1-9])\s?(?:nd|st|rd|th)?' + r'[\ \,\-]\s?((?:20|19)?[0-9]{2}))(\s|$)') patterns = regex_pattern.findall(self.processed_text.lower()) for pattern in patterns: original = pattern[0] @@ -1073,7 +1076,8 @@ def _day_in_next_week(self, date_list=None, original_list=None): day = self.__get_day_index(probable_day) current_day = self.__get_day_index(self.now_date.strftime("%A")) if day and current_day: - date_after_days = int(day) - int(current_day) + 7 + day, current_day = int(day), int(current_day) + date_after_days = day - current_day + 7 day_to_set = self.now_date + datetime.timedelta(days=date_after_days) dd = day_to_set.day mm = day_to_set.month @@ -1124,10 +1128,11 @@ def _day_within_one_week(self, date_list=None, original_list=None): day = self.__get_day_index(probable_day) current_day = self.__get_day_index(self.now_date.strftime("%A")) if day and current_day: - if int(current_day) <= int(day): - date_after_days = int(day) - int(current_day) + day, current_day = int(day), int(current_day) + if current_day <= day: + date_after_days = day - current_day else: - date_after_days = int(day) - int(current_day) + 7 + date_after_days = day - current_day + 7 day_to_set = self.now_date + datetime.timedelta(days=date_after_days) dd = day_to_set.day mm = day_to_set.month @@ -1372,11 +1377,11 @@ def _date_identification_everyday_except_weekends(self, date_list=None, original date_list = [] now = self.now_date end = now + datetime.timedelta(days=n_days) - regex_pattern = re.compile(r'\b(([eE]veryday|[dD]aily)|all\sdays[\s]?except[\s]?([wW]eekend|[wW]eekends))\b') + regex_pattern = re.compile(r'\b((every\s?day|daily|all\s?days)\s+except\s+weekends?)\b') patterns = regex_pattern.findall(self.processed_text.lower()) if not patterns: - weekday_regex_pattern = re.compile(r'\b(weekdays|weekday|week day|week days| all weekdays)\b') + weekday_regex_pattern = re.compile(r'\b((week\s?days?|all\sweekdays))\b') patterns = weekday_regex_pattern.findall(self.processed_text.lower()) constant_type = WEEKDAYS if self._is_everyday_present(self.text): @@ -1450,11 +1455,10 @@ def _date_identification_everyday_except_weekdays(self, date_list=None, original original_list = [] now = self.now_date end = now + datetime.timedelta(days=n_days) - regex_pattern = re.compile(r'\b(([eE]veryday|[dD]aily)|[eE]very\s*day|all[\s]?except[\s]?' - r'([wW]eekday|[wW]eekdays))\b') + regex_pattern = re.compile(r'\b((every\s?day|daily|all\s?days)\s+except\s+weekdays?)\b') patterns = regex_pattern.findall(self.processed_text.lower()) if not patterns: - weekend_regex_pattern = re.compile(r'\b((weekends|weekend|week end|week ends | all weekends))\b') + weekend_regex_pattern = re.compile(r'\b((week\s?ends?|all\sweekends))\b') patterns = weekend_regex_pattern.findall(self.processed_text.lower()) constant_type = WEEKENDS if self._is_everyday_present(self.text): @@ -1528,29 +1532,36 @@ def _day_month_format_for_arrival_departure(self, date_list=None, original_list= original_list = [] if date_list is None: date_list = [] - regex_pattern = re.compile(r'\b(([12][0-9]|3[01]|0?[1-9])\s?(?:nd|st|rd|th)?\s?(?:-|to|-|till)\s?' - r'([12][0-9]|3[01]|0?[1-9])\s?(?:nd|st|rd|th)?[\ \,]\s?(?:of)?\s?([A-Za-z]+))\b') + # FIXME: This ignores any mentioned year + regex_pattern = re.compile(r'\b(([12][0-9]|3[01]|0?[1-9])\s*(?:nd|st|rd|th)?' + r'(?:(?:\s*\-\s*)|\s+(?:to|till|se)\s+)' + r'([12][0-9]|3[01]|0?[1-9])\s?(?:nd|st|rd|th)?[\s\,]+(?:of\s+)?([A-Za-z]+))\b') patterns = regex_pattern.findall(self.processed_text.lower()) for pattern in patterns: original = pattern[0] - dd1 = pattern[1] - dd2 = pattern[2] - probable_mm = pattern[3] - mm = self.__get_month_index(probable_mm) - yy = self.now_date.year - if mm: - if self.now_date.month > int(mm): - yy += 1 + dd1, mm1, yy1 = int(pattern[1]), None, None + dd2, mm2, yy2 = int(pattern[2]), self.__get_month_index(pattern[3]), self.now_date.year + + if mm2: + mm2 = int(mm2) + dt2 = self.timezone.localize(datetime.datetime(year=yy2, month=mm2, day=dd2)) + dd1, mm1, yy1 = get_previous_date_with_dd(dd=dd1, before_datetime=dt2) + if dd1 and mm1 and yy1: + dt1 = self.timezone.localize(datetime.datetime(year=yy1, month=mm1, day=dd1)) + if dt1 < self.now_date: + yy1 = yy2 = yy2 + 1 + + if all(part for part in [dd1, mm1, yy1, dd2, mm2, yy2]): date_dict_1 = { 'dd': int(dd1), - 'mm': int(mm), - 'yy': int(yy), + 'mm': int(mm1), + 'yy': int(yy1), 'type': TYPE_EXACT } date_dict_2 = { 'dd': int(dd2), - 'mm': int(mm), - 'yy': int(yy), + 'mm': int(mm2), + 'yy': int(yy2), 'type': TYPE_EXACT } date_list.append(date_dict_1) @@ -1589,7 +1600,7 @@ def _day_range_for_nth_week_month(self, date_list=None, original_list=None): if date_list is None: date_list = [] ordinal_choices = "|".join(ORDINALS_MAP.keys()) - regex_pattern = re.compile(r'((' + ordinal_choices + ')\s+week\s+(of\s+)?([a-zA-z]+)(?:\s+month)?)\s+') + regex_pattern = re.compile(r'((' + ordinal_choices + r')\s+week\s+(of\s+)?([A-Za-z]+)(?:\s+month)?)\s+') patterns = regex_pattern.findall(self.processed_text.lower()) for pattern in patterns: original = pattern[0] @@ -1647,45 +1658,33 @@ def _date_range_ddth_of_mmm_to_ddth(self, date_list=None, original_list=None): original_list = [] if date_list is None: date_list = [] - regex_pattern = re.compile(r'\b(([12][0-9]|3[01]|0?[1-9])\s?(?:nd|st|rd|th)?\s+(?:of\s+)?([A-Za-z]+)\s+' - r'(?:-|to|-|till)\s+([12][0-9]|3[01]|0?[1-9])\s?(?:nd|st|rd|th)?\s?([a-zA-Z]+)?)\b') + # FIXME: This ignores any mentioned year + regex_pattern = re.compile(r'\b(([12][0-9]|3[01]|0?[1-9])\s?(?:nd|st|rd|th)?[\s\,]+(?:of\s+)?([A-Za-z]+)' + r'(?:(?:\s*\-\s*)|\s+(?:to|till|se)\s+)' + r'([12][0-9]|3[01]|0?[1-9])\s?(?:nd|st|rd|th)?' + r'(?:[\s\,]+(?:of\s+)?([A-Za-z]+))?)\b') patterns = regex_pattern.findall(self.processed_text.lower()) for pattern in patterns: original = pattern[0] - dd1 = int(pattern[1]) - dd2 = int(pattern[3]) - probable_mm1 = pattern[2] - probable_mm2 = pattern[4] - mm1 = self.__get_month_index(probable_mm1) - mm2_mention = self.__get_month_index(probable_mm2) - - mm2 = mm2_mention - if not mm2: - mm2 = mm1 - - yy1 = self.now_date.year - - if mm1 and mm2: + dd1, mm1, yy1 = int(pattern[1]), self.__get_month_index(pattern[2]), self.now_date.year + dd2, mm2, yy2 = int(pattern[3]), self.__get_month_index(pattern[4]), self.now_date.year + if mm1: mm1 = int(mm1) - mm2 = int(mm2) - - if not mm2_mention and dd2 < dd1: - mm2 += 1 - if mm2 > 12: - mm2 = 1 - dt1 = self.timezone.localize(datetime.datetime(year=yy1, month=mm1, day=dd1)) - if dt1 < self.now_date: - yy1 += 1 - - yy2 = yy1 - dt1 = self.timezone.localize(datetime.datetime(year=yy1, month=mm1, day=dd1)) - dt2 = self.timezone.localize(datetime.datetime(year=yy2, month=mm2, day=dd2)) - - if dt2 < dt1: - yy2 += 1 + yy2 = yy1 = yy1 + 1 + dt1 = self.timezone.localize(datetime.datetime(year=yy1, month=mm1, day=dd1)) + + if mm2: + # find the correct yy2 such that dd2/mm2/yy2 >= dd1/mm1/yy1 + mm2 = int(mm2) + dt2 = self.timezone.localize(datetime.datetime(year=yy2, month=mm2, day=dd2)) + yy2 = yy2 + 1 if dt2 < dt1 else yy2 + else: + # find the closest dd2 after dt1 + dd2, mm2, yy2 = get_next_date_with_dd(dd=dd2, after_datetime=dt1) + if all(part for part in [dd1, mm1, yy1, dd2, mm2, yy2]): date_dict_1 = { 'dd': int(dd1), 'mm': int(mm1), @@ -1734,9 +1733,10 @@ def _date_range_ddth_to_ddth_of_next_month(self, date_list=None, original_list=N original_list = [] if date_list is None: date_list = [] - regex_pattern = re.compile(r'\b(([12][0-9]|3[01]|0?[1-9])\s?(?:nd|st|rd|th)?\s+(?:-|to|-|till)\s+' - r'([12][0-9]|3[01]|0?[1-9])\s?(?:nd|st|rd|th)?[\ \,\s]+(?:of\s+)?' - r'(?:next|nxt|comm?ing?|foll?owing?|)\s+(?:mo?nth))\b') + regex_pattern = re.compile(r'\b(([12][0-9]|3[01]|0?[1-9])\s?(?:nd|st|rd|th)?' + r'(?:(?:\s*\-\s*)|\s+(?:to|till|se)\s+)' + r'([12][0-9]|3[01]|0?[1-9])\s?(?:nd|st|rd|th)?[\s\,]+(?:of\s+)?' + r'(?:next|nxt|comm?ing?|foll?owing?)\s+(?:mo?nth))\b') patterns = regex_pattern.findall(self.processed_text.lower()) for pattern in patterns: original = pattern[0] @@ -1862,6 +1862,7 @@ def _weeks_identification(self, date_list=None, original_list=None): return date_list, original_list def __get_month_index(self, value): + # type: (str) -> Optional[int] """ Gets the index of month by comparing the value with month names and their variants from the data store @@ -1878,6 +1879,7 @@ def __get_month_index(self, value): return None def __get_day_index(self, value): + # type: (str) -> Optional[int] """ Gets the index of month by comparing the value with day names and their variants from the data store diff --git a/ner_v2/detectors/temporal/utils.py b/ner_v2/detectors/temporal/utils.py index 751a83a91..bb224cc18 100644 --- a/ner_v2/detectors/temporal/utils.py +++ b/ner_v2/detectors/temporal/utils.py @@ -1,12 +1,15 @@ import calendar from datetime import datetime, timedelta + import pandas as pd + from ner_v2.detectors.temporal.constant import POSITIVE_TIME_DIFF, NEGATIVE_TIME_DIFF, CONSTANT_FILE_KEY def nth_weekday(weekday, n, ref_date): """ Method to return python datetime object for given nth weekday w.r.t ref_date (reference date) + Args: weekday (int): int count of weekday like 0 for monday, 1 for tuesday n (int): nth weekday @@ -24,6 +27,7 @@ def nth_weekday(weekday, n, ref_date): def next_weekday(current_date, weekday, n): """ Method to return python datetime object to find next weekday from current date + Args: current_date (datetime): python datetime object weekday (int): int count of weekday like 0 for monday, 1 for tuesday @@ -42,9 +46,11 @@ def next_weekday(current_date, weekday, n): def get_hour_min_diff(time1, time2): """ Method to return difference between two times in hours and minutes. + Args: time1 (datetime): datetime object time2 (datetime): datetime object + Returns: hh (int): hour difference between two times mm (int): minute difference between two times @@ -64,6 +70,7 @@ def get_hour_min_diff(time1, time2): def get_tuple_dict(csv_file): """ Method to convert language constant csv into tuple dict + Args: csv_file (str): csv file path @@ -85,10 +92,12 @@ def get_tuple_dict(csv_file): def get_weekdays_for_month(weeknumber, month, year): """ Return list of day for given weeknumber of given month and year + Args: weeknumber (int): week number month (int): month year (int): year + Returns: (list): list of days """ @@ -98,3 +107,156 @@ def get_weekdays_for_month(weeknumber, month, year): elif 0 < weeknumber <= len(calendar_month): return [day for day in calendar_month[weeknumber - 1] if day != 0] return [] + + +def is_valid_date(dd, mm, yy, tz=None): + # type: (int, int, int, 'pytz.tzfile.*') -> bool + """ + Given dd, mm, yy check if it is a valid date in a year + + Args: + dd (int): upto 2 digit integer + mm (int): upto 2 digit integer + yy (int): upto 4 digit integer + tz (pytz.tzfile.*, optional): A valid pytz timezone. defaults to None + + Returns: + bool: if dd/mm/yy is a valid date + + Raises: + TypeError: when any of dd, mm, yy is not an int + """ + if dd and mm and yy: + try: + dt = datetime(year=yy, month=mm, day=dd) + if tz: + tz.localize(dt) + return True + except (ValueError, AttributeError): + pass + return False + + +def get_previous_month_number(mm, yy): + # type: (int, int) -> Tuple[int, int] + """ + Given month number and year get previous month number and adjust year if we flow into previous year + + Args: + mm (int): upto 2 digit month number, between 1 and 12 + yy (int): any year + + Returns: + tuple: tuple containing + int: previous month number after mm + int: adjusted year for the previous month number + + Raises: + ValueError: when mm is not between 1 and 12 + + """ + if 1 <= mm <= 12: + if mm == 1: + mm = 12 + yy -= 1 + else: + mm -= 1 + else: + raise ValueError('mm should be between 1 and 12 inclusive') + + return mm, yy + + +def get_next_month_number(mm, yy): + # type: (int, int) -> Tuple[int, int] + """ + Given month number and year get next month number and adjust year if we flow into next year + + Args: + mm (int): upto 2 digit month number, between 1 and 12 + yy (int): any year + + Returns: + tuple: tuple containing + int: next month number after mm + int: adjusted year for the next month number + + Raises: + ValueError: when mm is not between 1 and 12 + + """ + if 1 <= mm <= 12: + if mm == 12: + mm = 1 + yy += 1 + else: + mm += 1 + else: + raise ValueError('mm should be between 1 and 12 inclusive') + + return mm, yy + + +def get_previous_date_with_dd(dd, before_datetime): + # type: (int, datetime.datetime) -> Tuple[Optional[int], Optional[int], Optional[int]] + """ + Get closest date with day same as `dd` on or before `before_datetime` + + Args: + dd (int): 2 digit int, expected between 1 and 31 + before_datetime (datetime.datetime): python datetime object, the date to look back from + + Returns: + tuple: tuple containing + int or None: day part of found date, if no such valid date can be found None + int or None: month part of found date, if no such valid date can be found None + int or None: year part of found date, if no such valid date can be found None + + """ + + end_dd = before_datetime.day + mm = before_datetime.month + yy = before_datetime.year + + if dd > end_dd: + mm, yy = get_previous_month_number(mm=mm, yy=yy) + + # Try in previous three months, it should be possible to get closest valid date with same dd in last 3 months + for _ in range(3): + if is_valid_date(dd=dd, mm=mm, yy=yy): + return dd, mm, yy + mm, yy = get_previous_month_number(mm=mm, yy=yy) + + return None, None, None + + +def get_next_date_with_dd(dd, after_datetime): + # type: (int, datetime.datetime) -> Tuple[Optional[int], Optional[int], Optional[int]] + """ + Get closest date with day same as `dd` on or after `after_datetime` + + Args: + dd (int): 2 digit int, expected between 1 and 31 + after_datetime (datetime.datetime): python datetime object, the date to look ahead from + + Returns: + tuple: tuple containing + int or None: day part of found date, if no such valid date can be found None + int or None: month part of found date, if no such valid date can be found None + int or None: year part of found date, if no such valid date can be found None + + """ + start_dd = after_datetime.day + mm = after_datetime.month + yy = after_datetime.year + + if dd < start_dd: + mm, yy = get_next_month_number(mm=mm, yy=yy) + + # Try in next three months, it should be possible to get closest valid date with same dd in next 3 months + for _ in range(3): + if is_valid_date(dd=dd, mm=mm, yy=yy): + return dd, mm, yy + mm, yy = get_next_month_number(mm=mm, yy=yy) + + return None, None, None diff --git a/ner_v2/tests/numeral/number/en/test_number_detection.py b/ner_v2/tests/numeral/number/en/test_number_detection.py index 6d9793a88..5eb98d61a 100644 --- a/ner_v2/tests/numeral/number/en/test_number_detection.py +++ b/ner_v2/tests/numeral/number/en/test_number_detection.py @@ -37,7 +37,6 @@ def setUp(self): u'm': NumberVariant(scale=1000000, increment=0), u'mil': NumberVariant(scale=1000000, increment=0), u'million': NumberVariant(scale=1000000, increment=0), - u'ml': NumberVariant(scale=1000000, increment=0), u'nine': NumberVariant(scale=1, increment=9), u'nineteen': NumberVariant(scale=1, increment=19), u'ninety': NumberVariant(scale=1, increment=90), diff --git a/requirements.txt b/requirements.txt index 6b27fb16b..e239e987b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,3 +19,5 @@ python-dateutil==2.7.3 pandas==0.19.0 mock==2.0.0 django-nose==1.4.5 +typing==3.6.2 +flake8==3.4.1 \ No newline at end of file