Ağ bağlantısını kontrol etme


133

Çevrimiçi bir API'ya erişip erişemediğimi görmek istiyorum, ancak bunun için İnternet erişimim olması gerekiyor.

Python kullanarak kullanılabilir ve etkin bir bağlantı olup olmadığını nasıl görebilirim?


python kullanıyorsanız, bağlantı hatası veya zaman aşımı durumunda neredeyse kesinlikle bir istisna atar. Bunu deneyebilir / yakalayabilir veya sadece yüzeye bırakabilirsiniz.
jdizzle

1
@Triptych: Umarım bu bir şakaydı, çünkü çalışmıyor
inspectorG4dget

1
@ inspectorG4dget:easy_install system_of_tubes
S.Lott

2
@aF: Unutbu'nun çözümüne bakın. Google.com'a erişip erişemediğinizi (mümkün olan en hızlı şekilde) gösterir. Sorununuz API'ya erişmekle ilgiliyse, neden zaman aşımı = 1 ayarına erişmeye çalışmıyorsunuz? Bu, tam olarak erişmek istediğiniz API'nın erişilebilir olup olmadığını gösterir. Bunu öğrendikten sonra, devam edip API'ya erişebilir veya erişebildiğiniz bir süre bekleyebilirsiniz.
inspectorG4dget

Dediğim gibi unutbu'nun söylediği gibi basit bir şeye ihtiyacım vardı.
Bununla

Yanıtlar:


132

Belki böyle bir şey kullanabilirsiniz:

import urllib2

def internet_on():
    try:
        urllib2.urlopen('http://216.58.192.142', timeout=1)
        return True
    except urllib2.URLError as err: 
        return False

Şu anda, 216.58.192.142 google.com için IP adreslerinden biridir. Hızlı bir şekilde yanıt vermesi beklenen herhangi bir sitede değişiklik http://216.58.192.142yapın .

Bu sabit IP sonsuza kadar google.com ile eşleşmez. Bu nedenle bu kod sağlam değildir - çalışmasını sağlamak için sürekli bakıma ihtiyaç duyar.

Yukarıdaki kodun tam etki alanı adı (FQDN) yerine sabit bir IP adresi kullanmasının nedeni, FQDN'nin DNS araması gerektirmesidir. Makinenin çalışan bir internet bağlantısı yoksa, DNS aramasının kendisi urllib_request.urlopenbir saniyeden uzun bir süredir çağrıyı engelleyebilir . @ Rzetterberg'e bunu işaret ettiği için teşekkürler.


Yukarıdaki sabit IP adresi çalışmıyorsa, çalıştırarak google.com (unix'te) için geçerli bir IP adresi bulabilirsiniz

% dig google.com  +trace 
...
google.com.     300 IN  A   216.58.192.142

1
Sadece bir not " urlopeninternet" açık "olmasa bile için çağrı 1 saniyeden daha uzun sürmez. - alıntı. Sağlanan url geçersizse bu doğru değildir, o zaman DNS araması engellenir. Yalnızca web sunucusuna gerçek bağlantı için geçerlidir. Bu DNS arama bloğunu önlemenin en basit yolu IP adresini kullanmaktır, o zaman sadece 1 saniye sürmesi garanti edilir :)
rzetterberg

8
BU ARTIK YAYINDA DEĞİL. Eylül 2013 itibariyle, 74.125.113.99 uzun süre sonra zaman aşımına uğradı , bu nedenle bu işlev her zaman Yanlış değerini döndürecektir. Sanırım Google ağlarını değiştirdi.
theamk

4
Şimdi gerisi basit. "74.125.113.99 urllib" için Google. Yanlış kodu içeren binlerce açık kaynaklı proje döndürecektir. (benim için, sadece ilk sayfa en az 5 içerir: nvpy, sweekychebot, malteseDict, upy, checkConnection). Şimdi hepsi kırıldı.
theamk

4
Açık değilse, bu yöntemi kullanarak TAVSİYE ETMEM. Eski IP 3 yıldan az bir süre için iyi oldu. Yeni IP bugün çalışıyor. Projenize koyun ve gizemli bir şekilde 3 yıldan daha kısa bir süre içinde kırılabilir.
theamk

1
Ee ... sadece aç http://google.comve sonra herkesin burada konuşmaya devam ettiği tüm sorunları çözersin. IP adresi kullanmaya gerek yok ...
Jason C

106

Bazı İnternet sunucularına bağlanabiliyorsak, aslında bağlantımız var. Bununla birlikte, en hızlı ve en güvenilir yaklaşım için, tüm çözümler en azından aşağıdaki gereksinimlere uymalıdır:

  • DNS çözümlemesinden kaçının (iyi bilinen ve çoğu zaman kullanılabilir olduğu garanti edilen bir IP'ye ihtiyacımız olacaktır)
  • Uygulama katmanı bağlantılarından kaçının (bir HTTP / FTP / IMAP servisine bağlanma)
  • Python'dan veya başka bir dilden harici yardımcı programlara çağrı yapmaktan kaçının (üçüncü taraf çözümlerine dayanmayan bir dilde agnostik çözüm bulmamız gerekir)

Bunlara uymak için bir yaklaşım, Google'ın genel DNS sunucularından birinin erişilebilir olup olmadığını kontrol etmek olabilir . Bu sunucular için IPv4 adresleri 8.8.8.8ve8.8.4.4 . Bunlardan herhangi birine bağlanmayı deneyebiliriz.

Ev sahibinin hızlı bir Nmap 8.8.8.8aşağıdaki sonucu verdi:

$ sudo nmap 8.8.8.8

Starting Nmap 6.40 ( http://nmap.org ) at 2015-10-14 10:17 IST
Nmap scan report for google-public-dns-a.google.com (8.8.8.8)
Host is up (0.0048s latency).
Not shown: 999 filtered ports
PORT   STATE SERVICE
53/tcp open  domain

Nmap done: 1 IP address (1 host up) scanned in 23.81 seconds

Gördüğümüz gibi 53/tcp, açık ve filtrelenmemiş. Olmayan bir kök kullanıcı iseniz, kullanmayı unutmayın sudoveya-Pn Nmap için hazırlanmış prob paketleri göndermek ve bir ana bilgisayarın hazır olup olmadığını belirlemek argümanı .

Python ile denemeden önce, harici bir araç olan Netcat kullanarak bağlantıyı test edelim:

$ nc 8.8.8.8 53 -zv
Connection to 8.8.8.8 53 port [tcp/domain] succeeded!

Netcat onaylar biz ulaşabilmesi 8.8.8.8üzerinde 53/tcp. Şimdi bağlantıyı 8.8.8.8:53/tcpkontrol etmek için Python'da bir soket bağlantısı kurabiliriz :

import socket

def internet(host="8.8.8.8", port=53, timeout=3):
    """
    Host: 8.8.8.8 (google-public-dns-a.google.com)
    OpenPort: 53/tcp
    Service: domain (DNS/TCP)
    """
    try:
        socket.setdefaulttimeout(timeout)
        socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((host, port))
        return True
    except socket.error as ex:
        print(ex)
        return False

internet()

Başka bir yaklaşım, bu sunuculardan birine manuel olarak hazırlanmış bir DNS probu göndermek ve bir yanıt beklemek olabilir. Ancak, paket düşüşleri, DNS çözümleme hatası vb.Nedenlerle karşılaştırıldığında daha yavaş olabileceğini düşünüyorum. Aksi düşünürseniz lütfen yorum yapın.

GÜNCELLEME 1: @ theamk'nin yorumu sayesinde, zaman aşımı artık bir argüman ve 3svarsayılan olarak başlatıldı .

GÜNCELLEME # 2: Bu soruya verilen tüm geçerli cevapların en hızlı ve en genel uygulamasını belirlemek için hızlı testler yaptım. İşte özet:

$ ls *.py | sort -n | xargs -I % sh -c 'echo %; ./timeit.sh %; echo'
defos.py
True
00:00:00:00.487

iamaziz.py
True
00:00:00:00.335

ivelin.py
True
00:00:00:00.105

jaredb.py
True
00:00:00:00.533

kevinc.py
True
00:00:00:00.295

unutbu.py
True
00:00:00:00.546

7h3rAm.py
True
00:00:00:00.032

Ve bir kez daha:

$ ls *.py | sort -n | xargs -I % sh -c 'echo %; ./timeit.sh %; echo'
defos.py
True
00:00:00:00.450

iamaziz.py
True
00:00:00:00.358

ivelin.py
True
00:00:00:00.099

jaredb.py
True
00:00:00:00.585

kevinc.py
True
00:00:00:00.492

unutbu.py
True
00:00:00:00.485

7h3rAm.py
True
00:00:00:00.035

TrueYukarıdaki çıktıda, ilgili yazarlardan gelen tüm bu uygulamaların İnternet bağlantısını doğru şekilde tanımladığı belirtilmektedir. Zaman milisaniye çözünürlükte gösterilir.

GÜNCELLEME # 3: İstisna işleme değişikliğinden sonra tekrar test edildi:

defos.py
True
00:00:00:00.410

iamaziz.py
True
00:00:00:00.240

ivelin.py
True
00:00:00:00.109

jaredb.py
True
00:00:00:00.520

kevinc.py
True
00:00:00:00.317

unutbu.py
True
00:00:00:00.436

7h3rAm.py
True
00:00:00:00.030

6
Bu, DNS çözümlemesinden kaçınmanın ve ironik bir şekilde Google'ın 53 numaralı bağlantı noktasındaki DNS hizmetine danışmanın en iyi yanıtıdır.
m3nda

1
@AviMehenwal Google, bu IP'yi ücretsiz DNS ad çözümleme hizmetinin bir parçası olarak sunmaktadır. Google'ın aksi karar vermediği sürece IP'nin değişmemesi gerekiyor. Birkaç yıldır herhangi bir sorun olmadan alternatif bir DNS sunucusu olarak kullanıyorum.
7h3rAm

1
@ Bunu işaret ettiğin için teşekkürler. Kullanıcıları istisna hakkında bilgilendirmek ve False'ı varsayılan yanıt olarak döndürmek için yanıtı güncelledim.
7h3rAm

2
@JasonC TCP / 53'e bağlanmak, bağlantı noktası 53 üzerinden DNS bağlantısından farklıdır. Analojinize göre, bir uygulama tarafından kullanılan her TCP bağlantı noktası, uygulama düzeyi protokol bağlantısı olarak sınıflandırılır. Hayır, bu doğru değil. Bir TCP soketi üzerinden bir bağlantı noktasına bağlanmak uygulama düzeyinde bağlantı DEĞİLDİR. DNS araması yapmıyorum, sadece yarım TCP el sıkışma. Tam bir DNS araması yapmakla aynı şey değildir.
07h3rAm

2
close()Soketi aramamalı mıyız ?
brk

60

Sadece bir HEAD isteği yapmak daha hızlı olur, böylece HTML getirilmez.
Ayrıca eminim google bu şekilde daha iyi istiyorum :)

try:
    import httplib
except:
    import http.client as httplib

def have_internet():
    conn = httplib.HTTPConnection("www.google.com", timeout=5)
    try:
        conn.request("HEAD", "/")
        conn.close()
        return True
    except:
        conn.close()
        return False

8
Üst yanıt 1 saniye sürerken sadece 20 mili saniye sürer.
Wally

8
+1 Yalnızca sunucunun erişilebilir ve yanıt verip vermediğini kontrol etmek istiyorsanız sayfanın tamamını indirmek mantıklı değildir. İçeriğe ihtiyacınız varsa içeriği indirin
17'de

Hiçbir nedenle, '8.8' url'sini kullanmak hala işe yarıyor, ki bu açıkça '8.8' veya ' 8.8 ' gerçek bir web tarayıcısında çalışmıyor.
Polv

2 saat çalışan bir çözüm arıyor ve sonra bunu buldum ... temiz ve basit
Pedro Serpa

21

Ubutnu / Kevin C cevaplarına alternatif olarak, requestspaketi şu şekilde kullanıyorum:

import requests

def connected_to_internet(url='http://www.google.com/', timeout=5):
    try:
        _ = requests.get(url, timeout=timeout)
        return True
    except requests.ConnectionError:
        print("No internet connection available.")
    return False

Bonus: Bu, bir web sitesine ping yapan bu işleve genişletilebilir.

def web_site_online(url='http://www.google.com/', timeout=5):
    try:
        req = requests.get(url, timeout=timeout)
        # HTTP errors are not raised by default, this statement does that
        req.raise_for_status()
        return True
    except requests.HTTPError as e:
        print("Checking internet connection failed, status code {0}.".format(
        e.response.status_code))
    except requests.ConnectionError:
        print("No internet connection available.")
    return False

1
İstek harika bir kütüphanedir. Ancak buradaki birçok örnekten farklı olarak, IANA'nın example.com veya example.org'u ICANN tarafından tamamen kontrol edildiği için daha güvenilir uzun vadeli bir seçim olarak kullanacağım .
chirale

İnternet çalışma durumunu kontrol etmenin başka bir yolu var mı? Çünkü google.comtekrar pining yaparsanız , IP adresimizi bloke ederler. Başka yolu var mı?
Sanjiv

15

Sadece unutbu'nun Python 3.2'deki yeni kod için söylediklerini güncellemek için

def check_connectivity(reference):
    try:
        urllib.request.urlopen(reference, timeout=1)
        return True
    except urllib.request.URLError:
        return False

Ve sadece not etmek gerekirse, buradaki giriş (referans) kontrol etmek istediğiniz url'dir: Yaşadığınız yerde hızlı bağlanan bir şey seçmenizi öneririm - yani Güney Kore'de yaşıyorum, bu yüzden muhtemelen http: / /www.naver.com .


Kullanılabilir bir DNS sunucusu yoksa 30 saniye bekleyeceğim.
Viktor Joras

10

Sadece veri indirmeyi deneyebilirsiniz ve bağlantı başarısız olursa, bağlantıya sahip olan şeylerin iyi olmadığını bilirsiniz.

Temel olarak bilgisayarın internete bağlı olup olmadığını kontrol edemezsiniz. Hatalı DNS yapılandırması, güvenlik duvarları, NAT gibi birçok hata nedeni olabilir. Bu nedenle, bazı testler yapsanız bile, denemeden API'nızla bağlantı kuracağınızı garanti edemezsiniz.


2
"
Affetmek

bunun o kadar iyi olması gerekmez. Ben sadece bir siteye bağlanmak veya bir şey ping denemek gerekir ve zaman aşımı voilá verirse. Bunu nasıl yapabilirim?
aF.

API'ya bağlanmayı denememenizin herhangi bir nedeni var mı? Gerçek bağlantıdan önce neden kontrol etmelisiniz?
Tomasz Wysocki

Python kullanarak bir html sayfası yapıyorum. Html sayfası python programında verdiğim argümanlara bağlı. Ben sadece API erişebilir eğer bazı html kodu koymak gerekir. Bu yüzden daha önce bilmem gerek.
aF.

6
import urllib

def connected(host='http://google.com'):
    try:
        urllib.urlopen(host)
        return True
    except:
        return False

# test
print( 'connected' if connected() else 'no internet!' )

Python 3 için şunu kullanın: urllib.request.urlopen(host)


4

Yine de yapmaya çalıştığınız işlemi deneyin. Başarısız olursa, python size bildirmek için bir istisna atmalıdır.

Bir bağlantı tespit etmek için önce bazı önemsiz işlemleri denemek için bir yarış durumu getirecektir. Test ettiğinizde internet bağlantısı geçerliyse, ancak gerçek bir iş yapmanız gerekmeden önce kapanırsa ne olur?


3

Localhost olarak değiştirildi, bu işe yaramayabilir 127.0.0.1 Try

import socket
ipaddress=socket.gethostbyname(socket.gethostname())
if ipaddress=="127.0.0.1":
    print("You are not connected to the internet!")
else:
    print("You are connected to the internet with the IP address of "+ ipaddress )

Düzenlenmedikçe, internete bağlı olmadığınızda bilgisayarlarınızın IP'si 127.0.0.1 olacaktır. Bu kod temel olarak IP adresini alır ve ardından yerel ana bilgisayar IP adresi olup olmadığını sorar. umarım yardımcı olur


Bu ilginç bir kontrol, ancak yalnızca bir ağa bağlı olup olmadığınızı belirleyecektir. İnternet mi yoksa NAT'd mi bir alt ağ mı, hala bir soru olarak kalacaktır.
7h3rAm

@ 7h3rAm, bu iyi bir nokta, DCHP internet bağlantısı gerektirmiyor, benim hatam.

Bu sadece bir IP atanmış bir ağ NIC bağlantısı gerektirir. Diğer tüm cevapların aksine, LAN, yönlendirici, güvenlik duvarı, ISP'ye başka bir sisteme kadar bağlantı gerektirmez. DHCP tarafından atanmamış bir adresse (statik) NIC'nin bağlı olduğunu
gösterememektedir

@ user150471, daha önce belirtti, katkınız için teşekkür ederiz.

3

İşte benim versiyonum

import requests

try:
    if requests.get('https://google.com').ok:
        print("You're Online")
except:
    print("You're Offline")

1
Bunu beğendim, ancak isteklerden ortaya çıkan belirli bir Zaman Aşımı veya Bağlantı Hatası dışında daha iyi olurdu. Olduğu gibi, yıldırım hızında bir Ctrl-C çevrimdışı yazdırır.
user2561747

2

Aşağıdakileri içeren modern bir taşınabilir çözüm requests:

import requests

def internet():
    """Detect an internet connection."""

    connection = None
    try:
        r = requests.get("https://google.com")
        r.raise_for_status()
        print("Internet connection detected.")
        connection = True
    except:
        print("Internet connection not detected.")
        connection = False
    finally:
        return connection

Veya istisna oluşturan bir sürüm:

import requests
from requests.exceptions import ConnectionError

def internet():
    """Detect an internet connection."""

    try:
        r = requests.get("https://google.com")
        r.raise_for_status()
        print("Internet connection detected.")
    except ConnectionError as e:
        print("Internet connection not detected.")
        raise e

1

Bunu yapmanın en iyi yolu, web sitesini bulamazsa python'un her zaman verdiği bir IP adresine karşı kontrol etmektir. Bu durumda bu benim kodum:

import socket

print("website connection checker")
while True:
    website = input("please input website: ")
    print("")
    print(socket.gethostbyname(website))
    if socket.gethostbyname(website) == "92.242.140.2":
        print("Website could be experiencing an issue/Doesn't exist")
    else:
        socket.gethostbyname(website)
        print("Website is operational!")
        print("")

1

en sevdiğim, bir kümede komut dosyası çalıştırıp çalıştırmadığınızda

import subprocess

def online(timeout):
    try:
        return subprocess.run(
            ['wget', '-q', '--spider', 'google.com'],
            timeout=timeout
        ).returncode == 0
    except subprocess.TimeoutExpired:
        return False

Bu, hiçbir şeyi indirmeden değil, verilen uzak dosyanın web'de var olup olmadığını kontrol ederek sessizce çalışır


0

Alarak unutbu cevabını bir başlangıç noktası olarak, ve, basit bir sınıf yaptık değişen bir "statik" IP adresine göre geçmişte yakılmış olan bu çekler "yani URL'yi kullanarak (DNS aramasını kullanarak kez https: // www .google.com ") ve ardından yanıt veren sunucunun IP adresini sonraki denetimlerde kullanmak üzere saklar. Bu şekilde, IP adresi her zaman günceldir (sınıfın en az birkaç yılda bir yeniden başlatıldığı varsayılarak). Ayrıca , sunucunun IP adresini (yeniden yönlendirme vb. Sonra) nasıl alacağımı gösteren bu cevap için gawry'ye kredi veriyorum . Lütfen bu çözümün görünür hileliğini göz ardı edin, burada minimal bir çalışma örneği alacağım. :)

İşte ne var:

import socket

try:
    from urllib2 import urlopen, URLError
    from urlparse import urlparse
except ImportError:  # Python 3
    from urllib.parse import urlparse
    from urllib.request import urlopen, URLError

class InternetChecker(object):
    conn_url = 'https://www.google.com/'

    def __init__(self):
        pass

    def test_internet(self):
        try:
            data = urlopen(self.conn_url, timeout=5)
        except URLError:
            return False

        try:
            host = data.fp._sock.fp._sock.getpeername()
        except AttributeError:  # Python 3
            host = data.fp.raw._sock.getpeername()

        # Ensure conn_url is an IPv4 address otherwise future queries will fail
        self.conn_url = 'http://' + (host[0] if len(host) == 2 else
                                     socket.gethostbyname(urlparse(data.geturl()).hostname))

        return True

# Usage example
checker = InternetChecker()
checker.test_internet()

0

Six'in cevabını almak, yeni teknikler konusunda yeni gelenlerin kaybolması nedeniyle önemli bir konuyu basitleştirebileceğimizi düşünüyorum.

Burada nihayet PV izleme için günde bir kez bağlantımın (3G, yavaş) kurulmasını beklerken kullanacağım.

Raspbian 3.4.2 ile Pyth3 altında çalışır

from urllib.request import urlopen
from time import sleep
urltotest=http://www.lsdx.eu             # my own web page
nboftrials=0
answer='NO'
while answer=='NO' and nboftrials<10:
    try:
        urlopen(urltotest)
        answer='YES'
    except:
        essai='NO'
        nboftrials+=1
        sleep(30)       

maksimum koşu: 5 dakika ulaştı eğer bir saat içinde deneyeceğim ama onun komut dosyası biraz daha!


senin essai var alışmıyor, değil mi?
kidCoder

0

Alarak Ivelin yanıtını ve benim yönlendirici onun ip adresi 192.168.0.1 sunar ve hiçbir internet bağlantısı sorgulama google.com varsa kafa döndürür gibi bazı ekstra kontrol ekleyin.

import socket

def haveInternet():
    try:
        # first check if we get the correct IP-Address or just the router's IP-Address
        info = socket.getaddrinfo("www.google.com", None)[0]
        ipAddr = info[4][0]
        if ipAddr == "192.168.0.1" :
            return False
    except:
        return False

    conn = httplib.HTTPConnection("www.google.com", timeout=5)
    try:
        conn.request("HEAD", "/")
        conn.close()
        return True
    except:
        conn.close()
        return False

0

Bu benim için Python'da çalışıyor3.6

import urllib
from urllib.request import urlopen


def is_internet():
    """
    Query internet using python
    :return:
    """
    try:
        urlopen('https://www.google.com', timeout=1)
        return True
    except urllib.error.URLError as Error:
        print(Error)
        return False


if is_internet():
    print("Internet is active")
else:
    print("Internet disconnected")

0

Joel'in koduna birkaç tane ekledim.

    import socket,time
    mem1 = 0
    while True:
        try:
                host = socket.gethostbyname("www.google.com") #Change to personal choice of site
                s = socket.create_connection((host, 80), 2)
                s.close()
                mem2 = 1
                if (mem2 == mem1):
                    pass #Add commands to be executed on every check
                else:
                    mem1 = mem2
                    print ("Internet is working") #Will be executed on state change

        except Exception as e:
                mem2 = 0
                if (mem2 == mem1):
                    pass
                else:
                    mem1 = mem2
                    print ("Internet is down")
        time.sleep(10) #timeInterval for checking

0

Projelerim için google genel DNS sunucusuna 8.8.8.8 ping atmak için değiştirilmiş komut dosyası kullanıyorum . Harici bağımlılığı olmayan 1 saniyelik zaman aşımı ve çekirdek python kitaplıkları kullanma:

import struct
import socket
import select


def send_one_ping(to='8.8.8.8'):
   ping_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname('icmp'))
   checksum = 49410
   header = struct.pack('!BBHHH', 8, 0, checksum, 0x123, 1)
   data = b'BCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwx'
   header = struct.pack(
      '!BBHHH', 8, 0, checksum, 0x123, 1
   )
   packet = header + data
   ping_socket.sendto(packet, (to, 1))
   inputready, _, _ = select.select([ping_socket], [], [], 1.0)
   if inputready == []:
      raise Exception('No internet') ## or return False
   _, address = ping_socket.recvfrom(2048)
   print(address) ## or return True


send_one_ping()

Select zaman aşımı değeri 1'dir, ancak bu örnekte 1 saniyeden daha kolay başarısız seçim de ondalık sayı olabilir.


0

istekleri içe aktarın ve bu basit python kodunu deneyin.

def check_internet():
url = 'http://www.google.com/'
timeout = 5
try:
    _ = requests.get(url, timeout=timeout)
    return True
except requests.ConnectionError:
return False
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.