Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Luciano Barletta
/
message-service
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
1
Wiki
Network
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Commit e46c9ea7
authored
2020-06-28 21:57:53 -0300
by
Tu Nombre
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
Se agregan validaciones y tolearancia a fallos
1 parent
35581615
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
301 additions
and
22 deletions
ValidacionTelefonos.py
deploy.py
enums.py
services.py
vslifs.py
ValidacionTelefonos.py
0 → 100644
View file @
e46c9ea
import
re
CaracTelAR
=
(
11
,
220
,
221
,
223
,
230
,
236
,
237
,
249
,
260
,
261
,
263
,
264
,
266
,
280
,
291
,
294
,
297
,
298
,
299
,
336
,
341
,
342
,
343
,
345
,
348
,
351
,
353
,
358
,
362
,
364
,
370
,
376
,
379
,
380
,
381
,
383
,
385
,
387
,
388
,
2202
,
2221
,
2223
,
2224
,
2225
,
2226
,
2227
,
2229
,
2241
,
2242
,
2243
,
2244
,
2245
,
2246
,
2252
,
2254
,
2255
,
2257
,
2261
,
2262
,
2264
,
2265
,
2266
,
2267
,
2268
,
2271
,
2272
,
2273
,
2274
,
2281
,
2283
,
2284
,
2285
,
2286
,
2291
,
2292
,
2296
,
2297
,
2302
,
2314
,
2316
,
2317
,
2320
,
2323
,
2324
,
2325
,
2326
,
2331
,
2333
,
2334
,
2335
,
2336
,
2337
,
2338
,
2342
,
2343
,
2344
,
2345
,
2346
,
2352
,
2353
,
2354
,
2355
,
2356
,
2357
,
2358
,
2392
,
2393
,
2394
,
2395
,
2396
,
2473
,
2474
,
2475
,
2477
,
2478
,
2622
,
2624
,
2625
,
2626
,
2646
,
2647
,
2648
,
2651
,
2652
,
2655
,
2656
,
2657
,
2658
,
2901
,
2902
,
2903
,
2920
,
2921
,
2922
,
2923
,
2924
,
2925
,
2926
,
2927
,
2928
,
2929
,
2931
,
2932
,
2933
,
2934
,
2935
,
2936
,
2940
,
2942
,
2945
,
2946
,
2948
,
2952
,
2953
,
2954
,
2962
,
2963
,
2964
,
2966
,
2972
,
2982
,
2983
,
3327
,
3329
,
3382
,
3385
,
3387
,
3388
,
3400
,
3401
,
3402
,
3404
,
3405
,
3406
,
3407
,
3408
,
3409
,
3435
,
3436
,
3437
,
3438
,
3442
,
3444
,
3445
,
3446
,
3447
,
3454
,
3456
,
3458
,
3460
,
3462
,
3463
,
3464
,
3465
,
3466
,
3467
,
3468
,
3469
,
3471
,
3472
,
3476
,
3482
,
3483
,
3487
,
3489
,
3491
,
3493
,
3496
,
3497
,
3498
,
3521
,
3522
,
3524
,
3525
,
3532
,
3533
,
3537
,
3541
,
3542
,
3543
,
3544
,
3546
,
3547
,
3548
,
3549
,
3562
,
3563
,
3564
,
3571
,
3572
,
3573
,
3574
,
3575
,
3576
,
3582
,
3583
,
3584
,
3585
,
3711
,
3715
,
3716
,
3718
,
3721
,
3725
,
3731
,
3734
,
3735
,
3741
,
3743
,
3751
,
3754
,
3755
,
3756
,
3757
,
3758
,
3772
,
3773
,
3774
,
3775
,
3777
,
3781
,
3782
,
3786
,
3821
,
3825
,
3826
,
3827
,
3832
,
3835
,
3837
,
3838
,
3841
,
3843
,
3844
,
3845
,
3846
,
3854
,
3855
,
3856
,
3857
,
3858
,
3861
,
3862
,
3863
,
3865
,
3867
,
3868
,
3869
,
3873
,
3876
,
3877
,
3878
,
3885
,
3886
,
3889
,
3888
,
3891
,
3892
,
3894
)
RootDomain
=
(
"com"
,
"org"
,
"net"
,
"int"
,
"edu"
,
"gov"
,
"mil"
)
PaisDom
=
(
"ac"
,
"ad"
,
"ae"
,
"af"
,
"ag"
,
"ai"
,
"al"
,
"am"
,
"ao"
,
"aq"
,
"ar"
,
"as"
,
"at"
,
"au"
,
"aw"
,
"ax"
,
"az"
,
"ba"
,
"bb"
,
"bd"
,
"be"
,
"bf"
,
"bg"
,
"bh"
,
"bi"
,
"bj"
,
"bm"
,
"bn"
,
"bo"
,
"bq"
,
"br"
,
"bs"
,
"bt"
,
"bw"
,
"by"
,
"bz"
,
"ca"
,
"cc"
,
"cd"
,
"cf"
,
"cg"
,
"ch"
,
"ci"
,
"ck"
,
"cl"
,
"cm"
,
"cn"
,
"co"
,
"cr"
,
"cu"
,
"cv"
,
"cw"
,
"cx"
,
"cy"
,
"cz"
,
"de"
,
"dj"
,
"dk"
,
"dm"
,
"do"
,
"dz"
,
"ec"
,
"eg"
,
"eh"
,
"er"
,
"es"
,
"et"
,
"eu"
,
"fi"
,
"fj"
,
"fk"
,
"fm"
,
"fo"
,
"fr"
,
"ga"
,
"gd"
,
"ge"
,
"gf"
,
"gg"
,
"gh"
,
"gi"
,
"gl"
,
"gm"
,
"gn"
,
"gp"
,
"gq"
,
"gr"
,
"gs"
,
"gt"
,
"gu"
,
"gw"
,
"gy"
,
"hk"
,
"hm"
,
"hr"
,
"ht"
,
"hu"
,
"id"
,
"ie"
,
"il"
,
"im"
,
"in"
,
"io"
,
"iq"
,
"ir"
,
"is"
,
"it"
,
"je"
,
"jm"
,
"jo"
,
"jp"
,
"ke"
,
"kg"
,
"kh"
,
"ki"
,
"km"
,
"kn"
,
"kp"
,
"kr"
,
"kw"
,
"ky"
,
"kz"
,
"la"
,
"lb"
,
"lc"
,
"li"
,
"lk"
,
"lr"
,
"ls"
,
"lt"
,
"lu"
,
"lv"
,
"ly"
,
"ma"
,
"mc"
,
"md"
,
"me"
,
"mg"
,
"mh"
,
"mk"
,
"ml"
,
"mm"
,
"mn"
,
"mo"
,
"mp"
,
"mq"
,
"mr"
,
"ms"
,
"mt"
,
"mu"
,
"mv"
,
"mw"
,
"mx"
,
"my"
,
"mz"
,
"na"
,
"nc"
,
"ne"
,
"nf"
,
"ng"
,
"ni"
,
"nl"
,
"no"
,
"np"
,
"nr"
,
"nu"
,
"nz"
,
"om"
,
"pa"
,
"pe"
,
"pf"
,
"pg"
,
"ph"
,
"pk"
,
"pl"
,
"pm"
,
"pn"
,
"pr"
,
"ps"
,
"pt"
,
"pw"
,
"py"
,
"qa"
,
"re"
,
"ro"
,
"rs"
,
"ru"
,
"rw"
,
"sa"
,
"sb"
,
"sc"
,
"sd"
,
"se"
,
"sg"
,
"sh"
,
"si"
,
"sk"
,
"sl"
,
"sm"
,
"sn"
,
"so"
,
"sr"
,
"ss"
,
"st"
,
"su"
,
"sv"
,
"sx"
,
"sy"
,
"sz"
,
"tc"
,
"td"
,
"tf"
,
"tg"
,
"th"
,
"tj"
,
"tk"
,
"tl"
,
"tm"
,
"tn"
,
"to"
,
"tr"
,
"tt"
,
"tv"
,
"tw"
,
"tz"
,
"ua"
,
"ug"
,
"uk"
,
"us"
,
"uy"
,
"uz"
,
"va"
,
"vc"
,
"ve"
,
"vg"
,
"vi"
,
"vn"
,
"vu"
,
"wf"
,
"ws"
,
"ye"
,
"yt"
,
"za"
,
"zm"
,
"zw"
)
class
ValidacionCorreo
():
"""clase para revisar que los mails tengan los requisitos minimos para tratar de envia"""
def
ValidarCorreo
(
self
,
correo
):
"""si cumpre devuelve el mail, sino devuelve False"""
Correo
=
str
(
correo
)
.
lower
()
if
self
.
validarcorreo
(
Correo
)
==
False
:
Correo
=
False
return
(
Correo
)
def
validarcorreo
(
self
,
correo
):
c
=
correo
.
split
(
"@"
)
estado
=
True
usuario
=
c
[
0
]
dominio
=
c
[
1
]
if
len
(
usuario
)
<
2
:
estado
=
False
if
False
==
self
.
validacionDominio
(
dominio
):
estado
=
False
return
(
estado
)
def
validacionDominio
(
self
,
dominio
):
"""si es un dominio valido, devuelve true sino false"""
d
=
dominio
.
split
(
"."
)
error
=
True
if
len
(
d
)
>
3
:
error
=
False
if
2
>
len
(
d
):
error
=
False
if
not
d
[
1
]
in
RootDomain
:
error
=
False
if
len
(
d
)
==
3
:
if
not
d
[
2
]
in
PaisDom
:
error
=
False
return
(
error
)
class
ValidacionTelefonosArgentinos
():
"""Esta clase maneja numeros de telefonos humanos y reconstruye los
Codigos internacionales"""
def
__init__
(
self
):
self
.
CarcTelAr
=
CaracTelAR
self
.
AreaDefault
=
"341"
self
.
Internacional
=
True
self
.
InternalCod
=
"54"
def
ValidarTelefono
(
self
,
tel
,
area
=
""
,
internacional
=
""
,
CodigoInternacional
=
""
):
if
area
==
""
:
area
=
self
.
AreaDefault
if
internacional
==
""
:
internacional
=
self
.
Internacional
if
CodigoInternacional
==
""
:
CodigoInternacional
=
self
.
InternalCod
try
:
n
=
self
.
validarTelefono
(
tel
,
area
)
if
internacional
==
True
:
n
=
CodigoInternacional
+
n
except
:
n
=
False
return
(
n
)
def
internacionalNumero
(
self
,
tel
):
if
tel
[
0
]
+
tel
[
1
]
==
self
.
InternalCod
:
print
(
"borro codigo internacional"
)
tel
=
tel
[
1
:]
tel
=
tel
[
1
:]
return
(
tel
)
def
validarTelefono
(
self
,
tel
,
area
):
TEL
=
self
.
ExtraerNoNumero
(
tel
)
TEL
=
self
.
internacionalNumero
(
TEL
)
#print(TEL)
TEL
=
self
.
QuitarCeroDelante
(
TEL
)
TEL
=
self
.
AgregarAreaDefault
(
TEL
,
area
)
Caract
=
self
.
ComprovacionCaracteristica
(
TEL
)
TEL
=
self
.
SacarEl15
(
TEL
,
Caract
)
self
.
LargoTelefono
(
TEL
)
Caract
=
self
.
ComprovacionCaracteristica
(
TEL
)
if
Caract
==
False
:
TEL
=
False
if
not
len
(
TEL
)
==
10
:
TEL
=
False
return
(
TEL
)
def
AgregarAreaDefault
(
self
,
tel
,
area
):
if
len
(
tel
)
<
10
:
tel
=
area
+
tel
return
(
tel
)
def
SacarEl15
(
self
,
tel
,
Caract
):
if
len
(
tel
)
<
10
:
return
(
False
)
if
len
(
tel
)
==
10
:
return
(
tel
)
#n = len(tel)
c
=
len
(
Caract
)
for
x
in
range
(
c
+
2
):
tel
=
tel
[
1
:]
return
(
Caract
+
tel
)
def
ComprovacionCaracteristica
(
self
,
tel
):
for
numero
in
CaracTelAR
:
numero
=
str
(
numero
)
l
=
len
(
numero
)
#print(tel)
if
l
==
2
:
Tl
=
tel
[
0
]
+
tel
[
1
]
if
l
==
3
:
Tl
=
tel
[
0
]
+
tel
[
1
]
+
tel
[
2
]
if
l
==
4
:
Tl
=
tel
[
0
]
+
tel
[
1
]
+
tel
[
2
]
+
tel
[
3
]
if
Tl
==
numero
:
return
(
numero
)
return
(
False
)
def
ExtraerNoNumero
(
self
,
tel
):
tel
=
str
(
tel
)
tel
=
re
.
sub
(
"[^0-9]"
,
""
,
tel
)
return
(
tel
)
def
validarnumero
(
self
):
pass
def
QuitarCeroDelante
(
self
,
tel
):
if
self
.
DetectarCeroDelante
(
tel
)
==
True
:
return
(
tel
[
1
:])
return
(
tel
)
def
DetectarCeroDelante
(
self
,
tel
):
if
str
(
tel
)[
0
]
==
"0"
:
return
(
True
)
return
(
False
)
def
LargoTelefono
(
self
,
tel
):
l
=
len
(
str
(
tel
))
if
l
==
10
:
return
(
str
(
tel
))
return
(
False
)
\ No newline at end of file
deploy.py
View file @
e46c9ea
...
...
@@ -6,6 +6,7 @@ from python_arptable import get_arp_table
from
enums
import
States
,
Table
import
os
,
ipdb
,
time
,
threading
,
random
,
datetime
app
=
Flask
(
__name__
)
# carpeta de los mensajes
...
...
@@ -147,4 +148,4 @@ if __name__ == "__main__":
# creo msg/ si no existe
if
not
os
.
path
.
exists
(
msgfolder
):
os
.
mkdir
(
msgfolder
)
app
.
run
(
"0.0.0.0"
)
\ No newline at end of file
app
.
run
(
host
=
"0.0.0.0"
,
port
=
8080
)
enums.py
View file @
e46c9ea
...
...
@@ -24,6 +24,8 @@ class States:
class
Services
:
wpp1
=
"wpp1"
mail
=
"mail"
sms
=
"sms"
@staticmethod
def
validate
(
serv
):
...
...
services.py
View file @
e46c9ea
...
...
@@ -5,6 +5,7 @@ from email.mime.text import MIMEText
from
email.mime.image
import
MIMEImage
from
email.mime.audio
import
MIMEAudio
from
email.mime.application
import
MIMEApplication
from
ValidacionTelefonos
import
ValidacionTelefonosArgentinos
,
ValidacionCorreo
import
requests
,
json
,
os
,
smtplib
class
ServiceBase
(
ABC
):
...
...
@@ -37,26 +38,52 @@ class Wpp1(ServiceBase):
Datatypes
.
link
:
'link'
}
token
=
"fd378337aebead91c2eb25209aa51a7d5ce9754ea1718"
uid
=
"549341
367483
2"
uid
=
"549341
264102
2"
server
=
"https://archivos.hgtsa.com.ar/"
def
send
(
self
,
data
):
tel
=
data
[
"dest"
]
v
=
ValidacionTelefonosArgentinos
()
tel
=
v
.
ValidarTelefono
(
tel
)
if
tel
==
False
:
print
(
"Error de numero"
)
tel
=
"Error"
#print("telefono a envia ",tel)
data
[
"dest"
]
=
tel
n
=
self
.
_send
(
data
)
return
(
n
)
def
_send
(
self
,
data
):
print
(
data
)
types
=
json
.
loads
(
data
[
Table
.
type
])
try
:
origen
=
json
.
loads
(
data
[
"info"
])[
"origin"
]
except
:
origen
=
Wpp1
.
uid
print
(
origen
)
succ
=
{}
if
data
[
"dest"
]
==
"Error"
:
for
f
in
types
:
print
(
f
)
succ
[
f
]
=
True
return
(
succ
)
for
file
in
types
:
filepath
=
data
[
Table
.
path
]
+
file
if
types
[
file
]
==
Datatypes
.
text
:
f
=
open
(
filepath
)
text
=
f
.
read
()
f
.
close
()
if
type
(
text
)
==
bytes
:
text
=
text
.
decode
(
"utf-8"
)
result
=
requests
.
get
(
url
=
Wpp1
.
URL
+
Wpp1
.
URLmode
[
types
[
file
]],
params
=
{
'token'
:
Wpp1
.
token
,
'uid'
:
Wpp1
.
uid
,
'to'
:
data
[
Table
.
dest
],
'text'
:
text
})
succ
[
file
]
=
result
.
json
()[
'success'
]
else
:
path
=
requests
.
post
(
url
=
Wpp1
.
server
,
files
=
{
'data'
:
(
file
,
open
(
filepath
,
'rb'
))
})
result
=
requests
.
get
(
url
=
Wpp1
.
URL
+
Wpp1
.
URLmode
[
types
[
file
]],
params
=
{
'token'
:
Wpp1
.
token
,
'uid'
:
Wpp1
.
uid
,
'to'
:
data
[
Table
.
dest
],
'url'
:
Wpp1
.
server
+
path
.
text
})
succ
[
file
]
=
result
.
json
()[
'success'
]
try
:
if
types
[
file
]
==
Datatypes
.
text
:
f
=
open
(
filepath
)
text
=
f
.
read
()
f
.
close
()
if
type
(
text
)
==
bytes
:
text
=
text
.
decode
(
"utf-8"
)
result
=
requests
.
get
(
url
=
Wpp1
.
URL
+
Wpp1
.
URLmode
[
types
[
file
]],
params
=
{
'token'
:
Wpp1
.
token
,
'uid'
:
origen
,
'to'
:
data
[
Table
.
dest
],
'text'
:
text
})
succ
[
file
]
=
result
.
json
()[
'success'
]
else
:
path
=
requests
.
post
(
url
=
Wpp1
.
server
,
files
=
{
'data'
:
(
file
,
open
(
filepath
,
'rb'
))
})
result
=
requests
.
get
(
url
=
Wpp1
.
URL
+
Wpp1
.
URLmode
[
types
[
file
]],
params
=
{
'token'
:
Wpp1
.
token
,
'uid'
:
origen
,
'to'
:
data
[
Table
.
dest
],
'url'
:
Wpp1
.
server
+
path
.
text
})
succ
[
file
]
=
result
.
json
()[
'success'
]
except
:
succ
[
file
]
=
False
return
succ
def
validatetype
(
self
,
type
):
...
...
@@ -65,8 +92,10 @@ class Wpp1(ServiceBase):
def
validateinfo
(
self
,
info
):
if
info
==
None
:
return
True
#print("parametro a chequear", info, type(info))
i
=
json
.
loads
(
info
)
for
param
in
i
:
#print("parametro a chequear", i)
if
param
not
in
Wpp1
.
Parameters
:
return
False
return
True
...
...
@@ -74,31 +103,74 @@ class Wpp1(ServiceBase):
class
Mail
(
ServiceBase
):
Allowed
=
[
Datatypes
.
text
,
Datatypes
.
image
,
Datatypes
.
document
,
Datatypes
.
link
]
Parameters
=
[
"origin"
,
"subject"
]
Parameters
=
[
"origin"
,
"subject"
,
"smtp"
]
def
__init__
(
self
):
self
.
__username
=
"prueba@anacsoft.com"
self
.
__password
=
"prueba2019"
self
.
s
=
smtplib
.
SMTP
(
host
=
"mail.anacsoft.com"
,
port
=
26
)
#self.__username = "prueba@anacsoft.com"
#self.__password = "prueba2019"
#self.s = smtplib.SMTP(host = "mail.anacsoft.com", port = 26)
self
.
__username
=
"anac.avisos@gmail.com"
self
.
__password
=
"xvc7733455"
self
.
s
=
smtplib
.
SMTP
(
host
=
"smtp.gmail.com"
,
port
=
587
)
self
.
s
.
starttls
()
self
.
s
.
login
(
self
.
__username
,
self
.
__password
)
#def send(self,data):
# N = self._send(data)
# return(N)
def
send
(
self
,
data
):
types
=
json
.
loads
(
data
[
Table
.
type
])
info
=
json
.
loads
(
data
[
Table
.
info
])
msg
=
MIMEMultipart
()
msg
[
'From'
]
=
self
.
_Mail__username
msg
[
'To'
]
=
data
[
Table
.
dest
]
Cr
=
ValidacionCorreo
()
msg
[
'From'
]
=
self
.
Usuario
(
info
)
msg
[
'To'
]
=
Cr
.
ValidarCorreo
(
data
[
Table
.
dest
])
msg
[
'Subject'
]
=
info
[
'subject'
]
succ
=
{}
if
msg
[
'To'
]
==
False
:
print
(
"mail no sale"
)
for
file
in
types
:
succ
[
file
]
=
True
return
(
succ
)
for
file
in
types
:
filepath
=
data
[
Table
.
path
]
+
file
MIME
=
self
.
MIMEmode
(
file
,
filepath
,
types
[
file
])
msg
.
attach
(
MIME
)
succ
[
file
]
=
True
self
.
s
.
send_message
(
msg
)
#self.s.send_message(msg)
self
.
Envio
(
msg
,
info
)
return
succ
def
Usuario
(
self
,
info
):
try
:
u
=
info
[
"smtp"
][
"username"
]
except
:
u
=
self
.
_Mail__username
return
(
u
)
def
Envio
(
self
,
msg
,
info
):
try
:
smtp
=
info
[
"smtp"
]
except
:
smtp
=
False
if
smtp
==
False
:
#print(info, type(info))
print
(
"mail sale por default"
)
n
=
self
.
s
.
send_message
(
msg
)
else
:
print
(
"mail sale por cliente"
)
n
=
self
.
SMTPcliente
(
msg
,
smtp
)
return
(
n
)
def
SMTPcliente
(
self
,
msg
,
Serversmtp
):
print
(
Serversmtp
,
type
(
Serversmtp
))
dg
=
smtplib
.
SMTP
(
host
=
Serversmtp
[
"host"
],
port
=
Serversmtp
[
"port"
])
dg
.
starttls
()
dg
.
login
(
Serversmtp
[
"username"
],
Serversmtp
[
"password"
])
#import ipdb; ipdb.set_trace()
dg
.
send_message
(
msg
)
def
MIMEmode
(
self
,
name
,
path
,
datatype
):
mode
=
None
...
...
@@ -141,9 +213,39 @@ class Mail(ServiceBase):
return
False
return
True
class
SMS
(
ServiceBase
):
Allowed
=
[
Datatypes
.
text
]
URL
=
"http://192.168.15.120:8080/v1/sms/send/"
def
send
(
self
,
data
):
types
=
json
.
loads
(
data
[
Table
.
type
])
success
=
{}
for
file
in
types
:
with
open
(
data
[
Table
.
path
]
+
file
)
as
m
:
text
=
m
.
read
()
if
type
(
text
)
==
bytes
:
text
=
text
.
decode
(
"utf-8"
)
try
:
response
=
requests
.
get
(
url
=
SMS
.
URL
,
params
=
{
"phone"
:
data
[
Table
.
dest
],
"message"
:
text
})
success
[
file
]
=
True
if
response
.
text
==
"OK"
else
False
except
:
success
[
file
]
=
False
return
success
def
validatetype
(
self
,
type
):
return
type
in
SMS
.
Allowed
def
validateinfo
(
self
,
info
):
if
info
==
None
:
return
True
return
False
def
serviceFactory
(
serv
):
if
serv
==
Services
.
wpp1
:
return
Wpp1
()
if
serv
==
Services
.
mail
:
return
Mail
()
if
serv
==
Services
.
sms
:
return
SMS
()
return
None
vslifs.py
0 → 100644
View file @
e46c9ea
PaisDom
=
(
"ac"
,
"ad"
,
"ae"
,
"af"
,
"ag"
,
"ai"
,
"al"
,
"am"
,
"ao"
,
"aq"
,
"ar"
,
"as"
,
"at"
,
"au"
,
"aw"
,
"ax"
,
"az"
,
"ba"
,
"bb"
,
"bd"
,
"be"
,
"bf"
,
"bg"
,
"bh"
,
"bi"
,
"bj"
,
"bm"
,
"bn"
,
"bo"
,
"bq"
,
"br"
,
"bs"
,
"bt"
,
"bw"
,
"by"
,
"bz"
,
"ca"
,
"cc"
,
"cd"
,
"cf"
,
"cg"
,
"ch"
,
"ci"
,
"ck"
,
"cl"
,
"cm"
,
"cn"
,
"co"
,
"cr"
,
"cu"
,
"cv"
,
"cw"
,
"cx"
,
"cy"
,
"cz"
,
"de"
,
"dj"
,
"dk"
,
"dm"
,
"do"
,
"dz"
,
"ec"
,
"eg"
,
"eh"
,
"er"
,
"es"
,
"et"
,
"eu"
,
"fi"
,
"fj"
,
"fk"
,
"fm"
,
"fo"
,
"fr"
,
"ga"
,
"gd"
,
"ge"
,
"gf"
,
"gg"
,
"gh"
,
"gi"
,
"gl"
,
"gm"
,
"gn"
,
"gp"
,
"gq"
,
"gr"
,
"gs"
,
"gt"
,
"gu"
,
"gw"
,
"gy"
,
"hk"
,
"hm"
,
"hr"
,
"ht"
,
"hu"
,
"id"
,
"ie"
,
"il"
,
"im"
,
"in"
,
"io"
,
"iq"
,
"ir"
,
"is"
,
"it"
,
"je"
,
"jm"
,
"jo"
,
"jp"
,
"ke"
,
"kg"
,
"kh"
,
"ki"
,
"km"
,
"kn"
,
"kp"
,
"kr"
,
"kw"
,
"ky"
,
"kz"
,
"la"
,
"lb"
,
"lc"
,
"li"
,
"lk"
,
"lr"
,
"ls"
,
"lt"
,
"lu"
,
"lv"
,
"ly"
,
"ma"
,
"mc"
,
"md"
,
"me"
,
"mg"
,
"mh"
,
"mk"
,
"ml"
,
"mm"
,
"mn"
,
"mo"
,
"mp"
,
"mq"
,
"mr"
,
"ms"
,
"mt"
,
"mu"
,
"mv"
,
"mw"
,
"mx"
,
"my"
,
"mz"
,
"na"
,
"nc"
,
"ne"
,
"nf"
,
"ng"
,
"ni"
,
"nl"
,
"no"
,
"np"
,
"nr"
,
"nu"
,
"nz"
,
"om"
,
"pa"
,
"pe"
,
"pf"
,
"pg"
,
"ph"
,
"pk"
,
"pl"
,
"pm"
,
"pn"
,
"pr"
,
"ps"
,
"pt"
,
"pw"
,
"py"
,
"qa"
,
"re"
,
"ro"
,
"rs"
,
"ru"
,
"rw"
,
"sa"
,
"sb"
,
"sc"
,
"sd"
,
"se"
,
"sg"
,
"sh"
,
"si"
,
"sk"
,
"sl"
,
"sm"
,
"sn"
,
"so"
,
"sr"
,
"ss"
,
"st"
,
"su"
,
"sv"
,
"sx"
,
"sy"
,
"sz"
,
"tc"
,
"td"
,
"tf"
,
"tg"
,
"th"
,
"tj"
,
"tk"
,
"tl"
,
"tm"
,
"tn"
,
"to"
,
"tr"
,
"tt"
,
"tv"
,
"tw"
,
"tz"
,
"ua"
,
"ug"
,
"uk"
,
"us"
,
"uy"
,
"uz"
,
"va"
,
"vc"
,
"ve"
,
"vg"
,
"vi"
,
"vn"
,
"vu"
,
"wf"
,
"ws"
,
"ye"
,
"yt"
,
"za"
,
"zm"
,
"zw"
)
\ No newline at end of file
Write
Preview
Styling with
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment