From 3114c678a4c2585a281bbf3fd8cd1f0e486985ec Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 6 Apr 2022 12:35:08 +0200 Subject: [PATCH 01/22] add user model fields #3017 --- .../1b61613d1c19_add_new_fields_in_agent.py | 35 ++++++++ ereuse_devicehub/resources/agent/models.py | 86 ++++++++++++------- ereuse_devicehub/resources/user/models.py | 58 ++++++++----- .../ereuse_devicehub/user_profile.html | 73 +++++++++++----- ereuse_devicehub/views.py | 2 + 5 files changed, 182 insertions(+), 72 deletions(-) create mode 100644 ereuse_devicehub/migrations/versions/1b61613d1c19_add_new_fields_in_agent.py diff --git a/ereuse_devicehub/migrations/versions/1b61613d1c19_add_new_fields_in_agent.py b/ereuse_devicehub/migrations/versions/1b61613d1c19_add_new_fields_in_agent.py new file mode 100644 index 00000000..13d71b82 --- /dev/null +++ b/ereuse_devicehub/migrations/versions/1b61613d1c19_add_new_fields_in_agent.py @@ -0,0 +1,35 @@ +"""add new fields in agent + +Revision ID: 1b61613d1c19 +Revises: 8571fb32c912 +Create Date: 2022-04-06 12:23:37.644108 + +""" +import citext +import sqlalchemy as sa +from alembic import context, op + +# revision identifiers, used by Alembic. +revision = '1b61613d1c19' +down_revision = '8571fb32c912' +branch_labels = None +depends_on = None + + +def get_inv(): + INV = context.get_x_argument(as_dictionary=True).get('inventory') + if not INV: + raise ValueError("Inventory value is not specified") + return INV + + +def upgrade(): + op.add_column( + "agent", + sa.Column("last_name", citext.CIText(), nullable=True), + schema=f'{get_inv()}', + ) + + +def downgrade(): + op.drop_column('agent', 'last_name', schema=f'{get_inv()}') diff --git a/ereuse_devicehub/resources/agent/models.py b/ereuse_devicehub/resources/agent/models.py index ab9e073a..4554d227 100644 --- a/ereuse_devicehub/resources/agent/models.py +++ b/ereuse_devicehub/resources/agent/models.py @@ -3,7 +3,9 @@ from operator import attrgetter from uuid import uuid4 from citext import CIText -from sqlalchemy import Column, Enum as DBEnum, ForeignKey, Unicode, UniqueConstraint +from sqlalchemy import Column +from sqlalchemy import Enum as DBEnum +from sqlalchemy import ForeignKey, Unicode, UniqueConstraint from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.orm import backref, relationship, validates @@ -29,6 +31,7 @@ class Agent(Thing): id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4) type = Column(Unicode, nullable=False) name = Column(CIText()) + last_name = Column(CIText()) name.comment = """The name of the organization or person.""" tax_id = Column(Unicode(length=STR_SM_SIZE), check_lower('tax_id')) tax_id.comment = """The Tax / Fiscal ID of the organization, @@ -42,9 +45,15 @@ class Agent(Thing): __table_args__ = ( UniqueConstraint(tax_id, country, name='Registration Number per country.'), UniqueConstraint(tax_id, name, name='One tax ID with one name.'), - db.Index('agent_type', type, postgresql_using='hash') + db.Index('agent_type', type, postgresql_using='hash'), ) + @property + def get_full_name(self): + if self.last_name: + return "{} {}".format(self.name, self.last_name) + return self.name + @declared_attr def __mapper_args__(cls): """Defines inheritance. @@ -63,7 +72,9 @@ class Agent(Thing): @property def actions(self) -> list: # todo test - return sorted(chain(self.actions_agent, self.actions_to), key=attrgetter('created')) + return sorted( + chain(self.actions_agent, self.actions_to), key=attrgetter('created') + ) @validates('name') def does_not_contain_slash(self, _, value: str): @@ -76,15 +87,17 @@ class Agent(Thing): class Organization(JoinedTableMixin, Agent): - default_of = db.relationship(Inventory, - uselist=False, - lazy=True, - backref=backref('org', lazy=True), - # We need to use this as we cannot do Inventory.foreign -> Org - # as foreign keys can only reference to one table - # and we have multiple organization table (one per schema) - foreign_keys=[Inventory.org_id], - primaryjoin=lambda: Organization.id == Inventory.org_id) + default_of = db.relationship( + Inventory, + uselist=False, + lazy=True, + backref=backref('org', lazy=True), + # We need to use this as we cannot do Inventory.foreign -> Org + # as foreign keys can only reference to one table + # and we have multiple organization table (one per schema) + foreign_keys=[Inventory.org_id], + primaryjoin=lambda: Organization.id == Inventory.org_id, + ) def __init__(self, name: str, **kwargs) -> None: super().__init__(**kwargs, name=name) @@ -97,12 +110,17 @@ class Organization(JoinedTableMixin, Agent): class Individual(JoinedTableMixin, Agent): active_org_id = Column(UUID(as_uuid=True), ForeignKey(Organization.id)) - active_org = relationship(Organization, primaryjoin=active_org_id == Organization.id) + + active_org = relationship( + Organization, primaryjoin=active_org_id == Organization.id + ) user_id = Column(UUID(as_uuid=True), ForeignKey(User.id), unique=True) - user = relationship(User, - backref=backref('individuals', lazy=True, collection_class=set), - primaryjoin=user_id == User.id) + user = relationship( + User, + backref=backref('individuals', lazy=True, collection_class=set), + primaryjoin=user_id == User.id, + ) class Membership(Thing): @@ -110,20 +128,29 @@ class Membership(Thing): For example, because the individual works in or because is a member of. """ - id = Column(Unicode(), check_lower('id')) - organization_id = Column(UUID(as_uuid=True), ForeignKey(Organization.id), primary_key=True) - organization = relationship(Organization, - backref=backref('members', collection_class=set, lazy=True), - primaryjoin=organization_id == Organization.id) - individual_id = Column(UUID(as_uuid=True), ForeignKey(Individual.id), primary_key=True) - individual = relationship(Individual, - backref=backref('member_of', collection_class=set, lazy=True), - primaryjoin=individual_id == Individual.id) - def __init__(self, organization: Organization, individual: Individual, id: str = None) -> None: - super().__init__(organization=organization, - individual=individual, - id=id) + id = Column(Unicode(), check_lower('id')) + organization_id = Column( + UUID(as_uuid=True), ForeignKey(Organization.id), primary_key=True + ) + organization = relationship( + Organization, + backref=backref('members', collection_class=set, lazy=True), + primaryjoin=organization_id == Organization.id, + ) + individual_id = Column( + UUID(as_uuid=True), ForeignKey(Individual.id), primary_key=True + ) + individual = relationship( + Individual, + backref=backref('member_of', collection_class=set, lazy=True), + primaryjoin=individual_id == Individual.id, + ) + + def __init__( + self, organization: Organization, individual: Individual, id: str = None + ) -> None: + super().__init__(organization=organization, individual=individual, id=id) __table_args__ = ( UniqueConstraint(id, organization_id, name='One member id per organization.'), @@ -134,6 +161,7 @@ class Person(Individual): """A person in the system. There can be several persons pointing to a real. """ + pass diff --git a/ereuse_devicehub/resources/user/models.py b/ereuse_devicehub/resources/user/models.py index 70f14e00..039a4bf3 100644 --- a/ereuse_devicehub/resources/user/models.py +++ b/ereuse_devicehub/resources/user/models.py @@ -2,37 +2,44 @@ from uuid import uuid4 from flask import current_app as app from flask_login import UserMixin -from sqlalchemy import Column, Boolean, BigInteger, Sequence +from sqlalchemy import BigInteger, Boolean, Column, Sequence from sqlalchemy.dialects.postgresql import UUID from sqlalchemy_utils import EmailType, PasswordType from teal.db import IntEnum from ereuse_devicehub.db import db +from ereuse_devicehub.resources.enums import SessionType from ereuse_devicehub.resources.inventory.model import Inventory from ereuse_devicehub.resources.models import STR_SIZE, Thing -from ereuse_devicehub.resources.enums import SessionType class User(UserMixin, Thing): __table_args__ = {'schema': 'common'} id = Column(UUID(as_uuid=True), default=uuid4, primary_key=True) email = Column(EmailType, nullable=False, unique=True) - password = Column(PasswordType(max_length=STR_SIZE, - onload=lambda **kwargs: dict( - schemes=app.config['PASSWORD_SCHEMES'], - **kwargs - ))) + password = Column( + PasswordType( + max_length=STR_SIZE, + onload=lambda **kwargs: dict( + schemes=app.config['PASSWORD_SCHEMES'], **kwargs + ), + ) + ) token = Column(UUID(as_uuid=True), default=uuid4, unique=True, nullable=False) active = Column(Boolean, default=True, nullable=False) phantom = Column(Boolean, default=False, nullable=False) - inventories = db.relationship(Inventory, - backref=db.backref('users', lazy=True, collection_class=set), - secondary=lambda: UserInventory.__table__, - collection_class=set) + inventories = db.relationship( + Inventory, + backref=db.backref('users', lazy=True, collection_class=set), + secondary=lambda: UserInventory.__table__, + collection_class=set, + ) # todo set restriction that user has, at least, one active db - def __init__(self, email, password=None, inventories=None, active=True, phantom=False) -> None: + def __init__( + self, email, password=None, inventories=None, active=True, phantom=False + ) -> None: """Creates an user. :param email: :param password: @@ -44,8 +51,13 @@ class User(UserMixin, Thing): create during the trade actions """ inventories = inventories or {Inventory.current} - super().__init__(email=email, password=password, inventories=inventories, - active=active, phantom=phantom) + super().__init__( + email=email, + password=password, + inventories=inventories, + active=active, + phantom=phantom, + ) def __repr__(self) -> str: return ''.format(self) @@ -73,8 +85,9 @@ class User(UserMixin, Thing): @property def get_full_name(self): - # TODO(@slamora) create first_name & last_name fields and use - # them to generate user full name + if self.individual: + return self.individual.get_full_name + return self.email def check_password(self, password): @@ -84,9 +97,12 @@ class User(UserMixin, Thing): class UserInventory(db.Model): """Relationship between users and their inventories.""" + __table_args__ = {'schema': 'common'} user_id = db.Column(db.UUID(as_uuid=True), db.ForeignKey(User.id), primary_key=True) - inventory_id = db.Column(db.Unicode(), db.ForeignKey(Inventory.id), primary_key=True) + inventory_id = db.Column( + db.Unicode(), db.ForeignKey(Inventory.id), primary_key=True + ) class Session(Thing): @@ -96,9 +112,11 @@ class Session(Thing): token = Column(UUID(as_uuid=True), default=uuid4, unique=True, nullable=False) type = Column(IntEnum(SessionType), default=SessionType.Internal, nullable=False) user_id = db.Column(db.UUID(as_uuid=True), db.ForeignKey(User.id)) - user = db.relationship(User, - backref=db.backref('sessions', lazy=True, collection_class=set), - collection_class=set) + user = db.relationship( + User, + backref=db.backref('sessions', lazy=True, collection_class=set), + collection_class=set, + ) def __str__(self) -> str: return '{0.token}'.format(self) diff --git a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html index 71ab39fa..326f3991 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html @@ -27,7 +27,7 @@ -
+
@@ -54,46 +54,73 @@
-
About
-

Sunt est soluta temporibus accusantium neque nam maiores cumque temporibus. Tempora libero non est unde veniam est qui dolor. Ut sunt iure rerum quae quisquam autem eveniet perspiciatis odit. Fuga sequi sed ea saepe at unde.

-
Profile Details
+
+
Account user
+
{{ current_user.email or ''}}
+
+ + {% for u in current_user.individuals %} +
Full Name
-
Kevin Anderson
-
- -
-
Company
-
Lueilwitz, Wisoky and Leuschke
-
- -
-
Job
-
Web Designer
+
{{ u.get_full_name or ''}}
Country
-
USA
-
- -
-
Address
-
A108 Adam Street, New York, NY 535022
+
{{ u.country or ''}}
Phone
-
(436) 486-3538 x29071
+
{{ u.telephone or ''}}
Email
-
k.anderson@example.com
+
{{ u.email or ''}}
+
+
Created
+
{{ u.created.strftime('%H:%M %d-%m-%Y') or ''}}
+
+ +
+
Last login
+
+ {% for s in sessions %} + {{ s }}
+ {% endfor %} +
+
+ + {% if u.active_org %} +
+
Company name
+
{{ u.active_org.name or ''}}
+
+ +
+
Company country
+
{{ u.active_org.country or '' }}
+
+ +
+
Company Phone
+
{{ u.active_org.telephone or '' }}
+
+ +
+
Company Email
+
{{ u.active_org.email or '' }}
+
+ + {% endif %} + {% endfor %} +
diff --git a/ereuse_devicehub/views.py b/ereuse_devicehub/views.py index 0c9b4361..1a2112a2 100644 --- a/ereuse_devicehub/views.py +++ b/ereuse_devicehub/views.py @@ -50,8 +50,10 @@ class UserProfileView(View): template_name = 'ereuse_devicehub/user_profile.html' def dispatch_request(self): + sessions = {s.created.strftime('%H:%M %d-%m-%Y') for s in current_user.sessions} context = { 'current_user': current_user, + 'sessions': sessions, 'version': __version__, } return flask.render_template(self.template_name, **context) From 9f8465902683c1e60fc250ecd32ab82680c43116 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 6 Apr 2022 13:49:15 +0200 Subject: [PATCH 02/22] clean white space --- ereuse_devicehub/resources/agent/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ereuse_devicehub/resources/agent/models.py b/ereuse_devicehub/resources/agent/models.py index 4554d227..36d7fcd8 100644 --- a/ereuse_devicehub/resources/agent/models.py +++ b/ereuse_devicehub/resources/agent/models.py @@ -34,7 +34,7 @@ class Agent(Thing): last_name = Column(CIText()) name.comment = """The name of the organization or person.""" tax_id = Column(Unicode(length=STR_SM_SIZE), check_lower('tax_id')) - tax_id.comment = """The Tax / Fiscal ID of the organization, + tax_id.comment = """The Tax / Fiscal ID of the organization, e.g. the TIN in the US or the CIF/NIF in Spain. """ country = Column(DBEnum(enums.Country)) From d1310a67bfa6ca5e87f80e3658385eac889113cf Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 6 Apr 2022 13:50:08 +0200 Subject: [PATCH 03/22] add profile form --- ereuse_devicehub/forms.py | 36 ++++++- .../ereuse_devicehub/user_profile.html | 101 ++---------------- ereuse_devicehub/views.py | 4 +- 3 files changed, 47 insertions(+), 94 deletions(-) diff --git a/ereuse_devicehub/forms.py b/ereuse_devicehub/forms.py index d88c9cf1..dca1044c 100644 --- a/ereuse_devicehub/forms.py +++ b/ereuse_devicehub/forms.py @@ -1,9 +1,19 @@ from flask_wtf import FlaskForm from werkzeug.security import generate_password_hash -from wtforms import BooleanField, EmailField, PasswordField, validators +from wtforms import ( + BooleanField, + EmailField, + PasswordField, + SelectField, + StringField, + validators, +) +from ereuse_devicehub.enums import Country from ereuse_devicehub.resources.user.models import User +COUNTRY = [(x.name, x.value) for x in Country] + class LoginForm(FlaskForm): email = EmailField('Email Address', [validators.Length(min=6, max=35)]) @@ -59,3 +69,27 @@ class LoginForm(FlaskForm): self.form_errors.append(self.error_messages['inactive']) return user.is_active + + +class ProfileForm(FlaskForm): + name = StringField( + 'First name', + [validators.Length(min=2, max=35)], + render_kw={'class': "form-control"}, + ) + last_name = StringField( + 'Last name', + [validators.Length(min=2, max=35)], + render_kw={'class': "form-control"}, + ) + email = StringField( + 'Email Address', + [validators.Length(min=6, max=35)], + render_kw={'class': "form-control"}, + ) + telephone = StringField( + 'Phone', [validators.Length(min=6, max=35)], render_kw={'class': "form-control"} + ) + country = SelectField( + 'Country', choices=COUNTRY, default="es", render_kw={'class': "form-select"} + ) diff --git a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html index 326f3991..4b6468ba 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html @@ -126,102 +126,19 @@
-
+ + {% for f in profile_form %} + {% if f == profile_form.csrf_token %} + {{ f }} + {% else %}
- +
- Profile -
- - -
+ {{ f }}
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- + {% endif %} + {% endfor %}
diff --git a/ereuse_devicehub/views.py b/ereuse_devicehub/views.py index 1a2112a2..f6ed21f4 100644 --- a/ereuse_devicehub/views.py +++ b/ereuse_devicehub/views.py @@ -4,7 +4,7 @@ from flask.views import View from flask_login import current_user, login_required, login_user, logout_user from ereuse_devicehub import __version__ -from ereuse_devicehub.forms import LoginForm +from ereuse_devicehub.forms import LoginForm, ProfileForm from ereuse_devicehub.resources.user.models import User from ereuse_devicehub.utils import is_safe_url @@ -50,11 +50,13 @@ class UserProfileView(View): template_name = 'ereuse_devicehub/user_profile.html' def dispatch_request(self): + form = ProfileForm() sessions = {s.created.strftime('%H:%M %d-%m-%Y') for s in current_user.sessions} context = { 'current_user': current_user, 'sessions': sessions, 'version': __version__, + 'profile_form': form, } return flask.render_template(self.template_name, **context) From 1820b15255c22379d10a643acb2211590bd4f47c Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 11 Apr 2022 17:16:20 +0200 Subject: [PATCH 04/22] save data profile --- ereuse_devicehub/forms.py | 24 +++++++++++++++++++ .../ereuse_devicehub/user_profile.html | 9 ++++++- ereuse_devicehub/views.py | 17 +++++++++++-- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/ereuse_devicehub/forms.py b/ereuse_devicehub/forms.py index dca1044c..1bfd7907 100644 --- a/ereuse_devicehub/forms.py +++ b/ereuse_devicehub/forms.py @@ -1,3 +1,4 @@ +from flask import g from flask_wtf import FlaskForm from werkzeug.security import generate_password_hash from wtforms import ( @@ -9,6 +10,7 @@ from wtforms import ( validators, ) +from ereuse_devicehub.db import db from ereuse_devicehub.enums import Country from ereuse_devicehub.resources.user.models import User @@ -93,3 +95,25 @@ class ProfileForm(FlaskForm): country = SelectField( 'Country', choices=COUNTRY, default="es", render_kw={'class': "form-select"} ) + + def __init__(self, *args, **kwargs): + user = kwargs.pop('user', None) + super().__init__(*args, **kwargs) + if user: + self.name.data = user.name + self.last_name.data = user.last_name + self.email.data = user.email + self.telephone.data = user.telephone + self.country.data = user.country + + def save(self, commit=True): + agent = g.user.individual + agent.name = self.name.data + agent.last_name = self.last_name.data + agent.email = self.email.data + agent.telephone = self.telephone.data + agent.country = self.country.data + + db.session.add(agent) + if commit: + db.session.commit() diff --git a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html index 4b6468ba..dba8db62 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html @@ -135,6 +135,13 @@
{{ f }} + {% if f.errors %} +

+ {% for error in f.errors %} + {{ error }}
+ {% endfor %} +

+ {% endif %}
{% endif %} @@ -149,7 +156,7 @@
- +
diff --git a/ereuse_devicehub/views.py b/ereuse_devicehub/views.py index f6ed21f4..682d858d 100644 --- a/ereuse_devicehub/views.py +++ b/ereuse_devicehub/views.py @@ -1,9 +1,10 @@ import flask -from flask import Blueprint +from flask import Blueprint, request from flask.views import View from flask_login import current_user, login_required, login_user, logout_user -from ereuse_devicehub import __version__ +from ereuse_devicehub import __version__, messages +from ereuse_devicehub.db import db from ereuse_devicehub.forms import LoginForm, ProfileForm from ereuse_devicehub.resources.user.models import User from ereuse_devicehub.utils import is_safe_url @@ -46,11 +47,15 @@ class LogoutView(View): class UserProfileView(View): + methods = ['GET', 'POST'] decorators = [login_required] template_name = 'ereuse_devicehub/user_profile.html' def dispatch_request(self): form = ProfileForm() + if request.method == 'GET': + form = ProfileForm(user=current_user.individual) + sessions = {s.created.strftime('%H:%M %d-%m-%Y') for s in current_user.sessions} context = { 'current_user': current_user, @@ -58,6 +63,14 @@ class UserProfileView(View): 'version': __version__, 'profile_form': form, } + + if form.validate_on_submit(): + form.save(commit=False) + messages.success('Modify user Profile datas successfully!') + elif form.errors: + messages.error('Error modify user Profile data!') + + db.session.commit() return flask.render_template(self.template_name, **context) From 9d4ca5a2dcc21188b904457d19a6a67573ec9818 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 11 Apr 2022 19:48:59 +0200 Subject: [PATCH 05/22] change password --- ereuse_devicehub/forms.py | 43 +++++++++++++++++++ .../ereuse_devicehub/user_profile.html | 37 ++++++++-------- ereuse_devicehub/views.py | 26 +++++++++-- 3 files changed, 83 insertions(+), 23 deletions(-) diff --git a/ereuse_devicehub/forms.py b/ereuse_devicehub/forms.py index 1bfd7907..9789a06e 100644 --- a/ereuse_devicehub/forms.py +++ b/ereuse_devicehub/forms.py @@ -117,3 +117,46 @@ class ProfileForm(FlaskForm): db.session.add(agent) if commit: db.session.commit() + + +class PasswordForm(FlaskForm): + password = PasswordField( + 'Current Password', + [validators.DataRequired()], + render_kw={'class': "form-control"}, + ) + newpassword = PasswordField( + 'New Password', + [validators.DataRequired()], + render_kw={'class': "form-control"}, + ) + renewpassword = PasswordField( + 'Re-enter New Password', + [validators.DataRequired()], + render_kw={'class': "form-control"}, + ) + + def validate(self, extra_validators=None): + is_valid = super().validate(extra_validators) + + if not is_valid: + return False + + if not g.user.check_password(self.password.data): + self.password.errors = ['Incorrect password'] + return False + + if self.newpassword.data != self.renewpassword.data: + self.newpassword.errors = ['Is not the same password'] + self.renewpassword.errors = ['Is not the same password'] + return False + + return True + + def save(self, commit=True): + g.user.password = generate_password_hash(self.newpassword.data) + + db.session.add(g.user) + if commit: + db.session.commit() + return diff --git a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html index dba8db62..782b92c8 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html @@ -132,7 +132,7 @@ {{ f }} {% else %}
- +
{{ f }} {% if f.errors %} @@ -197,29 +197,26 @@
- - + + {% for f in password_form %} + {% if f == password_form.csrf_token %} + {{ f }} + {% else %}
- +
- + {{ f }} + {% if f.errors %} +

+ {% for error in f.errors %} + {{ error }}
+ {% endfor %} +

+ {% endif %}
- -
- -
- -
-
- -
- -
- -
-
- + {% endif %} + {% endfor %}
diff --git a/ereuse_devicehub/views.py b/ereuse_devicehub/views.py index 682d858d..bdbea6ae 100644 --- a/ereuse_devicehub/views.py +++ b/ereuse_devicehub/views.py @@ -5,7 +5,7 @@ from flask_login import current_user, login_required, login_user, logout_user from ereuse_devicehub import __version__, messages from ereuse_devicehub.db import db -from ereuse_devicehub.forms import LoginForm, ProfileForm +from ereuse_devicehub.forms import LoginForm, PasswordForm, ProfileForm from ereuse_devicehub.resources.user.models import User from ereuse_devicehub.utils import is_safe_url @@ -62,18 +62,38 @@ class UserProfileView(View): 'sessions': sessions, 'version': __version__, 'profile_form': form, + 'password_form': PasswordForm(), } if form.validate_on_submit(): form.save(commit=False) messages.success('Modify user Profile datas successfully!') + db.session.commit() elif form.errors: - messages.error('Error modify user Profile data!') + messages.error('Error modifying user Profile data!') + + return flask.render_template(self.template_name, **context) + + +class UserPasswordView(View): + methods = ['POST'] + decorators = [login_required] + + def dispatch_request(self): + form = PasswordForm() + # import pdb; pdb.set_trace() + db.session.commit() + if form.validate_on_submit(): + form.save(commit=False) + messages.success('Reset user password successfully!') + else: + messages.error('Error modifying user password!') db.session.commit() - return flask.render_template(self.template_name, **context) + return flask.redirect(flask.url_for('core.user-profile')) core.add_url_rule('/login/', view_func=LoginView.as_view('login')) core.add_url_rule('/logout/', view_func=LogoutView.as_view('logout')) core.add_url_rule('/profile/', view_func=UserProfileView.as_view('user-profile')) +core.add_url_rule('/set_password/', view_func=UserPasswordView.as_view('set-password')) From 46bfc7fd47ba9c11b1a70a5e61784228b780cc2d Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 12 Apr 2022 16:59:13 +0200 Subject: [PATCH 06/22] fix save correctly the new password and fix save profile --- ereuse_devicehub/forms.py | 7 ++----- ereuse_devicehub/views.py | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/ereuse_devicehub/forms.py b/ereuse_devicehub/forms.py index 9789a06e..c5ede0cc 100644 --- a/ereuse_devicehub/forms.py +++ b/ereuse_devicehub/forms.py @@ -104,7 +104,7 @@ class ProfileForm(FlaskForm): self.last_name.data = user.last_name self.email.data = user.email self.telephone.data = user.telephone - self.country.data = user.country + self.country.data = user.country.name def save(self, commit=True): agent = g.user.individual @@ -143,18 +143,15 @@ class PasswordForm(FlaskForm): return False if not g.user.check_password(self.password.data): - self.password.errors = ['Incorrect password'] return False if self.newpassword.data != self.renewpassword.data: - self.newpassword.errors = ['Is not the same password'] - self.renewpassword.errors = ['Is not the same password'] return False return True def save(self, commit=True): - g.user.password = generate_password_hash(self.newpassword.data) + g.user.password = self.newpassword.data db.session.add(g.user) if commit: diff --git a/ereuse_devicehub/views.py b/ereuse_devicehub/views.py index bdbea6ae..12f6d4ba 100644 --- a/ereuse_devicehub/views.py +++ b/ereuse_devicehub/views.py @@ -81,7 +81,6 @@ class UserPasswordView(View): def dispatch_request(self): form = PasswordForm() - # import pdb; pdb.set_trace() db.session.commit() if form.validate_on_submit(): form.save(commit=False) From 89bb4770d91eb2fb7806531f3bfdfcc2135ea1d3 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 12 Apr 2022 16:59:45 +0200 Subject: [PATCH 07/22] fix individual call --- ereuse_devicehub/resources/user/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ereuse_devicehub/resources/user/models.py b/ereuse_devicehub/resources/user/models.py index 039a4bf3..7981fec5 100644 --- a/ereuse_devicehub/resources/user/models.py +++ b/ereuse_devicehub/resources/user/models.py @@ -85,7 +85,7 @@ class User(UserMixin, Thing): @property def get_full_name(self): - if self.individual: + if self.individuals: return self.individual.get_full_name return self.email From 0d65dd768603696377a34dd5685b66602ffc71c6 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 13 Apr 2022 13:14:01 +0200 Subject: [PATCH 08/22] enums of tail --- ereuse_devicehub/enums.py | 4421 +++++++++++++++++++++++++++++++++++++ 1 file changed, 4421 insertions(+) create mode 100644 ereuse_devicehub/enums.py diff --git a/ereuse_devicehub/enums.py b/ereuse_devicehub/enums.py new file mode 100644 index 00000000..175b2227 --- /dev/null +++ b/ereuse_devicehub/enums.py @@ -0,0 +1,4421 @@ +from enum import Enum, unique + + +@unique +class Currency(Enum): + """Currencies as for ISO 4217.""" + + AFN = 1 + ARS = 2 + AWG = 3 + AUD = 4 + AZN = 5 + BSD = 6 + BBD = 7 + BDT = 8 + BYR = 9 + BZD = 10 + BMD = 11 + BOB = 12 + BAM = 13 + BWP = 14 + BGN = 15 + BRL = 16 + BND = 17 + KHR = 18 + CAD = 19 + KYD = 20 + CLP = 21 + CNY = 22 + COP = 23 + CRC = 24 + HRK = 25 + CUP = 26 + CZK = 27 + DKK = 28 + DOP = 29 + XCD = 30 + EGP = 31 + SVC = 32 + EEK = 33 + EUR = 34 + FKP = 35 + FJD = 36 + GHC = 37 + GIP = 38 + GTQ = 39 + GGP = 40 + GYD = 41 + HNL = 42 + HKD = 43 + HUF = 44 + ISK = 45 + INR = 46 + IDR = 47 + IRR = 48 + IMP = 49 + ILS = 50 + JMD = 51 + JPY = 52 + JEP = 53 + KZT = 54 + KPW = 55 + KRW = 56 + KGS = 57 + LAK = 58 + LVL = 59 + LBP = 60 + LRD = 61 + LTL = 62 + MKD = 63 + MYR = 64 + MUR = 65 + MXN = 66 + MNT = 67 + MZN = 68 + NAD = 69 + NPR = 70 + ANG = 71 + NZD = 72 + NIO = 73 + NGN = 74 + NOK = 75 + OMR = 76 + PKR = 77 + PAB = 78 + PYG = 79 + PEN = 80 + PHP = 81 + PLN = 82 + QAR = 83 + RON = 84 + RUB = 85 + SHP = 86 + SAR = 87 + RSD = 88 + SCR = 89 + SGD = 90 + SBD = 91 + SOS = 92 + ZAR = 93 + LKR = 94 + SEK = 95 + CHF = 96 + SRD = 97 + SYP = 98 + TWD = 99 + THB = 100 + TTD = 101 + TRY = 102 + TRL = 103 + TVD = 104 + UAH = 105 + GBP = 106 + USD = 107 + UYU = 108 + UZS = 109 + VEF = 110 + VND = 111 + YER = 112 + ZWD = 113 + + def __str__(self): + if self == Currency.EUR: + return '€' + else: + return self.name + + +@unique +class Continent(Enum): + """ + Continent codes. + + From `Data hub `_. + """ + + AF = 'Africa' + NA = 'North America' + OC = 'Oceania' + AN = 'Antartica' + AS = 'Asia' + EU = 'Europe' + SA = 'South America' + + +@unique +class Country(Enum): + """ + Countries as ISO 3166-1 alpha 2. + + Taken from table from `iso-3616-1 commit + 8e31d749b9ce331cfa50c280a29b04ae2d805b7e `_. + """ + + AF = "Afghanistan" + AX = "Åland Islands" + AL = "Albania" + DZ = "Algeria" + AS = "American Samoa" + AD = "Andorra" + AO = "Angola" + AI = "Anguilla" + AQ = "Antarctica" + AG = "Antigua and Barbuda" + AR = "Argentina" + AM = "Armenia" + AW = "Aruba" + AU = "Australia" + AT = "Austria" + AZ = "Azerbaijan" + BS = "Bahamas" + BH = "Bahrain" + BD = "Bangladesh" + BB = "Barbados" + BY = "Belarus" + BE = "Belgium" + BZ = "Belize" + BJ = "Benin" + BM = "Bermuda" + BT = "Bhutan" + BO = "Bolivia (Plurinational State of)" + BQ = "Bonaire, Sint Eustatius and Saba" + BA = "Bosnia and Herzegovina" + BW = "Botswana" + BV = "Bouvet Island" + BR = "Brazil" + IO = "British Indian Ocean Territory" + BN = "Brunei Darussalam" + BG = "Bulgaria" + BF = "Burkina Faso" + BI = "Burundi" + KH = "Cambodia" + CM = "Cameroon" + CA = "Canada" + CV = "Cabo Verde" + KY = "Cayman Islands" + CF = "Central African Republic" + TD = "Chad" + CL = "Chile" + CN = "China" + CX = "Christmas Island" + CC = "Cocos (Keeling) Islands" + CO = "Colombia" + KM = "Comoros" + CG = "Congo" + CD = "Congo (Democratic Republic of the)" + CK = "Cook Islands" + CR = "Costa Rica" + CI = "Côte d'Ivoire" + HR = "Croatia" + CU = "Cuba" + CW = "Curaçao" + CY = "Cyprus" + CZ = "Czech Republic" + DK = "Denmark" + DJ = "Djibouti" + DM = "Dominica" + DO = "Dominican Republic" + EC = "Ecuador" + EG = "Egypt" + SV = "El Salvador" + GQ = "Equatorial Guinea" + ER = "Eritrea" + EE = "Estonia" + ET = "Ethiopia" + FK = "Falkland Islands (Malvinas)" + FO = "Faroe Islands" + FJ = "Fiji" + FI = "Finland" + FR = "France" + GF = "French Guiana" + PF = "French Polynesia" + TF = "French Southern Territories" + GA = "Gabon" + GM = "Gambia" + GE = "Georgia" + DE = "Germany" + GH = "Ghana" + GI = "Gibraltar" + GR = "Greece" + GL = "Greenland" + GD = "Grenada" + GP = "Guadeloupe" + GU = "Guam" + GT = "Guatemala" + GG = "Guernsey" + GN = "Guinea" + GW = "Guinea-Bissau" + GY = "Guyana" + HT = "Haiti" + HM = "Heard Island and McDonald Islands" + VA = "Holy See" + HN = "Honduras" + HK = "Hong Kong" + HU = "Hungary" + IS = "Iceland" + IN = "India" + ID = "Indonesia" + IR = "Iran (Islamic Republic of)" + IQ = "Iraq" + IE = "Ireland" + IM = "Isle of Man" + IL = "Israel" + IT = "Italy" + JM = "Jamaica" + JP = "Japan" + JE = "Jersey" + JO = "Jordan" + KZ = "Kazakhstan" + KE = "Kenya" + KI = "Kiribati" + KP = "Korea (Democratic People's Republic of)" + KR = "Korea (Republic of)" + KW = "Kuwait" + KG = "Kyrgyzstan" + LA = "Lao People's Democratic Republic" + LV = "Latvia" + LB = "Lebanon" + LS = "Lesotho" + LR = "Liberia" + LY = "Libya" + LI = "Liechtenstein" + LT = "Lithuania" + LU = "Luxembourg" + MO = "Macao" + MK = "Macedonia (the former Yugoslav Republic of)" + MG = "Madagascar" + MW = "Malawi" + MY = "Malaysia" + MV = "Maldives" + ML = "Mali" + MT = "Malta" + MH = "Marshall Islands" + MQ = "Martinique" + MR = "Mauritania" + MU = "Mauritius" + YT = "Mayotte" + MX = "Mexico" + FM = "Micronesia (Federated States of)" + MD = "Moldova (Republic of)" + MC = "Monaco" + MN = "Mongolia" + ME = "Montenegro" + MS = "Montserrat" + MA = "Morocco" + MZ = "Mozambique" + MM = "Myanmar" + NA = "Namibia" + NR = "Nauru" + NP = "Nepal" + NL = "Netherlands" + NC = "New Caledonia" + NZ = "New Zealand" + NI = "Nicaragua" + NE = "Niger" + NG = "Nigeria" + NU = "Niue" + NF = "Norfolk Island" + MP = "Northern Mariana Islands" + NO = "Norway" + OM = "Oman" + PK = "Pakistan" + PW = "Palau" + PS = "Palestine, State of" + PA = "Panama" + PG = "Papua New Guinea" + PY = "Paraguay" + PE = "Peru" + PH = "Philippines" + PN = "Pitcairn" + PL = "Poland" + PT = "Portugal" + PR = "Puerto Rico" + QA = "Qatar" + RE = "Réunion" + RO = "Romania" + RU = "Russian Federation" + RW = "Rwanda" + BL = "Saint Barthélemy" + SH = "Saint Helena, Ascension and Tristan da Cunha" + KN = "Saint Kitts and Nevis" + LC = "Saint Lucia" + MF = "Saint Martin (French part)" + PM = "Saint Pierre and Miquelon" + VC = "Saint Vincent and the Grenadines" + WS = "Samoa" + SM = "San Marino" + ST = "Sao Tome and Principe" + SA = "Saudi Arabia" + SN = "Senegal" + RS = "Serbia" + SC = "Seychelles" + SL = "Sierra Leone" + SG = "Singapore" + SX = "Sint Maarten (Dutch part)" + SK = "Slovakia" + SI = "Slovenia" + SB = "Solomon Islands" + SO = "Somalia" + ZA = "South Africa" + GS = "South Georgia and the South Sandwich Islands" + SS = "South Sudan" + ES = "Spain" + LK = "Sri Lanka" + SD = "Sudan" + SR = "Suriname" + SJ = "Svalbard and Jan Mayen" + SZ = "Swaziland" + SE = "Sweden" + CH = "Switzerland" + SY = "Syrian Arab Republic" + TW = "Taiwan, Province of China" + TJ = "Tajikistan" + TZ = "Tanzania, United Republic of" + TH = "Thailand" + TL = "Timor-Leste" + TG = "Togo" + TK = "Tokelau" + TO = "Tonga" + TT = "Trinidad and Tobago" + TN = "Tunisia" + TR = "Turkey" + TM = "Turkmenistan" + TC = "Turks and Caicos Islands" + TV = "Tuvalu" + UG = "Uganda" + UA = "Ukraine" + AE = "United Arab Emirates" + GB = "United Kingdom of Great Britain and Northern Ireland" + US = "United States of America" + UM = "United States Minor Outlying Islands" + UY = "Uruguay" + UZ = "Uzbekistan" + VU = "Vanuatu" + VE = "Venezuela (Bolivarian Republic of)" + VN = "Viet Nam" + VG = "Virgin Islands (British)" + VI = "Virgin Islands (U.S.)" + WF = "Wallis and Futuna" + EH = "Western Sahara" + YE = "Yemen" + ZM = "Zambia" + ZW = "Zimbabwe" + + def __contains__(self, item: 'Subdivision'): + """Checks if a Subdivision is inside of this Country.""" + if not isinstance(item, Subdivision): + raise TypeError('Only subdivisions can be inside a country.') + return item.country == self + + def __str__(self): + return self.value + + +class SubdivisionMixin: + @property + def country(self: Enum) -> Country: + """Returns the Country of the Subdivision.""" + return Country[self.name[0:2]] + + +# noinspection PyArgumentList +Subdivision = Enum( + 'Subdivision', + type=SubdivisionMixin, + module=__name__, + names=( + 'AE-AJ', + 'AE-AZ', + 'AE-DU', + 'AE-FU', + 'AE-RK', + 'AE-SH', + 'AE-UQ', + 'AF-BAL', + 'AF-BAM', + 'AF-BDG', + 'AF-BDS', + 'AF-BGL', + 'AF-FRAU', + 'AF-FYB', + 'AF-GHA', + 'AF-GHO', + 'AF-HEL', + 'AF-HER', + 'AF-JOW', + 'AF-KAB', + 'AF-KANN', + 'AF-KAP', + 'AF-KDZ', + 'AF-KNR', + 'AF-LAG', + 'AF-LOW', + 'AF-NAN', + 'AF-NIM', + 'AF-ORU', + 'AF-PAR', + 'AF-PIA', + 'AF-PKA', + 'AF-SAM', + 'AF-SAR', + 'AF-TAK', + 'AF-WAR', + 'AF-ZAB', + 'AL-BR', + 'AL-BU', + 'AL-DI', + 'AL-DL', + 'AL-DR', + 'AL-DV', + 'AL-EL', + 'AL-ER', + 'AL-FR', + 'AL-GJ', + 'AL-GR', + 'AL-HA', + 'AL-KA', + 'AL-KB', + 'AL-KC', + 'AL-KO', + 'AL-KR', + 'AL-KU', + 'AL-LA', + 'AL-LB', + 'AL-LE', + 'AL-LU', + 'AL-MK', + 'AL-MM', + 'AL-MR', + 'AL-MT', + 'AL-PG', + 'AL-PQ', + 'AL-PR', + 'AL-PU', + 'AL-SH', + 'AL-SK', + 'AL-SR', + 'AL-TE', + 'AL-TP', + 'AL-TR', + 'AL-VL', + 'AM-AG', + 'AM-AR', + 'AM-AV', + 'AM-ER', + 'AM-GR', + 'AM-KT', + 'AM-LO', + 'AM-SH', + 'AM-SU', + 'AM-TV', + 'AM-VD', + 'AO-BGO', + 'AO-BGU', + 'AO-BIE', + 'AO-CAB', + 'AO-CCU', + 'AO-CNN', + 'AO-CNO', + 'AO-CUS', + 'AO-HUA', + 'AO-HUI', + 'AO-LNO', + 'AO-LSU', + 'AO-LUA', + 'AO-MAL', + 'AO-MOX', + 'AO-NAM', + 'AO-UIG', + 'AO-ZAI', + 'AR-A', + 'AR-B', + 'AR-C', + 'AR-D', + 'AR-E', + 'AR-F', + 'AR-G', + 'AR-H', + 'AR-J', + 'AR-K', + 'AR-L', + 'AR-M', + 'AR-N', + 'AR-P', + 'AR-Q', + 'AR-R', + 'AR-S', + 'AR-T', + 'AR-U', + 'AR-V', + 'AR-W', + 'AR-X', + 'AR-Y', + 'AR-Z', + 'AT-1', + 'AT-2', + 'AT-3', + 'AT-4', + 'AT-5', + 'AT-6', + 'AT-7', + 'AT-8', + 'AT-9', + 'AU-CT', + 'AU-NS', + 'AU-NT', + 'AU-QL', + 'AU-SA', + 'AU-TS', + 'AU-VI', + 'AU-WA', + 'AZ-AB', + 'AZ-ABS', + 'AZ-AGA', + 'AZ-AGC', + 'AZ-AGM', + 'AZ-AGS', + 'AZ-AGU', + 'AZ-AST', + 'AZ-BA', + 'AZ-BAB', + 'AZ-BAL', + 'AZ-BAR', + 'AZ-BEY', + 'AZ-BIL', + 'AZ-CAB', + 'AZ-CAL', + 'AZ-CUL', + 'AZ-DAS', + 'AZ-DAV', + 'AZ-FUZ', + 'AZ-GA', + 'AZ-GAD', + 'AZ-GOR', + 'AZ-GOY', + 'AZ-HAC', + 'AZ-IMI', + 'AZ-ISM', + 'AZ-KAL', + 'AZ-KUR', + 'AZ-LA', + 'AZ-LAC', + 'AZ-LAN', + 'AZ-LER', + 'AZ-MAS', + 'AZ-MI', + 'AZ-MM', + 'AZ-NA', + 'AZ-NEF', + 'AZ-OGU', + 'AZ-ORD', + 'AZ-QAB', + 'AZ-QAX', + 'AZ-QAZ', + 'AZ-QBA', + 'AZ-QBI', + 'AZ-QOB', + 'AZ-QUS', + 'AZ-SA', + 'AZ-SAB', + 'AZ-SAD', + 'AZ-SAH', + 'AZ-SAK', + 'AZ-SAL', + 'AZ-SAR', + 'AZ-SAT', + 'AZ-SIY', + 'AZ-SKR', + 'AZ-SM', + 'AZ-SMI', + 'AZ-SMX', + 'AZ-SS', + 'AZ-SUS', + 'AZ-TAR', + 'AZ-TOV', + 'AZ-UCA', + 'AZ-XA', + 'AZ-XAC', + 'AZ-XAN', + 'AZ-XCI', + 'AZ-XIZ', + 'AZ-XVD', + 'AZ-YAR', + 'AZ-YE', + 'AZ-YEV', + 'AZ-ZAN', + 'AZ-ZAQ', + 'AZ-ZAR', + 'BA-BIH', + 'BA-SRP', + 'BD-01', + 'BD-02', + 'BD-03', + 'BD-04', + 'BD-05', + 'BD-06', + 'BD-07', + 'BD-08', + 'BD-09', + 'BD-1', + 'BD-10', + 'BD-11', + 'BD-12', + 'BD-13', + 'BD-14', + 'BD-15', + 'BD-16', + 'BD-17', + 'BD-18', + 'BD-19', + 'BD-2', + 'BD-20', + 'BD-21', + 'BD-22', + 'BD-23', + 'BD-24', + 'BD-25', + 'BD-26', + 'BD-27', + 'BD-28', + 'BD-29', + 'BD-3', + 'BD-30', + 'BD-31', + 'BD-32', + 'BD-33', + 'BD-34', + 'BD-35', + 'BD-36', + 'BD-37', + 'BD-38', + 'BD-39', + 'BD-4', + 'BD-40', + 'BD-41', + 'BD-42', + 'BD-43', + 'BD-44', + 'BD-45', + 'BD-46', + 'BD-47', + 'BD-48', + 'BD-49', + 'BD-5', + 'BD-50', + 'BD-51', + 'BD-52', + 'BD-53', + 'BD-54', + 'BD-55', + 'BD-56', + 'BD-57', + 'BD-58', + 'BD-59', + 'BD-6', + 'BD-60', + 'BD-61', + 'BD-62', + 'BD-63', + 'BD-64', + 'BE-BRU', + 'BE-VAN', + 'BE-VBR', + 'BE-VLG', + 'BE-VLI', + 'BE-VOV', + 'BE-VWV', + 'BE-WAL', + 'BE-WBR', + 'BE-WHT', + 'BE-WLG', + 'BE-WLX', + 'BE-WNA', + 'BF-BAL', + 'BF-BAM', + 'BF-BAN', + 'BF-BAZ', + 'BF-BGR', + 'BF-BLG', + 'BF-BLK', + 'BF-COM', + 'BF-GAN', + 'BF-GNA', + 'BF-GOU', + 'BF-HOU', + 'BF-IOB', + 'BF-KAD', + 'BF-KEN', + 'BF-KMD', + 'BF-KMP', + 'BF-KOP', + 'BF-KOS', + 'BF-KOT', + 'BF-KOW', + 'BF-LER', + 'BF-LOR', + 'BF-MOU', + 'BF-NAM', + 'BF-NAO', + 'BF-NAY', + 'BF-NOU', + 'BF-OUB', + 'BF-OUD', + 'BF-PAS', + 'BF-PON', + 'BF-SEN', + 'BF-SIS', + 'BF-SMT', + 'BF-SNG', + 'BF-SOM', + 'BF-SOR', + 'BF-TAP', + 'BF-TUI', + 'BF-YAG', + 'BF-YAT', + 'BF-ZIR', + 'BF-ZON', + 'BF-ZOU', + 'BG-01', + 'BG-02', + 'BG-03', + 'BG-04', + 'BG-05', + 'BG-06', + 'BG-07', + 'BG-08', + 'BG-09', + 'BG-10', + 'BG-11', + 'BG-12', + 'BG-13', + 'BG-14', + 'BG-15', + 'BG-16', + 'BG-17', + 'BG-18', + 'BG-19', + 'BG-20', + 'BG-21', + 'BG-22', + 'BG-23', + 'BG-24', + 'BG-25', + 'BG-26', + 'BG-27', + 'BG-28', + 'BH-01', + 'BH-02', + 'BH-03', + 'BH-04', + 'BH-05', + 'BH-06', + 'BH-07', + 'BH-08', + 'BH-09', + 'BH-10', + 'BH-11', + 'BH-12', + 'BI-BB', + 'BI-BJ', + 'BI-BR', + 'BI-CA', + 'BI-CI', + 'BI-GI', + 'BI-KI', + 'BI-KR', + 'BI-KY', + 'BI-MA', + 'BI-MU', + 'BI-MW', + 'BI-MY', + 'BI-NG', + 'BI-RT', + 'BI-RY', + 'BJ-AK', + 'BJ-AL', + 'BJ-AQ', + 'BJ-BO', + 'BJ-CO', + 'BJ-DO', + 'BJ-KO', + 'BJ-LI', + 'BJ-MO', + 'BJ-OU', + 'BJ-PL', + 'BJ-ZO', + 'BN-BE', + 'BN-BM', + 'BN-TE', + 'BN-TU', + 'BO-B', + 'BO-C', + 'BO-H', + 'BO-L', + 'BO-N', + 'BO-O', + 'BO-P', + 'BO-S', + 'BO-T', + 'BR-AC', + 'BR-AL', + 'BR-AM', + 'BR-AP', + 'BR-BA', + 'BR-CE', + 'BR-DF', + 'BR-ES', + 'BR-GO', + 'BR-MA', + 'BR-MG', + 'BR-MS', + 'BR-MT', + 'BR-PA', + 'BR-PB', + 'BR-PE', + 'BR-PI', + 'BR-PR', + 'BR-RJ', + 'BR-RN', + 'BR-RO', + 'BR-RR', + 'BR-RS', + 'BR-SC', + 'BR-SE', + 'BR-SP', + 'BR-TO', + 'BS-AC', + 'BS-BI', + 'BS-CI', + 'BS-EX', + 'BS-FC', + 'BS-FP', + 'BS-GH', + 'BS-GT', + 'BS-HI', + 'BS-HR', + 'BS-IN', + 'BS-KB', + 'BS-LI', + 'BS-MG', + 'BS-MH', + 'BS-NB', + 'BS-NP', + 'BS-RI', + 'BS-RS', + 'BS-SP', + 'BS-SR', + 'BT-11', + 'BT-12', + 'BT-13', + 'BT-14', + 'BT-15', + 'BT-21', + 'BT-22', + 'BT-23', + 'BT-24', + 'BT-31', + 'BT-32', + 'BT-33', + 'BT-34', + 'BT-41', + 'BT-42', + 'BT-43', + 'BT-44', + 'BT-45', + 'BT-GA', + 'BT-TY', + 'BW-CE', + 'BW-CH', + 'BW-GH', + 'BW-KG', + 'BW-KL', + 'BW-KW', + 'BW-NE', + 'BW-NG', + 'BW-SE', + 'BW-SO', + 'BY-BR', + 'BY-HO', + 'BY-HR', + 'BY-MA', + 'BY-MI', + 'BY-VI', + 'BZ-BZ', + 'BZ-CY', + 'BZ-CZL', + 'BZ-OW', + 'BZ-SC', + 'BZ-TOL', + 'CA-AB', + 'CA-BC', + 'CA-MB', + 'CA-NB', + 'CA-NL', + 'CA-NS', + 'CA-NT', + 'CA-NU', + 'CA-ON', + 'CA-PE', + 'CA-QC', + 'CA-SK', + 'CA-YT', + 'CD-BC', + 'CD-BN', + 'CD-EQ', + 'CD-KA', + 'CD-KE', + 'CD-KN', + 'CD-KW', + 'CD-MA', + 'CD-NK', + 'CD-OR', + 'CD-SK', + 'CF-AC', + 'CF-BB', + 'CF-BGF', + 'CF-BK', + 'CF-HK', + 'CF-HM', + 'CF-HS', + 'CF-KB', + 'CF-KG', + 'CF-LB', + 'CF-MB', + 'CF-MP', + 'CF-NM', + 'CF-OP', + 'CF-SE', + 'CF-UK', + 'CF-VK', + 'CG-11', + 'CG-12', + 'CG-13', + 'CG-14', + 'CG-15', + 'CG-2', + 'CG-5', + 'CG-7', + 'CG-8', + 'CG-9', + 'CG-BZV', + 'CH-AG', + 'CH-AI', + 'CH-AR', + 'CH-BE', + 'CH-BL', + 'CH-BS', + 'CH-FR', + 'CH-GE', + 'CH-GL', + 'CH-GR', + 'CH-JU', + 'CH-LU', + 'CH-NE', + 'CH-NW', + 'CH-OW', + 'CH-SG', + 'CH-SH', + 'CH-SO', + 'CH-SZ', + 'CH-TG', + 'CH-TI', + 'CH-UR', + 'CH-VD', + 'CH-VS', + 'CH-ZG', + 'CH-ZH', + 'CI-01', + 'CI-02', + 'CI-03', + 'CI-04', + 'CI-05', + 'CI-06', + 'CI-07', + 'CI-08', + 'CI-09', + 'CI-10', + 'CI-11', + 'CI-12', + 'CI-13', + 'CI-14', + 'CI-15', + 'CI-16', + 'CL-AI', + 'CL-AN', + 'CL-AR', + 'CL-AT', + 'CL-BI', + 'CL-CO', + 'CL-LI', + 'CL-LL', + 'CL-MA', + 'CL-ML', + 'CL-RM', + 'CL-TA', + 'CL-VS', + 'CM-AD', + 'CM-CE', + 'CM-EN', + 'CM-ES', + 'CM-LT', + 'CM-NO', + 'CM-NW', + 'CM-OU', + 'CM-SU', + 'CM-SW', + 'CN-11', + 'CN-12', + 'CN-13', + 'CN-14', + 'CN-15', + 'CN-21', + 'CN-22', + 'CN-23', + 'CN-31', + 'CN-32', + 'CN-33', + 'CN-34', + 'CN-35', + 'CN-36', + 'CN-37', + 'CN-41', + 'CN-42', + 'CN-43', + 'CN-44', + 'CN-45', + 'CN-46', + 'CN-50', + 'CN-51', + 'CN-52', + 'CN-53', + 'CN-54', + 'CN-61', + 'CN-62', + 'CN-63', + 'CN-64', + 'CN-65', + 'CN-71', + 'CN-91', + 'CN-92', + 'CO-AMA', + 'CO-ANT', + 'CO-ARA', + 'CO-ATL', + 'CO-BOL', + 'CO-BOY', + 'CO-CAL', + 'CO-CAQ', + 'CO-CAS', + 'CO-CAU', + 'CO-CES', + 'CO-CHO', + 'CO-COR', + 'CO-CUN', + 'CO-DC', + 'CO-GUA', + 'CO-GUV', + 'CO-HUI', + 'CO-LAG', + 'CO-MAG', + 'CO-MET', + 'CO-NAR', + 'CO-NSA', + 'CO-PUT', + 'CO-QUI', + 'CO-RIS', + 'CO-SAN', + 'CO-SAP', + 'CO-SUC', + 'CO-TOL', + 'CO-VAC', + 'CO-VAU', + 'CO-VID', + 'CR-A', + 'CR-C', + 'CR-G', + 'CR-H', + 'CR-L', + 'CR-P', + 'CR-SJ', + 'CU-01', + 'CU-02', + 'CU-03', + 'CU-04', + 'CU-05', + 'CU-06', + 'CU-07', + 'CU-08', + 'CU-09', + 'CU-10', + 'CU-11', + 'CU-12', + 'CU-13', + 'CU-14', + 'CU-99', + 'CV-B', + 'CV-BR', + 'CV-BV', + 'CV-CA', + 'CV-CR', + 'CV-CS', + 'CV-FO', + 'CV-MA', + 'CV-MO', + 'CV-PA', + 'CV-PN', + 'CV-PR', + 'CV-RG', + 'CV-S', + 'CV-SF', + 'CV-SL', + 'CV-SN', + 'CV-SV', + 'CV-TA', + 'CY-01', + 'CY-02', + 'CY-03', + 'CY-04', + 'CY-05', + 'CY-06', + 'CZ-JC', + 'CZ-JM', + 'CZ-KA', + 'CZ-KR', + 'CZ-LI', + 'CZ-MO', + 'CZ-OL', + 'CZ-PA', + 'CZ-PL', + 'CZ-PR', + 'CZ-ST', + 'CZ-US', + 'CZ-VY', + 'CZ-ZL', + 'DE-BB', + 'DE-BE', + 'DE-BW', + 'DE-BY', + 'DE-HB', + 'DE-HE', + 'DE-HH', + 'DE-MV', + 'DE-NI', + 'DE-NW', + 'DE-RP', + 'DE-SH', + 'DE-SL', + 'DE-SN', + 'DE-ST', + 'DE-TH', + 'DJ-AS', + 'DJ-DI', + 'DJ-DJ', + 'DJ-OB', + 'DJ-TA', + 'DK-015', + 'DK-020', + 'DK-025', + 'DK-030', + 'DK-035', + 'DK-040', + 'DK-042', + 'DK-050', + 'DK-055', + 'DK-060', + 'DK-065', + 'DK-070', + 'DK-076', + 'DK-080', + 'DK-101', + 'DK-147', + 'DO-01', + 'DO-02', + 'DO-03', + 'DO-04', + 'DO-05', + 'DO-06', + 'DO-07', + 'DO-08', + 'DO-09', + 'DO-10', + 'DO-11', + 'DO-12', + 'DO-13', + 'DO-14', + 'DO-15', + 'DO-16', + 'DO-17', + 'DO-18', + 'DO-19', + 'DO-20', + 'DO-21', + 'DO-22', + 'DO-23', + 'DO-24', + 'DO-25', + 'DO-26', + 'DO-27', + 'DO-28', + 'DO-29', + 'DO-30', + 'DZ-01', + 'DZ-02', + 'DZ-03', + 'DZ-04', + 'DZ-05', + 'DZ-06', + 'DZ-07', + 'DZ-08', + 'DZ-09', + 'DZ-10', + 'DZ-11', + 'DZ-12', + 'DZ-13', + 'DZ-14', + 'DZ-15', + 'DZ-16', + 'DZ-17', + 'DZ-18', + 'DZ-19', + 'DZ-20', + 'DZ-21', + 'DZ-22', + 'DZ-23', + 'DZ-24', + 'DZ-25', + 'DZ-26', + 'DZ-27', + 'DZ-28', + 'DZ-29', + 'DZ-30', + 'DZ-31', + 'DZ-32', + 'DZ-33', + 'DZ-34', + 'DZ-35', + 'DZ-36', + 'DZ-37', + 'DZ-38', + 'DZ-39', + 'DZ-40', + 'DZ-41', + 'DZ-42', + 'DZ-43', + 'DZ-44', + 'DZ-45', + 'DZ-46', + 'DZ-47', + 'DZ-48', + 'EC-A', + 'EC-B', + 'EC-C', + 'EC-D', + 'EC-E', + 'EC-F', + 'EC-G', + 'EC-H', + 'EC-I', + 'EC-L', + 'EC-M', + 'EC-N', + 'EC-O', + 'EC-P', + 'EC-R', + 'EC-S', + 'EC-T', + 'EC-U', + 'EC-W', + 'EC-X', + 'EC-Y', + 'EC-Z', + 'EE-37', + 'EE-39', + 'EE-44', + 'EE-49', + 'EE-51', + 'EE-57', + 'EE-59', + 'EE-65', + 'EE-67', + 'EE-70', + 'EE-74', + 'EE-78', + 'EE-82', + 'EE-84', + 'EE-86', + 'EG-ALX', + 'EG-ASN', + 'EG-AST', + 'EG-BA', + 'EG-BH', + 'EG-BNS', + 'EG-C', + 'EG-DK', + 'EG-DT', + 'EG-FYM', + 'EG-GH', + 'EG-GZ', + 'EG-IS', + 'EG-JS', + 'EG-KB', + 'EG-KFS', + 'EG-KN', + 'EG-MN', + 'EG-MNF', + 'EG-MT', + 'EG-PTS', + 'EG-SHG', + 'EG-SHR', + 'EG-SIN', + 'EG-SUZ', + 'EG-WAD', + 'ER-AN', + 'ER-DK', + 'ER-DU', + 'ER-GB', + 'ER-MA', + 'ER-SK', + 'ES-A', + 'ES-AB', + 'ES-AL', + 'ES-AN', + 'ES-AR', + 'ES-AV', + 'ES-B', + 'ES-BA', + 'ES-BI', + 'ES-BU', + 'ES-C', + 'ES-CA', + 'ES-CC', + 'ES-CE', + 'ES-CL', + 'ES-CM', + 'ES-CN', + 'ES-CO', + 'ES-CR', + 'ES-CS', + 'ES-CT', + 'ES-CU', + 'ES-EX', + 'ES-GA', + 'ES-GC', + 'ES-GI', + 'ES-GR', + 'ES-GU', + 'ES-H', + 'ES-HU', + 'ES-J', + 'ES-L', + 'ES-LE', + 'ES-LO', + 'ES-LU', + 'ES-M', + 'ES-MA', + 'ES-ML', + 'ES-MU', + 'ES-NA', + 'ES-O', + 'ES-OR', + 'ES-P', + 'ES-PM', + 'ES-PO', + 'ES-PV', + 'ES-S', + 'ES-SA', + 'ES-SE', + 'ES-SG', + 'ES-SO', + 'ES-SS', + 'ES-T', + 'ES-TE', + 'ES-TF', + 'ES-TO', + 'ES-V', + 'ES-VA', + 'ES-VC', + 'ES-VI', + 'ES-Z', + 'ES-ZA', + 'ET-AA', + 'ET-AF', + 'ET-AM', + 'ET-BE', + 'ET-DD', + 'ET-GA', + 'ET-HA', + 'ET-OR', + 'ET-SN', + 'ET-SO', + 'ET-TI', + 'FI-AL', + 'FI-ES', + 'FI-IS', + 'FI-LL', + 'FI-LS', + 'FI-OL', + 'FJ-C', + 'FJ-E', + 'FJ-N', + 'FJ-R', + 'FJ-W', + 'FM-KSA', + 'FM-PNI', + 'FM-TRK', + 'FM-YAP', + 'FR-01', + 'FR-02', + 'FR-03', + 'FR-04', + 'FR-05', + 'FR-06', + 'FR-07', + 'FR-08', + 'FR-09', + 'FR-10', + 'FR-11', + 'FR-12', + 'FR-13', + 'FR-14', + 'FR-15', + 'FR-16', + 'FR-17', + 'FR-18', + 'FR-19', + 'FR-21', + 'FR-22', + 'FR-23', + 'FR-24', + 'FR-25', + 'FR-26', + 'FR-27', + 'FR-28', + 'FR-29', + 'FR-2A', + 'FR-2B', + 'FR-30', + 'FR-31', + 'FR-32', + 'FR-33', + 'FR-34', + 'FR-35', + 'FR-36', + 'FR-37', + 'FR-38', + 'FR-39', + 'FR-40', + 'FR-41', + 'FR-42', + 'FR-43', + 'FR-44', + 'FR-45', + 'FR-46', + 'FR-47', + 'FR-48', + 'FR-49', + 'FR-50', + 'FR-51', + 'FR-52', + 'FR-53', + 'FR-54', + 'FR-55', + 'FR-56', + 'FR-57', + 'FR-58', + 'FR-59', + 'FR-60', + 'FR-61', + 'FR-62', + 'FR-63', + 'FR-64', + 'FR-65', + 'FR-66', + 'FR-67', + 'FR-68', + 'FR-69', + 'FR-70', + 'FR-71', + 'FR-72', + 'FR-73', + 'FR-74', + 'FR-75', + 'FR-76', + 'FR-77', + 'FR-78', + 'FR-79', + 'FR-80', + 'FR-81', + 'FR-82', + 'FR-83', + 'FR-84', + 'FR-85', + 'FR-86', + 'FR-87', + 'FR-88', + 'FR-89', + 'FR-90', + 'FR-91', + 'FR-92', + 'FR-93', + 'FR-94', + 'FR-95', + 'FR-A', + 'FR-B', + 'FR-C', + 'FR-D', + 'FR-E', + 'FR-F', + 'FR-G', + 'FR-GF', + 'FR-GP', + 'FR-H', + 'FR-I', + 'FR-J', + 'FR-K', + 'FR-L', + 'FR-M', + 'FR-MQ', + 'FR-N', + 'FR-NC', + 'FR-O', + 'FR-P', + 'FR-PF', + 'FR-PM', + 'FR-Q', + 'FR-R', + 'FR-RE', + 'FR-S', + 'FR-T', + 'FR-TF', + 'FR-U', + 'FR-V', + 'FR-WF', + 'FR-YT', + 'GA-1', + 'GA-2', + 'GA-3', + 'GA-4', + 'GA-5', + 'GA-6', + 'GA-7', + 'GA-8', + 'GA-9', + 'GB-ABD', + 'GB-ABE', + 'GB-AGB', + 'GB-AGY', + 'GB-ANS', + 'GB-ANT', + 'GB-ARD', + 'GB-ARM', + 'GB-BAS', + 'GB-BBD', + 'GB-BDF', + 'GB-BDG', + 'GB-BEN', + 'GB-BEX', + 'GB-BFS', + 'GB-BGE', + 'GB-BGW', + 'GB-BIR', + 'GB-BKM', + 'GB-BLA', + 'GB-BLY', + 'GB-BMH', + 'GB-BNB', + 'GB-BNE', + 'GB-BNH', + 'GB-BNS', + 'GB-BOL', + 'GB-BPL', + 'GB-BRC', + 'GB-BRD', + 'GB-BRY', + 'GB-BST', + 'GB-BUR', + 'GB-CAM', + 'GB-CAY', + 'GB-CGN', + 'GB-CGV', + 'GB-CHA', + 'GB-CHS', + 'GB-CKF', + 'GB-CKT', + 'GB-CLD', + 'GB-CLK', + 'GB-CLR', + 'GB-CMA', + 'GB-CMD', + 'GB-CMN', + 'GB-CON', + 'GB-COV', + 'GB-CRF', + 'GB-CRY', + 'GB-CSR', + 'GB-CWY', + 'GB-DAL', + 'GB-DBY', + 'GB-DEN', + 'GB-DER', + 'GB-DEV', + 'GB-DGN', + 'GB-DGY', + 'GB-DNC', + 'GB-DND', + 'GB-DOR', + 'GB-DOW', + 'GB-DRY', + 'GB-DUD', + 'GB-DUR', + 'GB-EAL', + 'GB-EAW', + 'GB-EAY', + 'GB-EDH', + 'GB-EDU', + 'GB-ELN', + 'GB-ELS', + 'GB-ENF', + 'GB-ENG', + 'GB-ERW', + 'GB-ERY', + 'GB-ESS', + 'GB-ESX', + 'GB-FAL', + 'GB-FER', + 'GB-FIF', + 'GB-FLN', + 'GB-GAT', + 'GB-GBN', + 'GB-GLG', + 'GB-GLS', + 'GB-GRE', + 'GB-GSY', + 'GB-GWN', + 'GB-HAL', + 'GB-HAM', + 'GB-HAV', + 'GB-HCK', + 'GB-HEF', + 'GB-HIL', + 'GB-HLD', + 'GB-HMF', + 'GB-HNS', + 'GB-HPL', + 'GB-HRT', + 'GB-HRW', + 'GB-HRY', + 'GB-IOM', + 'GB-IOS', + 'GB-IOW', + 'GB-ISL', + 'GB-IVC', + 'GB-JSY', + 'GB-KEC', + 'GB-KEN', + 'GB-KHL', + 'GB-KIR', + 'GB-KTT', + 'GB-KWL', + 'GB-LAN', + 'GB-LBH', + 'GB-LCE', + 'GB-LDS', + 'GB-LEC', + 'GB-LEW', + 'GB-LIN', + 'GB-LIV', + 'GB-LMV', + 'GB-LND', + 'GB-LRN', + 'GB-LSB', + 'GB-LUT', + 'GB-MAN', + 'GB-MDB', + 'GB-MDW', + 'GB-MFT', + 'GB-MIK', + 'GB-MLN', + 'GB-MON', + 'GB-MRT', + 'GB-MRY', + 'GB-MTY', + 'GB-MYL', + 'GB-NAY', + 'GB-NBL', + 'GB-NDN', + 'GB-NEL', + 'GB-NET', + 'GB-NFK', + 'GB-NGM', + 'GB-NIR', + 'GB-NLK', + 'GB-NLN', + 'GB-NSM', + 'GB-NTA', + 'GB-NTH', + 'GB-NTL', + 'GB-NTT', + 'GB-NTY', + 'GB-NWM', + 'GB-NWP', + 'GB-NYK', + 'GB-NYM', + 'GB-OLD', + 'GB-OMH', + 'GB-ORK', + 'GB-OXF', + 'GB-PEM', + 'GB-PKN', + 'GB-PLY', + 'GB-POL', + 'GB-POR', + 'GB-POW', + 'GB-PTE', + 'GB-RCC', + 'GB-RCH', + 'GB-RCT', + 'GB-RDB', + 'GB-RDG', + 'GB-RFW', + 'GB-RIC', + 'GB-ROT', + 'GB-RUT', + 'GB-SAW', + 'GB-SAY', + 'GB-SCB', + 'GB-SCT', + 'GB-SFK', + 'GB-SFT', + 'GB-SGC', + 'GB-SHF', + 'GB-SHN', + 'GB-SHR', + 'GB-SKP', + 'GB-SLF', + 'GB-SLG', + 'GB-SLK', + 'GB-SND', + 'GB-SOL', + 'GB-SOM', + 'GB-SOS', + 'GB-SRY', + 'GB-STB', + 'GB-STE', + 'GB-STG', + 'GB-STH', + 'GB-STN', + 'GB-STS', + 'GB-STT', + 'GB-STY', + 'GB-SWA', + 'GB-SWD', + 'GB-SWK', + 'GB-TAM', + 'GB-TFW', + 'GB-THR', + 'GB-TOB', + 'GB-TOF', + 'GB-TRF', + 'GB-TWH', + 'GB-UKM', + 'GB-VGL', + 'GB-WAR', + 'GB-WBK', + 'GB-WDU', + 'GB-WFT', + 'GB-WGN', + 'GB-WILL', + 'GB-WKF', + 'GB-WLL', + 'GB-WLN', + 'GB-WLS', + 'GB-WLV', + 'GB-WND', + 'GB-WNM', + 'GB-WOK', + 'GB-WOR', + 'GB-WRL', + 'GB-WRT', + 'GB-WRX', + 'GB-WSM', + 'GB-WSX', + 'GB-YOR', + 'GB-ZET', + 'GE-AB', + 'GE-AJ', + 'GE-GU', + 'GE-IM', + 'GE-KA', + 'GE-KK', + 'GE-MM', + 'GE-RL', + 'GE-SJ', + 'GE-SK', + 'GE-SZ', + 'GE-TB', + 'GH-AA', + 'GH-AH', + 'GH-BA', + 'GH-CP', + 'GH-EP', + 'GH-NP', + 'GH-TV', + 'GH-UE', + 'GH-UW', + 'GH-WP', + 'GM-B', + 'GM-L', + 'GM-M', + 'GM-N', + 'GM-U', + 'GM-W', + 'GN-B', + 'GN-BE', + 'GN-BF', + 'GN-BK', + 'GN-C', + 'GN-CO', + 'GN-D', + 'GN-DB', + 'GN-DI', + 'GN-DL', + 'GN-DU', + 'GN-F', + 'GN-FA', + 'GN-FO', + 'GN-FR', + 'GN-GA', + 'GN-GU', + 'GN-K', + 'GN-KA', + 'GN-KB', + 'GN-KD; 2', + 'GN-KE', + 'GN-KN', + 'GN-KO', + 'GN-KS', + 'GN-L', + 'GN-LA', + 'GN-LE', + 'GN-LO', + 'GN-M', + 'GN-MC', + 'GN-MD', + 'GN-ML', + 'GN-MM', + 'GN-N', + 'GN-NZ', + 'GN-PI', + 'GN-SI', + 'GN-TE', + 'GN-TO', + 'GN-YO', + 'GQ-AN', + 'GQ-BN', + 'GQ-BS', + 'GQ-C', + 'GQ-CS', + 'GQ-I', + 'GQ-KN', + 'GQ-LI', + 'GQ-WN', + 'GR-01', + 'GR-03', + 'GR-04', + 'GR-05', + 'GR-06', + 'GR-07', + 'GR-11', + 'GR-12', + 'GR-13', + 'GR-14', + 'GR-15', + 'GR-16', + 'GR-17', + 'GR-21', + 'GR-22', + 'GR-23', + 'GR-24', + 'GR-31', + 'GR-32', + 'GR-33', + 'GR-34', + 'GR-41', + 'GR-42', + 'GR-43', + 'GR-44', + 'GR-51', + 'GR-52', + 'GR-53', + 'GR-54', + 'GR-55', + 'GR-56', + 'GR-57', + 'GR-58', + 'GR-59', + 'GR-61', + 'GR-62', + 'GR-63', + 'GR-64', + 'GR-69', + 'GR-71', + 'GR-72', + 'GR-73', + 'GR-81', + 'GR-82', + 'GR-83', + 'GR-84', + 'GR-85', + 'GR-91', + 'GR-92', + 'GR-93', + 'GR-94', + 'GR-A1', + 'GR-I', + 'GR-II', + 'GR-III', + 'GR-IV', + 'GR-IX', + 'GR-V', + 'GR-VI', + 'GR-VII', + 'GR-VIII', + 'GR-X', + 'GR-XI', + 'GR-XII', + 'GR-XIII', + 'GT-AV', + 'GT-BV', + 'GT-CM', + 'GT-CQ', + 'GT-ES', + 'GT-GU', + 'GT-HU', + 'GT-IZ', + 'GT-JA', + 'GT-JU', + 'GT-PE', + 'GT-PR', + 'GT-QC', + 'GT-QZ', + 'GT-RE', + 'GT-SA', + 'GT-SM', + 'GT-SO', + 'GT-SR', + 'GT-SU', + 'GT-TO', + 'GT-ZA', + 'GW-BA', + 'GW-BL', + 'GW-BM', + 'GW-BS', + 'GW-CA', + 'GW-GA', + 'GW-L', + 'GW-N', + 'GW-OI', + 'GW-QU', + 'GW-S', + 'GW-TO', + 'GY-BA', + 'GY-CU', + 'GY-DE', + 'GY-EB', + 'GY-ES', + 'GY-MA', + 'GY-PM', + 'GY-PT', + 'GY-UD', + 'GY-UT', + 'HN-AT', + 'HN-CH', + 'HN-CL', + 'HN-CM', + 'HN-CP', + 'HN-CR', + 'HN-EP', + 'HN-FM', + 'HN-GD', + 'HN-IB', + 'HN-IN', + 'HN-LE', + 'HN-LP', + 'HN-OC', + 'HN-OL', + 'HN-SB', + 'HN-VA', + 'HN-YO', + 'HR-01', + 'HR-02', + 'HR-03', + 'HR-04', + 'HR-05', + 'HR-06', + 'HR-07', + 'HR-08', + 'HR-09', + 'HR-10', + 'HR-11', + 'HR-12', + 'HR-13', + 'HR-14', + 'HR-15', + 'HR-16', + 'HR-17', + 'HR-18', + 'HR-19', + 'HR-20', + 'HR-21', + 'HT-AR', + 'HT-CE', + 'HT-GA', + 'HT-ND', + 'HT-NE', + 'HT-NO', + 'HT-OU', + 'HT-SD', + 'HT-SE', + 'HU-BA', + 'HU-BC', + 'HU-BE', + 'HU-BK', + 'HU-BU', + 'HU-BZ', + 'HU-CS', + 'HU-DE', + 'HU-DU', + 'HU-EG', + 'HU-FE', + 'HU-GS', + 'HU-GY', + 'HU-HB', + 'HU-HE', + 'HU-HV', + 'HU-JN', + 'HU-KE', + 'HU-KM', + 'HU-KV', + 'HU-MI', + 'HU-NK', + 'HU-NO', + 'HU-NY', + 'HU-PE', + 'HU-PS', + 'HU-SD', + 'HU-SF', + 'HU-SH', + 'HU-SK', + 'HU-SN', + 'HU-SO', + 'HU-SS', + 'HU-ST', + 'HU-SZ', + 'HU-TB', + 'HU-TO', + 'HU-VA', + 'HU-VE', + 'HU-VM', + 'HU-ZA', + 'HU-ZE', + 'ID-AC', + 'ID-BA', + 'ID-BB', + 'ID-BE', + 'ID-BT', + 'ID-GO', + 'ID-IJ', + 'ID-JA', + 'ID-JB', + 'ID-JI', + 'ID-JK', + 'ID-JT', + 'ID-JW', + 'ID-KA', + 'ID-KB', + 'ID-KI', + 'ID-KS', + 'ID-KT', + 'ID-LA', + 'ID-MA', + 'ID-MU', + 'ID-NB', + 'ID-NT', + 'ID-NU', + 'ID-PA', + 'ID-RI', + 'ID-SA', + 'ID-SB', + 'ID-SG', + 'ID-SL', + 'ID-SM', + 'ID-SN', + 'ID-SS', + 'ID-ST', + 'ID-SU', + 'ID-YO', + 'IE-C', + 'IE-C; 2', + 'IE-CE', + 'IE-CN', + 'IE-CW', + 'IE-D', + 'IE-DL', + 'IE-G', + 'IE-KE', + 'IE-KK', + 'IE-KY', + 'IE-L', + 'IE-LD', + 'IE-LH', + 'IE-LK', + 'IE-LM', + 'IE-LS', + 'IE-M', + 'IE-MH', + 'IE-MN', + 'IE-MO', + 'IE-OY', + 'IE-RN', + 'IE-SO', + 'IE-TA', + 'IE-U', + 'IE-WD', + 'IE-WH', + 'IE-WW', + 'IE-WX', + 'IL-D', + 'IL-HA', + 'IL-JM', + 'IL-M', + 'IL-TA', + 'IL-Z', + 'IN-AN', + 'IN-AP', + 'IN-AR', + 'IN-AS', + 'IN-BR', + 'IN-CH', + 'IN-CT', + 'IN-DD', + 'IN-DL', + 'IN-DN', + 'IN-GA', + 'IN-GJ', + 'IN-HP', + 'IN-HR', + 'IN-JH', + 'IN-JK', + 'IN-KA', + 'IN-KL', + 'IN-LD', + 'IN-MH', + 'IN-ML', + 'IN-MN', + 'IN-MP', + 'IN-MZ', + 'IN-NL', + 'IN-OR', + 'IN-PB', + 'IN-PY', + 'IN-RJ', + 'IN-SK', + 'IN-TN', + 'IN-TR', + 'IN-UL', + 'IN-UP', + 'IN-WB', + 'IQ-AN', + 'IQ-AR', + 'IQ-BA', + 'IQ-BB', + 'IQ-BG', + 'IQ-DA', + 'IQ-DI', + 'IQ-DQ', + 'IQ-KA', + 'IQ-MA', + 'IQ-MU', + 'IQ-NA', + 'IQ-NI', + 'IQ-QA', + 'IQ-SD', + 'IQ-SU', + 'IQ-TS', + 'IQ-WA', + 'IR-01', + 'IR-02', + 'IR-03', + 'IR-04', + 'IR-05', + 'IR-06', + 'IR-07', + 'IR-08', + 'IR-09', + 'IR-10', + 'IR-11', + 'IR-12', + 'IR-13', + 'IR-14', + 'IR-15', + 'IR-16', + 'IR-17', + 'IR-18', + 'IR-19', + 'IR-20', + 'IR-21', + 'IR-22', + 'IR-23', + 'IR-24', + 'IR-25', + 'IR-26', + 'IR-27', + 'IR-28', + 'IS-0', + 'IS-1', + 'IS-2', + 'IS-3', + 'IS-4', + 'IS-5', + 'IS-6', + 'IS-7', + 'IS-8', + 'IT-21', + 'IT-23', + 'IT-25', + 'IT-32', + 'IT-34', + 'IT-36', + 'IT-42', + 'IT-45', + 'IT-52', + 'IT-55', + 'IT-57', + 'IT-62', + 'IT-65', + 'IT-67', + 'IT-72', + 'IT-75', + 'IT-77', + 'IT-78', + 'IT-82', + 'IT-88', + 'IT-AG', + 'IT-AL', + 'IT-AN', + 'IT-AO', + 'IT-AP', + 'IT-AQ', + 'IT-AR', + 'IT-AT', + 'IT-AV', + 'IT-BA', + 'IT-BG', + 'IT-BI', + 'IT-BL', + 'IT-BN', + 'IT-BO', + 'IT-BR', + 'IT-BS', + 'IT-BZ', + 'IT-CA', + 'IT-CB', + 'IT-CE', + 'IT-CH', + 'IT-CL', + 'IT-CN', + 'IT-CO', + 'IT-CR', + 'IT-CS', + 'IT-CT', + 'IT-CZ', + 'IT-DU', + 'IT-EN', + 'IT-FE', + 'IT-FG', + 'IT-FI', + 'IT-FO', + 'IT-FR', + 'IT-GE', + 'IT-GO', + 'IT-GR', + 'IT-IM', + 'IT-IS', + 'IT-KR', + 'IT-LC', + 'IT-LE', + 'IT-LI', + 'IT-LO', + 'IT-LT', + 'IT-LU', + 'IT-MC', + 'IT-ME', + 'IT-MI', + 'IT-MN', + 'IT-MO', + 'IT-MS', + 'IT-MT', + 'IT-NA', + 'IT-NO', + 'IT-NU', + 'IT-OR', + 'IT-PA', + 'IT-PC', + 'IT-PD', + 'IT-PE', + 'IT-PG', + 'IT-PI', + 'IT-PN', + 'IT-PO', + 'IT-PR', + 'IT-PS', + 'IT-PT', + 'IT-PV', + 'IT-PZ', + 'IT-RA', + 'IT-RC', + 'IT-RE', + 'IT-RG', + 'IT-RI', + 'IT-RM', + 'IT-RN', + 'IT-RO', + 'IT-SA', + 'IT-SI', + 'IT-SO', + 'IT-SP', + 'IT-SR', + 'IT-SS', + 'IT-SV', + 'IT-TA', + 'IT-TE', + 'IT-TN', + 'IT-TO', + 'IT-TP', + 'IT-TR', + 'IT-TS', + 'IT-TV', + 'IT-VA', + 'IT-VB', + 'IT-VC', + 'IT-VE', + 'IT-VI', + 'IT-VR', + 'IT-VT', + 'IT-VV', + 'JM-01', + 'JM-02', + 'JM-03', + 'JM-04', + 'JM-05', + 'JM-06', + 'JM-07', + 'JM-08', + 'JM-09', + 'JM-10', + 'JM-11', + 'JM-12', + 'JM-13', + 'JM-14', + 'JO-AJ', + 'JO-AM', + 'JO-AQ', + 'JO-AT', + 'JO-AZ', + 'JO-BA', + 'JO-IR', + 'JO-JA', + 'JO-KA', + 'JO-MA', + 'JO-MD', + 'JO-MN', + 'JP-01', + 'JP-02', + 'JP-03', + 'JP-04', + 'JP-05', + 'JP-06', + 'JP-07', + 'JP-08', + 'JP-09', + 'JP-10', + 'JP-11', + 'JP-12', + 'JP-13', + 'JP-14', + 'JP-15', + 'JP-16', + 'JP-17', + 'JP-18', + 'JP-19', + 'JP-20', + 'JP-21', + 'JP-22', + 'JP-23', + 'JP-24', + 'JP-25', + 'JP-26', + 'JP-27', + 'JP-28', + 'JP-29', + 'JP-30', + 'JP-31', + 'JP-32', + 'JP-33', + 'JP-34', + 'JP-35', + 'JP-36', + 'JP-37', + 'JP-38', + 'JP-39', + 'JP-40', + 'JP-41', + 'JP-42', + 'JP-43', + 'JP-44', + 'JP-45', + 'JP-46', + 'JP-47', + 'KE-110', + 'KE-200', + 'KE-300', + 'KE-400', + 'KE-500', + 'KE-600', + 'KE-700', + 'KE-900', + 'KG-B', + 'KG-C', + 'KG-GB', + 'KG-J', + 'KG-N', + 'KG-O', + 'KG-T', + 'KG-Y', + 'KH-1', + 'KH-10', + 'KH-11', + 'KH-12', + 'KH-13', + 'KH-14', + 'KH-15', + 'KH-16', + 'KH-17', + 'KH-18', + 'KH-19', + 'KH-2', + 'KH-20', + 'KH-21', + 'KH-22', + 'KH-23', + 'KH-24', + 'KH-3', + 'KH-4', + 'KH-5', + 'KH-6', + 'KH-7', + 'KH-8', + 'KH-9', + 'KI-G', + 'KI-L', + 'KI-P', + 'KM-A', + 'KM-G', + 'KM-M', + 'KP-CHA', + 'KP-HAB', + 'KP-HAN', + 'KP-HWB', + 'KP-HWN', + 'KP-KAE', + 'KP-KAN', + 'KP-NAJ', + 'KP-NAM', + 'KP-PYB', + 'KP-PYN', + 'KP-PYO', + 'KP-YAN', + 'KR-11', + 'KR-26', + 'KR-27', + 'KR-28', + 'KR-29', + 'KR-30', + 'KR-31', + 'KR-41', + 'KR-42', + 'KR-43', + 'KR-44', + 'KR-45', + 'KR-46', + 'KR-47', + 'KR-48', + 'KR-49', + 'KW-AH', + 'KW-FA', + 'KW-HA', + 'KW-JA', + 'KW-KU', + 'KZ-AKM', + 'KZ-AKT', + 'KZ-ALA', + 'KZ-ALM', + 'KZ-AST', + 'KZ-ATY', + 'KZ-KAR', + 'KZ-KUS', + 'KZ-KZY', + 'KZ-MAN', + 'KZ-PAV', + 'KZ-SEV', + 'KZ-VOS', + 'KZ-YUZ', + 'KZ-ZAP', + 'KZ-ZHA', + 'LA-AT', + 'LA-BK', + 'LA-BL', + 'LA-CH', + 'LA-HO', + 'LA-KH', + 'LA-LM', + 'LA-LP', + 'LA-OU', + 'LA-PH', + 'LA-SL', + 'LA-SV', + 'LA-VI', + 'LA-VT', + 'LA-XA', + 'LA-XE', + 'LA-XI', + 'LA-XN', + 'LB-AS', + 'LB-BA', + 'LB-BI', + 'LB-JA', + 'LB-JL', + 'LB-NA', + 'LK-1', + 'LK-11', + 'LK-12', + 'LK-13', + 'LK-2', + 'LK-21', + 'LK-22', + 'LK-23', + 'LK-3', + 'LK-31', + 'LK-32', + 'LK-33', + 'LK-4', + 'LK-41', + 'LK-42', + 'LK-43', + 'LK-44', + 'LK-45', + 'LK-5', + 'LK-51', + 'LK-52', + 'LK-53', + 'LK-6', + 'LK-61', + 'LK-62', + 'LK-7', + 'LK-71', + 'LK-72', + 'LK-8', + 'LK-81', + 'LK-82', + 'LK-9', + 'LK-91', + 'LK-92', + 'LR-BG', + 'LR-BM', + 'LR-CM', + 'LR-GB', + 'LR-GG', + 'LR-GK', + 'LR-LO', + 'LR-MG', + 'LR-MO', + 'LR-MY', + 'LR-NI', + 'LR-RI', + 'LR-SI', + 'LS-A', + 'LS-B', + 'LS-C', + 'LS-D', + 'LS-E', + 'LS-F', + 'LS-G', + 'LS-H', + 'LS-J', + 'LS-K', + 'LT-AL', + 'LT-KL', + 'LT-KU', + 'LT-MR', + 'LT-PN', + 'LT-SA', + 'LT-TA', + 'LT-TE', + 'LT-UT', + 'LT-VL', + 'LU-D', + 'LU-G', + 'LU-L', + 'LV-AI', + 'LV-AL', + 'LV-BL', + 'LV-BU', + 'LV-CE', + 'LV-DA', + 'LV-DGV', + 'LV-DO', + 'LV-GU', + 'LV-JEL', + 'LV-JK', + 'LV-JL', + 'LV-JUR', + 'LV-KR', + 'LV-KU', + 'LV-LE', + 'LV-LM', + 'LV-LPX', + 'LV-LU', + 'LV-MA', + 'LV-OG', + 'LV-PR', + 'LV-RE', + 'LV-REZ', + 'LV-RI', + 'LV-RIX', + 'LV-SA', + 'LV-TA', + 'LV-TU', + 'LV-VE', + 'LV-VEN', + 'LV-VK', + 'LV-VM', + 'LY-BA', + 'LY-BU', + 'LY-FA', + 'LY-JA', + 'LY-JG', + 'LY-JU', + 'LY-MI', + 'LY-NA', + 'LY-SF', + 'LY-TB', + 'LY-WA', + 'LY-WU', + 'LY-ZA', + 'MA-01', + 'MA-02', + 'MA-03', + 'MA-04', + 'MA-05', + 'MA-06', + 'MA-07', + 'MA-08', + 'MA-09', + 'MA-10', + 'MA-11', + 'MA-12', + 'MA-13', + 'MA-14', + 'MA-15', + 'MA-16', + 'MA-AGD', + 'MA-ASZ', + 'MA-AZI', + 'MA-BAH', + 'MA-BEM', + 'MA-BER', + 'MA-BES', + 'MA-BOD', + 'MA-BOM', + 'MA-CAS', + 'MA-CHE', + 'MA-CHI', + 'MA-ERR', + 'MA-ESI', + 'MA-ESM', + 'MA-FES', + 'MA-FIG', + 'MA-GUE', + 'MA-HAJ', + 'MA-HAO', + 'MA-HOC', + 'MA-IFR', + 'MA-JDI', + 'MA-JRA', + 'MA-KEN', + 'MA-KES', + 'MA-KHE', + 'MA-KHN', + 'MA-KHO', + 'MA-LAA', + 'MA-LAR', + 'MA-MAR', + 'MA-MEK', + 'MA-MEL', + 'MA-NAD', + 'MA-OUA', + 'MA-OUD', + 'MA-OUJ', + 'MA-RBA', + 'MA-SAF', + 'MA-SEF', + 'MA-SET', + 'MA-SIK', + 'MA-TAO', + 'MA-TAR', + 'MA-TAT', + 'MA-TAZ', + 'MA-TET', + 'MA-TIZ', + 'MA-TNG', + 'MA-TNT', + 'MD-BA', + 'MD-CA', + 'MD-CH', + 'MD-CU', + 'MD-ED', + 'MD-GA', + 'MD-LA', + 'MD-OR', + 'MD-SN', + 'MD-SO', + 'MD-TA', + 'MD-TI', + 'MD-UN', + 'MG-A', + 'MG-D', + 'MG-F', + 'MG-M', + 'MG-T', + 'MG-U', + 'MH-ALK', + 'MH-ALL', + 'MH-ARN', + 'MH-AUR', + 'MH-EBO', + 'MH-ENI', + 'MH-JAL', + 'MH-KIL', + 'MH-KWA', + 'MH-L', + 'MH-LAE', + 'MH-LIB', + 'MH-LIK', + 'MH-MAJ', + 'MH-MAL', + 'MH-MEJ', + 'MH-MIL', + 'MH-NMK', + 'MH-NMU', + 'MH-RON', + 'MH-T', + 'MH-UJA', + 'MH-UJL', + 'MH-UTI', + 'MH-WTH', + 'MH-WTJ', + 'ML-1', + 'ML-2', + 'ML-3', + 'ML-4', + 'ML-5', + 'ML-6', + 'ML-7', + 'ML-8', + 'ML-BKO', + 'MM-01', + 'MM-02', + 'MM-03', + 'MM-04', + 'MM-05', + 'MM-06', + 'MM-07', + 'MM-11', + 'MM-12', + 'MM-13', + 'MM-14', + 'MM-15', + 'MM-16', + 'MM-17', + 'MN-035', + 'MN-037', + 'MN-039', + 'MN-041', + 'MN-043', + 'MN-046', + 'MN-047', + 'MN-049', + 'MN-051', + 'MN-053', + 'MN-055', + 'MN-057', + 'MN-059', + 'MN-061', + 'MN-063', + 'MN-064', + 'MN-065', + 'MN-067', + 'MN-069', + 'MN-071', + 'MN-073', + 'MN-1', + 'MR-01', + 'MR-02', + 'MR-03', + 'MR-04', + 'MR-05', + 'MR-06', + 'MR-07', + 'MR-08', + 'MR-09', + 'MR-10', + 'MR-11', + 'MR-12', + 'MR-NKC', + 'MU-AG', + 'MU-BL', + 'MU-BR', + 'MU-CC', + 'MU-CU', + 'MU-FL', + 'MU-GP', + 'MU-MO', + 'MU-PA', + 'MU-PL', + 'MU-PU', + 'MU-PW', + 'MU-QB', + 'MU-RO', + 'MU-RR', + 'MU-SA', + 'MU-VP', + 'MV-01', + 'MV-02', + 'MV-03', + 'MV-04', + 'MV-05', + 'MV-07', + 'MV-08', + 'MV-12', + 'MV-13', + 'MV-14', + 'MV-17', + 'MV-20', + 'MV-23', + 'MV-24', + 'MV-25', + 'MV-26', + 'MV-27', + 'MV-28', + 'MV-29', + 'MV-MLE', + 'MW-BA', + 'MW-BL', + 'MW-C', + 'MW-CK', + 'MW-CR', + 'MW-CT', + 'MW-DE', + 'MW-DO', + 'MW-KR', + 'MW-KS', + 'MW-LI', + 'MW-LK', + 'MW-MC', + 'MW-MG', + 'MW-MH', + 'MW-MU', + 'MW-MW', + 'MW-MZ', + 'MW-N', + 'MW-NB', + 'MW-NI', + 'MW-NK', + 'MW-NS', + 'MW-NU', + 'MW-PH', + 'MW-RU', + 'MW-S', + 'MW-SA', + 'MW-TH', + 'MW-ZO', + 'MX-AGU', + 'MX-BCN', + 'MX-BCS', + 'MX-CAM', + 'MX-CHH', + 'MX-CHP', + 'MX-COA', + 'MX-COL', + 'MX-DIF', + 'MX-DUR', + 'MX-GRO', + 'MX-GUA', + 'MX-HID', + 'MX-JAL', + 'MX-MEX', + 'MX-MIC', + 'MX-MOR', + 'MX-NAY', + 'MX-NLE', + 'MX-OAX', + 'MX-PUE', + 'MX-QUE', + 'MX-ROO', + 'MX-SIN', + 'MX-SLP', + 'MX-SON', + 'MX-TAB', + 'MX-TAM', + 'MX-TLA', + 'MX-VER', + 'MX-YUC', + 'MX-ZAC', + 'MY-A', + 'MY-B', + 'MY-C', + 'MY-D', + 'MY-J', + 'MY-K', + 'MY-L', + 'MY-M', + 'MY-N', + 'MY-P', + 'MY-R', + 'MY-SA', + 'MY-SK', + 'MY-T', + 'MY-W', + 'MZ-A', + 'MZ-B', + 'MZ-G', + 'MZ-I', + 'MZ-L', + 'MZ-MPM', + 'MZ-N', + 'MZ-P', + 'MZ-Q', + 'MZ-S', + 'MZ-T', + 'NA-CA', + 'NA-ER', + 'NA-HA', + 'NA-KA', + 'NA-KH', + 'NA-KU', + 'NA-OD', + 'NA-OH', + 'NA-OK', + 'NA-ON', + 'NA-OS', + 'NA-OT', + 'NA-OW', + 'NE-1', + 'NE-2', + 'NE-3', + 'NE-4', + 'NE-5', + 'NE-6', + 'NE-7', + 'NE-8', + 'NG-AB', + 'NG-AD', + 'NG-AK', + 'NG-AN', + 'NG-BA', + 'NG-BE', + 'NG-BO', + 'NG-BY', + 'NG-CR', + 'NG-DE', + 'NG-EB', + 'NG-ED', + 'NG-EK', + 'NG-EN', + 'NG-FC', + 'NG-GO', + 'NG-IM', + 'NG-JI', + 'NG-KD', + 'NG-KE', + 'NG-KN', + 'NG-KO', + 'NG-KT', + 'NG-KW', + 'NG-LA', + 'NG-NA', + 'NG-NI', + 'NG-OG', + 'NG-ON', + 'NG-OS', + 'NG-OY', + 'NG-PL', + 'NG-RI', + 'NG-SO', + 'NG-TA', + 'NG-YO', + 'NG-ZA', + 'NI-AN', + 'NI-AS', + 'NI-BO', + 'NI-CA', + 'NI-CI', + 'NI-CO', + 'NI-ES', + 'NI-GR', + 'NI-JI', + 'NI-LE', + 'NI-MD', + 'NI-MN', + 'NI-MS', + 'NI-MT', + 'NI-NS', + 'NI-RI', + 'NI-SJ', + 'NL-DR', + 'NL-FL', + 'NL-FR', + 'NL-GE', + 'NL-GR', + 'NL-LI', + 'NL-NB', + 'NL-NH', + 'NL-OV', + 'NL-UT', + 'NL-ZE', + 'NL-ZH', + 'NO-01', + 'NO-02', + 'NO-03', + 'NO-04', + 'NO-05', + 'NO-06', + 'NO-07', + 'NO-08', + 'NO-09', + 'NO-10', + 'NO-11', + 'NO-12', + 'NO-14', + 'NO-15', + 'NO-16', + 'NO-17', + 'NO-18', + 'NO-19', + 'NO-20', + 'NO-21', + 'NO-22', + 'NP-1', + 'NP-2', + 'NP-3', + 'NP-4', + 'NP-5', + 'NP-BA', + 'NP-BH', + 'NP-DH', + 'NP-GA', + 'NP-JA', + 'NP-KA', + 'NP-KO', + 'NP-LU', + 'NP-MA', + 'NP-ME', + 'NP-NA', + 'NP-RA', + 'NP-SA', + 'NP-SE', + 'NZ-AUK', + 'NZ-BOP', + 'NZ-CAN', + 'NZ-GIS', + 'NZ-HKB', + 'NZ-MBH', + 'NZ-MWT', + 'NZ-N', + 'NZ-NSN', + 'NZ-NTL', + 'NZ-OTA', + 'NZ-S', + 'NZ-STL', + 'NZ-TAS', + 'NZ-TKI', + 'NZ-WGN', + 'NZ-WKO', + 'NZ-WTC', + 'OM-BA', + 'OM-DA', + 'OM-JA', + 'OM-MA', + 'OM-MU', + 'OM-SH', + 'OM-WU', + 'OM-ZA', + 'PA-0', + 'PA-1', + 'PA-2', + 'PA-3', + 'PA-4', + 'PA-5', + 'PA-6', + 'PA-7', + 'PA-8', + 'PA-9', + 'PE-AMA', + 'PE-ANC', + 'PE-APU', + 'PE-ARE', + 'PE-AYA', + 'PE-CAJ', + 'PE-CAL', + 'PE-CUS', + 'PE-HUC', + 'PE-HUV', + 'PE-ICA', + 'PE-JUN', + 'PE-LAL', + 'PE-LAM', + 'PE-LIM', + 'PE-LOR', + 'PE-MDD', + 'PE-MOQ', + 'PE-PAS', + 'PE-PIU', + 'PE-PUN', + 'PE-SAM', + 'PE-TAC', + 'PE-TUM', + 'PE-UCA', + 'PG-CPK', + 'PG-CPM', + 'PG-EBR', + 'PG-EHG', + 'PG-EPW', + 'PG-ESW', + 'PG-GPK', + 'PG-MBA', + 'PG-MPL', + 'PG-MPM', + 'PG-MRL', + 'PG-NCD', + 'PG-NIK', + 'PG-NPP', + 'PG-NSA', + 'PG-SAN', + 'PG-SHM', + 'PG-WBK', + 'PG-WHM', + 'PG-WPD', + 'PH-00', + 'PH-01', + 'PH-02', + 'PH-03', + 'PH-04', + 'PH-05', + 'PH-06', + 'PH-07', + 'PH-08', + 'PH-09', + 'PH-10', + 'PH-11', + 'PH-12', + 'PH-13', + 'PH-14', + 'PH-15', + 'PH-ABR', + 'PH-AGN', + 'PH-AGS', + 'PH-AKL', + 'PH-ALB', + 'PH-ANT', + 'PH-APA', + 'PH-AUR', + 'PH-BAN', + 'PH-BAS', + 'PH-BEN', + 'PH-BIL', + 'PH-BOH', + 'PH-BTG', + 'PH-BTN', + 'PH-BUK', + 'PH-BUL', + 'PH-CAG', + 'PH-CAM', + 'PH-CAN', + 'PH-CAP', + 'PH-CAS', + 'PH-CAT', + 'PH-CAV', + 'PH-CEB', + 'PH-COM', + 'PH-DAO', + 'PH-DAS', + 'PH-DAV', + 'PH-EAS', + 'PH-GUI', + 'PH-IFU', + 'PH-ILI', + 'PH-ILN', + 'PH-ILS', + 'PH-ISA', + 'PH-KAL', + 'PH-LAG', + 'PH-LAN', + 'PH-LAS', + 'PH-LEY', + 'PH-LUN', + 'PH-MAD', + 'PH-MAG', + 'PH-MAS', + 'PH-MDC', + 'PH-MDR', + 'PH-MOU', + 'PH-MSC', + 'PH-MSR', + 'PH-NCO', + 'PH-NEC', + 'PH-NER', + 'PH-NSA', + 'PH-NUE', + 'PH-NUV', + 'PH-PAM', + 'PH-PAN', + 'PH-PLW', + 'PH-QUE', + 'PH-QUI', + 'PH-RIZ', + 'PH-ROM', + 'PH-SAR', + 'PH-SCO', + 'PH-SIG', + 'PH-SLE', + 'PH-SLU', + 'PH-SOR', + 'PH-SUK', + 'PH-SUN', + 'PH-SUR', + 'PH-TAR', + 'PH-TAW', + 'PH-WSA', + 'PH-ZAN', + 'PH-ZAS', + 'PH-ZMB', + 'PH-ZSI', + 'PK-BA', + 'PK-IS', + 'PK-JK', + 'PK-NA', + 'PK-NW', + 'PK-PB', + 'PK-SD', + 'PK-TA', + 'PL-DS', + 'PL-KP', + 'PL-LB', + 'PL-LD', + 'PL-LU', + 'PL-MA', + 'PL-MZ', + 'PL-OP', + 'PL-PD', + 'PL-PK', + 'PL-PM', + 'PL-SK', + 'PL-SL', + 'PL-WN', + 'PL-WP', + 'PL-ZP', + 'PT-01', + 'PT-02', + 'PT-03', + 'PT-04', + 'PT-05', + 'PT-06', + 'PT-07', + 'PT-08', + 'PT-09', + 'PT-10', + 'PT-11', + 'PT-12', + 'PT-13', + 'PT-14', + 'PT-15', + 'PT-16', + 'PT-17', + 'PT-18', + 'PT-20', + 'PT-30', + 'PY-1', + 'PY-10', + 'PY-11', + 'PY-12', + 'PY-13', + 'PY-14', + 'PY-15', + 'PY-16', + 'PY-19', + 'PY-2', + 'PY-3', + 'PY-4', + 'PY-5', + 'PY-6', + 'PY-7', + 'PY-8', + 'PY-9', + 'PY-ASU', + 'QA-DA', + 'QA-GH', + 'QA-JB', + 'QA-JU', + 'QA-KH', + 'QA-MS', + 'QA-RA', + 'QA-US', + 'QA-WA', + 'RO-AB', + 'RO-AG', + 'RO-AR', + 'RO-B', + 'RO-BC', + 'RO-BH', + 'RO-BN', + 'RO-BR', + 'RO-BT', + 'RO-BV', + 'RO-BZ', + 'RO-CJ', + 'RO-CL', + 'RO-CS', + 'RO-CT', + 'RO-CV', + 'RO-DB', + 'RO-DJ', + 'RO-GJ', + 'RO-GL', + 'RO-GR', + 'RO-HD', + 'RO-HR', + 'RO-IF', + 'RO-IL', + 'RO-IS', + 'RO-MH', + 'RO-MM', + 'RO-MS', + 'RO-NT', + 'RO-OT', + 'RO-PH', + 'RO-SB', + 'RO-SJ', + 'RO-SM', + 'RO-SV', + 'RO-TL', + 'RO-TM', + 'RO-TR', + 'RO-VL', + 'RO-VN', + 'RO-VS', + 'RU-AD', + 'RU-AGB', + 'RU-AL', + 'RU-ALT', + 'RU-AMU', + 'RU-ARK', + 'RU-AST', + 'RU-BA', + 'RU-BEL', + 'RU-BRY', + 'RU-BU', + 'RU-CE', + 'RU-CHE', + 'RU-CHI', + 'RU-CHU', + 'RU-CU', + 'RU-DA', + 'RU-DU', + 'RU-EVE', + 'RU-IN', + 'RU-IRK', + 'RU-IVA', + 'RU-KAM', + 'RU-KB', + 'RU-KC', + 'RU-KDA', + 'RU-KEM', + 'RU-KGD', + 'RU-KGN', + 'RU-KHA', + 'RU-KHM', + 'RU-KIR', + 'RU-KK', + 'RU-KL', + 'RU-KLU', + 'RU-KO', + 'RU-KOP', + 'RU-KOR', + 'RU-KOS', + 'RU-KR', + 'RU-KRS', + 'RU-KYA', + 'RU-LEN', + 'RU-LIP', + 'RU-MAG', + 'RU-ME', + 'RU-MO', + 'RU-MOS', + 'RU-MOW', + 'RU-MUR', + 'RU-NEN', + 'RU-NGR', + 'RU-NIZ', + 'RU-NVS', + 'RU-OMS', + 'RU-ORE', + 'RU-ORL', + 'RU-PER', + 'RU-PNZ', + 'RU-PRI', + 'RU-PSK', + 'RU-ROS', + 'RU-RYA', + 'RU-SA', + 'RU-SAK', + 'RU-SAM', + 'RU-SAR', + 'RU-SE', + 'RU-SMO', + 'RU-SPE', + 'RU-STA', + 'RU-SVE', + 'RU-TA', + 'RU-TAM', + 'RU-TAY', + 'RU-TOM', + 'RU-TUL', + 'RU-TVE', + 'RU-TY', + 'RU-TYU', + 'RU-ULY', + 'RU-UOB', + 'RU-VGG', + 'RU-VLA', + 'RU-VLG', + 'RU-VOR', + 'RU-YAN', + 'RU-YAR', + 'RU-YEV', + 'RW-B', + 'RW-C', + 'RW-D', + 'RW-E', + 'RW-F', + 'RW-G', + 'RW-H', + 'RW-I', + 'RW-J', + 'RW-K', + 'RW-L', + 'RW-M', + 'SA-01', + 'SA-02', + 'SA-03', + 'SA-04', + 'SA-05', + 'SA-06', + 'SA-07', + 'SA-08', + 'SA-09', + 'SA-10', + 'SA-11', + 'SA-12', + 'SA-14', + 'SB-CE', + 'SB-CT', + 'SB-GU', + 'SB-IS', + 'SB-MK', + 'SB-ML', + 'SB-TE', + 'SB-WE', + 'SD-01', + 'SD-02', + 'SD-03', + 'SD-04', + 'SD-05', + 'SD-06', + 'SD-07', + 'SD-08', + 'SD-09', + 'SD-10', + 'SD-11', + 'SD-12', + 'SD-13', + 'SD-14', + 'SD-15', + 'SD-16', + 'SD-17', + 'SD-18', + 'SD-19', + 'SD-20', + 'SD-21', + 'SD-22', + 'SD-23', + 'SD-24', + 'SD-25', + 'SD-26', + 'SE-AB', + 'SE-AC', + 'SE-BD', + 'SE-C', + 'SE-D', + 'SE-E', + 'SE-F', + 'SE-G', + 'SE-H', + 'SE-I', + 'SE-K', + 'SE-M', + 'SE-N', + 'SE-O', + 'SE-S', + 'SE-T', + 'SE-U', + 'SE-W', + 'SE-X', + 'SE-Y', + 'SE-Z', + 'SH-AC', + 'SH-SH', + 'SH-TA', + 'SI-01', + 'SI-02', + 'SI-03', + 'SI-04', + 'SI-05', + 'SI-06', + 'SI-07', + 'SI-08', + 'SI-09', + 'SI-10', + 'SI-11', + 'SI-12', + 'SK-BC', + 'SK-BL', + 'SK-KI', + 'SK-NI', + 'SK-PV', + 'SK-TA', + 'SK-TC', + 'SK-ZI', + 'SL-E', + 'SL-N', + 'SL-S', + 'SL-W', + 'SN-DB', + 'SN-DK', + 'SN-FK', + 'SN-KD', + 'SN-KL', + 'SN-LG', + 'SN-SL', + 'SN-TC', + 'SN-TH', + 'SN-ZG', + 'SO-AW', + 'SO-BK', + 'SO-BN', + 'SO-BR', + 'SO-BY', + 'SO-GA', + 'SO-GE', + 'SO-HI', + 'SO-JD', + 'SO-JH', + 'SO-MU', + 'SO-NU', + 'SO-SA', + 'SO-SD', + 'SO-SH', + 'SO-SO', + 'SO-TO', + 'SO-WO', + 'SR-BR', + 'SR-CM', + 'SR-CR', + 'SR-MA', + 'SR-NI', + 'SR-PM', + 'SR-PR', + 'SR-SA', + 'SR-SI', + 'SR-WA', + 'ST-P', + 'ST-S', + 'SV-AH', + 'SV-CA', + 'SV-CH', + 'SV-CU', + 'SV-LI', + 'SV-MO', + 'SV-PA', + 'SV-SA', + 'SV-SM', + 'SV-SO', + 'SV-SS', + 'SV-SV', + 'SV-UN', + 'SV-US', + 'SY-DI', + 'SY-DR', + 'SY-DY', + 'SY-HA', + 'SY-HI', + 'SY-HL', + 'SY-HM', + 'SY-ID', + 'SY-LA', + 'SY-QU', + 'SY-RA', + 'SY-RD', + 'SY-SU', + 'SY-TA', + 'SZ-HH', + 'SZ-LU', + 'SZ-MA', + 'SZ-SH', + 'TD-BA', + 'TD-BET', + 'TD-BI', + 'TD-CB', + 'TD-GR', + 'TD-KA', + 'TD-LC', + 'TD-LO', + 'TD-LR', + 'TD-MC', + 'TD-MK', + 'TD-OD', + 'TD-SA', + 'TD-TA', + 'TG-C', + 'TG-K', + 'TG-M', + 'TG-P', + 'TG-S', + 'TH-10', + 'TH-11', + 'TH-12', + 'TH-13', + 'TH-14', + 'TH-15', + 'TH-16', + 'TH-17', + 'TH-18', + 'TH-19', + 'TH-20', + 'TH-21', + 'TH-22', + 'TH-23', + 'TH-24', + 'TH-25', + 'TH-26', + 'TH-27', + 'TH-30', + 'TH-31', + 'TH-32', + 'TH-33', + 'TH-34', + 'TH-35', + 'TH-36', + 'TH-37', + 'TH-39', + 'TH-40', + 'TH-41', + 'TH-42', + 'TH-43', + 'TH-44', + 'TH-45', + 'TH-46', + 'TH-47', + 'TH-48', + 'TH-49', + 'TH-50', + 'TH-51', + 'TH-52', + 'TH-53', + 'TH-54', + 'TH-55', + 'TH-56', + 'TH-57', + 'TH-58', + 'TH-60', + 'TH-61', + 'TH-62', + 'TH-63', + 'TH-64', + 'TH-65', + 'TH-66', + 'TH-67', + 'TH-70', + 'TH-71', + 'TH-72', + 'TH-73', + 'TH-74', + 'TH-75', + 'TH-76', + 'TH-77', + 'TH-80', + 'TH-81', + 'TH-82', + 'TH-83', + 'TH-84', + 'TH-85', + 'TH-86', + 'TH-90', + 'TH-91', + 'TH-92', + 'TH-93', + 'TH-94', + 'TH-95', + 'TH-96', + 'TH-S', + 'TJ-GB', + 'TJ-KT', + 'TJ-SU', + 'TL-AL', + 'TL-AN', + 'TL-BA', + 'TL-BO', + 'TL-CO', + 'TL-DI', + 'TL-ER', + 'TL-LA', + 'TL-LI', + 'TL-MF', + 'TL-MT', + 'TL-OE', + 'TL-VI', + 'TM-A', + 'TM-B', + 'TM-D', + 'TM-L', + 'TM-M', + 'TN-11', + 'TN-12', + 'TN-13', + 'TN-21', + 'TN-22', + 'TN-23', + 'TN-31', + 'TN-32', + 'TN-33', + 'TN-34', + 'TN-41', + 'TN-42', + 'TN-43', + 'TN-51', + 'TN-52', + 'TN-53', + 'TN-61', + 'TN-71', + 'TN-72', + 'TN-73', + 'TN-81', + 'TN-82', + 'TN-83', + 'TR-01', + 'TR-02', + 'TR-03', + 'TR-04', + 'TR-05', + 'TR-06', + 'TR-07', + 'TR-08', + 'TR-09', + 'TR-10', + 'TR-11', + 'TR-12', + 'TR-13', + 'TR-14', + 'TR-15', + 'TR-16', + 'TR-17', + 'TR-18', + 'TR-19', + 'TR-20', + 'TR-21', + 'TR-22', + 'TR-23', + 'TR-24', + 'TR-25', + 'TR-26', + 'TR-27', + 'TR-28', + 'TR-29', + 'TR-30', + 'TR-31', + 'TR-32', + 'TR-33', + 'TR-34', + 'TR-35', + 'TR-36', + 'TR-37', + 'TR-38', + 'TR-39', + 'TR-40', + 'TR-41', + 'TR-42', + 'TR-43', + 'TR-44', + 'TR-45', + 'TR-46', + 'TR-47', + 'TR-48', + 'TR-49', + 'TR-50', + 'TR-51', + 'TR-52', + 'TR-53', + 'TR-54', + 'TR-55', + 'TR-56', + 'TR-57', + 'TR-58', + 'TR-59', + 'TR-60', + 'TR-61', + 'TR-62', + 'TR-63', + 'TR-64', + 'TR-65', + 'TR-66', + 'TR-67', + 'TR-68', + 'TR-69', + 'TR-70', + 'TR-71', + 'TR-72', + 'TR-73', + 'TR-74', + 'TR-75', + 'TR-76', + 'TR-77', + 'TR-78', + 'TR-79', + 'TR-80', + 'TR-81', + 'TT-ARI', + 'TT-CHA', + 'TT-CTT', + 'TT-DMN', + 'TT-ETO', + 'TT-PED', + 'TT-POS', + 'TT-PRT', + 'TT-PTF', + 'TT-RCM', + 'TT-SFO', + 'TT-SGE', + 'TT-SIP', + 'TT-SJL', + 'TT-TUP', + 'TT-WTO', + 'TW-CHA', + 'TW-CYQ', + 'TW-HSQ', + 'TW-HUA', + 'TW-ILA', + 'TW-KEE', + 'TW-KHQ', + 'TW-MIA', + 'TW-NAN', + 'TW-PEN', + 'TW-PIF', + 'TW-TAO', + 'TW-TNQ', + 'TW-TPQ', + 'TW-TTT', + 'TW-TXQ', + 'TW-YUN', + 'TZ-01', + 'TZ-02', + 'TZ-03', + 'TZ-04', + 'TZ-05', + 'TZ-06', + 'TZ-07', + 'TZ-08', + 'TZ-09', + 'TZ-10', + 'TZ-11', + 'TZ-12', + 'TZ-13', + 'TZ-14', + 'TZ-15', + 'TZ-16', + 'TZ-17', + 'TZ-18', + 'TZ-19', + 'TZ-20', + 'TZ-21', + 'TZ-22', + 'TZ-23', + 'TZ-24', + 'TZ-25', + 'UA-05', + 'UA-07', + 'UA-09', + 'UA-12', + 'UA-14', + 'UA-18', + 'UA-21', + 'UA-23', + 'UA-26', + 'UA-30', + 'UA-32', + 'UA-35', + 'UA-40', + 'UA-43', + 'UA-46', + 'UA-48', + 'UA-51', + 'UA-53', + 'UA-56', + 'UA-59', + 'UA-61', + 'UA-63', + 'UA-65', + 'UA-68', + 'UA-71', + 'UA-74', + 'UA-77', + 'UG-AJM', + 'UG-APA', + 'UG-ARU', + 'UG-BUA', + 'UG-BUG', + 'UG-BUN', + 'UG-BUS', + 'UG-C', + 'UG-E', + 'UG-GUL', + 'UG-HOI', + 'UG-IGA', + 'UG-JIN', + 'UG-KAP', + 'UG-KAS', + 'UG-KAT', + 'UG-KBL', + 'UG-KBR', + 'UG-KIB', + 'UG-KIS', + 'UG-KIT', + 'UG-KLA', + 'UG-KLE', + 'UG-KLG', + 'UG-KLI', + 'UG-KOT', + 'UG-KUM', + 'UG-LIR', + 'UG-LUW', + 'UG-MBL', + 'UG-MBR', + 'UG-MOR', + 'UG-MOY', + 'UG-MPI', + 'UG-MSI', + 'UG-MSK', + 'UG-MUB', + 'UG-MUK', + 'UG-N', + 'UG-NAK', + 'UG-NEB', + 'UG-NTU', + 'UG-PAL', + 'UG-RAK', + 'UG-RUK', + 'UG-SEM', + 'UG-SOR', + 'UG-TOR', + 'UG-W', + 'UM-67', + 'UM-71', + 'UM-76', + 'UM-79', + 'UM-81', + 'UM-84', + 'UM-86', + 'UM-89', + 'UM-95', + 'US-AK', + 'US-AL', + 'US-AR', + 'US-AS', + 'US-AZ', + 'US-CA', + 'US-CO', + 'US-CT', + 'US-DC', + 'US-DE', + 'US-FL', + 'US-GA', + 'US-GU', + 'US-HI', + 'US-IA', + 'US-ID', + 'US-IL', + 'US-IN', + 'US-KS', + 'US-KY', + 'US-LA', + 'US-MA', + 'US-MD', + 'US-ME', + 'US-MI', + 'US-MN', + 'US-MO', + 'US-MP', + 'US-MS', + 'US-MT', + 'US-NC', + 'US-ND', + 'US-NE', + 'US-NH', + 'US-NJ', + 'US-NM', + 'US-NV', + 'US-NY', + 'US-OH', + 'US-OK', + 'US-OR', + 'US-PA', + 'US-PR', + 'US-RI', + 'US-SC', + 'US-SD', + 'US-TN', + 'US-TX', + 'US-UM', + 'US-UT', + 'US-VA', + 'US-VI', + 'US-VT', + 'US-WA', + 'US-WI', + 'US-WV', + 'US-WY', + 'UY-AR', + 'UY-CA', + 'UY-CL', + 'UY-CO', + 'UY-DU', + 'UY-FD', + 'UY-FS', + 'UY-LA', + 'UY-MA', + 'UY-MO', + 'UY-PA', + 'UY-RN', + 'UY-RO', + 'UY-RV', + 'UY-SA', + 'UY-SJ', + 'UY-SO', + 'UY-TA', + 'UY-TT', + 'UZ-AN', + 'UZ-BU', + 'UZ-FA', + 'UZ-JI', + 'UZ-NG', + 'UZ-NW', + 'UZ-QA', + 'UZ-QR', + 'UZ-SA', + 'UZ-SI', + 'UZ-SU', + 'UZ-TK', + 'UZ-TO', + 'UZ-XO', + 'VE-A', + 'VE-B', + 'VE-C', + 'VE-D', + 'VE-E', + 'VE-F', + 'VE-G', + 'VE-H', + 'VE-I', + 'VE-J', + 'VE-K', + 'VE-L', + 'VE-M', + 'VE-N', + 'VE-O', + 'VE-P', + 'VE-R', + 'VE-S', + 'VE-T', + 'VE-U', + 'VE-V', + 'VE-W', + 'VE-X', + 'VE-Y', + 'VE-Z', + 'VN-01', + 'VN-02', + 'VN-03', + 'VN-04', + 'VN-05', + 'VN-06', + 'VN-07', + 'VN-09', + 'VN-13', + 'VN-14', + 'VN-15', + 'VN-18', + 'VN-20', + 'VN-21', + 'VN-22', + 'VN-23', + 'VN-24', + 'VN-25', + 'VN-26', + 'VN-27', + 'VN-28', + 'VN-29', + 'VN-30', + 'VN-31', + 'VN-32', + 'VN-33', + 'VN-34', + 'VN-35', + 'VN-36', + 'VN-37', + 'VN-39', + 'VN-40', + 'VN-41', + 'VN-43', + 'VN-44', + 'VN-45', + 'VN-46', + 'VN-47', + 'VN-48', + 'VN-49', + 'VN-50', + 'VN-51', + 'VN-52', + 'VN-53', + 'VN-54', + 'VN-55', + 'VN-56', + 'VN-57', + 'VN-58', + 'VN-59', + 'VN-60', + 'VN-61', + 'VN-62', + 'VN-63', + 'VN-64', + 'VN-65', + 'VN-66', + 'VN-67', + 'VN-68', + 'VN-69', + 'VN-70', + 'VU-MAP', + 'VU-PAM', + 'VU-SAM', + 'VU-SEE', + 'VU-TAE', + 'VU-TOB', + 'WS-AA', + 'WS-AL', + 'WS-AT', + 'WS-FA', + 'WS-GE', + 'WS-GI', + 'WS-PA', + 'WS-SA', + 'WS-TU', + 'WS-VF', + 'WS-VS', + 'YE-AB', + 'YE-AD', + 'YE-AM', + 'YE-BA', + 'YE-DA', + 'YE-DH', + 'YE-HD', + 'YE-HJ', + 'YE-HU', + 'YE-IB', + 'YE-JA', + 'YE-LA', + 'YE-MA', + 'YE-MR', + 'YE-MW', + 'YE-SD', + 'YE-SH', + 'YE-SN', + 'YE-TA', + 'YU-CG', + 'YU-KM', + 'YU-SR', + 'YU-VO', + 'ZA-EC', + 'ZA-FS', + 'ZA-GT', + 'ZA-MP', + 'ZA-NC', + 'ZA-NL', + 'ZA-NP', + 'ZA-NW', + 'ZA-WC', + 'ZM-01', + 'ZM-02', + 'ZM-03', + 'ZM-04', + 'ZM-05', + 'ZM-06', + 'ZM-07', + 'ZM-08', + 'ZM-09', + 'ZW-BU', + 'ZW-HA', + 'ZW-MA', + 'ZW-MC', + 'ZW-ME', + 'ZW-MI', + 'ZW-MN', + 'ZW-MS', + 'ZW-MV', + 'ZW-MW', + ), +) + +Subdivision.__doc__ = """ +Subvidision country codes from ISO 3166-2. + +Taken from `here `_. +""" + + +class Layouts(Enum): + """Keyboard layouts. Taken from Debian's 9 + /usr/share/X11/xkb/rules/evdev.lst. + """ + + US = 'English (US)' + AF = 'Afghani' + ARA = 'Arabic' + AL = 'Albanian' + AM = 'Armenian' + AT = 'German (Austria)' + AU = 'English (Australian)' + AZ = 'Azerbaijani' + BY = 'Belarusian' + BE = 'Belgian' + BD = 'Bangla' + BA = 'Bosnian' + BR = 'Portuguese (Brazil)' + BG = 'Bulgarian' + DZ = 'Berber (Algeria, Latin characters)' + MA = 'Arabic (Morocco)' + CM = 'English (Cameroon)' + MM = 'Burmese' + CA = 'French (Canada)' + CD = 'French (Democratic Republic of the Congo)' + CN = 'Chinese' + HR = 'Croatian' + CZ = 'Czech' + DK = 'Danish' + NL = 'Dutch' + BT = 'Dzongkha' + EE = 'Estonian' + IR = 'Persian' + IQ = 'Iraqi' + FO = 'Faroese' + FI = 'Finnish' + FR = 'French' + GH = 'English (Ghana)' + GN = 'French (Guinea)' + GE = 'Georgian' + DE = 'German' + GR = 'Greek' + HU = 'Hungarian' + IL = 'Hebrew' + IT = 'Italian' + JP = 'Japanese' + KG = 'Kyrgyz' + KH = 'Khmer (Cambodia)' + KZ = 'Kazakh' + LA = 'Lao' + LATAM = 'Spanish (Latin American)' + LT = 'Lithuanian' + LV = 'Latvian' + MAO = 'Maori' + ME = 'Montenegrin' + MK = 'Macedonian' + MT = 'Maltese' + MN = 'Mongolian' + NO = 'Norwegian' + PL = 'Polish' + PT = 'Portuguese' + RO = 'Romanian' + RU = 'Russian' + RS = 'Serbian' + SI = 'Slovenian' + SK = 'Slovak' + ES = 'Spanish' + SE = 'Swedish' + CH = 'German (Switzerland)' + SY = 'Arabic (Syria)' + TJ = 'Tajik' + LK = 'Sinhala (phonetic)' + TH = 'Thai' + TR = 'Turkish' + TW = 'Taiwanese' + UA = 'Ukrainian' + GB = 'English (UK)' + UZ = 'Uzbek' + VN = 'Vietnamese' + KR = 'Korean' + IE = 'Irish' + PK = 'Urdu (Pakistan)' + MV = 'Dhivehi' + ZA = 'English (South Africa)' + EPO = 'Esperanto' + NP = 'Nepali' + NG = 'English (Nigeria)' + ET = 'Amharic' + SN = 'Wolof' + BRAI = 'Braille' + TM = 'Turkmen' + ML = 'Bambara' + TZ = 'Swahili (Tanzania)' + TG = 'French (Togo)' + KE = 'Swahili (Kenya)' + BW = 'Tswana' + PH = 'Filipino' + MD = 'Moldavian' + ID = 'Indonesian (Jawi)' + MY = 'Malay (Jawi)' + BN = 'Malay (Jawi)' + IN = 'Indian' + IS = 'Icelandic' + NEC_VNDR_JP = 'Japanese (PC-98xx Series)' + + def __str__(self): + return self.value From 0b5d8d46d19f2d5734d4291aefc3f0d47b3254f3 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 13 Apr 2022 13:27:58 +0200 Subject: [PATCH 09/22] fixing bug --- ereuse_devicehub/enums.py | 4421 --------------------- ereuse_devicehub/resources/user/models.py | 3 +- 2 files changed, 2 insertions(+), 4422 deletions(-) delete mode 100644 ereuse_devicehub/enums.py diff --git a/ereuse_devicehub/enums.py b/ereuse_devicehub/enums.py deleted file mode 100644 index 175b2227..00000000 --- a/ereuse_devicehub/enums.py +++ /dev/null @@ -1,4421 +0,0 @@ -from enum import Enum, unique - - -@unique -class Currency(Enum): - """Currencies as for ISO 4217.""" - - AFN = 1 - ARS = 2 - AWG = 3 - AUD = 4 - AZN = 5 - BSD = 6 - BBD = 7 - BDT = 8 - BYR = 9 - BZD = 10 - BMD = 11 - BOB = 12 - BAM = 13 - BWP = 14 - BGN = 15 - BRL = 16 - BND = 17 - KHR = 18 - CAD = 19 - KYD = 20 - CLP = 21 - CNY = 22 - COP = 23 - CRC = 24 - HRK = 25 - CUP = 26 - CZK = 27 - DKK = 28 - DOP = 29 - XCD = 30 - EGP = 31 - SVC = 32 - EEK = 33 - EUR = 34 - FKP = 35 - FJD = 36 - GHC = 37 - GIP = 38 - GTQ = 39 - GGP = 40 - GYD = 41 - HNL = 42 - HKD = 43 - HUF = 44 - ISK = 45 - INR = 46 - IDR = 47 - IRR = 48 - IMP = 49 - ILS = 50 - JMD = 51 - JPY = 52 - JEP = 53 - KZT = 54 - KPW = 55 - KRW = 56 - KGS = 57 - LAK = 58 - LVL = 59 - LBP = 60 - LRD = 61 - LTL = 62 - MKD = 63 - MYR = 64 - MUR = 65 - MXN = 66 - MNT = 67 - MZN = 68 - NAD = 69 - NPR = 70 - ANG = 71 - NZD = 72 - NIO = 73 - NGN = 74 - NOK = 75 - OMR = 76 - PKR = 77 - PAB = 78 - PYG = 79 - PEN = 80 - PHP = 81 - PLN = 82 - QAR = 83 - RON = 84 - RUB = 85 - SHP = 86 - SAR = 87 - RSD = 88 - SCR = 89 - SGD = 90 - SBD = 91 - SOS = 92 - ZAR = 93 - LKR = 94 - SEK = 95 - CHF = 96 - SRD = 97 - SYP = 98 - TWD = 99 - THB = 100 - TTD = 101 - TRY = 102 - TRL = 103 - TVD = 104 - UAH = 105 - GBP = 106 - USD = 107 - UYU = 108 - UZS = 109 - VEF = 110 - VND = 111 - YER = 112 - ZWD = 113 - - def __str__(self): - if self == Currency.EUR: - return '€' - else: - return self.name - - -@unique -class Continent(Enum): - """ - Continent codes. - - From `Data hub `_. - """ - - AF = 'Africa' - NA = 'North America' - OC = 'Oceania' - AN = 'Antartica' - AS = 'Asia' - EU = 'Europe' - SA = 'South America' - - -@unique -class Country(Enum): - """ - Countries as ISO 3166-1 alpha 2. - - Taken from table from `iso-3616-1 commit - 8e31d749b9ce331cfa50c280a29b04ae2d805b7e `_. - """ - - AF = "Afghanistan" - AX = "Åland Islands" - AL = "Albania" - DZ = "Algeria" - AS = "American Samoa" - AD = "Andorra" - AO = "Angola" - AI = "Anguilla" - AQ = "Antarctica" - AG = "Antigua and Barbuda" - AR = "Argentina" - AM = "Armenia" - AW = "Aruba" - AU = "Australia" - AT = "Austria" - AZ = "Azerbaijan" - BS = "Bahamas" - BH = "Bahrain" - BD = "Bangladesh" - BB = "Barbados" - BY = "Belarus" - BE = "Belgium" - BZ = "Belize" - BJ = "Benin" - BM = "Bermuda" - BT = "Bhutan" - BO = "Bolivia (Plurinational State of)" - BQ = "Bonaire, Sint Eustatius and Saba" - BA = "Bosnia and Herzegovina" - BW = "Botswana" - BV = "Bouvet Island" - BR = "Brazil" - IO = "British Indian Ocean Territory" - BN = "Brunei Darussalam" - BG = "Bulgaria" - BF = "Burkina Faso" - BI = "Burundi" - KH = "Cambodia" - CM = "Cameroon" - CA = "Canada" - CV = "Cabo Verde" - KY = "Cayman Islands" - CF = "Central African Republic" - TD = "Chad" - CL = "Chile" - CN = "China" - CX = "Christmas Island" - CC = "Cocos (Keeling) Islands" - CO = "Colombia" - KM = "Comoros" - CG = "Congo" - CD = "Congo (Democratic Republic of the)" - CK = "Cook Islands" - CR = "Costa Rica" - CI = "Côte d'Ivoire" - HR = "Croatia" - CU = "Cuba" - CW = "Curaçao" - CY = "Cyprus" - CZ = "Czech Republic" - DK = "Denmark" - DJ = "Djibouti" - DM = "Dominica" - DO = "Dominican Republic" - EC = "Ecuador" - EG = "Egypt" - SV = "El Salvador" - GQ = "Equatorial Guinea" - ER = "Eritrea" - EE = "Estonia" - ET = "Ethiopia" - FK = "Falkland Islands (Malvinas)" - FO = "Faroe Islands" - FJ = "Fiji" - FI = "Finland" - FR = "France" - GF = "French Guiana" - PF = "French Polynesia" - TF = "French Southern Territories" - GA = "Gabon" - GM = "Gambia" - GE = "Georgia" - DE = "Germany" - GH = "Ghana" - GI = "Gibraltar" - GR = "Greece" - GL = "Greenland" - GD = "Grenada" - GP = "Guadeloupe" - GU = "Guam" - GT = "Guatemala" - GG = "Guernsey" - GN = "Guinea" - GW = "Guinea-Bissau" - GY = "Guyana" - HT = "Haiti" - HM = "Heard Island and McDonald Islands" - VA = "Holy See" - HN = "Honduras" - HK = "Hong Kong" - HU = "Hungary" - IS = "Iceland" - IN = "India" - ID = "Indonesia" - IR = "Iran (Islamic Republic of)" - IQ = "Iraq" - IE = "Ireland" - IM = "Isle of Man" - IL = "Israel" - IT = "Italy" - JM = "Jamaica" - JP = "Japan" - JE = "Jersey" - JO = "Jordan" - KZ = "Kazakhstan" - KE = "Kenya" - KI = "Kiribati" - KP = "Korea (Democratic People's Republic of)" - KR = "Korea (Republic of)" - KW = "Kuwait" - KG = "Kyrgyzstan" - LA = "Lao People's Democratic Republic" - LV = "Latvia" - LB = "Lebanon" - LS = "Lesotho" - LR = "Liberia" - LY = "Libya" - LI = "Liechtenstein" - LT = "Lithuania" - LU = "Luxembourg" - MO = "Macao" - MK = "Macedonia (the former Yugoslav Republic of)" - MG = "Madagascar" - MW = "Malawi" - MY = "Malaysia" - MV = "Maldives" - ML = "Mali" - MT = "Malta" - MH = "Marshall Islands" - MQ = "Martinique" - MR = "Mauritania" - MU = "Mauritius" - YT = "Mayotte" - MX = "Mexico" - FM = "Micronesia (Federated States of)" - MD = "Moldova (Republic of)" - MC = "Monaco" - MN = "Mongolia" - ME = "Montenegro" - MS = "Montserrat" - MA = "Morocco" - MZ = "Mozambique" - MM = "Myanmar" - NA = "Namibia" - NR = "Nauru" - NP = "Nepal" - NL = "Netherlands" - NC = "New Caledonia" - NZ = "New Zealand" - NI = "Nicaragua" - NE = "Niger" - NG = "Nigeria" - NU = "Niue" - NF = "Norfolk Island" - MP = "Northern Mariana Islands" - NO = "Norway" - OM = "Oman" - PK = "Pakistan" - PW = "Palau" - PS = "Palestine, State of" - PA = "Panama" - PG = "Papua New Guinea" - PY = "Paraguay" - PE = "Peru" - PH = "Philippines" - PN = "Pitcairn" - PL = "Poland" - PT = "Portugal" - PR = "Puerto Rico" - QA = "Qatar" - RE = "Réunion" - RO = "Romania" - RU = "Russian Federation" - RW = "Rwanda" - BL = "Saint Barthélemy" - SH = "Saint Helena, Ascension and Tristan da Cunha" - KN = "Saint Kitts and Nevis" - LC = "Saint Lucia" - MF = "Saint Martin (French part)" - PM = "Saint Pierre and Miquelon" - VC = "Saint Vincent and the Grenadines" - WS = "Samoa" - SM = "San Marino" - ST = "Sao Tome and Principe" - SA = "Saudi Arabia" - SN = "Senegal" - RS = "Serbia" - SC = "Seychelles" - SL = "Sierra Leone" - SG = "Singapore" - SX = "Sint Maarten (Dutch part)" - SK = "Slovakia" - SI = "Slovenia" - SB = "Solomon Islands" - SO = "Somalia" - ZA = "South Africa" - GS = "South Georgia and the South Sandwich Islands" - SS = "South Sudan" - ES = "Spain" - LK = "Sri Lanka" - SD = "Sudan" - SR = "Suriname" - SJ = "Svalbard and Jan Mayen" - SZ = "Swaziland" - SE = "Sweden" - CH = "Switzerland" - SY = "Syrian Arab Republic" - TW = "Taiwan, Province of China" - TJ = "Tajikistan" - TZ = "Tanzania, United Republic of" - TH = "Thailand" - TL = "Timor-Leste" - TG = "Togo" - TK = "Tokelau" - TO = "Tonga" - TT = "Trinidad and Tobago" - TN = "Tunisia" - TR = "Turkey" - TM = "Turkmenistan" - TC = "Turks and Caicos Islands" - TV = "Tuvalu" - UG = "Uganda" - UA = "Ukraine" - AE = "United Arab Emirates" - GB = "United Kingdom of Great Britain and Northern Ireland" - US = "United States of America" - UM = "United States Minor Outlying Islands" - UY = "Uruguay" - UZ = "Uzbekistan" - VU = "Vanuatu" - VE = "Venezuela (Bolivarian Republic of)" - VN = "Viet Nam" - VG = "Virgin Islands (British)" - VI = "Virgin Islands (U.S.)" - WF = "Wallis and Futuna" - EH = "Western Sahara" - YE = "Yemen" - ZM = "Zambia" - ZW = "Zimbabwe" - - def __contains__(self, item: 'Subdivision'): - """Checks if a Subdivision is inside of this Country.""" - if not isinstance(item, Subdivision): - raise TypeError('Only subdivisions can be inside a country.') - return item.country == self - - def __str__(self): - return self.value - - -class SubdivisionMixin: - @property - def country(self: Enum) -> Country: - """Returns the Country of the Subdivision.""" - return Country[self.name[0:2]] - - -# noinspection PyArgumentList -Subdivision = Enum( - 'Subdivision', - type=SubdivisionMixin, - module=__name__, - names=( - 'AE-AJ', - 'AE-AZ', - 'AE-DU', - 'AE-FU', - 'AE-RK', - 'AE-SH', - 'AE-UQ', - 'AF-BAL', - 'AF-BAM', - 'AF-BDG', - 'AF-BDS', - 'AF-BGL', - 'AF-FRAU', - 'AF-FYB', - 'AF-GHA', - 'AF-GHO', - 'AF-HEL', - 'AF-HER', - 'AF-JOW', - 'AF-KAB', - 'AF-KANN', - 'AF-KAP', - 'AF-KDZ', - 'AF-KNR', - 'AF-LAG', - 'AF-LOW', - 'AF-NAN', - 'AF-NIM', - 'AF-ORU', - 'AF-PAR', - 'AF-PIA', - 'AF-PKA', - 'AF-SAM', - 'AF-SAR', - 'AF-TAK', - 'AF-WAR', - 'AF-ZAB', - 'AL-BR', - 'AL-BU', - 'AL-DI', - 'AL-DL', - 'AL-DR', - 'AL-DV', - 'AL-EL', - 'AL-ER', - 'AL-FR', - 'AL-GJ', - 'AL-GR', - 'AL-HA', - 'AL-KA', - 'AL-KB', - 'AL-KC', - 'AL-KO', - 'AL-KR', - 'AL-KU', - 'AL-LA', - 'AL-LB', - 'AL-LE', - 'AL-LU', - 'AL-MK', - 'AL-MM', - 'AL-MR', - 'AL-MT', - 'AL-PG', - 'AL-PQ', - 'AL-PR', - 'AL-PU', - 'AL-SH', - 'AL-SK', - 'AL-SR', - 'AL-TE', - 'AL-TP', - 'AL-TR', - 'AL-VL', - 'AM-AG', - 'AM-AR', - 'AM-AV', - 'AM-ER', - 'AM-GR', - 'AM-KT', - 'AM-LO', - 'AM-SH', - 'AM-SU', - 'AM-TV', - 'AM-VD', - 'AO-BGO', - 'AO-BGU', - 'AO-BIE', - 'AO-CAB', - 'AO-CCU', - 'AO-CNN', - 'AO-CNO', - 'AO-CUS', - 'AO-HUA', - 'AO-HUI', - 'AO-LNO', - 'AO-LSU', - 'AO-LUA', - 'AO-MAL', - 'AO-MOX', - 'AO-NAM', - 'AO-UIG', - 'AO-ZAI', - 'AR-A', - 'AR-B', - 'AR-C', - 'AR-D', - 'AR-E', - 'AR-F', - 'AR-G', - 'AR-H', - 'AR-J', - 'AR-K', - 'AR-L', - 'AR-M', - 'AR-N', - 'AR-P', - 'AR-Q', - 'AR-R', - 'AR-S', - 'AR-T', - 'AR-U', - 'AR-V', - 'AR-W', - 'AR-X', - 'AR-Y', - 'AR-Z', - 'AT-1', - 'AT-2', - 'AT-3', - 'AT-4', - 'AT-5', - 'AT-6', - 'AT-7', - 'AT-8', - 'AT-9', - 'AU-CT', - 'AU-NS', - 'AU-NT', - 'AU-QL', - 'AU-SA', - 'AU-TS', - 'AU-VI', - 'AU-WA', - 'AZ-AB', - 'AZ-ABS', - 'AZ-AGA', - 'AZ-AGC', - 'AZ-AGM', - 'AZ-AGS', - 'AZ-AGU', - 'AZ-AST', - 'AZ-BA', - 'AZ-BAB', - 'AZ-BAL', - 'AZ-BAR', - 'AZ-BEY', - 'AZ-BIL', - 'AZ-CAB', - 'AZ-CAL', - 'AZ-CUL', - 'AZ-DAS', - 'AZ-DAV', - 'AZ-FUZ', - 'AZ-GA', - 'AZ-GAD', - 'AZ-GOR', - 'AZ-GOY', - 'AZ-HAC', - 'AZ-IMI', - 'AZ-ISM', - 'AZ-KAL', - 'AZ-KUR', - 'AZ-LA', - 'AZ-LAC', - 'AZ-LAN', - 'AZ-LER', - 'AZ-MAS', - 'AZ-MI', - 'AZ-MM', - 'AZ-NA', - 'AZ-NEF', - 'AZ-OGU', - 'AZ-ORD', - 'AZ-QAB', - 'AZ-QAX', - 'AZ-QAZ', - 'AZ-QBA', - 'AZ-QBI', - 'AZ-QOB', - 'AZ-QUS', - 'AZ-SA', - 'AZ-SAB', - 'AZ-SAD', - 'AZ-SAH', - 'AZ-SAK', - 'AZ-SAL', - 'AZ-SAR', - 'AZ-SAT', - 'AZ-SIY', - 'AZ-SKR', - 'AZ-SM', - 'AZ-SMI', - 'AZ-SMX', - 'AZ-SS', - 'AZ-SUS', - 'AZ-TAR', - 'AZ-TOV', - 'AZ-UCA', - 'AZ-XA', - 'AZ-XAC', - 'AZ-XAN', - 'AZ-XCI', - 'AZ-XIZ', - 'AZ-XVD', - 'AZ-YAR', - 'AZ-YE', - 'AZ-YEV', - 'AZ-ZAN', - 'AZ-ZAQ', - 'AZ-ZAR', - 'BA-BIH', - 'BA-SRP', - 'BD-01', - 'BD-02', - 'BD-03', - 'BD-04', - 'BD-05', - 'BD-06', - 'BD-07', - 'BD-08', - 'BD-09', - 'BD-1', - 'BD-10', - 'BD-11', - 'BD-12', - 'BD-13', - 'BD-14', - 'BD-15', - 'BD-16', - 'BD-17', - 'BD-18', - 'BD-19', - 'BD-2', - 'BD-20', - 'BD-21', - 'BD-22', - 'BD-23', - 'BD-24', - 'BD-25', - 'BD-26', - 'BD-27', - 'BD-28', - 'BD-29', - 'BD-3', - 'BD-30', - 'BD-31', - 'BD-32', - 'BD-33', - 'BD-34', - 'BD-35', - 'BD-36', - 'BD-37', - 'BD-38', - 'BD-39', - 'BD-4', - 'BD-40', - 'BD-41', - 'BD-42', - 'BD-43', - 'BD-44', - 'BD-45', - 'BD-46', - 'BD-47', - 'BD-48', - 'BD-49', - 'BD-5', - 'BD-50', - 'BD-51', - 'BD-52', - 'BD-53', - 'BD-54', - 'BD-55', - 'BD-56', - 'BD-57', - 'BD-58', - 'BD-59', - 'BD-6', - 'BD-60', - 'BD-61', - 'BD-62', - 'BD-63', - 'BD-64', - 'BE-BRU', - 'BE-VAN', - 'BE-VBR', - 'BE-VLG', - 'BE-VLI', - 'BE-VOV', - 'BE-VWV', - 'BE-WAL', - 'BE-WBR', - 'BE-WHT', - 'BE-WLG', - 'BE-WLX', - 'BE-WNA', - 'BF-BAL', - 'BF-BAM', - 'BF-BAN', - 'BF-BAZ', - 'BF-BGR', - 'BF-BLG', - 'BF-BLK', - 'BF-COM', - 'BF-GAN', - 'BF-GNA', - 'BF-GOU', - 'BF-HOU', - 'BF-IOB', - 'BF-KAD', - 'BF-KEN', - 'BF-KMD', - 'BF-KMP', - 'BF-KOP', - 'BF-KOS', - 'BF-KOT', - 'BF-KOW', - 'BF-LER', - 'BF-LOR', - 'BF-MOU', - 'BF-NAM', - 'BF-NAO', - 'BF-NAY', - 'BF-NOU', - 'BF-OUB', - 'BF-OUD', - 'BF-PAS', - 'BF-PON', - 'BF-SEN', - 'BF-SIS', - 'BF-SMT', - 'BF-SNG', - 'BF-SOM', - 'BF-SOR', - 'BF-TAP', - 'BF-TUI', - 'BF-YAG', - 'BF-YAT', - 'BF-ZIR', - 'BF-ZON', - 'BF-ZOU', - 'BG-01', - 'BG-02', - 'BG-03', - 'BG-04', - 'BG-05', - 'BG-06', - 'BG-07', - 'BG-08', - 'BG-09', - 'BG-10', - 'BG-11', - 'BG-12', - 'BG-13', - 'BG-14', - 'BG-15', - 'BG-16', - 'BG-17', - 'BG-18', - 'BG-19', - 'BG-20', - 'BG-21', - 'BG-22', - 'BG-23', - 'BG-24', - 'BG-25', - 'BG-26', - 'BG-27', - 'BG-28', - 'BH-01', - 'BH-02', - 'BH-03', - 'BH-04', - 'BH-05', - 'BH-06', - 'BH-07', - 'BH-08', - 'BH-09', - 'BH-10', - 'BH-11', - 'BH-12', - 'BI-BB', - 'BI-BJ', - 'BI-BR', - 'BI-CA', - 'BI-CI', - 'BI-GI', - 'BI-KI', - 'BI-KR', - 'BI-KY', - 'BI-MA', - 'BI-MU', - 'BI-MW', - 'BI-MY', - 'BI-NG', - 'BI-RT', - 'BI-RY', - 'BJ-AK', - 'BJ-AL', - 'BJ-AQ', - 'BJ-BO', - 'BJ-CO', - 'BJ-DO', - 'BJ-KO', - 'BJ-LI', - 'BJ-MO', - 'BJ-OU', - 'BJ-PL', - 'BJ-ZO', - 'BN-BE', - 'BN-BM', - 'BN-TE', - 'BN-TU', - 'BO-B', - 'BO-C', - 'BO-H', - 'BO-L', - 'BO-N', - 'BO-O', - 'BO-P', - 'BO-S', - 'BO-T', - 'BR-AC', - 'BR-AL', - 'BR-AM', - 'BR-AP', - 'BR-BA', - 'BR-CE', - 'BR-DF', - 'BR-ES', - 'BR-GO', - 'BR-MA', - 'BR-MG', - 'BR-MS', - 'BR-MT', - 'BR-PA', - 'BR-PB', - 'BR-PE', - 'BR-PI', - 'BR-PR', - 'BR-RJ', - 'BR-RN', - 'BR-RO', - 'BR-RR', - 'BR-RS', - 'BR-SC', - 'BR-SE', - 'BR-SP', - 'BR-TO', - 'BS-AC', - 'BS-BI', - 'BS-CI', - 'BS-EX', - 'BS-FC', - 'BS-FP', - 'BS-GH', - 'BS-GT', - 'BS-HI', - 'BS-HR', - 'BS-IN', - 'BS-KB', - 'BS-LI', - 'BS-MG', - 'BS-MH', - 'BS-NB', - 'BS-NP', - 'BS-RI', - 'BS-RS', - 'BS-SP', - 'BS-SR', - 'BT-11', - 'BT-12', - 'BT-13', - 'BT-14', - 'BT-15', - 'BT-21', - 'BT-22', - 'BT-23', - 'BT-24', - 'BT-31', - 'BT-32', - 'BT-33', - 'BT-34', - 'BT-41', - 'BT-42', - 'BT-43', - 'BT-44', - 'BT-45', - 'BT-GA', - 'BT-TY', - 'BW-CE', - 'BW-CH', - 'BW-GH', - 'BW-KG', - 'BW-KL', - 'BW-KW', - 'BW-NE', - 'BW-NG', - 'BW-SE', - 'BW-SO', - 'BY-BR', - 'BY-HO', - 'BY-HR', - 'BY-MA', - 'BY-MI', - 'BY-VI', - 'BZ-BZ', - 'BZ-CY', - 'BZ-CZL', - 'BZ-OW', - 'BZ-SC', - 'BZ-TOL', - 'CA-AB', - 'CA-BC', - 'CA-MB', - 'CA-NB', - 'CA-NL', - 'CA-NS', - 'CA-NT', - 'CA-NU', - 'CA-ON', - 'CA-PE', - 'CA-QC', - 'CA-SK', - 'CA-YT', - 'CD-BC', - 'CD-BN', - 'CD-EQ', - 'CD-KA', - 'CD-KE', - 'CD-KN', - 'CD-KW', - 'CD-MA', - 'CD-NK', - 'CD-OR', - 'CD-SK', - 'CF-AC', - 'CF-BB', - 'CF-BGF', - 'CF-BK', - 'CF-HK', - 'CF-HM', - 'CF-HS', - 'CF-KB', - 'CF-KG', - 'CF-LB', - 'CF-MB', - 'CF-MP', - 'CF-NM', - 'CF-OP', - 'CF-SE', - 'CF-UK', - 'CF-VK', - 'CG-11', - 'CG-12', - 'CG-13', - 'CG-14', - 'CG-15', - 'CG-2', - 'CG-5', - 'CG-7', - 'CG-8', - 'CG-9', - 'CG-BZV', - 'CH-AG', - 'CH-AI', - 'CH-AR', - 'CH-BE', - 'CH-BL', - 'CH-BS', - 'CH-FR', - 'CH-GE', - 'CH-GL', - 'CH-GR', - 'CH-JU', - 'CH-LU', - 'CH-NE', - 'CH-NW', - 'CH-OW', - 'CH-SG', - 'CH-SH', - 'CH-SO', - 'CH-SZ', - 'CH-TG', - 'CH-TI', - 'CH-UR', - 'CH-VD', - 'CH-VS', - 'CH-ZG', - 'CH-ZH', - 'CI-01', - 'CI-02', - 'CI-03', - 'CI-04', - 'CI-05', - 'CI-06', - 'CI-07', - 'CI-08', - 'CI-09', - 'CI-10', - 'CI-11', - 'CI-12', - 'CI-13', - 'CI-14', - 'CI-15', - 'CI-16', - 'CL-AI', - 'CL-AN', - 'CL-AR', - 'CL-AT', - 'CL-BI', - 'CL-CO', - 'CL-LI', - 'CL-LL', - 'CL-MA', - 'CL-ML', - 'CL-RM', - 'CL-TA', - 'CL-VS', - 'CM-AD', - 'CM-CE', - 'CM-EN', - 'CM-ES', - 'CM-LT', - 'CM-NO', - 'CM-NW', - 'CM-OU', - 'CM-SU', - 'CM-SW', - 'CN-11', - 'CN-12', - 'CN-13', - 'CN-14', - 'CN-15', - 'CN-21', - 'CN-22', - 'CN-23', - 'CN-31', - 'CN-32', - 'CN-33', - 'CN-34', - 'CN-35', - 'CN-36', - 'CN-37', - 'CN-41', - 'CN-42', - 'CN-43', - 'CN-44', - 'CN-45', - 'CN-46', - 'CN-50', - 'CN-51', - 'CN-52', - 'CN-53', - 'CN-54', - 'CN-61', - 'CN-62', - 'CN-63', - 'CN-64', - 'CN-65', - 'CN-71', - 'CN-91', - 'CN-92', - 'CO-AMA', - 'CO-ANT', - 'CO-ARA', - 'CO-ATL', - 'CO-BOL', - 'CO-BOY', - 'CO-CAL', - 'CO-CAQ', - 'CO-CAS', - 'CO-CAU', - 'CO-CES', - 'CO-CHO', - 'CO-COR', - 'CO-CUN', - 'CO-DC', - 'CO-GUA', - 'CO-GUV', - 'CO-HUI', - 'CO-LAG', - 'CO-MAG', - 'CO-MET', - 'CO-NAR', - 'CO-NSA', - 'CO-PUT', - 'CO-QUI', - 'CO-RIS', - 'CO-SAN', - 'CO-SAP', - 'CO-SUC', - 'CO-TOL', - 'CO-VAC', - 'CO-VAU', - 'CO-VID', - 'CR-A', - 'CR-C', - 'CR-G', - 'CR-H', - 'CR-L', - 'CR-P', - 'CR-SJ', - 'CU-01', - 'CU-02', - 'CU-03', - 'CU-04', - 'CU-05', - 'CU-06', - 'CU-07', - 'CU-08', - 'CU-09', - 'CU-10', - 'CU-11', - 'CU-12', - 'CU-13', - 'CU-14', - 'CU-99', - 'CV-B', - 'CV-BR', - 'CV-BV', - 'CV-CA', - 'CV-CR', - 'CV-CS', - 'CV-FO', - 'CV-MA', - 'CV-MO', - 'CV-PA', - 'CV-PN', - 'CV-PR', - 'CV-RG', - 'CV-S', - 'CV-SF', - 'CV-SL', - 'CV-SN', - 'CV-SV', - 'CV-TA', - 'CY-01', - 'CY-02', - 'CY-03', - 'CY-04', - 'CY-05', - 'CY-06', - 'CZ-JC', - 'CZ-JM', - 'CZ-KA', - 'CZ-KR', - 'CZ-LI', - 'CZ-MO', - 'CZ-OL', - 'CZ-PA', - 'CZ-PL', - 'CZ-PR', - 'CZ-ST', - 'CZ-US', - 'CZ-VY', - 'CZ-ZL', - 'DE-BB', - 'DE-BE', - 'DE-BW', - 'DE-BY', - 'DE-HB', - 'DE-HE', - 'DE-HH', - 'DE-MV', - 'DE-NI', - 'DE-NW', - 'DE-RP', - 'DE-SH', - 'DE-SL', - 'DE-SN', - 'DE-ST', - 'DE-TH', - 'DJ-AS', - 'DJ-DI', - 'DJ-DJ', - 'DJ-OB', - 'DJ-TA', - 'DK-015', - 'DK-020', - 'DK-025', - 'DK-030', - 'DK-035', - 'DK-040', - 'DK-042', - 'DK-050', - 'DK-055', - 'DK-060', - 'DK-065', - 'DK-070', - 'DK-076', - 'DK-080', - 'DK-101', - 'DK-147', - 'DO-01', - 'DO-02', - 'DO-03', - 'DO-04', - 'DO-05', - 'DO-06', - 'DO-07', - 'DO-08', - 'DO-09', - 'DO-10', - 'DO-11', - 'DO-12', - 'DO-13', - 'DO-14', - 'DO-15', - 'DO-16', - 'DO-17', - 'DO-18', - 'DO-19', - 'DO-20', - 'DO-21', - 'DO-22', - 'DO-23', - 'DO-24', - 'DO-25', - 'DO-26', - 'DO-27', - 'DO-28', - 'DO-29', - 'DO-30', - 'DZ-01', - 'DZ-02', - 'DZ-03', - 'DZ-04', - 'DZ-05', - 'DZ-06', - 'DZ-07', - 'DZ-08', - 'DZ-09', - 'DZ-10', - 'DZ-11', - 'DZ-12', - 'DZ-13', - 'DZ-14', - 'DZ-15', - 'DZ-16', - 'DZ-17', - 'DZ-18', - 'DZ-19', - 'DZ-20', - 'DZ-21', - 'DZ-22', - 'DZ-23', - 'DZ-24', - 'DZ-25', - 'DZ-26', - 'DZ-27', - 'DZ-28', - 'DZ-29', - 'DZ-30', - 'DZ-31', - 'DZ-32', - 'DZ-33', - 'DZ-34', - 'DZ-35', - 'DZ-36', - 'DZ-37', - 'DZ-38', - 'DZ-39', - 'DZ-40', - 'DZ-41', - 'DZ-42', - 'DZ-43', - 'DZ-44', - 'DZ-45', - 'DZ-46', - 'DZ-47', - 'DZ-48', - 'EC-A', - 'EC-B', - 'EC-C', - 'EC-D', - 'EC-E', - 'EC-F', - 'EC-G', - 'EC-H', - 'EC-I', - 'EC-L', - 'EC-M', - 'EC-N', - 'EC-O', - 'EC-P', - 'EC-R', - 'EC-S', - 'EC-T', - 'EC-U', - 'EC-W', - 'EC-X', - 'EC-Y', - 'EC-Z', - 'EE-37', - 'EE-39', - 'EE-44', - 'EE-49', - 'EE-51', - 'EE-57', - 'EE-59', - 'EE-65', - 'EE-67', - 'EE-70', - 'EE-74', - 'EE-78', - 'EE-82', - 'EE-84', - 'EE-86', - 'EG-ALX', - 'EG-ASN', - 'EG-AST', - 'EG-BA', - 'EG-BH', - 'EG-BNS', - 'EG-C', - 'EG-DK', - 'EG-DT', - 'EG-FYM', - 'EG-GH', - 'EG-GZ', - 'EG-IS', - 'EG-JS', - 'EG-KB', - 'EG-KFS', - 'EG-KN', - 'EG-MN', - 'EG-MNF', - 'EG-MT', - 'EG-PTS', - 'EG-SHG', - 'EG-SHR', - 'EG-SIN', - 'EG-SUZ', - 'EG-WAD', - 'ER-AN', - 'ER-DK', - 'ER-DU', - 'ER-GB', - 'ER-MA', - 'ER-SK', - 'ES-A', - 'ES-AB', - 'ES-AL', - 'ES-AN', - 'ES-AR', - 'ES-AV', - 'ES-B', - 'ES-BA', - 'ES-BI', - 'ES-BU', - 'ES-C', - 'ES-CA', - 'ES-CC', - 'ES-CE', - 'ES-CL', - 'ES-CM', - 'ES-CN', - 'ES-CO', - 'ES-CR', - 'ES-CS', - 'ES-CT', - 'ES-CU', - 'ES-EX', - 'ES-GA', - 'ES-GC', - 'ES-GI', - 'ES-GR', - 'ES-GU', - 'ES-H', - 'ES-HU', - 'ES-J', - 'ES-L', - 'ES-LE', - 'ES-LO', - 'ES-LU', - 'ES-M', - 'ES-MA', - 'ES-ML', - 'ES-MU', - 'ES-NA', - 'ES-O', - 'ES-OR', - 'ES-P', - 'ES-PM', - 'ES-PO', - 'ES-PV', - 'ES-S', - 'ES-SA', - 'ES-SE', - 'ES-SG', - 'ES-SO', - 'ES-SS', - 'ES-T', - 'ES-TE', - 'ES-TF', - 'ES-TO', - 'ES-V', - 'ES-VA', - 'ES-VC', - 'ES-VI', - 'ES-Z', - 'ES-ZA', - 'ET-AA', - 'ET-AF', - 'ET-AM', - 'ET-BE', - 'ET-DD', - 'ET-GA', - 'ET-HA', - 'ET-OR', - 'ET-SN', - 'ET-SO', - 'ET-TI', - 'FI-AL', - 'FI-ES', - 'FI-IS', - 'FI-LL', - 'FI-LS', - 'FI-OL', - 'FJ-C', - 'FJ-E', - 'FJ-N', - 'FJ-R', - 'FJ-W', - 'FM-KSA', - 'FM-PNI', - 'FM-TRK', - 'FM-YAP', - 'FR-01', - 'FR-02', - 'FR-03', - 'FR-04', - 'FR-05', - 'FR-06', - 'FR-07', - 'FR-08', - 'FR-09', - 'FR-10', - 'FR-11', - 'FR-12', - 'FR-13', - 'FR-14', - 'FR-15', - 'FR-16', - 'FR-17', - 'FR-18', - 'FR-19', - 'FR-21', - 'FR-22', - 'FR-23', - 'FR-24', - 'FR-25', - 'FR-26', - 'FR-27', - 'FR-28', - 'FR-29', - 'FR-2A', - 'FR-2B', - 'FR-30', - 'FR-31', - 'FR-32', - 'FR-33', - 'FR-34', - 'FR-35', - 'FR-36', - 'FR-37', - 'FR-38', - 'FR-39', - 'FR-40', - 'FR-41', - 'FR-42', - 'FR-43', - 'FR-44', - 'FR-45', - 'FR-46', - 'FR-47', - 'FR-48', - 'FR-49', - 'FR-50', - 'FR-51', - 'FR-52', - 'FR-53', - 'FR-54', - 'FR-55', - 'FR-56', - 'FR-57', - 'FR-58', - 'FR-59', - 'FR-60', - 'FR-61', - 'FR-62', - 'FR-63', - 'FR-64', - 'FR-65', - 'FR-66', - 'FR-67', - 'FR-68', - 'FR-69', - 'FR-70', - 'FR-71', - 'FR-72', - 'FR-73', - 'FR-74', - 'FR-75', - 'FR-76', - 'FR-77', - 'FR-78', - 'FR-79', - 'FR-80', - 'FR-81', - 'FR-82', - 'FR-83', - 'FR-84', - 'FR-85', - 'FR-86', - 'FR-87', - 'FR-88', - 'FR-89', - 'FR-90', - 'FR-91', - 'FR-92', - 'FR-93', - 'FR-94', - 'FR-95', - 'FR-A', - 'FR-B', - 'FR-C', - 'FR-D', - 'FR-E', - 'FR-F', - 'FR-G', - 'FR-GF', - 'FR-GP', - 'FR-H', - 'FR-I', - 'FR-J', - 'FR-K', - 'FR-L', - 'FR-M', - 'FR-MQ', - 'FR-N', - 'FR-NC', - 'FR-O', - 'FR-P', - 'FR-PF', - 'FR-PM', - 'FR-Q', - 'FR-R', - 'FR-RE', - 'FR-S', - 'FR-T', - 'FR-TF', - 'FR-U', - 'FR-V', - 'FR-WF', - 'FR-YT', - 'GA-1', - 'GA-2', - 'GA-3', - 'GA-4', - 'GA-5', - 'GA-6', - 'GA-7', - 'GA-8', - 'GA-9', - 'GB-ABD', - 'GB-ABE', - 'GB-AGB', - 'GB-AGY', - 'GB-ANS', - 'GB-ANT', - 'GB-ARD', - 'GB-ARM', - 'GB-BAS', - 'GB-BBD', - 'GB-BDF', - 'GB-BDG', - 'GB-BEN', - 'GB-BEX', - 'GB-BFS', - 'GB-BGE', - 'GB-BGW', - 'GB-BIR', - 'GB-BKM', - 'GB-BLA', - 'GB-BLY', - 'GB-BMH', - 'GB-BNB', - 'GB-BNE', - 'GB-BNH', - 'GB-BNS', - 'GB-BOL', - 'GB-BPL', - 'GB-BRC', - 'GB-BRD', - 'GB-BRY', - 'GB-BST', - 'GB-BUR', - 'GB-CAM', - 'GB-CAY', - 'GB-CGN', - 'GB-CGV', - 'GB-CHA', - 'GB-CHS', - 'GB-CKF', - 'GB-CKT', - 'GB-CLD', - 'GB-CLK', - 'GB-CLR', - 'GB-CMA', - 'GB-CMD', - 'GB-CMN', - 'GB-CON', - 'GB-COV', - 'GB-CRF', - 'GB-CRY', - 'GB-CSR', - 'GB-CWY', - 'GB-DAL', - 'GB-DBY', - 'GB-DEN', - 'GB-DER', - 'GB-DEV', - 'GB-DGN', - 'GB-DGY', - 'GB-DNC', - 'GB-DND', - 'GB-DOR', - 'GB-DOW', - 'GB-DRY', - 'GB-DUD', - 'GB-DUR', - 'GB-EAL', - 'GB-EAW', - 'GB-EAY', - 'GB-EDH', - 'GB-EDU', - 'GB-ELN', - 'GB-ELS', - 'GB-ENF', - 'GB-ENG', - 'GB-ERW', - 'GB-ERY', - 'GB-ESS', - 'GB-ESX', - 'GB-FAL', - 'GB-FER', - 'GB-FIF', - 'GB-FLN', - 'GB-GAT', - 'GB-GBN', - 'GB-GLG', - 'GB-GLS', - 'GB-GRE', - 'GB-GSY', - 'GB-GWN', - 'GB-HAL', - 'GB-HAM', - 'GB-HAV', - 'GB-HCK', - 'GB-HEF', - 'GB-HIL', - 'GB-HLD', - 'GB-HMF', - 'GB-HNS', - 'GB-HPL', - 'GB-HRT', - 'GB-HRW', - 'GB-HRY', - 'GB-IOM', - 'GB-IOS', - 'GB-IOW', - 'GB-ISL', - 'GB-IVC', - 'GB-JSY', - 'GB-KEC', - 'GB-KEN', - 'GB-KHL', - 'GB-KIR', - 'GB-KTT', - 'GB-KWL', - 'GB-LAN', - 'GB-LBH', - 'GB-LCE', - 'GB-LDS', - 'GB-LEC', - 'GB-LEW', - 'GB-LIN', - 'GB-LIV', - 'GB-LMV', - 'GB-LND', - 'GB-LRN', - 'GB-LSB', - 'GB-LUT', - 'GB-MAN', - 'GB-MDB', - 'GB-MDW', - 'GB-MFT', - 'GB-MIK', - 'GB-MLN', - 'GB-MON', - 'GB-MRT', - 'GB-MRY', - 'GB-MTY', - 'GB-MYL', - 'GB-NAY', - 'GB-NBL', - 'GB-NDN', - 'GB-NEL', - 'GB-NET', - 'GB-NFK', - 'GB-NGM', - 'GB-NIR', - 'GB-NLK', - 'GB-NLN', - 'GB-NSM', - 'GB-NTA', - 'GB-NTH', - 'GB-NTL', - 'GB-NTT', - 'GB-NTY', - 'GB-NWM', - 'GB-NWP', - 'GB-NYK', - 'GB-NYM', - 'GB-OLD', - 'GB-OMH', - 'GB-ORK', - 'GB-OXF', - 'GB-PEM', - 'GB-PKN', - 'GB-PLY', - 'GB-POL', - 'GB-POR', - 'GB-POW', - 'GB-PTE', - 'GB-RCC', - 'GB-RCH', - 'GB-RCT', - 'GB-RDB', - 'GB-RDG', - 'GB-RFW', - 'GB-RIC', - 'GB-ROT', - 'GB-RUT', - 'GB-SAW', - 'GB-SAY', - 'GB-SCB', - 'GB-SCT', - 'GB-SFK', - 'GB-SFT', - 'GB-SGC', - 'GB-SHF', - 'GB-SHN', - 'GB-SHR', - 'GB-SKP', - 'GB-SLF', - 'GB-SLG', - 'GB-SLK', - 'GB-SND', - 'GB-SOL', - 'GB-SOM', - 'GB-SOS', - 'GB-SRY', - 'GB-STB', - 'GB-STE', - 'GB-STG', - 'GB-STH', - 'GB-STN', - 'GB-STS', - 'GB-STT', - 'GB-STY', - 'GB-SWA', - 'GB-SWD', - 'GB-SWK', - 'GB-TAM', - 'GB-TFW', - 'GB-THR', - 'GB-TOB', - 'GB-TOF', - 'GB-TRF', - 'GB-TWH', - 'GB-UKM', - 'GB-VGL', - 'GB-WAR', - 'GB-WBK', - 'GB-WDU', - 'GB-WFT', - 'GB-WGN', - 'GB-WILL', - 'GB-WKF', - 'GB-WLL', - 'GB-WLN', - 'GB-WLS', - 'GB-WLV', - 'GB-WND', - 'GB-WNM', - 'GB-WOK', - 'GB-WOR', - 'GB-WRL', - 'GB-WRT', - 'GB-WRX', - 'GB-WSM', - 'GB-WSX', - 'GB-YOR', - 'GB-ZET', - 'GE-AB', - 'GE-AJ', - 'GE-GU', - 'GE-IM', - 'GE-KA', - 'GE-KK', - 'GE-MM', - 'GE-RL', - 'GE-SJ', - 'GE-SK', - 'GE-SZ', - 'GE-TB', - 'GH-AA', - 'GH-AH', - 'GH-BA', - 'GH-CP', - 'GH-EP', - 'GH-NP', - 'GH-TV', - 'GH-UE', - 'GH-UW', - 'GH-WP', - 'GM-B', - 'GM-L', - 'GM-M', - 'GM-N', - 'GM-U', - 'GM-W', - 'GN-B', - 'GN-BE', - 'GN-BF', - 'GN-BK', - 'GN-C', - 'GN-CO', - 'GN-D', - 'GN-DB', - 'GN-DI', - 'GN-DL', - 'GN-DU', - 'GN-F', - 'GN-FA', - 'GN-FO', - 'GN-FR', - 'GN-GA', - 'GN-GU', - 'GN-K', - 'GN-KA', - 'GN-KB', - 'GN-KD; 2', - 'GN-KE', - 'GN-KN', - 'GN-KO', - 'GN-KS', - 'GN-L', - 'GN-LA', - 'GN-LE', - 'GN-LO', - 'GN-M', - 'GN-MC', - 'GN-MD', - 'GN-ML', - 'GN-MM', - 'GN-N', - 'GN-NZ', - 'GN-PI', - 'GN-SI', - 'GN-TE', - 'GN-TO', - 'GN-YO', - 'GQ-AN', - 'GQ-BN', - 'GQ-BS', - 'GQ-C', - 'GQ-CS', - 'GQ-I', - 'GQ-KN', - 'GQ-LI', - 'GQ-WN', - 'GR-01', - 'GR-03', - 'GR-04', - 'GR-05', - 'GR-06', - 'GR-07', - 'GR-11', - 'GR-12', - 'GR-13', - 'GR-14', - 'GR-15', - 'GR-16', - 'GR-17', - 'GR-21', - 'GR-22', - 'GR-23', - 'GR-24', - 'GR-31', - 'GR-32', - 'GR-33', - 'GR-34', - 'GR-41', - 'GR-42', - 'GR-43', - 'GR-44', - 'GR-51', - 'GR-52', - 'GR-53', - 'GR-54', - 'GR-55', - 'GR-56', - 'GR-57', - 'GR-58', - 'GR-59', - 'GR-61', - 'GR-62', - 'GR-63', - 'GR-64', - 'GR-69', - 'GR-71', - 'GR-72', - 'GR-73', - 'GR-81', - 'GR-82', - 'GR-83', - 'GR-84', - 'GR-85', - 'GR-91', - 'GR-92', - 'GR-93', - 'GR-94', - 'GR-A1', - 'GR-I', - 'GR-II', - 'GR-III', - 'GR-IV', - 'GR-IX', - 'GR-V', - 'GR-VI', - 'GR-VII', - 'GR-VIII', - 'GR-X', - 'GR-XI', - 'GR-XII', - 'GR-XIII', - 'GT-AV', - 'GT-BV', - 'GT-CM', - 'GT-CQ', - 'GT-ES', - 'GT-GU', - 'GT-HU', - 'GT-IZ', - 'GT-JA', - 'GT-JU', - 'GT-PE', - 'GT-PR', - 'GT-QC', - 'GT-QZ', - 'GT-RE', - 'GT-SA', - 'GT-SM', - 'GT-SO', - 'GT-SR', - 'GT-SU', - 'GT-TO', - 'GT-ZA', - 'GW-BA', - 'GW-BL', - 'GW-BM', - 'GW-BS', - 'GW-CA', - 'GW-GA', - 'GW-L', - 'GW-N', - 'GW-OI', - 'GW-QU', - 'GW-S', - 'GW-TO', - 'GY-BA', - 'GY-CU', - 'GY-DE', - 'GY-EB', - 'GY-ES', - 'GY-MA', - 'GY-PM', - 'GY-PT', - 'GY-UD', - 'GY-UT', - 'HN-AT', - 'HN-CH', - 'HN-CL', - 'HN-CM', - 'HN-CP', - 'HN-CR', - 'HN-EP', - 'HN-FM', - 'HN-GD', - 'HN-IB', - 'HN-IN', - 'HN-LE', - 'HN-LP', - 'HN-OC', - 'HN-OL', - 'HN-SB', - 'HN-VA', - 'HN-YO', - 'HR-01', - 'HR-02', - 'HR-03', - 'HR-04', - 'HR-05', - 'HR-06', - 'HR-07', - 'HR-08', - 'HR-09', - 'HR-10', - 'HR-11', - 'HR-12', - 'HR-13', - 'HR-14', - 'HR-15', - 'HR-16', - 'HR-17', - 'HR-18', - 'HR-19', - 'HR-20', - 'HR-21', - 'HT-AR', - 'HT-CE', - 'HT-GA', - 'HT-ND', - 'HT-NE', - 'HT-NO', - 'HT-OU', - 'HT-SD', - 'HT-SE', - 'HU-BA', - 'HU-BC', - 'HU-BE', - 'HU-BK', - 'HU-BU', - 'HU-BZ', - 'HU-CS', - 'HU-DE', - 'HU-DU', - 'HU-EG', - 'HU-FE', - 'HU-GS', - 'HU-GY', - 'HU-HB', - 'HU-HE', - 'HU-HV', - 'HU-JN', - 'HU-KE', - 'HU-KM', - 'HU-KV', - 'HU-MI', - 'HU-NK', - 'HU-NO', - 'HU-NY', - 'HU-PE', - 'HU-PS', - 'HU-SD', - 'HU-SF', - 'HU-SH', - 'HU-SK', - 'HU-SN', - 'HU-SO', - 'HU-SS', - 'HU-ST', - 'HU-SZ', - 'HU-TB', - 'HU-TO', - 'HU-VA', - 'HU-VE', - 'HU-VM', - 'HU-ZA', - 'HU-ZE', - 'ID-AC', - 'ID-BA', - 'ID-BB', - 'ID-BE', - 'ID-BT', - 'ID-GO', - 'ID-IJ', - 'ID-JA', - 'ID-JB', - 'ID-JI', - 'ID-JK', - 'ID-JT', - 'ID-JW', - 'ID-KA', - 'ID-KB', - 'ID-KI', - 'ID-KS', - 'ID-KT', - 'ID-LA', - 'ID-MA', - 'ID-MU', - 'ID-NB', - 'ID-NT', - 'ID-NU', - 'ID-PA', - 'ID-RI', - 'ID-SA', - 'ID-SB', - 'ID-SG', - 'ID-SL', - 'ID-SM', - 'ID-SN', - 'ID-SS', - 'ID-ST', - 'ID-SU', - 'ID-YO', - 'IE-C', - 'IE-C; 2', - 'IE-CE', - 'IE-CN', - 'IE-CW', - 'IE-D', - 'IE-DL', - 'IE-G', - 'IE-KE', - 'IE-KK', - 'IE-KY', - 'IE-L', - 'IE-LD', - 'IE-LH', - 'IE-LK', - 'IE-LM', - 'IE-LS', - 'IE-M', - 'IE-MH', - 'IE-MN', - 'IE-MO', - 'IE-OY', - 'IE-RN', - 'IE-SO', - 'IE-TA', - 'IE-U', - 'IE-WD', - 'IE-WH', - 'IE-WW', - 'IE-WX', - 'IL-D', - 'IL-HA', - 'IL-JM', - 'IL-M', - 'IL-TA', - 'IL-Z', - 'IN-AN', - 'IN-AP', - 'IN-AR', - 'IN-AS', - 'IN-BR', - 'IN-CH', - 'IN-CT', - 'IN-DD', - 'IN-DL', - 'IN-DN', - 'IN-GA', - 'IN-GJ', - 'IN-HP', - 'IN-HR', - 'IN-JH', - 'IN-JK', - 'IN-KA', - 'IN-KL', - 'IN-LD', - 'IN-MH', - 'IN-ML', - 'IN-MN', - 'IN-MP', - 'IN-MZ', - 'IN-NL', - 'IN-OR', - 'IN-PB', - 'IN-PY', - 'IN-RJ', - 'IN-SK', - 'IN-TN', - 'IN-TR', - 'IN-UL', - 'IN-UP', - 'IN-WB', - 'IQ-AN', - 'IQ-AR', - 'IQ-BA', - 'IQ-BB', - 'IQ-BG', - 'IQ-DA', - 'IQ-DI', - 'IQ-DQ', - 'IQ-KA', - 'IQ-MA', - 'IQ-MU', - 'IQ-NA', - 'IQ-NI', - 'IQ-QA', - 'IQ-SD', - 'IQ-SU', - 'IQ-TS', - 'IQ-WA', - 'IR-01', - 'IR-02', - 'IR-03', - 'IR-04', - 'IR-05', - 'IR-06', - 'IR-07', - 'IR-08', - 'IR-09', - 'IR-10', - 'IR-11', - 'IR-12', - 'IR-13', - 'IR-14', - 'IR-15', - 'IR-16', - 'IR-17', - 'IR-18', - 'IR-19', - 'IR-20', - 'IR-21', - 'IR-22', - 'IR-23', - 'IR-24', - 'IR-25', - 'IR-26', - 'IR-27', - 'IR-28', - 'IS-0', - 'IS-1', - 'IS-2', - 'IS-3', - 'IS-4', - 'IS-5', - 'IS-6', - 'IS-7', - 'IS-8', - 'IT-21', - 'IT-23', - 'IT-25', - 'IT-32', - 'IT-34', - 'IT-36', - 'IT-42', - 'IT-45', - 'IT-52', - 'IT-55', - 'IT-57', - 'IT-62', - 'IT-65', - 'IT-67', - 'IT-72', - 'IT-75', - 'IT-77', - 'IT-78', - 'IT-82', - 'IT-88', - 'IT-AG', - 'IT-AL', - 'IT-AN', - 'IT-AO', - 'IT-AP', - 'IT-AQ', - 'IT-AR', - 'IT-AT', - 'IT-AV', - 'IT-BA', - 'IT-BG', - 'IT-BI', - 'IT-BL', - 'IT-BN', - 'IT-BO', - 'IT-BR', - 'IT-BS', - 'IT-BZ', - 'IT-CA', - 'IT-CB', - 'IT-CE', - 'IT-CH', - 'IT-CL', - 'IT-CN', - 'IT-CO', - 'IT-CR', - 'IT-CS', - 'IT-CT', - 'IT-CZ', - 'IT-DU', - 'IT-EN', - 'IT-FE', - 'IT-FG', - 'IT-FI', - 'IT-FO', - 'IT-FR', - 'IT-GE', - 'IT-GO', - 'IT-GR', - 'IT-IM', - 'IT-IS', - 'IT-KR', - 'IT-LC', - 'IT-LE', - 'IT-LI', - 'IT-LO', - 'IT-LT', - 'IT-LU', - 'IT-MC', - 'IT-ME', - 'IT-MI', - 'IT-MN', - 'IT-MO', - 'IT-MS', - 'IT-MT', - 'IT-NA', - 'IT-NO', - 'IT-NU', - 'IT-OR', - 'IT-PA', - 'IT-PC', - 'IT-PD', - 'IT-PE', - 'IT-PG', - 'IT-PI', - 'IT-PN', - 'IT-PO', - 'IT-PR', - 'IT-PS', - 'IT-PT', - 'IT-PV', - 'IT-PZ', - 'IT-RA', - 'IT-RC', - 'IT-RE', - 'IT-RG', - 'IT-RI', - 'IT-RM', - 'IT-RN', - 'IT-RO', - 'IT-SA', - 'IT-SI', - 'IT-SO', - 'IT-SP', - 'IT-SR', - 'IT-SS', - 'IT-SV', - 'IT-TA', - 'IT-TE', - 'IT-TN', - 'IT-TO', - 'IT-TP', - 'IT-TR', - 'IT-TS', - 'IT-TV', - 'IT-VA', - 'IT-VB', - 'IT-VC', - 'IT-VE', - 'IT-VI', - 'IT-VR', - 'IT-VT', - 'IT-VV', - 'JM-01', - 'JM-02', - 'JM-03', - 'JM-04', - 'JM-05', - 'JM-06', - 'JM-07', - 'JM-08', - 'JM-09', - 'JM-10', - 'JM-11', - 'JM-12', - 'JM-13', - 'JM-14', - 'JO-AJ', - 'JO-AM', - 'JO-AQ', - 'JO-AT', - 'JO-AZ', - 'JO-BA', - 'JO-IR', - 'JO-JA', - 'JO-KA', - 'JO-MA', - 'JO-MD', - 'JO-MN', - 'JP-01', - 'JP-02', - 'JP-03', - 'JP-04', - 'JP-05', - 'JP-06', - 'JP-07', - 'JP-08', - 'JP-09', - 'JP-10', - 'JP-11', - 'JP-12', - 'JP-13', - 'JP-14', - 'JP-15', - 'JP-16', - 'JP-17', - 'JP-18', - 'JP-19', - 'JP-20', - 'JP-21', - 'JP-22', - 'JP-23', - 'JP-24', - 'JP-25', - 'JP-26', - 'JP-27', - 'JP-28', - 'JP-29', - 'JP-30', - 'JP-31', - 'JP-32', - 'JP-33', - 'JP-34', - 'JP-35', - 'JP-36', - 'JP-37', - 'JP-38', - 'JP-39', - 'JP-40', - 'JP-41', - 'JP-42', - 'JP-43', - 'JP-44', - 'JP-45', - 'JP-46', - 'JP-47', - 'KE-110', - 'KE-200', - 'KE-300', - 'KE-400', - 'KE-500', - 'KE-600', - 'KE-700', - 'KE-900', - 'KG-B', - 'KG-C', - 'KG-GB', - 'KG-J', - 'KG-N', - 'KG-O', - 'KG-T', - 'KG-Y', - 'KH-1', - 'KH-10', - 'KH-11', - 'KH-12', - 'KH-13', - 'KH-14', - 'KH-15', - 'KH-16', - 'KH-17', - 'KH-18', - 'KH-19', - 'KH-2', - 'KH-20', - 'KH-21', - 'KH-22', - 'KH-23', - 'KH-24', - 'KH-3', - 'KH-4', - 'KH-5', - 'KH-6', - 'KH-7', - 'KH-8', - 'KH-9', - 'KI-G', - 'KI-L', - 'KI-P', - 'KM-A', - 'KM-G', - 'KM-M', - 'KP-CHA', - 'KP-HAB', - 'KP-HAN', - 'KP-HWB', - 'KP-HWN', - 'KP-KAE', - 'KP-KAN', - 'KP-NAJ', - 'KP-NAM', - 'KP-PYB', - 'KP-PYN', - 'KP-PYO', - 'KP-YAN', - 'KR-11', - 'KR-26', - 'KR-27', - 'KR-28', - 'KR-29', - 'KR-30', - 'KR-31', - 'KR-41', - 'KR-42', - 'KR-43', - 'KR-44', - 'KR-45', - 'KR-46', - 'KR-47', - 'KR-48', - 'KR-49', - 'KW-AH', - 'KW-FA', - 'KW-HA', - 'KW-JA', - 'KW-KU', - 'KZ-AKM', - 'KZ-AKT', - 'KZ-ALA', - 'KZ-ALM', - 'KZ-AST', - 'KZ-ATY', - 'KZ-KAR', - 'KZ-KUS', - 'KZ-KZY', - 'KZ-MAN', - 'KZ-PAV', - 'KZ-SEV', - 'KZ-VOS', - 'KZ-YUZ', - 'KZ-ZAP', - 'KZ-ZHA', - 'LA-AT', - 'LA-BK', - 'LA-BL', - 'LA-CH', - 'LA-HO', - 'LA-KH', - 'LA-LM', - 'LA-LP', - 'LA-OU', - 'LA-PH', - 'LA-SL', - 'LA-SV', - 'LA-VI', - 'LA-VT', - 'LA-XA', - 'LA-XE', - 'LA-XI', - 'LA-XN', - 'LB-AS', - 'LB-BA', - 'LB-BI', - 'LB-JA', - 'LB-JL', - 'LB-NA', - 'LK-1', - 'LK-11', - 'LK-12', - 'LK-13', - 'LK-2', - 'LK-21', - 'LK-22', - 'LK-23', - 'LK-3', - 'LK-31', - 'LK-32', - 'LK-33', - 'LK-4', - 'LK-41', - 'LK-42', - 'LK-43', - 'LK-44', - 'LK-45', - 'LK-5', - 'LK-51', - 'LK-52', - 'LK-53', - 'LK-6', - 'LK-61', - 'LK-62', - 'LK-7', - 'LK-71', - 'LK-72', - 'LK-8', - 'LK-81', - 'LK-82', - 'LK-9', - 'LK-91', - 'LK-92', - 'LR-BG', - 'LR-BM', - 'LR-CM', - 'LR-GB', - 'LR-GG', - 'LR-GK', - 'LR-LO', - 'LR-MG', - 'LR-MO', - 'LR-MY', - 'LR-NI', - 'LR-RI', - 'LR-SI', - 'LS-A', - 'LS-B', - 'LS-C', - 'LS-D', - 'LS-E', - 'LS-F', - 'LS-G', - 'LS-H', - 'LS-J', - 'LS-K', - 'LT-AL', - 'LT-KL', - 'LT-KU', - 'LT-MR', - 'LT-PN', - 'LT-SA', - 'LT-TA', - 'LT-TE', - 'LT-UT', - 'LT-VL', - 'LU-D', - 'LU-G', - 'LU-L', - 'LV-AI', - 'LV-AL', - 'LV-BL', - 'LV-BU', - 'LV-CE', - 'LV-DA', - 'LV-DGV', - 'LV-DO', - 'LV-GU', - 'LV-JEL', - 'LV-JK', - 'LV-JL', - 'LV-JUR', - 'LV-KR', - 'LV-KU', - 'LV-LE', - 'LV-LM', - 'LV-LPX', - 'LV-LU', - 'LV-MA', - 'LV-OG', - 'LV-PR', - 'LV-RE', - 'LV-REZ', - 'LV-RI', - 'LV-RIX', - 'LV-SA', - 'LV-TA', - 'LV-TU', - 'LV-VE', - 'LV-VEN', - 'LV-VK', - 'LV-VM', - 'LY-BA', - 'LY-BU', - 'LY-FA', - 'LY-JA', - 'LY-JG', - 'LY-JU', - 'LY-MI', - 'LY-NA', - 'LY-SF', - 'LY-TB', - 'LY-WA', - 'LY-WU', - 'LY-ZA', - 'MA-01', - 'MA-02', - 'MA-03', - 'MA-04', - 'MA-05', - 'MA-06', - 'MA-07', - 'MA-08', - 'MA-09', - 'MA-10', - 'MA-11', - 'MA-12', - 'MA-13', - 'MA-14', - 'MA-15', - 'MA-16', - 'MA-AGD', - 'MA-ASZ', - 'MA-AZI', - 'MA-BAH', - 'MA-BEM', - 'MA-BER', - 'MA-BES', - 'MA-BOD', - 'MA-BOM', - 'MA-CAS', - 'MA-CHE', - 'MA-CHI', - 'MA-ERR', - 'MA-ESI', - 'MA-ESM', - 'MA-FES', - 'MA-FIG', - 'MA-GUE', - 'MA-HAJ', - 'MA-HAO', - 'MA-HOC', - 'MA-IFR', - 'MA-JDI', - 'MA-JRA', - 'MA-KEN', - 'MA-KES', - 'MA-KHE', - 'MA-KHN', - 'MA-KHO', - 'MA-LAA', - 'MA-LAR', - 'MA-MAR', - 'MA-MEK', - 'MA-MEL', - 'MA-NAD', - 'MA-OUA', - 'MA-OUD', - 'MA-OUJ', - 'MA-RBA', - 'MA-SAF', - 'MA-SEF', - 'MA-SET', - 'MA-SIK', - 'MA-TAO', - 'MA-TAR', - 'MA-TAT', - 'MA-TAZ', - 'MA-TET', - 'MA-TIZ', - 'MA-TNG', - 'MA-TNT', - 'MD-BA', - 'MD-CA', - 'MD-CH', - 'MD-CU', - 'MD-ED', - 'MD-GA', - 'MD-LA', - 'MD-OR', - 'MD-SN', - 'MD-SO', - 'MD-TA', - 'MD-TI', - 'MD-UN', - 'MG-A', - 'MG-D', - 'MG-F', - 'MG-M', - 'MG-T', - 'MG-U', - 'MH-ALK', - 'MH-ALL', - 'MH-ARN', - 'MH-AUR', - 'MH-EBO', - 'MH-ENI', - 'MH-JAL', - 'MH-KIL', - 'MH-KWA', - 'MH-L', - 'MH-LAE', - 'MH-LIB', - 'MH-LIK', - 'MH-MAJ', - 'MH-MAL', - 'MH-MEJ', - 'MH-MIL', - 'MH-NMK', - 'MH-NMU', - 'MH-RON', - 'MH-T', - 'MH-UJA', - 'MH-UJL', - 'MH-UTI', - 'MH-WTH', - 'MH-WTJ', - 'ML-1', - 'ML-2', - 'ML-3', - 'ML-4', - 'ML-5', - 'ML-6', - 'ML-7', - 'ML-8', - 'ML-BKO', - 'MM-01', - 'MM-02', - 'MM-03', - 'MM-04', - 'MM-05', - 'MM-06', - 'MM-07', - 'MM-11', - 'MM-12', - 'MM-13', - 'MM-14', - 'MM-15', - 'MM-16', - 'MM-17', - 'MN-035', - 'MN-037', - 'MN-039', - 'MN-041', - 'MN-043', - 'MN-046', - 'MN-047', - 'MN-049', - 'MN-051', - 'MN-053', - 'MN-055', - 'MN-057', - 'MN-059', - 'MN-061', - 'MN-063', - 'MN-064', - 'MN-065', - 'MN-067', - 'MN-069', - 'MN-071', - 'MN-073', - 'MN-1', - 'MR-01', - 'MR-02', - 'MR-03', - 'MR-04', - 'MR-05', - 'MR-06', - 'MR-07', - 'MR-08', - 'MR-09', - 'MR-10', - 'MR-11', - 'MR-12', - 'MR-NKC', - 'MU-AG', - 'MU-BL', - 'MU-BR', - 'MU-CC', - 'MU-CU', - 'MU-FL', - 'MU-GP', - 'MU-MO', - 'MU-PA', - 'MU-PL', - 'MU-PU', - 'MU-PW', - 'MU-QB', - 'MU-RO', - 'MU-RR', - 'MU-SA', - 'MU-VP', - 'MV-01', - 'MV-02', - 'MV-03', - 'MV-04', - 'MV-05', - 'MV-07', - 'MV-08', - 'MV-12', - 'MV-13', - 'MV-14', - 'MV-17', - 'MV-20', - 'MV-23', - 'MV-24', - 'MV-25', - 'MV-26', - 'MV-27', - 'MV-28', - 'MV-29', - 'MV-MLE', - 'MW-BA', - 'MW-BL', - 'MW-C', - 'MW-CK', - 'MW-CR', - 'MW-CT', - 'MW-DE', - 'MW-DO', - 'MW-KR', - 'MW-KS', - 'MW-LI', - 'MW-LK', - 'MW-MC', - 'MW-MG', - 'MW-MH', - 'MW-MU', - 'MW-MW', - 'MW-MZ', - 'MW-N', - 'MW-NB', - 'MW-NI', - 'MW-NK', - 'MW-NS', - 'MW-NU', - 'MW-PH', - 'MW-RU', - 'MW-S', - 'MW-SA', - 'MW-TH', - 'MW-ZO', - 'MX-AGU', - 'MX-BCN', - 'MX-BCS', - 'MX-CAM', - 'MX-CHH', - 'MX-CHP', - 'MX-COA', - 'MX-COL', - 'MX-DIF', - 'MX-DUR', - 'MX-GRO', - 'MX-GUA', - 'MX-HID', - 'MX-JAL', - 'MX-MEX', - 'MX-MIC', - 'MX-MOR', - 'MX-NAY', - 'MX-NLE', - 'MX-OAX', - 'MX-PUE', - 'MX-QUE', - 'MX-ROO', - 'MX-SIN', - 'MX-SLP', - 'MX-SON', - 'MX-TAB', - 'MX-TAM', - 'MX-TLA', - 'MX-VER', - 'MX-YUC', - 'MX-ZAC', - 'MY-A', - 'MY-B', - 'MY-C', - 'MY-D', - 'MY-J', - 'MY-K', - 'MY-L', - 'MY-M', - 'MY-N', - 'MY-P', - 'MY-R', - 'MY-SA', - 'MY-SK', - 'MY-T', - 'MY-W', - 'MZ-A', - 'MZ-B', - 'MZ-G', - 'MZ-I', - 'MZ-L', - 'MZ-MPM', - 'MZ-N', - 'MZ-P', - 'MZ-Q', - 'MZ-S', - 'MZ-T', - 'NA-CA', - 'NA-ER', - 'NA-HA', - 'NA-KA', - 'NA-KH', - 'NA-KU', - 'NA-OD', - 'NA-OH', - 'NA-OK', - 'NA-ON', - 'NA-OS', - 'NA-OT', - 'NA-OW', - 'NE-1', - 'NE-2', - 'NE-3', - 'NE-4', - 'NE-5', - 'NE-6', - 'NE-7', - 'NE-8', - 'NG-AB', - 'NG-AD', - 'NG-AK', - 'NG-AN', - 'NG-BA', - 'NG-BE', - 'NG-BO', - 'NG-BY', - 'NG-CR', - 'NG-DE', - 'NG-EB', - 'NG-ED', - 'NG-EK', - 'NG-EN', - 'NG-FC', - 'NG-GO', - 'NG-IM', - 'NG-JI', - 'NG-KD', - 'NG-KE', - 'NG-KN', - 'NG-KO', - 'NG-KT', - 'NG-KW', - 'NG-LA', - 'NG-NA', - 'NG-NI', - 'NG-OG', - 'NG-ON', - 'NG-OS', - 'NG-OY', - 'NG-PL', - 'NG-RI', - 'NG-SO', - 'NG-TA', - 'NG-YO', - 'NG-ZA', - 'NI-AN', - 'NI-AS', - 'NI-BO', - 'NI-CA', - 'NI-CI', - 'NI-CO', - 'NI-ES', - 'NI-GR', - 'NI-JI', - 'NI-LE', - 'NI-MD', - 'NI-MN', - 'NI-MS', - 'NI-MT', - 'NI-NS', - 'NI-RI', - 'NI-SJ', - 'NL-DR', - 'NL-FL', - 'NL-FR', - 'NL-GE', - 'NL-GR', - 'NL-LI', - 'NL-NB', - 'NL-NH', - 'NL-OV', - 'NL-UT', - 'NL-ZE', - 'NL-ZH', - 'NO-01', - 'NO-02', - 'NO-03', - 'NO-04', - 'NO-05', - 'NO-06', - 'NO-07', - 'NO-08', - 'NO-09', - 'NO-10', - 'NO-11', - 'NO-12', - 'NO-14', - 'NO-15', - 'NO-16', - 'NO-17', - 'NO-18', - 'NO-19', - 'NO-20', - 'NO-21', - 'NO-22', - 'NP-1', - 'NP-2', - 'NP-3', - 'NP-4', - 'NP-5', - 'NP-BA', - 'NP-BH', - 'NP-DH', - 'NP-GA', - 'NP-JA', - 'NP-KA', - 'NP-KO', - 'NP-LU', - 'NP-MA', - 'NP-ME', - 'NP-NA', - 'NP-RA', - 'NP-SA', - 'NP-SE', - 'NZ-AUK', - 'NZ-BOP', - 'NZ-CAN', - 'NZ-GIS', - 'NZ-HKB', - 'NZ-MBH', - 'NZ-MWT', - 'NZ-N', - 'NZ-NSN', - 'NZ-NTL', - 'NZ-OTA', - 'NZ-S', - 'NZ-STL', - 'NZ-TAS', - 'NZ-TKI', - 'NZ-WGN', - 'NZ-WKO', - 'NZ-WTC', - 'OM-BA', - 'OM-DA', - 'OM-JA', - 'OM-MA', - 'OM-MU', - 'OM-SH', - 'OM-WU', - 'OM-ZA', - 'PA-0', - 'PA-1', - 'PA-2', - 'PA-3', - 'PA-4', - 'PA-5', - 'PA-6', - 'PA-7', - 'PA-8', - 'PA-9', - 'PE-AMA', - 'PE-ANC', - 'PE-APU', - 'PE-ARE', - 'PE-AYA', - 'PE-CAJ', - 'PE-CAL', - 'PE-CUS', - 'PE-HUC', - 'PE-HUV', - 'PE-ICA', - 'PE-JUN', - 'PE-LAL', - 'PE-LAM', - 'PE-LIM', - 'PE-LOR', - 'PE-MDD', - 'PE-MOQ', - 'PE-PAS', - 'PE-PIU', - 'PE-PUN', - 'PE-SAM', - 'PE-TAC', - 'PE-TUM', - 'PE-UCA', - 'PG-CPK', - 'PG-CPM', - 'PG-EBR', - 'PG-EHG', - 'PG-EPW', - 'PG-ESW', - 'PG-GPK', - 'PG-MBA', - 'PG-MPL', - 'PG-MPM', - 'PG-MRL', - 'PG-NCD', - 'PG-NIK', - 'PG-NPP', - 'PG-NSA', - 'PG-SAN', - 'PG-SHM', - 'PG-WBK', - 'PG-WHM', - 'PG-WPD', - 'PH-00', - 'PH-01', - 'PH-02', - 'PH-03', - 'PH-04', - 'PH-05', - 'PH-06', - 'PH-07', - 'PH-08', - 'PH-09', - 'PH-10', - 'PH-11', - 'PH-12', - 'PH-13', - 'PH-14', - 'PH-15', - 'PH-ABR', - 'PH-AGN', - 'PH-AGS', - 'PH-AKL', - 'PH-ALB', - 'PH-ANT', - 'PH-APA', - 'PH-AUR', - 'PH-BAN', - 'PH-BAS', - 'PH-BEN', - 'PH-BIL', - 'PH-BOH', - 'PH-BTG', - 'PH-BTN', - 'PH-BUK', - 'PH-BUL', - 'PH-CAG', - 'PH-CAM', - 'PH-CAN', - 'PH-CAP', - 'PH-CAS', - 'PH-CAT', - 'PH-CAV', - 'PH-CEB', - 'PH-COM', - 'PH-DAO', - 'PH-DAS', - 'PH-DAV', - 'PH-EAS', - 'PH-GUI', - 'PH-IFU', - 'PH-ILI', - 'PH-ILN', - 'PH-ILS', - 'PH-ISA', - 'PH-KAL', - 'PH-LAG', - 'PH-LAN', - 'PH-LAS', - 'PH-LEY', - 'PH-LUN', - 'PH-MAD', - 'PH-MAG', - 'PH-MAS', - 'PH-MDC', - 'PH-MDR', - 'PH-MOU', - 'PH-MSC', - 'PH-MSR', - 'PH-NCO', - 'PH-NEC', - 'PH-NER', - 'PH-NSA', - 'PH-NUE', - 'PH-NUV', - 'PH-PAM', - 'PH-PAN', - 'PH-PLW', - 'PH-QUE', - 'PH-QUI', - 'PH-RIZ', - 'PH-ROM', - 'PH-SAR', - 'PH-SCO', - 'PH-SIG', - 'PH-SLE', - 'PH-SLU', - 'PH-SOR', - 'PH-SUK', - 'PH-SUN', - 'PH-SUR', - 'PH-TAR', - 'PH-TAW', - 'PH-WSA', - 'PH-ZAN', - 'PH-ZAS', - 'PH-ZMB', - 'PH-ZSI', - 'PK-BA', - 'PK-IS', - 'PK-JK', - 'PK-NA', - 'PK-NW', - 'PK-PB', - 'PK-SD', - 'PK-TA', - 'PL-DS', - 'PL-KP', - 'PL-LB', - 'PL-LD', - 'PL-LU', - 'PL-MA', - 'PL-MZ', - 'PL-OP', - 'PL-PD', - 'PL-PK', - 'PL-PM', - 'PL-SK', - 'PL-SL', - 'PL-WN', - 'PL-WP', - 'PL-ZP', - 'PT-01', - 'PT-02', - 'PT-03', - 'PT-04', - 'PT-05', - 'PT-06', - 'PT-07', - 'PT-08', - 'PT-09', - 'PT-10', - 'PT-11', - 'PT-12', - 'PT-13', - 'PT-14', - 'PT-15', - 'PT-16', - 'PT-17', - 'PT-18', - 'PT-20', - 'PT-30', - 'PY-1', - 'PY-10', - 'PY-11', - 'PY-12', - 'PY-13', - 'PY-14', - 'PY-15', - 'PY-16', - 'PY-19', - 'PY-2', - 'PY-3', - 'PY-4', - 'PY-5', - 'PY-6', - 'PY-7', - 'PY-8', - 'PY-9', - 'PY-ASU', - 'QA-DA', - 'QA-GH', - 'QA-JB', - 'QA-JU', - 'QA-KH', - 'QA-MS', - 'QA-RA', - 'QA-US', - 'QA-WA', - 'RO-AB', - 'RO-AG', - 'RO-AR', - 'RO-B', - 'RO-BC', - 'RO-BH', - 'RO-BN', - 'RO-BR', - 'RO-BT', - 'RO-BV', - 'RO-BZ', - 'RO-CJ', - 'RO-CL', - 'RO-CS', - 'RO-CT', - 'RO-CV', - 'RO-DB', - 'RO-DJ', - 'RO-GJ', - 'RO-GL', - 'RO-GR', - 'RO-HD', - 'RO-HR', - 'RO-IF', - 'RO-IL', - 'RO-IS', - 'RO-MH', - 'RO-MM', - 'RO-MS', - 'RO-NT', - 'RO-OT', - 'RO-PH', - 'RO-SB', - 'RO-SJ', - 'RO-SM', - 'RO-SV', - 'RO-TL', - 'RO-TM', - 'RO-TR', - 'RO-VL', - 'RO-VN', - 'RO-VS', - 'RU-AD', - 'RU-AGB', - 'RU-AL', - 'RU-ALT', - 'RU-AMU', - 'RU-ARK', - 'RU-AST', - 'RU-BA', - 'RU-BEL', - 'RU-BRY', - 'RU-BU', - 'RU-CE', - 'RU-CHE', - 'RU-CHI', - 'RU-CHU', - 'RU-CU', - 'RU-DA', - 'RU-DU', - 'RU-EVE', - 'RU-IN', - 'RU-IRK', - 'RU-IVA', - 'RU-KAM', - 'RU-KB', - 'RU-KC', - 'RU-KDA', - 'RU-KEM', - 'RU-KGD', - 'RU-KGN', - 'RU-KHA', - 'RU-KHM', - 'RU-KIR', - 'RU-KK', - 'RU-KL', - 'RU-KLU', - 'RU-KO', - 'RU-KOP', - 'RU-KOR', - 'RU-KOS', - 'RU-KR', - 'RU-KRS', - 'RU-KYA', - 'RU-LEN', - 'RU-LIP', - 'RU-MAG', - 'RU-ME', - 'RU-MO', - 'RU-MOS', - 'RU-MOW', - 'RU-MUR', - 'RU-NEN', - 'RU-NGR', - 'RU-NIZ', - 'RU-NVS', - 'RU-OMS', - 'RU-ORE', - 'RU-ORL', - 'RU-PER', - 'RU-PNZ', - 'RU-PRI', - 'RU-PSK', - 'RU-ROS', - 'RU-RYA', - 'RU-SA', - 'RU-SAK', - 'RU-SAM', - 'RU-SAR', - 'RU-SE', - 'RU-SMO', - 'RU-SPE', - 'RU-STA', - 'RU-SVE', - 'RU-TA', - 'RU-TAM', - 'RU-TAY', - 'RU-TOM', - 'RU-TUL', - 'RU-TVE', - 'RU-TY', - 'RU-TYU', - 'RU-ULY', - 'RU-UOB', - 'RU-VGG', - 'RU-VLA', - 'RU-VLG', - 'RU-VOR', - 'RU-YAN', - 'RU-YAR', - 'RU-YEV', - 'RW-B', - 'RW-C', - 'RW-D', - 'RW-E', - 'RW-F', - 'RW-G', - 'RW-H', - 'RW-I', - 'RW-J', - 'RW-K', - 'RW-L', - 'RW-M', - 'SA-01', - 'SA-02', - 'SA-03', - 'SA-04', - 'SA-05', - 'SA-06', - 'SA-07', - 'SA-08', - 'SA-09', - 'SA-10', - 'SA-11', - 'SA-12', - 'SA-14', - 'SB-CE', - 'SB-CT', - 'SB-GU', - 'SB-IS', - 'SB-MK', - 'SB-ML', - 'SB-TE', - 'SB-WE', - 'SD-01', - 'SD-02', - 'SD-03', - 'SD-04', - 'SD-05', - 'SD-06', - 'SD-07', - 'SD-08', - 'SD-09', - 'SD-10', - 'SD-11', - 'SD-12', - 'SD-13', - 'SD-14', - 'SD-15', - 'SD-16', - 'SD-17', - 'SD-18', - 'SD-19', - 'SD-20', - 'SD-21', - 'SD-22', - 'SD-23', - 'SD-24', - 'SD-25', - 'SD-26', - 'SE-AB', - 'SE-AC', - 'SE-BD', - 'SE-C', - 'SE-D', - 'SE-E', - 'SE-F', - 'SE-G', - 'SE-H', - 'SE-I', - 'SE-K', - 'SE-M', - 'SE-N', - 'SE-O', - 'SE-S', - 'SE-T', - 'SE-U', - 'SE-W', - 'SE-X', - 'SE-Y', - 'SE-Z', - 'SH-AC', - 'SH-SH', - 'SH-TA', - 'SI-01', - 'SI-02', - 'SI-03', - 'SI-04', - 'SI-05', - 'SI-06', - 'SI-07', - 'SI-08', - 'SI-09', - 'SI-10', - 'SI-11', - 'SI-12', - 'SK-BC', - 'SK-BL', - 'SK-KI', - 'SK-NI', - 'SK-PV', - 'SK-TA', - 'SK-TC', - 'SK-ZI', - 'SL-E', - 'SL-N', - 'SL-S', - 'SL-W', - 'SN-DB', - 'SN-DK', - 'SN-FK', - 'SN-KD', - 'SN-KL', - 'SN-LG', - 'SN-SL', - 'SN-TC', - 'SN-TH', - 'SN-ZG', - 'SO-AW', - 'SO-BK', - 'SO-BN', - 'SO-BR', - 'SO-BY', - 'SO-GA', - 'SO-GE', - 'SO-HI', - 'SO-JD', - 'SO-JH', - 'SO-MU', - 'SO-NU', - 'SO-SA', - 'SO-SD', - 'SO-SH', - 'SO-SO', - 'SO-TO', - 'SO-WO', - 'SR-BR', - 'SR-CM', - 'SR-CR', - 'SR-MA', - 'SR-NI', - 'SR-PM', - 'SR-PR', - 'SR-SA', - 'SR-SI', - 'SR-WA', - 'ST-P', - 'ST-S', - 'SV-AH', - 'SV-CA', - 'SV-CH', - 'SV-CU', - 'SV-LI', - 'SV-MO', - 'SV-PA', - 'SV-SA', - 'SV-SM', - 'SV-SO', - 'SV-SS', - 'SV-SV', - 'SV-UN', - 'SV-US', - 'SY-DI', - 'SY-DR', - 'SY-DY', - 'SY-HA', - 'SY-HI', - 'SY-HL', - 'SY-HM', - 'SY-ID', - 'SY-LA', - 'SY-QU', - 'SY-RA', - 'SY-RD', - 'SY-SU', - 'SY-TA', - 'SZ-HH', - 'SZ-LU', - 'SZ-MA', - 'SZ-SH', - 'TD-BA', - 'TD-BET', - 'TD-BI', - 'TD-CB', - 'TD-GR', - 'TD-KA', - 'TD-LC', - 'TD-LO', - 'TD-LR', - 'TD-MC', - 'TD-MK', - 'TD-OD', - 'TD-SA', - 'TD-TA', - 'TG-C', - 'TG-K', - 'TG-M', - 'TG-P', - 'TG-S', - 'TH-10', - 'TH-11', - 'TH-12', - 'TH-13', - 'TH-14', - 'TH-15', - 'TH-16', - 'TH-17', - 'TH-18', - 'TH-19', - 'TH-20', - 'TH-21', - 'TH-22', - 'TH-23', - 'TH-24', - 'TH-25', - 'TH-26', - 'TH-27', - 'TH-30', - 'TH-31', - 'TH-32', - 'TH-33', - 'TH-34', - 'TH-35', - 'TH-36', - 'TH-37', - 'TH-39', - 'TH-40', - 'TH-41', - 'TH-42', - 'TH-43', - 'TH-44', - 'TH-45', - 'TH-46', - 'TH-47', - 'TH-48', - 'TH-49', - 'TH-50', - 'TH-51', - 'TH-52', - 'TH-53', - 'TH-54', - 'TH-55', - 'TH-56', - 'TH-57', - 'TH-58', - 'TH-60', - 'TH-61', - 'TH-62', - 'TH-63', - 'TH-64', - 'TH-65', - 'TH-66', - 'TH-67', - 'TH-70', - 'TH-71', - 'TH-72', - 'TH-73', - 'TH-74', - 'TH-75', - 'TH-76', - 'TH-77', - 'TH-80', - 'TH-81', - 'TH-82', - 'TH-83', - 'TH-84', - 'TH-85', - 'TH-86', - 'TH-90', - 'TH-91', - 'TH-92', - 'TH-93', - 'TH-94', - 'TH-95', - 'TH-96', - 'TH-S', - 'TJ-GB', - 'TJ-KT', - 'TJ-SU', - 'TL-AL', - 'TL-AN', - 'TL-BA', - 'TL-BO', - 'TL-CO', - 'TL-DI', - 'TL-ER', - 'TL-LA', - 'TL-LI', - 'TL-MF', - 'TL-MT', - 'TL-OE', - 'TL-VI', - 'TM-A', - 'TM-B', - 'TM-D', - 'TM-L', - 'TM-M', - 'TN-11', - 'TN-12', - 'TN-13', - 'TN-21', - 'TN-22', - 'TN-23', - 'TN-31', - 'TN-32', - 'TN-33', - 'TN-34', - 'TN-41', - 'TN-42', - 'TN-43', - 'TN-51', - 'TN-52', - 'TN-53', - 'TN-61', - 'TN-71', - 'TN-72', - 'TN-73', - 'TN-81', - 'TN-82', - 'TN-83', - 'TR-01', - 'TR-02', - 'TR-03', - 'TR-04', - 'TR-05', - 'TR-06', - 'TR-07', - 'TR-08', - 'TR-09', - 'TR-10', - 'TR-11', - 'TR-12', - 'TR-13', - 'TR-14', - 'TR-15', - 'TR-16', - 'TR-17', - 'TR-18', - 'TR-19', - 'TR-20', - 'TR-21', - 'TR-22', - 'TR-23', - 'TR-24', - 'TR-25', - 'TR-26', - 'TR-27', - 'TR-28', - 'TR-29', - 'TR-30', - 'TR-31', - 'TR-32', - 'TR-33', - 'TR-34', - 'TR-35', - 'TR-36', - 'TR-37', - 'TR-38', - 'TR-39', - 'TR-40', - 'TR-41', - 'TR-42', - 'TR-43', - 'TR-44', - 'TR-45', - 'TR-46', - 'TR-47', - 'TR-48', - 'TR-49', - 'TR-50', - 'TR-51', - 'TR-52', - 'TR-53', - 'TR-54', - 'TR-55', - 'TR-56', - 'TR-57', - 'TR-58', - 'TR-59', - 'TR-60', - 'TR-61', - 'TR-62', - 'TR-63', - 'TR-64', - 'TR-65', - 'TR-66', - 'TR-67', - 'TR-68', - 'TR-69', - 'TR-70', - 'TR-71', - 'TR-72', - 'TR-73', - 'TR-74', - 'TR-75', - 'TR-76', - 'TR-77', - 'TR-78', - 'TR-79', - 'TR-80', - 'TR-81', - 'TT-ARI', - 'TT-CHA', - 'TT-CTT', - 'TT-DMN', - 'TT-ETO', - 'TT-PED', - 'TT-POS', - 'TT-PRT', - 'TT-PTF', - 'TT-RCM', - 'TT-SFO', - 'TT-SGE', - 'TT-SIP', - 'TT-SJL', - 'TT-TUP', - 'TT-WTO', - 'TW-CHA', - 'TW-CYQ', - 'TW-HSQ', - 'TW-HUA', - 'TW-ILA', - 'TW-KEE', - 'TW-KHQ', - 'TW-MIA', - 'TW-NAN', - 'TW-PEN', - 'TW-PIF', - 'TW-TAO', - 'TW-TNQ', - 'TW-TPQ', - 'TW-TTT', - 'TW-TXQ', - 'TW-YUN', - 'TZ-01', - 'TZ-02', - 'TZ-03', - 'TZ-04', - 'TZ-05', - 'TZ-06', - 'TZ-07', - 'TZ-08', - 'TZ-09', - 'TZ-10', - 'TZ-11', - 'TZ-12', - 'TZ-13', - 'TZ-14', - 'TZ-15', - 'TZ-16', - 'TZ-17', - 'TZ-18', - 'TZ-19', - 'TZ-20', - 'TZ-21', - 'TZ-22', - 'TZ-23', - 'TZ-24', - 'TZ-25', - 'UA-05', - 'UA-07', - 'UA-09', - 'UA-12', - 'UA-14', - 'UA-18', - 'UA-21', - 'UA-23', - 'UA-26', - 'UA-30', - 'UA-32', - 'UA-35', - 'UA-40', - 'UA-43', - 'UA-46', - 'UA-48', - 'UA-51', - 'UA-53', - 'UA-56', - 'UA-59', - 'UA-61', - 'UA-63', - 'UA-65', - 'UA-68', - 'UA-71', - 'UA-74', - 'UA-77', - 'UG-AJM', - 'UG-APA', - 'UG-ARU', - 'UG-BUA', - 'UG-BUG', - 'UG-BUN', - 'UG-BUS', - 'UG-C', - 'UG-E', - 'UG-GUL', - 'UG-HOI', - 'UG-IGA', - 'UG-JIN', - 'UG-KAP', - 'UG-KAS', - 'UG-KAT', - 'UG-KBL', - 'UG-KBR', - 'UG-KIB', - 'UG-KIS', - 'UG-KIT', - 'UG-KLA', - 'UG-KLE', - 'UG-KLG', - 'UG-KLI', - 'UG-KOT', - 'UG-KUM', - 'UG-LIR', - 'UG-LUW', - 'UG-MBL', - 'UG-MBR', - 'UG-MOR', - 'UG-MOY', - 'UG-MPI', - 'UG-MSI', - 'UG-MSK', - 'UG-MUB', - 'UG-MUK', - 'UG-N', - 'UG-NAK', - 'UG-NEB', - 'UG-NTU', - 'UG-PAL', - 'UG-RAK', - 'UG-RUK', - 'UG-SEM', - 'UG-SOR', - 'UG-TOR', - 'UG-W', - 'UM-67', - 'UM-71', - 'UM-76', - 'UM-79', - 'UM-81', - 'UM-84', - 'UM-86', - 'UM-89', - 'UM-95', - 'US-AK', - 'US-AL', - 'US-AR', - 'US-AS', - 'US-AZ', - 'US-CA', - 'US-CO', - 'US-CT', - 'US-DC', - 'US-DE', - 'US-FL', - 'US-GA', - 'US-GU', - 'US-HI', - 'US-IA', - 'US-ID', - 'US-IL', - 'US-IN', - 'US-KS', - 'US-KY', - 'US-LA', - 'US-MA', - 'US-MD', - 'US-ME', - 'US-MI', - 'US-MN', - 'US-MO', - 'US-MP', - 'US-MS', - 'US-MT', - 'US-NC', - 'US-ND', - 'US-NE', - 'US-NH', - 'US-NJ', - 'US-NM', - 'US-NV', - 'US-NY', - 'US-OH', - 'US-OK', - 'US-OR', - 'US-PA', - 'US-PR', - 'US-RI', - 'US-SC', - 'US-SD', - 'US-TN', - 'US-TX', - 'US-UM', - 'US-UT', - 'US-VA', - 'US-VI', - 'US-VT', - 'US-WA', - 'US-WI', - 'US-WV', - 'US-WY', - 'UY-AR', - 'UY-CA', - 'UY-CL', - 'UY-CO', - 'UY-DU', - 'UY-FD', - 'UY-FS', - 'UY-LA', - 'UY-MA', - 'UY-MO', - 'UY-PA', - 'UY-RN', - 'UY-RO', - 'UY-RV', - 'UY-SA', - 'UY-SJ', - 'UY-SO', - 'UY-TA', - 'UY-TT', - 'UZ-AN', - 'UZ-BU', - 'UZ-FA', - 'UZ-JI', - 'UZ-NG', - 'UZ-NW', - 'UZ-QA', - 'UZ-QR', - 'UZ-SA', - 'UZ-SI', - 'UZ-SU', - 'UZ-TK', - 'UZ-TO', - 'UZ-XO', - 'VE-A', - 'VE-B', - 'VE-C', - 'VE-D', - 'VE-E', - 'VE-F', - 'VE-G', - 'VE-H', - 'VE-I', - 'VE-J', - 'VE-K', - 'VE-L', - 'VE-M', - 'VE-N', - 'VE-O', - 'VE-P', - 'VE-R', - 'VE-S', - 'VE-T', - 'VE-U', - 'VE-V', - 'VE-W', - 'VE-X', - 'VE-Y', - 'VE-Z', - 'VN-01', - 'VN-02', - 'VN-03', - 'VN-04', - 'VN-05', - 'VN-06', - 'VN-07', - 'VN-09', - 'VN-13', - 'VN-14', - 'VN-15', - 'VN-18', - 'VN-20', - 'VN-21', - 'VN-22', - 'VN-23', - 'VN-24', - 'VN-25', - 'VN-26', - 'VN-27', - 'VN-28', - 'VN-29', - 'VN-30', - 'VN-31', - 'VN-32', - 'VN-33', - 'VN-34', - 'VN-35', - 'VN-36', - 'VN-37', - 'VN-39', - 'VN-40', - 'VN-41', - 'VN-43', - 'VN-44', - 'VN-45', - 'VN-46', - 'VN-47', - 'VN-48', - 'VN-49', - 'VN-50', - 'VN-51', - 'VN-52', - 'VN-53', - 'VN-54', - 'VN-55', - 'VN-56', - 'VN-57', - 'VN-58', - 'VN-59', - 'VN-60', - 'VN-61', - 'VN-62', - 'VN-63', - 'VN-64', - 'VN-65', - 'VN-66', - 'VN-67', - 'VN-68', - 'VN-69', - 'VN-70', - 'VU-MAP', - 'VU-PAM', - 'VU-SAM', - 'VU-SEE', - 'VU-TAE', - 'VU-TOB', - 'WS-AA', - 'WS-AL', - 'WS-AT', - 'WS-FA', - 'WS-GE', - 'WS-GI', - 'WS-PA', - 'WS-SA', - 'WS-TU', - 'WS-VF', - 'WS-VS', - 'YE-AB', - 'YE-AD', - 'YE-AM', - 'YE-BA', - 'YE-DA', - 'YE-DH', - 'YE-HD', - 'YE-HJ', - 'YE-HU', - 'YE-IB', - 'YE-JA', - 'YE-LA', - 'YE-MA', - 'YE-MR', - 'YE-MW', - 'YE-SD', - 'YE-SH', - 'YE-SN', - 'YE-TA', - 'YU-CG', - 'YU-KM', - 'YU-SR', - 'YU-VO', - 'ZA-EC', - 'ZA-FS', - 'ZA-GT', - 'ZA-MP', - 'ZA-NC', - 'ZA-NL', - 'ZA-NP', - 'ZA-NW', - 'ZA-WC', - 'ZM-01', - 'ZM-02', - 'ZM-03', - 'ZM-04', - 'ZM-05', - 'ZM-06', - 'ZM-07', - 'ZM-08', - 'ZM-09', - 'ZW-BU', - 'ZW-HA', - 'ZW-MA', - 'ZW-MC', - 'ZW-ME', - 'ZW-MI', - 'ZW-MN', - 'ZW-MS', - 'ZW-MV', - 'ZW-MW', - ), -) - -Subdivision.__doc__ = """ -Subvidision country codes from ISO 3166-2. - -Taken from `here `_. -""" - - -class Layouts(Enum): - """Keyboard layouts. Taken from Debian's 9 - /usr/share/X11/xkb/rules/evdev.lst. - """ - - US = 'English (US)' - AF = 'Afghani' - ARA = 'Arabic' - AL = 'Albanian' - AM = 'Armenian' - AT = 'German (Austria)' - AU = 'English (Australian)' - AZ = 'Azerbaijani' - BY = 'Belarusian' - BE = 'Belgian' - BD = 'Bangla' - BA = 'Bosnian' - BR = 'Portuguese (Brazil)' - BG = 'Bulgarian' - DZ = 'Berber (Algeria, Latin characters)' - MA = 'Arabic (Morocco)' - CM = 'English (Cameroon)' - MM = 'Burmese' - CA = 'French (Canada)' - CD = 'French (Democratic Republic of the Congo)' - CN = 'Chinese' - HR = 'Croatian' - CZ = 'Czech' - DK = 'Danish' - NL = 'Dutch' - BT = 'Dzongkha' - EE = 'Estonian' - IR = 'Persian' - IQ = 'Iraqi' - FO = 'Faroese' - FI = 'Finnish' - FR = 'French' - GH = 'English (Ghana)' - GN = 'French (Guinea)' - GE = 'Georgian' - DE = 'German' - GR = 'Greek' - HU = 'Hungarian' - IL = 'Hebrew' - IT = 'Italian' - JP = 'Japanese' - KG = 'Kyrgyz' - KH = 'Khmer (Cambodia)' - KZ = 'Kazakh' - LA = 'Lao' - LATAM = 'Spanish (Latin American)' - LT = 'Lithuanian' - LV = 'Latvian' - MAO = 'Maori' - ME = 'Montenegrin' - MK = 'Macedonian' - MT = 'Maltese' - MN = 'Mongolian' - NO = 'Norwegian' - PL = 'Polish' - PT = 'Portuguese' - RO = 'Romanian' - RU = 'Russian' - RS = 'Serbian' - SI = 'Slovenian' - SK = 'Slovak' - ES = 'Spanish' - SE = 'Swedish' - CH = 'German (Switzerland)' - SY = 'Arabic (Syria)' - TJ = 'Tajik' - LK = 'Sinhala (phonetic)' - TH = 'Thai' - TR = 'Turkish' - TW = 'Taiwanese' - UA = 'Ukrainian' - GB = 'English (UK)' - UZ = 'Uzbek' - VN = 'Vietnamese' - KR = 'Korean' - IE = 'Irish' - PK = 'Urdu (Pakistan)' - MV = 'Dhivehi' - ZA = 'English (South Africa)' - EPO = 'Esperanto' - NP = 'Nepali' - NG = 'English (Nigeria)' - ET = 'Amharic' - SN = 'Wolof' - BRAI = 'Braille' - TM = 'Turkmen' - ML = 'Bambara' - TZ = 'Swahili (Tanzania)' - TG = 'French (Togo)' - KE = 'Swahili (Kenya)' - BW = 'Tswana' - PH = 'Filipino' - MD = 'Moldavian' - ID = 'Indonesian (Jawi)' - MY = 'Malay (Jawi)' - BN = 'Malay (Jawi)' - IN = 'Indian' - IS = 'Icelandic' - NEC_VNDR_JP = 'Japanese (PC-98xx Series)' - - def __str__(self): - return self.value diff --git a/ereuse_devicehub/resources/user/models.py b/ereuse_devicehub/resources/user/models.py index 7981fec5..a02efd2b 100644 --- a/ereuse_devicehub/resources/user/models.py +++ b/ereuse_devicehub/resources/user/models.py @@ -69,7 +69,8 @@ class User(UserMixin, Thing): @property def individual(self): """The individual associated for this database, or None.""" - return next(iter(self.individuals), None) + if self.individuals: + return next(iter(self.individuals), None) @property def code(self): From febff54c6b5792695958c0b2c2a292fbd0b79cd4 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 13 Apr 2022 13:28:22 +0200 Subject: [PATCH 10/22] fix bug --- ereuse_devicehub/forms.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/forms.py b/ereuse_devicehub/forms.py index c5ede0cc..0194a855 100644 --- a/ereuse_devicehub/forms.py +++ b/ereuse_devicehub/forms.py @@ -1,5 +1,6 @@ from flask import g from flask_wtf import FlaskForm +from teal.enums import Country from werkzeug.security import generate_password_hash from wtforms import ( BooleanField, @@ -11,7 +12,6 @@ from wtforms import ( ) from ereuse_devicehub.db import db -from ereuse_devicehub.enums import Country from ereuse_devicehub.resources.user.models import User COUNTRY = [(x.name, x.value) for x in Country] @@ -104,7 +104,8 @@ class ProfileForm(FlaskForm): self.last_name.data = user.last_name self.email.data = user.email self.telephone.data = user.telephone - self.country.data = user.country.name + if user.country: + self.country.data = user.country.name def save(self, commit=True): agent = g.user.individual From 04cdb8181f2ed964874191ac1186455639e19783 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 13 Apr 2022 18:41:05 +0200 Subject: [PATCH 11/22] drop settings and last_name of agent --- ereuse_devicehub/forms.py | 7 --- .../1b61613d1c19_add_new_fields_in_agent.py | 35 -------------- ereuse_devicehub/resources/agent/models.py | 3 -- .../ereuse_devicehub/user_profile.html | 46 ------------------- 4 files changed, 91 deletions(-) delete mode 100644 ereuse_devicehub/migrations/versions/1b61613d1c19_add_new_fields_in_agent.py diff --git a/ereuse_devicehub/forms.py b/ereuse_devicehub/forms.py index 0194a855..7dddf884 100644 --- a/ereuse_devicehub/forms.py +++ b/ereuse_devicehub/forms.py @@ -79,11 +79,6 @@ class ProfileForm(FlaskForm): [validators.Length(min=2, max=35)], render_kw={'class': "form-control"}, ) - last_name = StringField( - 'Last name', - [validators.Length(min=2, max=35)], - render_kw={'class': "form-control"}, - ) email = StringField( 'Email Address', [validators.Length(min=6, max=35)], @@ -101,7 +96,6 @@ class ProfileForm(FlaskForm): super().__init__(*args, **kwargs) if user: self.name.data = user.name - self.last_name.data = user.last_name self.email.data = user.email self.telephone.data = user.telephone if user.country: @@ -110,7 +104,6 @@ class ProfileForm(FlaskForm): def save(self, commit=True): agent = g.user.individual agent.name = self.name.data - agent.last_name = self.last_name.data agent.email = self.email.data agent.telephone = self.telephone.data agent.country = self.country.data diff --git a/ereuse_devicehub/migrations/versions/1b61613d1c19_add_new_fields_in_agent.py b/ereuse_devicehub/migrations/versions/1b61613d1c19_add_new_fields_in_agent.py deleted file mode 100644 index 13d71b82..00000000 --- a/ereuse_devicehub/migrations/versions/1b61613d1c19_add_new_fields_in_agent.py +++ /dev/null @@ -1,35 +0,0 @@ -"""add new fields in agent - -Revision ID: 1b61613d1c19 -Revises: 8571fb32c912 -Create Date: 2022-04-06 12:23:37.644108 - -""" -import citext -import sqlalchemy as sa -from alembic import context, op - -# revision identifiers, used by Alembic. -revision = '1b61613d1c19' -down_revision = '8571fb32c912' -branch_labels = None -depends_on = None - - -def get_inv(): - INV = context.get_x_argument(as_dictionary=True).get('inventory') - if not INV: - raise ValueError("Inventory value is not specified") - return INV - - -def upgrade(): - op.add_column( - "agent", - sa.Column("last_name", citext.CIText(), nullable=True), - schema=f'{get_inv()}', - ) - - -def downgrade(): - op.drop_column('agent', 'last_name', schema=f'{get_inv()}') diff --git a/ereuse_devicehub/resources/agent/models.py b/ereuse_devicehub/resources/agent/models.py index 36d7fcd8..51dd7ab3 100644 --- a/ereuse_devicehub/resources/agent/models.py +++ b/ereuse_devicehub/resources/agent/models.py @@ -31,7 +31,6 @@ class Agent(Thing): id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4) type = Column(Unicode, nullable=False) name = Column(CIText()) - last_name = Column(CIText()) name.comment = """The name of the organization or person.""" tax_id = Column(Unicode(length=STR_SM_SIZE), check_lower('tax_id')) tax_id.comment = """The Tax / Fiscal ID of the organization, @@ -50,8 +49,6 @@ class Agent(Thing): @property def get_full_name(self): - if self.last_name: - return "{} {}".format(self.name, self.last_name) return self.name @declared_attr diff --git a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html index 782b92c8..f6560eb5 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html @@ -42,10 +42,6 @@ - - @@ -153,48 +149,6 @@
-
- - - - -
- -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- -
- -
- - -
-
From 4e19b9233ba49c58e3d38206ae628d2192ce97fe Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 13 Apr 2022 19:11:23 +0200 Subject: [PATCH 12/22] validate email is unique --- ereuse_devicehub/forms.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ereuse_devicehub/forms.py b/ereuse_devicehub/forms.py index 7dddf884..2ae69094 100644 --- a/ereuse_devicehub/forms.py +++ b/ereuse_devicehub/forms.py @@ -12,6 +12,7 @@ from wtforms import ( ) from ereuse_devicehub.db import db +from ereuse_devicehub.resources.agent.models import Agent from ereuse_devicehub.resources.user.models import User COUNTRY = [(x.name, x.value) for x in Country] @@ -101,6 +102,21 @@ class ProfileForm(FlaskForm): if user.country: self.country.data = user.country.name + def validate(self, extra_validators=None): + is_valid = super().validate(extra_validators) + + if not is_valid: + return False + + # import pdb; pdb.set_trace() + email = self.email.data + if email != g.user.individual.email: + if Agent.query.filter_by(email=email).first(): + self.email.errors = ['You can not use this email.'] + return False + + return True + def save(self, commit=True): agent = g.user.individual agent.name = self.name.data From d870d254f1979f1fc8564b73d93a014edbb46580 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 13 Apr 2022 19:12:12 +0200 Subject: [PATCH 13/22] drop pdbs --- ereuse_devicehub/forms.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ereuse_devicehub/forms.py b/ereuse_devicehub/forms.py index 2ae69094..4c614c95 100644 --- a/ereuse_devicehub/forms.py +++ b/ereuse_devicehub/forms.py @@ -108,7 +108,6 @@ class ProfileForm(FlaskForm): if not is_valid: return False - # import pdb; pdb.set_trace() email = self.email.data if email != g.user.individual.email: if Agent.query.filter_by(email=email).first(): From 13950a5ff69a70f22bdd3b46e5cdcbd81584a94d Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 26 Apr 2022 16:35:16 +0200 Subject: [PATCH 14/22] show only password reset --- .../ereuse_devicehub/user_profile.html | 117 +----------------- 1 file changed, 1 insertion(+), 116 deletions(-) diff --git a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html index f6560eb5..599895c0 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html @@ -32,124 +32,9 @@
-
-
-
Profile Details
- -
-
Account user
-
{{ current_user.email or ''}}
-
- - {% for u in current_user.individuals %} - -
-
Full Name
-
{{ u.get_full_name or ''}}
-
- -
-
Country
-
{{ u.country or ''}}
-
- -
-
Phone
-
{{ u.telephone or ''}}
-
- -
-
Email
-
{{ u.email or ''}}
-
- -
-
Created
-
{{ u.created.strftime('%H:%M %d-%m-%Y') or ''}}
-
- -
-
Last login
-
- {% for s in sessions %} - {{ s }}
- {% endfor %} -
-
- - {% if u.active_org %} -
-
Company name
-
{{ u.active_org.name or ''}}
-
- -
-
Company country
-
{{ u.active_org.country or '' }}
-
- -
-
Company Phone
-
{{ u.active_org.telephone or '' }}
-
- -
-
Company Email
-
{{ u.active_org.email or '' }}
-
- - {% endif %} - {% endfor %} - -
- -
- - - - {% for f in profile_form %} - {% if f == profile_form.csrf_token %} - {{ f }} - {% else %} -
- -
- {{ f }} - {% if f.errors %} -

- {% for error in f.errors %} - {{ error }}
- {% endfor %} -

- {% endif %} -
-
- {% endif %} - {% endfor %} -
- -
- - -
- -
+
{% for f in password_form %} From b11bb163a04be7f6d277e3903907f9ba1d4b3346 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 26 Apr 2022 17:35:29 +0200 Subject: [PATCH 15/22] hide 2 trade buttons --- ereuse_devicehub/templates/inventory/device_list.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ereuse_devicehub/templates/inventory/device_list.html b/ereuse_devicehub/templates/inventory/device_list.html index 3a6874a9..9cc69a17 100644 --- a/ereuse_devicehub/templates/inventory/device_list.html +++ b/ereuse_devicehub/templates/inventory/device_list.html @@ -38,12 +38,14 @@
{% if lot.is_temporary %} + {% if 1 == 2 %} Add supplier Add receiver + {% endif %} Delete Lot From 8125279619b890b05bd9fb6c3eba7cc6eb322c77 Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Thu, 28 Apr 2022 11:38:31 +0200 Subject: [PATCH 16/22] Add comment to not rendered code --- ereuse_devicehub/templates/inventory/device_list.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/templates/inventory/device_list.html b/ereuse_devicehub/templates/inventory/device_list.html index 9cc69a17..f0bbfb8b 100644 --- a/ereuse_devicehub/templates/inventory/device_list.html +++ b/ereuse_devicehub/templates/inventory/device_list.html @@ -38,14 +38,16 @@
{% if lot.is_temporary %} - {% if 1 == 2 %} + + {% if 1 == 2 %}{# #} Add supplier Add receiver - {% endif %} + {% endif %}{# #} + Delete Lot From 6946a2584b6812651f8a5f175777f8a710e18eed Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Thu, 28 Apr 2022 11:39:40 +0200 Subject: [PATCH 17/22] Refactor: group related code (delete button & modal status) --- ereuse_devicehub/templates/inventory/device_list.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ereuse_devicehub/templates/inventory/device_list.html b/ereuse_devicehub/templates/inventory/device_list.html index f0bbfb8b..827c3b68 100644 --- a/ereuse_devicehub/templates/inventory/device_list.html +++ b/ereuse_devicehub/templates/inventory/device_list.html @@ -37,7 +37,6 @@
{% if lot.is_temporary %} - {% if 1 == 2 %}{# #} @@ -51,6 +50,7 @@ Delete Lot + {% endif %}
From 3fd208c4791e05249fc9327b302b8d60ea9517f0 Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Thu, 28 Apr 2022 11:50:07 +0200 Subject: [PATCH 18/22] Restore tabs to include title "Change password" --- .../templates/ereuse_devicehub/user_profile.html | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html index 599895c0..fd8b8804 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html @@ -27,11 +27,16 @@
-
+
+
From 9afe6bf9e6a21241e147953821cdccdab744626e Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Thu, 28 Apr 2022 12:03:12 +0200 Subject: [PATCH 19/22] Revert all changes related to ProfileForm We need to talk about the concepts of Agent and User and their relationship before allowing the user to update their data. --- ereuse_devicehub/forms.py | 67 +---------------------- ereuse_devicehub/resources/user/models.py | 8 +-- ereuse_devicehub/views.py | 19 +------ 3 files changed, 6 insertions(+), 88 deletions(-) diff --git a/ereuse_devicehub/forms.py b/ereuse_devicehub/forms.py index 4c614c95..0f4cefbe 100644 --- a/ereuse_devicehub/forms.py +++ b/ereuse_devicehub/forms.py @@ -1,22 +1,11 @@ from flask import g from flask_wtf import FlaskForm -from teal.enums import Country from werkzeug.security import generate_password_hash -from wtforms import ( - BooleanField, - EmailField, - PasswordField, - SelectField, - StringField, - validators, -) +from wtforms import BooleanField, EmailField, PasswordField, validators from ereuse_devicehub.db import db -from ereuse_devicehub.resources.agent.models import Agent from ereuse_devicehub.resources.user.models import User -COUNTRY = [(x.name, x.value) for x in Country] - class LoginForm(FlaskForm): email = EmailField('Email Address', [validators.Length(min=6, max=35)]) @@ -74,60 +63,6 @@ class LoginForm(FlaskForm): return user.is_active -class ProfileForm(FlaskForm): - name = StringField( - 'First name', - [validators.Length(min=2, max=35)], - render_kw={'class': "form-control"}, - ) - email = StringField( - 'Email Address', - [validators.Length(min=6, max=35)], - render_kw={'class': "form-control"}, - ) - telephone = StringField( - 'Phone', [validators.Length(min=6, max=35)], render_kw={'class': "form-control"} - ) - country = SelectField( - 'Country', choices=COUNTRY, default="es", render_kw={'class': "form-select"} - ) - - def __init__(self, *args, **kwargs): - user = kwargs.pop('user', None) - super().__init__(*args, **kwargs) - if user: - self.name.data = user.name - self.email.data = user.email - self.telephone.data = user.telephone - if user.country: - self.country.data = user.country.name - - def validate(self, extra_validators=None): - is_valid = super().validate(extra_validators) - - if not is_valid: - return False - - email = self.email.data - if email != g.user.individual.email: - if Agent.query.filter_by(email=email).first(): - self.email.errors = ['You can not use this email.'] - return False - - return True - - def save(self, commit=True): - agent = g.user.individual - agent.name = self.name.data - agent.email = self.email.data - agent.telephone = self.telephone.data - agent.country = self.country.data - - db.session.add(agent) - if commit: - db.session.commit() - - class PasswordForm(FlaskForm): password = PasswordField( 'Current Password', diff --git a/ereuse_devicehub/resources/user/models.py b/ereuse_devicehub/resources/user/models.py index a02efd2b..5eadb21d 100644 --- a/ereuse_devicehub/resources/user/models.py +++ b/ereuse_devicehub/resources/user/models.py @@ -69,8 +69,7 @@ class User(UserMixin, Thing): @property def individual(self): """The individual associated for this database, or None.""" - if self.individuals: - return next(iter(self.individuals), None) + return next(iter(self.individuals), None) @property def code(self): @@ -86,9 +85,8 @@ class User(UserMixin, Thing): @property def get_full_name(self): - if self.individuals: - return self.individual.get_full_name - + # TODO(@slamora) create first_name & last_name fields??? + # needs to be discussed related to Agent <--> User concepts return self.email def check_password(self, password): diff --git a/ereuse_devicehub/views.py b/ereuse_devicehub/views.py index 12f6d4ba..1c975285 100644 --- a/ereuse_devicehub/views.py +++ b/ereuse_devicehub/views.py @@ -1,11 +1,11 @@ import flask -from flask import Blueprint, request +from flask import Blueprint from flask.views import View from flask_login import current_user, login_required, login_user, logout_user from ereuse_devicehub import __version__, messages from ereuse_devicehub.db import db -from ereuse_devicehub.forms import LoginForm, PasswordForm, ProfileForm +from ereuse_devicehub.forms import LoginForm, PasswordForm from ereuse_devicehub.resources.user.models import User from ereuse_devicehub.utils import is_safe_url @@ -47,31 +47,16 @@ class LogoutView(View): class UserProfileView(View): - methods = ['GET', 'POST'] decorators = [login_required] template_name = 'ereuse_devicehub/user_profile.html' def dispatch_request(self): - form = ProfileForm() - if request.method == 'GET': - form = ProfileForm(user=current_user.individual) - - sessions = {s.created.strftime('%H:%M %d-%m-%Y') for s in current_user.sessions} context = { 'current_user': current_user, - 'sessions': sessions, 'version': __version__, - 'profile_form': form, 'password_form': PasswordForm(), } - if form.validate_on_submit(): - form.save(commit=False) - messages.success('Modify user Profile datas successfully!') - db.session.commit() - elif form.errors: - messages.error('Error modifying user Profile data!') - return flask.render_template(self.template_name, **context) From d0e033197c7703a2405adb0afc813287846df284 Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Thu, 28 Apr 2022 12:06:43 +0200 Subject: [PATCH 20/22] Drop Agent.get_full_name because is unused --- ereuse_devicehub/resources/agent/models.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ereuse_devicehub/resources/agent/models.py b/ereuse_devicehub/resources/agent/models.py index 51dd7ab3..826d0545 100644 --- a/ereuse_devicehub/resources/agent/models.py +++ b/ereuse_devicehub/resources/agent/models.py @@ -47,10 +47,6 @@ class Agent(Thing): db.Index('agent_type', type, postgresql_using='hash'), ) - @property - def get_full_name(self): - return self.name - @declared_attr def __mapper_args__(cls): """Defines inheritance. From 3a5e806104e1500f332fc5baf87445bd00aa5172 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 28 Apr 2022 17:46:12 +0200 Subject: [PATCH 21/22] add icons types of devices in list of devices --- ereuse_devicehub/resources/device/models.py | 323 +++++++++++++----- .../templates/inventory/device_list.html | 3 + 2 files changed, 232 insertions(+), 94 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 98227c4c..15c36527 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -1,20 +1,30 @@ -import pathlib import copy +import pathlib import time -from flask import g from contextlib import suppress from fractions import Fraction from itertools import chain from operator import attrgetter from typing import Dict, List, Set -from flask_sqlalchemy import event from boltons import urlutils from citext import CIText from ereuse_utils.naming import HID_CONVERSION_DOC, Naming +from flask import g +from flask_sqlalchemy import event from more_itertools import unique_everseen -from sqlalchemy import BigInteger, Boolean, Column, Enum as DBEnum, Float, ForeignKey, Integer, \ - Sequence, SmallInteger, Unicode, inspect, text +from sqlalchemy import BigInteger, Boolean, Column +from sqlalchemy import Enum as DBEnum +from sqlalchemy import ( + Float, + ForeignKey, + Integer, + Sequence, + SmallInteger, + Unicode, + inspect, + text, +) from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.ext.hybrid import hybrid_property @@ -22,19 +32,41 @@ from sqlalchemy.orm import ColumnProperty, backref, relationship, validates from sqlalchemy.util import OrderedSet from sqlalchemy_utils import ColorType from stdnum import imei, meid -from teal.db import CASCADE_DEL, POLYMORPHIC_ID, POLYMORPHIC_ON, ResourceNotFound, URL, \ - check_lower, check_range, IntEnum +from teal.db import ( + CASCADE_DEL, + POLYMORPHIC_ID, + POLYMORPHIC_ON, + URL, + IntEnum, + ResourceNotFound, + check_lower, + check_range, +) from teal.enums import Layouts from teal.marshmallow import ValidationError from teal.resource import url_for_resource from ereuse_devicehub.db import db -from ereuse_devicehub.resources.utils import hashcode -from ereuse_devicehub.resources.enums import BatteryTechnology, CameraFacing, ComputerChassis, \ - DataStorageInterface, DisplayTech, PrinterTechnology, RamFormat, RamInterface, Severity, TransferState -from ereuse_devicehub.resources.models import STR_SM_SIZE, Thing, listener_reset_field_updated_in_actual_time -from ereuse_devicehub.resources.user.models import User from ereuse_devicehub.resources.device.metrics import Metrics +from ereuse_devicehub.resources.enums import ( + BatteryTechnology, + CameraFacing, + ComputerChassis, + DataStorageInterface, + DisplayTech, + PrinterTechnology, + RamFormat, + RamInterface, + Severity, + TransferState, +) +from ereuse_devicehub.resources.models import ( + STR_SM_SIZE, + Thing, + listener_reset_field_updated_in_actual_time, +) +from ereuse_devicehub.resources.user.models import User +from ereuse_devicehub.resources.utils import hashcode def create_code(context): @@ -58,17 +90,21 @@ class Device(Thing): Devices can contain ``Components``, which are just a type of device (it is a recursive relationship). """ + id = Column(BigInteger, Sequence('device_seq'), primary_key=True) id.comment = """The identifier of the device for this database. Used only internally for software; users should not use this. """ type = Column(Unicode(STR_SM_SIZE), nullable=False) hid = Column(Unicode(), check_lower('hid'), unique=False) - hid.comment = """The Hardware ID (HID) is the ID traceability + hid.comment = ( + """The Hardware ID (HID) is the ID traceability systems use to ID a device globally. This field is auto-generated from Devicehub using literal identifiers from the device, so it can re-generated *offline*. - """ + HID_CONVERSION_DOC + """ + + HID_CONVERSION_DOC + ) model = Column(Unicode(), check_lower('model')) model.comment = """The model of the device in lower case. @@ -118,14 +154,18 @@ class Device(Thing): image = db.Column(db.URL) image.comment = "An image of the device." - owner_id = db.Column(UUID(as_uuid=True), - db.ForeignKey(User.id), - nullable=False, - default=lambda: g.user.id) + owner_id = db.Column( + UUID(as_uuid=True), + db.ForeignKey(User.id), + nullable=False, + default=lambda: g.user.id, + ) owner = db.relationship(User, primaryjoin=owner_id == User.id) allocated = db.Column(Boolean, default=False) allocated.comment = "device is allocated or not." - devicehub_id = db.Column(db.CIText(), nullable=True, unique=True, default=create_code) + devicehub_id = db.Column( + db.CIText(), nullable=True, unique=True, default=create_code + ) devicehub_id.comment = "device have a unique code." active = db.Column(Boolean, default=True) @@ -152,12 +192,12 @@ class Device(Thing): 'image', 'allocated', 'devicehub_id', - 'active' + 'active', } __table_args__ = ( db.Index('device_id', id, postgresql_using='hash'), - db.Index('type_index', type, postgresql_using='hash') + db.Index('type_index', type, postgresql_using='hash'), ) def __init__(self, **kw) -> None: @@ -187,7 +227,9 @@ class Device(Thing): for ac in actions_one: ac.real_created = ac.created - return sorted(chain(actions_multiple, actions_one), key=lambda x: x.real_created) + return sorted( + chain(actions_multiple, actions_one), key=lambda x: x.real_created + ) @property def problems(self): @@ -196,8 +238,9 @@ class Device(Thing): There can be up to 3 actions: current Snapshot, current Physical action, current Trading action. """ - from ereuse_devicehub.resources.device import states from ereuse_devicehub.resources.action.models import Snapshot + from ereuse_devicehub.resources.device import states + actions = set() with suppress(LookupError, ValueError): actions.add(self.last_action_of(Snapshot)) @@ -217,11 +260,13 @@ class Device(Thing): """ # todo ensure to remove materialized values when start using them # todo or self.__table__.columns if inspect fails - return {c.key: getattr(self, c.key, None) - for c in inspect(self.__class__).attrs - if isinstance(c, ColumnProperty) - and not getattr(c, 'foreign_keys', None) - and c.key not in self._NON_PHYSICAL_PROPS} + return { + c.key: getattr(self, c.key, None) + for c in inspect(self.__class__).attrs + if isinstance(c, ColumnProperty) + and not getattr(c, 'foreign_keys', None) + and c.key not in self._NON_PHYSICAL_PROPS + } @property def public_properties(self) -> Dict[str, object or None]: @@ -234,11 +279,13 @@ class Device(Thing): """ non_public = ['amount', 'transfer_state', 'receiver_id'] hide_properties = list(self._NON_PHYSICAL_PROPS) + non_public - return {c.key: getattr(self, c.key, None) - for c in inspect(self.__class__).attrs - if isinstance(c, ColumnProperty) - and not getattr(c, 'foreign_keys', None) - and c.key not in hide_properties} + return { + c.key: getattr(self, c.key, None) + for c in inspect(self.__class__).attrs + if isinstance(c, ColumnProperty) + and not getattr(c, 'foreign_keys', None) + and c.key not in hide_properties + } @property def public_actions(self) -> List[object]: @@ -260,6 +307,7 @@ class Device(Thing): """The last Rate of the device.""" with suppress(LookupError, ValueError): from ereuse_devicehub.resources.action.models import Rate + return self.last_action_of(Rate) @property @@ -268,12 +316,14 @@ class Device(Thing): ever been set.""" with suppress(LookupError, ValueError): from ereuse_devicehub.resources.action.models import Price + return self.last_action_of(Price) @property def last_action_trading(self): """which is the last action trading""" from ereuse_devicehub.resources.device import states + with suppress(LookupError, ValueError): return self.last_action_of(*states.Trading.actions()) @@ -287,6 +337,7 @@ class Device(Thing): - Management """ from ereuse_devicehub.resources.device import states + with suppress(LookupError, ValueError): return self.last_action_of(*states.Status.actions()) @@ -300,6 +351,7 @@ class Device(Thing): - Management """ from ereuse_devicehub.resources.device import states + status_actions = [ac.t for ac in states.Status.actions()] history = [] for ac in self.actions: @@ -329,13 +381,15 @@ class Device(Thing): if not hasattr(lot, 'trade'): return - Status = {0: 'Trade', - 1: 'Confirm', - 2: 'NeedConfirmation', - 3: 'TradeConfirmed', - 4: 'Revoke', - 5: 'NeedConfirmRevoke', - 6: 'RevokeConfirmed'} + Status = { + 0: 'Trade', + 1: 'Confirm', + 2: 'NeedConfirmation', + 3: 'TradeConfirmed', + 4: 'Revoke', + 5: 'NeedConfirmRevoke', + 6: 'RevokeConfirmed', + } trade = lot.trade user_from = trade.user_from @@ -408,6 +462,7 @@ class Device(Thing): """If the actual trading state is an revoke action, this property show the id of that revoke""" from ereuse_devicehub.resources.device import states + with suppress(LookupError, ValueError): action = self.last_action_of(*states.Trading.actions()) if action.type == 'Revoke': @@ -417,6 +472,7 @@ class Device(Thing): def physical(self): """The actual physical state, None otherwise.""" from ereuse_devicehub.resources.device import states + with suppress(LookupError, ValueError): action = self.last_action_of(*states.Physical.actions()) return states.Physical(action.__class__) @@ -425,6 +481,7 @@ class Device(Thing): def traking(self): """The actual traking state, None otherwise.""" from ereuse_devicehub.resources.device import states + with suppress(LookupError, ValueError): action = self.last_action_of(*states.Traking.actions()) return states.Traking(action.__class__) @@ -433,6 +490,7 @@ class Device(Thing): def usage(self): """The actual usage state, None otherwise.""" from ereuse_devicehub.resources.device import states + with suppress(LookupError, ValueError): action = self.last_action_of(*states.Usage.actions()) return states.Usage(action.__class__) @@ -470,8 +528,11 @@ class Device(Thing): test has been executed. """ from ereuse_devicehub.resources.action.models import Test - current_tests = unique_everseen((e for e in reversed(self.actions) if isinstance(e, Test)), - key=attrgetter('type')) # last test of each type + + current_tests = unique_everseen( + (e for e in reversed(self.actions) if isinstance(e, Test)), + key=attrgetter('type'), + ) # last test of each type return self._warning_actions(current_tests) @property @@ -496,7 +557,9 @@ class Device(Thing): def set_hid(self): with suppress(TypeError): - self.hid = Naming.hid(self.type, self.manufacturer, self.model, self.serial_number) + self.hid = Naming.hid( + self.type, self.manufacturer, self.model, self.serial_number + ) def last_action_of(self, *types): """Gets the last action of the given types. @@ -509,7 +572,9 @@ class Device(Thing): actions.sort(key=lambda x: x.created) return next(e for e in reversed(actions) if isinstance(e, types)) except StopIteration: - raise LookupError('{!r} does not contain actions of types {}.'.format(self, types)) + raise LookupError( + '{!r} does not contain actions of types {}.'.format(self, types) + ) def which_user_put_this_device_in_trace(self): """which is the user than put this device in this trade""" @@ -546,6 +611,29 @@ class Device(Thing): metrics = Metrics(device=self) return metrics.get_metrics() + def get_type_logo(self): + # This is used for see one logo of type of device in the frontend + types = { + "Desktop": "bi bi-file-post-fill", + "Laptop": "bi bi-laptop", + "Server": "bi bi-server", + "Processor": "bi bi-cpu", + "RamModule": "bi bi-list", + "Motherboard": "bi bi-cpu-fill", + "NetworkAdapter": "bi bi-hdd-network", + "GraphicCard": "bi bi-brush", + "SoundCard": "bi bi-volume-up-fill", + "Monitor": "bi bi-display", + "TV": "bi bi-easel", + "Projector": "bi bi-camera-video", + "Tablet": "bi bi-tablet-landscape", + "Smartphone": "bi bi-phone", + "Cellphone": "bi bi-telephone", + "HardDrive": "bi bi-hdd-stack", + "SolidStateDrive": "bi bi-hdd", + } + return types.get(self.type, '') + def __lt__(self, other): return self.id < other.id @@ -571,19 +659,24 @@ class Device(Thing): class DisplayMixin: """Base class for the Display Component and the Monitor Device.""" - size = Column(Float(decimal_return_scale=1), check_range('size', 2, 150), nullable=True) + + size = Column( + Float(decimal_return_scale=1), check_range('size', 2, 150), nullable=True + ) size.comment = """The size of the monitor in inches.""" technology = Column(DBEnum(DisplayTech)) technology.comment = """The technology the monitor uses to display the image. """ - resolution_width = Column(SmallInteger, check_range('resolution_width', 10, 20000), - nullable=True) + resolution_width = Column( + SmallInteger, check_range('resolution_width', 10, 20000), nullable=True + ) resolution_width.comment = """The maximum horizontal resolution the monitor can natively support in pixels. """ - resolution_height = Column(SmallInteger, check_range('resolution_height', 10, 20000), - nullable=True) + resolution_height = Column( + SmallInteger, check_range('resolution_height', 10, 20000), nullable=True + ) resolution_height.comment = """The maximum vertical resolution the monitor can natively support in pixels. """ @@ -622,8 +715,12 @@ class DisplayMixin: def __str__(self) -> str: if self.size: - return '{0.t} {0.serial_number} {0.size}in ({0.aspect_ratio}) {0.technology}'.format(self) - return '{0.t} {0.serial_number} 0in ({0.aspect_ratio}) {0.technology}'.format(self) + return '{0.t} {0.serial_number} {0.size}in ({0.aspect_ratio}) {0.technology}'.format( + self + ) + return '{0.t} {0.serial_number} 0in ({0.aspect_ratio}) {0.technology}'.format( + self + ) def __format__(self, format_spec: str) -> str: v = '' @@ -645,6 +742,7 @@ class Computer(Device): Computer is broadly extended by ``Desktop``, ``Laptop``, and ``Server``. The property ``chassis`` defines it more granularly. """ + id = Column(BigInteger, ForeignKey(Device.id), primary_key=True) chassis = Column(DBEnum(ComputerChassis), nullable=True) chassis.comment = """The physical form of the computer. @@ -652,16 +750,18 @@ class Computer(Device): It is a subset of the Linux definition of DMI / DMI decode. """ amount = Column(Integer, check_range('amount', min=0, max=100), default=0) - owner_id = db.Column(UUID(as_uuid=True), - db.ForeignKey(User.id), - nullable=False, - default=lambda: g.user.id) + owner_id = db.Column( + UUID(as_uuid=True), + db.ForeignKey(User.id), + nullable=False, + default=lambda: g.user.id, + ) # author = db.relationship(User, primaryjoin=owner_id == User.id) - transfer_state = db.Column(IntEnum(TransferState), default=TransferState.Initial, nullable=False) + transfer_state = db.Column( + IntEnum(TransferState), default=TransferState.Initial, nullable=False + ) transfer_state.comment = TransferState.__doc__ - receiver_id = db.Column(UUID(as_uuid=True), - db.ForeignKey(User.id), - nullable=True) + receiver_id = db.Column(UUID(as_uuid=True), db.ForeignKey(User.id), nullable=True) receiver = db.relationship(User, primaryjoin=receiver_id == User.id) def __init__(self, *args, **kwargs) -> None: @@ -684,22 +784,30 @@ class Computer(Device): @property def ram_size(self) -> int: """The total of RAM memory the computer has.""" - return sum(ram.size or 0 for ram in self.components if isinstance(ram, RamModule)) + return sum( + ram.size or 0 for ram in self.components if isinstance(ram, RamModule) + ) @property def data_storage_size(self) -> int: """The total of data storage the computer has.""" - return sum(ds.size or 0 for ds in self.components if isinstance(ds, DataStorage)) + return sum( + ds.size or 0 for ds in self.components if isinstance(ds, DataStorage) + ) @property def processor_model(self) -> str: """The model of one of the processors of the computer.""" - return next((p.model for p in self.components if isinstance(p, Processor)), None) + return next( + (p.model for p in self.components if isinstance(p, Processor)), None + ) @property def graphic_card_model(self) -> str: """The model of one of the graphic cards of the computer.""" - return next((p.model for p in self.components if isinstance(p, GraphicCard)), None) + return next( + (p.model for p in self.components if isinstance(p, GraphicCard)), None + ) @property def network_speeds(self) -> List[int]: @@ -724,16 +832,18 @@ class Computer(Device): it is not None. """ return set( - privacy for privacy in - (hdd.privacy for hdd in self.components if isinstance(hdd, DataStorage)) + privacy + for privacy in ( + hdd.privacy for hdd in self.components if isinstance(hdd, DataStorage) + ) if privacy ) @property def external_document_erasure(self): - """Returns the external ``DataStorage`` proof of erasure. - """ + """Returns the external ``DataStorage`` proof of erasure.""" from ereuse_devicehub.resources.action.models import DataWipe + urls = set() try: ev = self.last_action_of(DataWipe) @@ -756,8 +866,11 @@ class Computer(Device): if not self.hid: return components = self.components if components_snap is None else components_snap - macs_network = [c.serial_number for c in components - if c.type == 'NetworkAdapter' and c.serial_number is not None] + macs_network = [ + c.serial_number + for c in components + if c.type == 'NetworkAdapter' and c.serial_number is not None + ] macs_network.sort() mac = macs_network[0] if macs_network else '' if not mac or mac in self.hid: @@ -823,9 +936,13 @@ class Mobile(Device): """ ram_size = db.Column(db.Integer, check_range('ram_size', min=128, max=36000)) ram_size.comment = """The total of RAM of the device in MB.""" - data_storage_size = db.Column(db.Integer, check_range('data_storage_size', 0, 10 ** 8)) + data_storage_size = db.Column( + db.Integer, check_range('data_storage_size', 0, 10**8) + ) data_storage_size.comment = """The total of data storage of the device in MB""" - display_size = db.Column(db.Float(decimal_return_scale=1), check_range('display_size', min=0.1, max=30.0)) + display_size = db.Column( + db.Float(decimal_return_scale=1), check_range('display_size', min=0.1, max=30.0) + ) display_size.comment = """The total size of the device screen""" @validates('imei') @@ -855,21 +972,24 @@ class Cellphone(Mobile): class Component(Device): """A device that can be inside another device.""" + id = Column(BigInteger, ForeignKey(Device.id), primary_key=True) parent_id = Column(BigInteger, ForeignKey(Computer.id)) - parent = relationship(Computer, - backref=backref('components', - lazy=True, - cascade=CASCADE_DEL, - order_by=lambda: Component.id, - collection_class=OrderedSet), - primaryjoin=parent_id == Computer.id) - - __table_args__ = ( - db.Index('parent_index', parent_id, postgresql_using='hash'), + parent = relationship( + Computer, + backref=backref( + 'components', + lazy=True, + cascade=CASCADE_DEL, + order_by=lambda: Component.id, + collection_class=OrderedSet, + ), + primaryjoin=parent_id == Computer.id, ) + __table_args__ = (db.Index('parent_index', parent_id, postgresql_using='hash'),) + def similar_one(self, parent: Computer, blacklist: Set[int]) -> 'Component': """Gets a component that: @@ -881,11 +1001,16 @@ class Component(Device): when looking for similar ones. """ assert self.hid is None, 'Don\'t use this method with a component that has HID' - component = self.__class__.query \ - .filter_by(parent=parent, hid=None, owner_id=self.owner_id, - **self.physical_properties) \ - .filter(~Component.id.in_(blacklist)) \ + component = ( + self.__class__.query.filter_by( + parent=parent, + hid=None, + owner_id=self.owner_id, + **self.physical_properties, + ) + .filter(~Component.id.in_(blacklist)) .first() + ) if not component: raise ResourceNotFound(self.type) return component @@ -908,7 +1033,8 @@ class GraphicCard(JoinedComponentTableMixin, Component): class DataStorage(JoinedComponentTableMixin, Component): """A device that stores information.""" - size = Column(Integer, check_range('size', min=1, max=10 ** 8)) + + size = Column(Integer, check_range('size', min=1, max=10**8)) size.comment = """The size of the data-storage in MB.""" interface = Column(DBEnum(DataStorageInterface)) @@ -919,6 +1045,7 @@ class DataStorage(JoinedComponentTableMixin, Component): This is, the last erasure performed to the data storage. """ from ereuse_devicehub.resources.action.models import EraseBasic + try: ev = self.last_action_of(EraseBasic) except LookupError: @@ -933,9 +1060,9 @@ class DataStorage(JoinedComponentTableMixin, Component): @property def external_document_erasure(self): - """Returns the external ``DataStorage`` proof of erasure. - """ + """Returns the external ``DataStorage`` proof of erasure.""" from ereuse_devicehub.resources.action.models import DataWipe + try: ev = self.last_action_of(DataWipe) return ev.document.url.to_text() @@ -985,6 +1112,7 @@ class NetworkAdapter(JoinedComponentTableMixin, NetworkMixin, Component): class Processor(JoinedComponentTableMixin, Component): """The CPU.""" + speed = Column(Float, check_range('speed', 0.1, 15)) speed.comment = """The regular CPU speed.""" cores = Column(SmallInteger, check_range('cores', 1, 10)) @@ -999,6 +1127,7 @@ class Processor(JoinedComponentTableMixin, Component): class RamModule(JoinedComponentTableMixin, Component): """A stick of RAM.""" + size = Column(SmallInteger, check_range('size', min=128, max=17000)) size.comment = """The capacity of the RAM stick.""" speed = Column(SmallInteger, check_range('speed', min=100, max=10000)) @@ -1016,6 +1145,7 @@ class Display(JoinedComponentTableMixin, DisplayMixin, Component): mobiles, smart-watches, and so on; excluding ``ComputerMonitor`` and ``TelevisionSet``. """ + pass @@ -1031,14 +1161,16 @@ class Battery(JoinedComponentTableMixin, Component): @property def capacity(self) -> float: - """The quantity of """ + """The quantity of""" from ereuse_devicehub.resources.action.models import MeasureBattery + real_size = self.last_action_of(MeasureBattery).size return real_size / self.size if real_size and self.size else None class Camera(Component): """The camera of a device.""" + focal_length = db.Column(db.SmallInteger) video_height = db.Column(db.SmallInteger) video_width = db.Column(db.Integer) @@ -1051,6 +1183,7 @@ class Camera(Component): class ComputerAccessory(Device): """Computer peripherals and similar accessories.""" + id = Column(BigInteger, ForeignKey(Device.id), primary_key=True) pass @@ -1073,6 +1206,7 @@ class MemoryCardReader(ComputerAccessory): class Networking(NetworkMixin, Device): """Routers, switches, hubs...""" + id = Column(BigInteger, ForeignKey(Device.id), primary_key=True) @@ -1118,6 +1252,7 @@ class Microphone(Sound): class Video(Device): """Devices related to video treatment.""" + pass @@ -1131,6 +1266,7 @@ class Videoconference(Video): class Cooking(Device): """Cooking devices.""" + pass @@ -1182,6 +1318,7 @@ class Manufacturer(db.Model): Ideally users should use the names from this list when submitting devices. """ + name = db.Column(CIText(), primary_key=True) name.comment = """The normalized name of the manufacturer.""" url = db.Column(URL(), unique=True) @@ -1192,7 +1329,7 @@ class Manufacturer(db.Model): __table_args__ = ( # from https://niallburkley.com/blog/index-columns-for-like-in-postgres/ db.Index('name_index', text('name gin_trgm_ops'), postgresql_using='gin'), - {'schema': 'common'} + {'schema': 'common'}, ) @classmethod @@ -1202,10 +1339,7 @@ class Manufacturer(db.Model): #: Dialect used to write the CSV with pathlib.Path(__file__).parent.joinpath('manufacturers.csv').open() as f: - cursor.copy_expert( - 'COPY common.manufacturer FROM STDIN (FORMAT csv)', - f - ) + cursor.copy_expert('COPY common.manufacturer FROM STDIN (FORMAT csv)', f) listener_reset_field_updated_in_actual_time(Device) @@ -1217,6 +1351,7 @@ def create_code_tag(mapper, connection, device): this tag is the same of devicehub_id. """ from ereuse_devicehub.resources.tag.model import Tag + if isinstance(device, Computer): tag = Tag(device_id=device.id, id=device.devicehub_id) db.session.add(tag) diff --git a/ereuse_devicehub/templates/inventory/device_list.html b/ereuse_devicehub/templates/inventory/device_list.html index 827c3b68..803498ea 100644 --- a/ereuse_devicehub/templates/inventory/device_list.html +++ b/ereuse_devicehub/templates/inventory/device_list.html @@ -336,6 +336,9 @@ /> + {% if dev.get_type_logo() %} + + {% endif %} {{ dev.verbose_name }} From 7362eb44927ddbbde106fd60b7dbd7ebb5001a08 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 28 Apr 2022 17:56:00 +0200 Subject: [PATCH 22/22] add computer monitor --- ereuse_devicehub/resources/device/models.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 15c36527..09451277 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -624,6 +624,9 @@ class Device(Thing): "GraphicCard": "bi bi-brush", "SoundCard": "bi bi-volume-up-fill", "Monitor": "bi bi-display", + "Display": "bi bi-display", + "ComputerMonitor": "bi bi-display", + "TelevisionSet": "bi bi-easel", "TV": "bi bi-easel", "Projector": "bi bi-camera-video", "Tablet": "bi bi-tablet-landscape",