diff --git a/channels/animeunity.py b/channels/animeunity.py index 5a8b277f..8c446791 100644 --- a/channels/animeunity.py +++ b/channels/animeunity.py @@ -7,12 +7,9 @@ import requests, json, copy, inspect from core import support from platformcode import autorenumber -try: from lib import cloudscraper -except: from lib import cloudscraper - host = support.config.get_channel_url() -response = cloudscraper.create_scraper().get(host + '/archivio') -csrf_token = support.match(response.text, patron= 'name="csrf-token" content="([^"]+)"').match +response = support.httptools.downloadpage(host + '/archivio') +csrf_token = support.match(response.data, patron='name="csrf-token" content="([^"]+)"').match headers = {'content-type': 'application/json;charset=UTF-8', 'x-csrf-token': csrf_token, 'Cookie' : '; '.join([x.name + '=' + x.value for x in response.cookies])} diff --git a/core/filetools.py b/core/filetools.py index d99662bc..c3ffdcf6 100644 --- a/core/filetools.py +++ b/core/filetools.py @@ -37,7 +37,6 @@ if not xbmc_vfs: except: samba = None # Python 2.4 Not compatible with samba module, you have to check - # Windows is "mbcs" linux, osx, android is "utf8" if os.name == "nt": fs_encoding = "" diff --git a/core/jsontools.py b/core/jsontools.py index 6bfe960f..a17b8f91 100644 --- a/core/jsontools.py +++ b/core/jsontools.py @@ -8,27 +8,7 @@ import traceback from platformcode import logger from inspect import stack -try: - import json -except: - logger.error("json included in the interpreter **NOT** available") - - try: - import simplejson as json - except: - logger.error("simplejson included in the interpreter **NOT** available") - try: - from lib import simplejson as json - except: - logger.error("simplejson in lib directory **NOT** available") - logger.error("A valid JSON parser was not found") - json = None - else: - logger.info("Using simplejson in the lib directory") - else: - logger.error("Using simplejson included in the interpreter") -# ~ else: - # ~ logger.info("Usando json incluido en el interprete") +import json import sys PY3 = False diff --git a/lib/MultipartPostHandler.py b/lib/MultipartPostHandler.py deleted file mode 100644 index af0abaf4..00000000 --- a/lib/MultipartPostHandler.py +++ /dev/null @@ -1,127 +0,0 @@ -#-*- coding: utf-8 -*- -# -#### -# 2006/02 Will Holcomb -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# 2007/07/26 Slightly modified by Brian Schneider -# -# in order to support unicode files ( multipart_encode function ) -# From http://peerit.blogspot.com/2007/07/multipartposthandler-doesnt-work-for.html -# -# 2013/07 Ken Olum -# -# Removed one of \r\n and send Content-Length -# -# 2014/05 Applied Fedora rpm patch -# -# https://bugzilla.redhat.com/show_bug.cgi?id=920778 -# http://pkgs.fedoraproject.org/cgit/python-MultipartPostHandler2.git/diff/python-MultipartPostHandler2-cut-out-main.patch?id=c1638bb3e45596232b4d02f1e69901db0c28cfdb -# -# 2014/05/09 Sérgio Basto -# -# Better deal with None values, don't throw an exception and just send an empty string. -# Simplified text example -# -""" -Usage: - Enables the use of multipart/form-data for posting forms - -Inspirations: - Upload files in python: - http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306 - urllib2_file: - Fabien Seisen: - -Example: - import MultipartPostHandler, urllib2 - - opener = urllib2.build_opener(MultipartPostHandler.MultipartPostHandler) - params = { "username" : "bob", "password" : "riviera", - "file" : open("filename", "rb") } - opener.open("http://wwww.bobsite.com/upload/", params) -""" - -import urllib -import urllib2 -import mimetools, mimetypes -import os, stat -from cStringIO import StringIO - -class Callable: - def __init__(self, anycallable): - self.__call__ = anycallable - -# Controls how sequences are uncoded. If true, elements may be given multiple values by -# assigning a sequence. -doseq = 1 - -class MultipartPostHandler(urllib2.BaseHandler): - handler_order = urllib2.HTTPHandler.handler_order - 10 # needs to run first - - def http_request(self, request): - data = request.get_data() - if data is not None and type(data) != str: - v_files = [] - v_vars = [] - try: - for(key, value) in data.items(): - if type(value) == file: - v_files.append((key, value)) - else: - v_vars.append((key, value)) - except TypeError: - systype, value, traceback = sys.exc_info() - raise TypeError, "not a valid non-string sequence or mapping object", traceback - - if len(v_files) == 0: - data = urllib.urlencode(v_vars, doseq) - else: - boundary, data = self.multipart_encode(v_vars, v_files) - contenttype = 'multipart/form-data; boundary=%s' % boundary - # ~ if(request.has_header('Content-Type') - # ~ and request.get_header('Content-Type').find('multipart/form-data') != 0): - # ~ print "Replacing %s with %s" % (request.get_header('content-type'), 'multipart/form-data') - request.add_unredirected_header('Content-Type', contenttype) - - request.add_data(data) - return request - - def multipart_encode(vars, files, boundary = None, buffer = None): - if boundary is None: - boundary = mimetools.choose_boundary() - if buffer is None: - buffer = StringIO() - for(key, value) in vars: - buffer.write('--%s\r\n' % boundary) - buffer.write('Content-Disposition: form-data; name="%s"' % key) - if value is None: - value = "" - # if type(value) is not str, we need str(value) to not error with cannot concatenate 'str' - # and 'dict' or 'tuple' or somethingelse objects - buffer.write('\r\n\r\n' + str(value) + '\r\n') - for(key, fd) in files: - file_size = os.fstat(fd.fileno())[stat.ST_SIZE] - filename = fd.name.split('/')[-1] - contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream' - buffer.write('--%s\r\n' % boundary) - buffer.write('Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key, filename)) - buffer.write('Content-Type: %s\r\n' % contenttype) - buffer.write('Content-Length: %s\r\n' % file_size) - fd.seek(0) - buffer.write('\r\n' + fd.read() + '\r\n') - buffer.write('--' + boundary + '--\r\n') - buffer = buffer.getvalue() - return boundary, buffer - multipart_encode = Callable(multipart_encode) - - https_request = http_request diff --git a/lib/cloudscraper/__init__.py b/lib/cloudscraper/__init__.py deleted file mode 100644 index ce20c8cb..00000000 --- a/lib/cloudscraper/__init__.py +++ /dev/null @@ -1,836 +0,0 @@ -# ------------------------------------------------------------------------------- # - -import logging -import re -import requests -import sys -import ssl - -from collections import OrderedDict -from copy import deepcopy - -from requests.adapters import HTTPAdapter -from requests.sessions import Session -from requests_toolbelt.utils import dump - -from time import sleep - -# ------------------------------------------------------------------------------- # - -try: - import brotli -except ImportError: - pass - -try: - import copyreg -except ImportError: - import copy_reg as copyreg - -try: - from HTMLParser import HTMLParser -except ImportError: - if sys.version_info >= (3, 4): - import html - else: - from html.parser import HTMLParser - -try: - from urlparse import urlparse, urljoin -except ImportError: - from urllib.parse import urlparse, urljoin - -# ------------------------------------------------------------------------------- # - -from .exceptions import ( - CloudflareLoopProtection, - CloudflareCode1020, - CloudflareIUAMError, - CloudflareSolveError, - CloudflareChallengeError, - CloudflareCaptchaError, - CloudflareCaptchaProvider -) - -from .interpreters import JavaScriptInterpreter -from .captcha import Captcha -from .user_agent import User_Agent - -# ------------------------------------------------------------------------------- # - -__version__ = '1.2.46' - -# ------------------------------------------------------------------------------- # - - -class CipherSuiteAdapter(HTTPAdapter): - - __attrs__ = [ - 'ssl_context', - 'max_retries', - 'config', - '_pool_connections', - '_pool_maxsize', - '_pool_block', - 'source_address' - ] - - def __init__(self, *args, **kwargs): - self.ssl_context = kwargs.pop('ssl_context', None) - self.cipherSuite = kwargs.pop('cipherSuite', None) - self.source_address = kwargs.pop('source_address', None) - - if self.source_address: - if isinstance(self.source_address, str): - self.source_address = (self.source_address, 0) - - if not isinstance(self.source_address, tuple): - raise TypeError( - "source_address must be IP address string or (ip, port) tuple" - ) - - if not self.ssl_context: - self.ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) - self.ssl_context.set_ciphers(self.cipherSuite) - self.ssl_context.set_ecdh_curve('prime256v1') - self.ssl_context.options |= (ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1) - - super(CipherSuiteAdapter, self).__init__(**kwargs) - - # ------------------------------------------------------------------------------- # - - def init_poolmanager(self, *args, **kwargs): - kwargs['ssl_context'] = self.ssl_context - kwargs['source_address'] = self.source_address - return super(CipherSuiteAdapter, self).init_poolmanager(*args, **kwargs) - - # ------------------------------------------------------------------------------- # - - def proxy_manager_for(self, *args, **kwargs): - kwargs['ssl_context'] = self.ssl_context - kwargs['source_address'] = self.source_address - return super(CipherSuiteAdapter, self).proxy_manager_for(*args, **kwargs) - -# ------------------------------------------------------------------------------- # - - -class CloudScraper(Session): - - def __init__(self, *args, **kwargs): - self.debug = kwargs.pop('debug', False) - self.delay = kwargs.pop('delay', None) - self.cipherSuite = kwargs.pop('cipherSuite', None) - self.ssl_context = kwargs.pop('ssl_context', None) - self.interpreter = kwargs.pop('interpreter', 'native') - self.captcha = kwargs.pop('captcha', {}) - self.requestPreHook = kwargs.pop('requestPreHook', None) - self.requestPostHook = kwargs.pop('requestPostHook', None) - self.source_address = kwargs.pop('source_address', None) - self.doubleDown = kwargs.pop('doubleDown', True) - - self.allow_brotli = kwargs.pop( - 'allow_brotli', - True if 'brotli' in sys.modules.keys() else False - ) - - self.user_agent = User_Agent( - allow_brotli=self.allow_brotli, - browser=kwargs.pop('browser', None) - ) - - self._solveDepthCnt = 0 - self.solveDepth = kwargs.pop('solveDepth', 3) - - super(CloudScraper, self).__init__(*args, **kwargs) - - # pylint: disable=E0203 - if 'requests' in self.headers['User-Agent']: - # ------------------------------------------------------------------------------- # - # Set a random User-Agent if no custom User-Agent has been set - # ------------------------------------------------------------------------------- # - self.headers = self.user_agent.headers - if not self.cipherSuite: - self.cipherSuite = self.user_agent.cipherSuite - - if isinstance(self.cipherSuite, list): - self.cipherSuite = ':'.join(self.cipherSuite) - - self.mount( - 'https://', - CipherSuiteAdapter( - cipherSuite=self.cipherSuite, - ssl_context=self.ssl_context, - source_address=self.source_address - ) - ) - - # purely to allow us to pickle dump - copyreg.pickle(ssl.SSLContext, lambda obj: (obj.__class__, (obj.protocol,))) - - # ------------------------------------------------------------------------------- # - # Allow us to pickle our session back with all variables - # ------------------------------------------------------------------------------- # - - def __getstate__(self): - return self.__dict__ - - # ------------------------------------------------------------------------------- # - # Allow replacing actual web request call via subclassing - # ------------------------------------------------------------------------------- # - - def perform_request(self, method, url, *args, **kwargs): - return super(CloudScraper, self).request(method, url, *args, **kwargs) - - # ------------------------------------------------------------------------------- # - # Raise an Exception with no stacktrace and reset depth counter. - # ------------------------------------------------------------------------------- # - - def simpleException(self, exception, msg): - self._solveDepthCnt = 0 - sys.tracebacklimit = 0 - raise exception(msg) - - # ------------------------------------------------------------------------------- # - # debug the request via the response - # ------------------------------------------------------------------------------- # - - @staticmethod - def debugRequest(req): - try: - print(dump.dump_all(req).decode('utf-8')) - except ValueError as e: - print("Debug Error: {}".format(getattr(e, 'message', e))) - - # ------------------------------------------------------------------------------- # - # Unescape / decode html entities - # ------------------------------------------------------------------------------- # - - @staticmethod - def unescape(html_text): - if sys.version_info >= (3, 0): - if sys.version_info >= (3, 4): - return html.unescape(html_text) - - return HTMLParser().unescape(html_text) - - return HTMLParser().unescape(html_text) - - # ------------------------------------------------------------------------------- # - # Decode Brotli on older versions of urllib3 manually - # ------------------------------------------------------------------------------- # - - def decodeBrotli(self, resp): - if requests.packages.urllib3.__version__ < '1.25.1' and resp.headers.get('Content-Encoding') == 'br': - if self.allow_brotli and resp._content: - resp._content = brotli.decompress(resp.content) - else: - logging.warning( - 'You\'re running urllib3 {}, Brotli content detected, ' - 'Which requires manual decompression, ' - 'But option allow_brotli is set to False, ' - 'We will not continue to decompress.'.format(requests.packages.urllib3.__version__) - ) - - return resp - - # ------------------------------------------------------------------------------- # - # Our hijacker request function - # ------------------------------------------------------------------------------- # - - def request(self, method, url, *args, **kwargs): - # pylint: disable=E0203 - if kwargs.get('proxies') and kwargs.get('proxies') != self.proxies: - self.proxies = kwargs.get('proxies') - - # ------------------------------------------------------------------------------- # - # Pre-Hook the request via user defined function. - # ------------------------------------------------------------------------------- # - - if self.requestPreHook: - (method, url, args, kwargs) = self.requestPreHook( - self, - method, - url, - *args, - **kwargs - ) - - # ------------------------------------------------------------------------------- # - # Make the request via requests. - # ------------------------------------------------------------------------------- # - - response = self.decodeBrotli( - self.perform_request(method, url, *args, **kwargs) - ) - - # ------------------------------------------------------------------------------- # - # Debug the request via the Response object. - # ------------------------------------------------------------------------------- # - - if self.debug: - self.debugRequest(response) - - # ------------------------------------------------------------------------------- # - # Post-Hook the request aka Post-Hook the response via user defined function. - # ------------------------------------------------------------------------------- # - - if self.requestPostHook: - response = self.requestPostHook(self, response) - - if self.debug: - self.debugRequest(response) - - # Check if Cloudflare anti-bot is on - if self.is_Challenge_Request(response): - # ------------------------------------------------------------------------------- # - # Try to solve the challenge and send it back - # ------------------------------------------------------------------------------- # - - if self._solveDepthCnt >= self.solveDepth: - _ = self._solveDepthCnt - self.simpleException( - CloudflareLoopProtection, - "!!Loop Protection!! We have tried to solve {} time(s) in a row.".format(_) - ) - - self._solveDepthCnt += 1 - - response = self.Challenge_Response(response, **kwargs) - else: - if not response.is_redirect and response.status_code not in [429, 503]: - self._solveDepthCnt = 0 - - return response - - # ------------------------------------------------------------------------------- # - # check if the response contains a valid Cloudflare challenge - # ------------------------------------------------------------------------------- # - - @staticmethod - def is_IUAM_Challenge(resp): - try: - return ( - resp.headers.get('Server', '').startswith('cloudflare') - and resp.status_code in [429, 503] - and re.search( - r'
1020', - resp.text, - re.M | re.DOTALL - ) - ) - except AttributeError: - pass - - return False - - # ------------------------------------------------------------------------------- # - # Wrapper for is_Captcha_Challenge, is_IUAM_Challenge, is_Firewall_Blocked - # ------------------------------------------------------------------------------- # - - def is_Challenge_Request(self, resp): - if self.is_Firewall_Blocked(resp): - self.simpleException( - CloudflareCode1020, - 'Cloudflare has blocked this request (Code 1020 Detected).' - ) - - if self.is_New_Captcha_Challenge(resp): - self.simpleException( - CloudflareChallengeError, - 'Detected a Cloudflare version 2 challenge, This feature is not available in the opensource (free) version.' - ) - - if self.is_New_IUAM_Challenge(resp): - self.simpleException( - CloudflareChallengeError, - 'Detected a Cloudflare version 2 Captcha challenge, This feature is not available in the opensource (free) version.' - ) - - if self.is_Captcha_Challenge(resp) or self.is_IUAM_Challenge(resp): - if self.debug: - print('Detected a Cloudflare version 1 challenge.') - return True - - return False - - # ------------------------------------------------------------------------------- # - # Try to solve cloudflare javascript challenge. - # ------------------------------------------------------------------------------- # - - def IUAM_Challenge_Response(self, body, url, interpreter): - try: - formPayload = re.search( - r'.*?="challenge-form" ' - r'action="(?P.*?' - r'__cf_chl_jschl_tk__=\S+)"(.*?))', - body, - re.M | re.DOTALL - ).groupdict() - - if not all(key in formPayload for key in ['form', 'challengeUUID']): - self.simpleException( - CloudflareIUAMError, - "Cloudflare IUAM detected, unfortunately we can't extract the parameters correctly." - ) - - payload = OrderedDict() - for challengeParam in re.findall(r'^\s*', formPayload['form'], re.M | re.S): - inputPayload = dict(re.findall(r'(\S+)="(\S+)"', challengeParam)) - if inputPayload.get('name') in ['r', 'jschl_vc', 'pass']: - payload.update({inputPayload['name']: inputPayload['value']}) - - except AttributeError: - self.simpleException( - CloudflareIUAMError, - "Cloudflare IUAM detected, unfortunately we can't extract the parameters correctly." - ) - - hostParsed = urlparse(url) - - try: - payload['jschl_answer'] = JavaScriptInterpreter.dynamicImport( - interpreter - ).solveChallenge(body, hostParsed.netloc) - except Exception as e: - self.simpleException( - CloudflareIUAMError, - 'Unable to parse Cloudflare anti-bots page: {}'.format( - getattr(e, 'message', e) - ) - ) - - return { - 'url': '{}://{}{}'.format( - hostParsed.scheme, - hostParsed.netloc, - self.unescape(formPayload['challengeUUID']) - ), - 'data': payload - } - - # ------------------------------------------------------------------------------- # - # Try to solve the Captcha challenge via 3rd party. - # ------------------------------------------------------------------------------- # - - def captcha_Challenge_Response(self, provider, provider_params, body, url): - try: - formPayload = re.search( - r'
.*?="challenge-form" ' - r'action="(?P.*?__cf_chl_captcha_tk__=\S+)"(.*?))', - body, - re.M | re.DOTALL - ).groupdict() - - if not all(key in formPayload for key in ['form', 'challengeUUID']): - self.simpleException( - CloudflareCaptchaError, - "Cloudflare Captcha detected, unfortunately we can't extract the parameters correctly." - ) - - payload = OrderedDict( - re.findall( - r'(name="r"\svalue|data-ray|data-sitekey|name="cf_captcha_kind"\svalue)="(.*?)"', - formPayload['form'] - ) - ) - - captchaType = 'reCaptcha' if payload['name="cf_captcha_kind" value'] == 're' else 'hCaptcha' - - except (AttributeError, KeyError): - self.simpleException( - CloudflareCaptchaError, - "Cloudflare Captcha detected, unfortunately we can't extract the parameters correctly." - ) - - # ------------------------------------------------------------------------------- # - # Pass proxy parameter to provider to solve captcha. - # ------------------------------------------------------------------------------- # - - if self.proxies and self.proxies != self.captcha.get('proxy'): - self.captcha['proxy'] = self.proxies - - # ------------------------------------------------------------------------------- # - # Pass User-Agent if provider supports it to solve captcha. - # ------------------------------------------------------------------------------- # - - self.captcha['User-Agent'] = self.headers['User-Agent'] - - # ------------------------------------------------------------------------------- # - # Submit job to provider to request captcha solve. - # ------------------------------------------------------------------------------- # - - captchaResponse = Captcha.dynamicImport( - provider.lower() - ).solveCaptcha( - captchaType, - url, - payload['data-sitekey'], - provider_params - ) - - # ------------------------------------------------------------------------------- # - # Parse and handle the response of solved captcha. - # ------------------------------------------------------------------------------- # - - dataPayload = OrderedDict([ - ('r', payload.get('name="r" value', '')), - ('cf_captcha_kind', payload['name="cf_captcha_kind" value']), - ('id', payload.get('data-ray')), - ('g-recaptcha-response', captchaResponse) - ]) - - if captchaType == 'hCaptcha': - dataPayload.update({'h-captcha-response': captchaResponse}) - - hostParsed = urlparse(url) - - return { - 'url': '{}://{}{}'.format( - hostParsed.scheme, - hostParsed.netloc, - self.unescape(formPayload['challengeUUID']) - ), - 'data': dataPayload - } - - # ------------------------------------------------------------------------------- # - # Attempt to handle and send the challenge response back to cloudflare - # ------------------------------------------------------------------------------- # - - def Challenge_Response(self, resp, **kwargs): - if self.is_Captcha_Challenge(resp): - # ------------------------------------------------------------------------------- # - # double down on the request as some websites are only checking - # if cfuid is populated before issuing Captcha. - # ------------------------------------------------------------------------------- # - - if self.doubleDown: - resp = self.decodeBrotli( - self.perform_request(resp.request.method, resp.url, **kwargs) - ) - - if not self.is_Captcha_Challenge(resp): - return resp - - # ------------------------------------------------------------------------------- # - # if no captcha provider raise a runtime error. - # ------------------------------------------------------------------------------- # - - if not self.captcha or not isinstance(self.captcha, dict) or not self.captcha.get('provider'): - self.simpleException( - CloudflareCaptchaProvider, - "Cloudflare Captcha detected, unfortunately you haven't loaded an anti Captcha provider " - "correctly via the 'captcha' parameter." - ) - - # ------------------------------------------------------------------------------- # - # if provider is return_response, return the response without doing anything. - # ------------------------------------------------------------------------------- # - - if self.captcha.get('provider') == 'return_response': - return resp - - # ------------------------------------------------------------------------------- # - # Submit request to parser wrapper to solve captcha - # ------------------------------------------------------------------------------- # - - submit_url = self.captcha_Challenge_Response( - self.captcha.get('provider'), - self.captcha, - resp.text, - resp.url - ) - else: - # ------------------------------------------------------------------------------- # - # Cloudflare requires a delay before solving the challenge - # ------------------------------------------------------------------------------- # - - if not self.delay: - try: - delay = float( - re.search( - r'submit\(\);\r?\n\s*},\s*([0-9]+)', - resp.text - ).group(1) - ) / float(1000) - if isinstance(delay, (int, float)): - self.delay = delay - except (AttributeError, ValueError): - self.simpleException( - CloudflareIUAMError, - "Cloudflare IUAM possibility malformed, issue extracing delay value." - ) - - sleep(self.delay) - - # ------------------------------------------------------------------------------- # - - submit_url = self.IUAM_Challenge_Response( - resp.text, - resp.url, - self.interpreter - ) - - # ------------------------------------------------------------------------------- # - # Send the Challenge Response back to Cloudflare - # ------------------------------------------------------------------------------- # - - if submit_url: - - def updateAttr(obj, name, newValue): - try: - obj[name].update(newValue) - return obj[name] - except (AttributeError, KeyError): - obj[name] = {} - obj[name].update(newValue) - return obj[name] - - cloudflare_kwargs = deepcopy(kwargs) - cloudflare_kwargs['allow_redirects'] = False - cloudflare_kwargs['data'] = updateAttr( - cloudflare_kwargs, - 'data', - submit_url['data'] - ) - - urlParsed = urlparse(resp.url) - cloudflare_kwargs['headers'] = updateAttr( - cloudflare_kwargs, - 'headers', - { - 'Origin': '{}://{}'.format(urlParsed.scheme, urlParsed.netloc), - 'Referer': resp.url - } - ) - - challengeSubmitResponse = self.request( - 'POST', - submit_url['url'], - **cloudflare_kwargs - ) - - if challengeSubmitResponse.status_code == 400: - self.simpleException( - CloudflareSolveError, - 'Invalid challenge answer detected, Cloudflare broken?' - ) - - # ------------------------------------------------------------------------------- # - # Return response if Cloudflare is doing content pass through instead of 3xx - # else request with redirect URL also handle protocol scheme change http -> https - # ------------------------------------------------------------------------------- # - - if not challengeSubmitResponse.is_redirect: - return challengeSubmitResponse - - else: - cloudflare_kwargs = deepcopy(kwargs) - cloudflare_kwargs['headers'] = updateAttr( - cloudflare_kwargs, - 'headers', - {'Referer': challengeSubmitResponse.url} - ) - - if not urlparse(challengeSubmitResponse.headers['Location']).netloc: - redirect_location = urljoin( - challengeSubmitResponse.url, - challengeSubmitResponse.headers['Location'] - ) - else: - redirect_location = challengeSubmitResponse.headers['Location'] - - return self.request( - resp.request.method, - redirect_location, - **cloudflare_kwargs - ) - - # ------------------------------------------------------------------------------- # - # We shouldn't be here... - # Re-request the original query and/or process again.... - # ------------------------------------------------------------------------------- # - - return self.request(resp.request.method, resp.url, **kwargs) - - # ------------------------------------------------------------------------------- # - - @classmethod - def create_scraper(cls, sess=None, **kwargs): - """ - Convenience function for creating a ready-to-go CloudScraper object. - """ - scraper = cls(**kwargs) - - if sess: - for attr in ['auth', 'cert', 'cookies', 'headers', 'hooks', 'params', 'proxies', 'data']: - val = getattr(sess, attr, None) - if val: - setattr(scraper, attr, val) - - return scraper - - # ------------------------------------------------------------------------------- # - # Functions for integrating cloudscraper with other applications and scripts - # ------------------------------------------------------------------------------- # - - @classmethod - def get_tokens(cls, url, **kwargs): - scraper = cls.create_scraper( - **{ - field: kwargs.pop(field, None) for field in [ - 'allow_brotli', - 'browser', - 'debug', - 'delay', - 'interpreter', - 'captcha', - 'requestPreHook', - 'requestPostHook', - 'source_address' - ] if field in kwargs - } - ) - - try: - resp = scraper.get(url, **kwargs) - resp.raise_for_status() - except Exception: - logging.error('"{}" returned an error. Could not collect tokens.'.format(url)) - raise - - domain = urlparse(resp.url).netloc - # noinspection PyUnusedLocal - cookie_domain = None - - for d in scraper.cookies.list_domains(): - if d.startswith('.') and d in ('.{}'.format(domain)): - cookie_domain = d - break - else: - cls.simpleException( - CloudflareIUAMError, - "Unable to find Cloudflare cookies. Does the site actually " - "have Cloudflare IUAM (I'm Under Attack Mode) enabled?" - ) - - return ( - { - '__cfduid': scraper.cookies.get('__cfduid', '', domain=cookie_domain), - 'cf_clearance': scraper.cookies.get('cf_clearance', '', domain=cookie_domain) - }, - scraper.headers['User-Agent'] - ) - - # ------------------------------------------------------------------------------- # - - @classmethod - def get_cookie_string(cls, url, **kwargs): - """ - Convenience function for building a Cookie HTTP header value. - """ - tokens, user_agent = cls.get_tokens(url, **kwargs) - return '; '.join('='.join(pair) for pair in tokens.items()), user_agent - - -# ------------------------------------------------------------------------------- # - -if ssl.OPENSSL_VERSION_INFO < (1, 1, 1): - print( - "DEPRECATION: The OpenSSL being used by this python install ({}) does not meet the minimum supported " - "version (>= OpenSSL 1.1.1) in order to support TLS 1.3 required by Cloudflare, " - "You may encounter an unexpected Captcha or cloudflare 1020 blocks.".format( - ssl.OPENSSL_VERSION - ) - ) - -# ------------------------------------------------------------------------------- # - -create_scraper = CloudScraper.create_scraper -get_tokens = CloudScraper.get_tokens -get_cookie_string = CloudScraper.get_cookie_string diff --git a/lib/cloudscraper/captcha/2captcha.py b/lib/cloudscraper/captcha/2captcha.py deleted file mode 100644 index 0c300edb..00000000 --- a/lib/cloudscraper/captcha/2captcha.py +++ /dev/null @@ -1,271 +0,0 @@ -from __future__ import absolute_import - -import requests -try: - from urlparse import urlparse -except ImportError: - from urllib.parse import urlparse - -from ..exceptions import ( - CaptchaServiceUnavailable, - CaptchaAPIError, - CaptchaTimeout, - CaptchaParameter, - CaptchaBadJobID, - CaptchaReportError -) - -try: - import polling -except ImportError: - raise ImportError( - "Please install the python module 'polling' via pip or download it from " - "https://github.com/justiniso/polling/" - ) - -from . import Captcha - - -class captchaSolver(Captcha): - - def __init__(self): - super(captchaSolver, self).__init__('2captcha') - self.host = 'https://2captcha.com' - self.session = requests.Session() - - # ------------------------------------------------------------------------------- # - - @staticmethod - def checkErrorStatus(response, request_type): - if response.status_code in [500, 502]: - raise CaptchaServiceUnavailable('2Captcha: Server Side Error {}'.format(response.status_code)) - - errors = { - 'in.php': { - "ERROR_WRONG_USER_KEY": "You've provided api_key parameter value is in incorrect format, it should contain 32 symbols.", - "ERROR_KEY_DOES_NOT_EXIST": "The api_key you've provided does not exists.", - "ERROR_ZERO_BALANCE": "You don't have sufficient funds on your account.", - "ERROR_PAGEURL": "pageurl parameter is missing in your request.", - "ERROR_NO_SLOT_AVAILABLE": - "No Slots Available.\nYou can receive this error in two cases:\n" - "1. If you solve ReCaptcha: the queue of your captchas that are not distributed to workers is too long. " - "Queue limit changes dynamically and depends on total amount of captchas awaiting solution and usually it's between 50 and 100 captchas.\n" - "2. If you solve Normal Captcha: your maximum rate for normal captchas is lower than current rate on the server." - "You can change your maximum rate in your account's settings.", - "ERROR_IP_NOT_ALLOWED": "The request is sent from the IP that is not on the list of your allowed IPs.", - "IP_BANNED": "Your IP address is banned due to many frequent attempts to access the server using wrong authorization keys.", - "ERROR_BAD_TOKEN_OR_PAGEURL": - "You can get this error code when sending ReCaptcha V2. " - "That happens if your request contains invalid pair of googlekey and pageurl. " - "The common reason for that is that ReCaptcha is loaded inside an iframe hosted on another domain/subdomain.", - "ERROR_GOOGLEKEY": - "You can get this error code when sending ReCaptcha V2. " - "That means that sitekey value provided in your request is incorrect: it's blank or malformed.", - "MAX_USER_TURN": "You made more than 60 requests within 3 seconds.Your account is banned for 10 seconds. Ban will be lifted automatically." - }, - 'res.php': { - "ERROR_CAPTCHA_UNSOLVABLE": - "We are unable to solve your captcha - three of our workers were unable solve it " - "or we didn't get an answer within 90 seconds (300 seconds for ReCaptcha V2). " - "We will not charge you for that request.", - "ERROR_WRONG_USER_KEY": "You've provided api_key parameter value in incorrect format, it should contain 32 symbols.", - "ERROR_KEY_DOES_NOT_EXIST": "The api_key you've provided does not exists.", - "ERROR_WRONG_ID_FORMAT": "You've provided captcha ID in wrong format. The ID can contain numbers only.", - "ERROR_WRONG_CAPTCHA_ID": "You've provided incorrect captcha ID.", - "ERROR_BAD_DUPLICATES": - "Error is returned when 100% accuracy feature is enabled. " - "The error means that max numbers of tries is reached but min number of matches not found.", - "REPORT_NOT_RECORDED": "Error is returned to your complain request if you already complained lots of correctly solved captchas.", - "ERROR_IP_ADDRES": - "You can receive this error code when registering a pingback (callback) IP or domain." - "That happes if your request is coming from an IP address that doesn't match the IP address of your pingback IP or domain.", - "ERROR_TOKEN_EXPIRED": "You can receive this error code when sending GeeTest. That error means that challenge value you provided is expired.", - "ERROR_EMPTY_ACTION": "Action parameter is missing or no value is provided for action parameter." - } - } - - if response.json().get('status') == 0 and response.json().get('request') in errors.get(request_type): - raise CaptchaAPIError( - '{} {}'.format( - response.json().get('request'), - errors.get(request_type).get(response.json().get('request')) - ) - ) - - # ------------------------------------------------------------------------------- # - - def reportJob(self, jobID): - if not jobID: - raise CaptchaBadJobID( - "2Captcha: Error bad job id to request Captcha." - ) - - def _checkRequest(response): - if response.ok and response.json().get('status') == 1: - return response - - self.checkErrorStatus(response, 'res.php') - - return None - - response = polling.poll( - lambda: self.session.get( - '{}/res.php'.format(self.host), - params={ - 'key': self.api_key, - 'action': 'reportbad', - 'id': jobID, - 'json': '1' - }, - timeout=30 - ), - check_success=_checkRequest, - step=5, - timeout=180 - ) - - if response: - return True - else: - raise CaptchaReportError( - "2Captcha: Error - Failed to report bad Captcha solve." - ) - - # ------------------------------------------------------------------------------- # - - def requestJob(self, jobID): - if not jobID: - raise CaptchaBadJobID("2Captcha: Error bad job id to request Captcha.") - - def _checkRequest(response): - if response.ok and response.json().get('status') == 1: - return response - - self.checkErrorStatus(response, 'res.php') - - return None - - response = polling.poll( - lambda: self.session.get( - '{}/res.php'.format(self.host), - params={ - 'key': self.api_key, - 'action': 'get', - 'id': jobID, - 'json': '1' - }, - timeout=30 - ), - check_success=_checkRequest, - step=5, - timeout=180 - ) - - if response: - return response.json().get('request') - else: - raise CaptchaTimeout( - "2Captcha: Error failed to solve Captcha." - ) - - # ------------------------------------------------------------------------------- # - - def requestSolve(self, captchaType, url, siteKey): - def _checkRequest(response): - if response.ok and response.json().get("status") == 1 and response.json().get('request'): - return response - - self.checkErrorStatus(response, 'in.php') - - return None - - data = { - 'key': self.api_key, - 'pageurl': url, - 'json': 1, - 'soft_id': 5507698 - } - - data.update( - { - 'method': 'userrcaptcha', - 'googlekey': siteKey - } if captchaType == 'reCaptcha' else { - 'method': 'hcaptcha', - 'sitekey': siteKey - } - ) - - if self.proxy: - data.update( - { - 'proxy': self.proxy, - 'proxytype': self.proxyType - } - ) - - response = polling.poll( - lambda: self.session.post( - '{}/in.php'.format(self.host), - data=data, - allow_redirects=False, - timeout=30 - ), - check_success=_checkRequest, - step=5, - timeout=180 - ) - - if response: - return response.json().get('request') - else: - raise CaptchaBadJobID( - '2Captcha: Error no job id was returned.' - ) - - # ------------------------------------------------------------------------------- # - - def getCaptchaAnswer(self, captchaType, url, siteKey, captchaParams): - jobID = None - - if not captchaParams.get('api_key'): - raise CaptchaParameter( - "2Captcha: Missing api_key parameter." - ) - - self.api_key = captchaParams.get('api_key') - - if captchaParams.get('proxy') and not captchaParams.get('no_proxy'): - hostParsed = urlparse(captchaParams.get('proxy', {}).get('https')) - - if not hostParsed.scheme: - raise CaptchaParameter('Cannot parse proxy correctly, bad scheme') - - if not hostParsed.netloc: - raise CaptchaParameter('Cannot parse proxy correctly, bad netloc') - - self.proxyType = hostParsed.scheme - self.proxy = hostParsed.netloc - else: - self.proxy = None - - try: - jobID = self.requestSolve(captchaType, url, siteKey) - return self.requestJob(jobID) - except polling.TimeoutException: - try: - if jobID: - self.reportJob(jobID) - except polling.TimeoutException: - raise CaptchaTimeout( - "2Captcha: Captcha solve took to long and also failed reporting the job the job id {}.".format(jobID) - ) - - raise CaptchaTimeout( - "2Captcha: Captcha solve took to long to execute job id {}, aborting.".format(jobID) - ) - - -# ------------------------------------------------------------------------------- # - -captchaSolver() diff --git a/lib/cloudscraper/captcha/9kw.py b/lib/cloudscraper/captcha/9kw.py deleted file mode 100644 index e1a7e6a0..00000000 --- a/lib/cloudscraper/captcha/9kw.py +++ /dev/null @@ -1,212 +0,0 @@ -from __future__ import absolute_import - -import re -import requests - -try: - import polling -except ImportError: - raise ImportError( - "Please install the python module 'polling' via pip or download it from " - "https://github.com/justiniso/polling/" - ) - -from ..exceptions import ( - reCaptchaServiceUnavailable, - reCaptchaAPIError, - reCaptchaTimeout, - reCaptchaParameter, - reCaptchaBadJobID -) - -from . import reCaptcha - - -class captchaSolver(reCaptcha): - - def __init__(self): - super(captchaSolver, self).__init__('9kw') - self.host = 'https://www.9kw.eu/index.cgi' - self.maxtimeout = 180 - self.session = requests.Session() - - # ------------------------------------------------------------------------------- # - - @staticmethod - def checkErrorStatus(response): - if response.status_code in [500, 502]: - raise reCaptchaServiceUnavailable( - '9kw: Server Side Error {}'.format(response.status_code) - ) - - error_codes = { - 1: 'No API Key available.', - 2: 'No API key found.', - 3: 'No active API key found.', - 4: 'API Key has been disabled by the operator. ', - 5: 'No user found.', - 6: 'No data found.', - 7: 'Found No ID.', - 8: 'found No captcha.', - 9: 'No image found.', - 10: 'Image size not allowed.', - 11: 'credit is not sufficient.', - 12: 'what was done.', - 13: 'No answer contain.', - 14: 'Captcha already been answered.', - 15: 'Captcha to quickly filed.', - 16: 'JD check active.', - 17: 'Unknown problem.', - 18: 'Found No ID.', - 19: 'Incorrect answer.', - 20: 'Do not timely filed (Incorrect UserID).', - 21: 'Link not allowed.', - 22: 'Prohibited submit.', - 23: 'Entering prohibited.', - 24: 'Too little credit.', - 25: 'No entry found.', - 26: 'No Conditions accepted.', - 27: 'No coupon code found in the database.', - 28: 'Already unused voucher code.', - 29: 'maxTimeout under 60 seconds.', - 30: 'User not found.', - 31: 'An account is not yet 24 hours in system.', - 32: 'An account does not have the full rights.', - 33: 'Plugin needed a update.', - 34: 'No HTTPS allowed.', - 35: 'No HTTP allowed.', - 36: 'Source not allowed.', - 37: 'Transfer denied.', - 38: 'Incorrect answer without space', - 39: 'Incorrect answer with space', - 40: 'Incorrect answer with not only numbers', - 41: 'Incorrect answer with not only A-Z, a-z', - 42: 'Incorrect answer with not only 0-9, A-Z, a-z', - 43: 'Incorrect answer with not only [0-9,- ]', - 44: 'Incorrect answer with not only [0-9A-Za-z,- ]', - 45: 'Incorrect answer with not only coordinates', - 46: 'Incorrect answer with not only multiple coordinates', - 47: 'Incorrect answer with not only data', - 48: 'Incorrect answer with not only rotate number', - 49: 'Incorrect answer with not only text', - 50: 'Incorrect answer with not only text and too short', - 51: 'Incorrect answer with not enough chars', - 52: 'Incorrect answer with too many chars', - 53: 'Incorrect answer without no or yes', - 54: 'Assignment was not found.' - } - - if response.text.startswith('{'): - if response.json().get('error'): - raise reCaptchaAPIError(error_codes.get(int(response.json().get('error')))) - else: - error_code = int(re.search(r'^00(?P\d+)', response.text).groupdict().get('error_code', 0)) - if error_code: - raise reCaptchaAPIError(error_codes.get(error_code)) - - # ------------------------------------------------------------------------------- # - - def requestJob(self, jobID): - if not jobID: - raise reCaptchaBadJobID( - "9kw: Error bad job id to request reCaptcha against." - ) - - def _checkRequest(response): - if response.ok and response.json().get('answer') != 'NO DATA': - return response - - self.checkErrorStatus(response) - - return None - - response = polling.poll( - lambda: self.session.get( - self.host, - params={ - 'apikey': self.api_key, - 'action': 'usercaptchacorrectdata', - 'id': jobID, - 'info': 1, - 'json': 1 - } - ), - check_success=_checkRequest, - step=10, - timeout=(self.maxtimeout + 10) - ) - - if response: - return response.json().get('answer') - else: - raise reCaptchaTimeout("9kw: Error failed to solve reCaptcha.") - - # ------------------------------------------------------------------------------- # - - def requestSolve(self, captchaType, url, siteKey): - def _checkRequest(response): - if response.ok and response.text.startswith('{') and response.json().get('captchaid'): - return response - - self.checkErrorStatus(response) - - return None - - captchaMap = { - 'reCaptcha': 'recaptchav2', - 'hCaptcha': 'hcaptcha' - } - - response = polling.poll( - lambda: self.session.post( - self.host, - data={ - 'apikey': self.api_key, - 'action': 'usercaptchaupload', - 'interactive': 1, - 'file-upload-01': siteKey, - 'oldsource': captchaMap[captchaType], - 'pageurl': url, - 'maxtimeout': self.maxtimeout, - 'json': 1 - }, - allow_redirects=False - ), - check_success=_checkRequest, - step=5, - timeout=(self.maxtimeout + 10) - ) - - if response: - return response.json().get('captchaid') - else: - raise reCaptchaBadJobID('9kw: Error no valid job id was returned.') - - # ------------------------------------------------------------------------------- # - - def getCaptchaAnswer(self, captchaType, url, siteKey, reCaptchaParams): - jobID = None - - if not reCaptchaParams.get('api_key'): - raise reCaptchaParameter("9kw: Missing api_key parameter.") - - self.api_key = reCaptchaParams.get('api_key') - - if reCaptchaParams.get('maxtimeout'): - self.maxtimeout = reCaptchaParams.get('maxtimeout') - - if reCaptchaParams.get('proxy'): - self.session.proxies = reCaptchaParams.get('proxies') - - try: - jobID = self.requestSolve(captchaType, url, siteKey) - return self.requestJob(jobID) - except polling.TimeoutException: - raise reCaptchaTimeout( - "9kw: reCaptcha solve took to long to execute 'captchaid' {}, aborting.".format(jobID) - ) - -# ------------------------------------------------------------------------------- # - - -captchaSolver() diff --git a/lib/cloudscraper/captcha/__init__.py b/lib/cloudscraper/captcha/__init__.py deleted file mode 100644 index 0e4f8f00..00000000 --- a/lib/cloudscraper/captcha/__init__.py +++ /dev/null @@ -1,46 +0,0 @@ -import abc -import logging -import sys - -if sys.version_info >= (3, 4): - ABC = abc.ABC # noqa -else: - ABC = abc.ABCMeta('ABC', (), {}) - -# ------------------------------------------------------------------------------- # - -captchaSolvers = {} - -# ------------------------------------------------------------------------------- # - - -class Captcha(ABC): - @abc.abstractmethod - def __init__(self, name): - captchaSolvers[name] = self - - # ------------------------------------------------------------------------------- # - - @classmethod - def dynamicImport(cls, name): - if name not in captchaSolvers: - try: - __import__('{}.{}'.format(cls.__module__, name)) - if not isinstance(captchaSolvers.get(name), Captcha): - raise ImportError('The anti captcha provider was not initialized.') - except ImportError: - logging.error("Unable to load {} anti captcha provider".format(name)) - raise - - return captchaSolvers[name] - - # ------------------------------------------------------------------------------- # - - @abc.abstractmethod - def getCaptchaAnswer(self, captchaType, url, siteKey, captchaParams): - pass - - # ------------------------------------------------------------------------------- # - - def solveCaptcha(self, captchaType, url, siteKey, captchaParams): - return self.getCaptchaAnswer(captchaType, url, siteKey, captchaParams) diff --git a/lib/cloudscraper/captcha/anticaptcha.py b/lib/cloudscraper/captcha/anticaptcha.py deleted file mode 100644 index ec453b9c..00000000 --- a/lib/cloudscraper/captcha/anticaptcha.py +++ /dev/null @@ -1,109 +0,0 @@ -from __future__ import absolute_import -from ..exceptions import ( - CaptchaParameter, - CaptchaTimeout, - CaptchaAPIError -) - -try: - from urlparse import urlparse -except ImportError: - from urllib.parse import urlparse - -try: - from python_anticaptcha import ( - AnticaptchaClient, - NoCaptchaTaskProxylessTask, - HCaptchaTaskProxyless, - NoCaptchaTask, - HCaptchaTask, - AnticaptchaException - ) -except ImportError: - raise ImportError( - "Please install/upgrade the python module 'python_anticaptcha' via " - "pip install python-anticaptcha or https://github.com/ad-m/python-anticaptcha/" - ) - -import sys - -from . import Captcha - - -class captchaSolver(Captcha): - - def __init__(self): - if sys.modules['python_anticaptcha'].__version__ < '0.6': - raise ImportError( - "Please upgrade the python module 'python_anticaptcha' via " - "pip install -U python-anticaptcha or https://github.com/ad-m/python-anticaptcha/" - ) - super(captchaSolver, self).__init__('anticaptcha') - - # ------------------------------------------------------------------------------- # - - def parseProxy(self, url, user_agent): - parsed = urlparse(url) - - return dict( - proxy_type=parsed.scheme, - proxy_address=parsed.hostname, - proxy_port=parsed.port, - proxy_login=parsed.username, - proxy_password=parsed.password, - user_agent=user_agent - ) - - # ------------------------------------------------------------------------------- # - - def getCaptchaAnswer(self, captchaType, url, siteKey, captchaParams): - if not captchaParams.get('api_key'): - raise CaptchaParameter("anticaptcha: Missing api_key parameter.") - - client = AnticaptchaClient(captchaParams.get('api_key')) - - if captchaParams.get('proxy') and not captchaParams.get('no_proxy'): - captchaMap = { - 'reCaptcha': NoCaptchaTask, - 'hCaptcha': HCaptchaTask - } - - proxy = self.parseProxy( - captchaParams.get('proxy', {}).get('https'), - captchaParams.get('User-Agent', '') - ) - - task = captchaMap[captchaType]( - url, - siteKey, - **proxy - ) - else: - captchaMap = { - 'reCaptcha': NoCaptchaTaskProxylessTask, - 'hCaptcha': HCaptchaTaskProxyless - } - task = captchaMap[captchaType](url, siteKey) - - if not hasattr(client, 'createTaskSmee'): - raise NotImplementedError( - "Please upgrade 'python_anticaptcha' via pip or download it from " - "https://github.com/ad-m/python-anticaptcha/tree/hcaptcha" - ) - - job = client.createTaskSmee(task, timeout=180) - - try: - job.join(maximum_time=180) - except (AnticaptchaException) as e: - raise CaptchaTimeout('{}'.format(getattr(e, 'message', e))) - - if 'solution' in job._last_result: - return job.get_solution_response() - else: - raise CaptchaAPIError('Job did not return `solution` key in payload.') - - -# ------------------------------------------------------------------------------- # - -captchaSolver() diff --git a/lib/cloudscraper/captcha/deathbycaptcha.py b/lib/cloudscraper/captcha/deathbycaptcha.py deleted file mode 100644 index 6079c1d4..00000000 --- a/lib/cloudscraper/captcha/deathbycaptcha.py +++ /dev/null @@ -1,233 +0,0 @@ -from __future__ import absolute_import - -import json -import requests - -try: - import polling -except ImportError: - raise ImportError( - "Please install the python module 'polling' via pip or download it from " - "https://github.com/justiniso/polling/" - ) - -from ..exceptions import ( - reCaptchaException, - reCaptchaServiceUnavailable, - reCaptchaAccountError, - reCaptchaTimeout, - reCaptchaParameter, - reCaptchaBadJobID, - reCaptchaReportError -) - -from . import reCaptcha - - -class captchaSolver(reCaptcha): - - def __init__(self): - super(captchaSolver, self).__init__('deathbycaptcha') - self.host = 'http://api.dbcapi.me/api' - self.session = requests.Session() - - # ------------------------------------------------------------------------------- # - - @staticmethod - def checkErrorStatus(response): - errors = dict( - [ - (400, "DeathByCaptcha: 400 Bad Request"), - (403, "DeathByCaptcha: 403 Forbidden - Invalid credentails or insufficient credits."), - # (500, "DeathByCaptcha: 500 Internal Server Error."), - (503, "DeathByCaptcha: 503 Service Temporarily Unavailable.") - ] - ) - - if response.status_code in errors: - raise reCaptchaServiceUnavailable(errors.get(response.status_code)) - - # ------------------------------------------------------------------------------- # - - def login(self, username, password): - self.username = username - self.password = password - - def _checkRequest(response): - if response.ok: - if response.json().get('is_banned'): - raise reCaptchaAccountError('DeathByCaptcha: Your account is banned.') - - if response.json().get('balanace') == 0: - raise reCaptchaAccountError('DeathByCaptcha: insufficient credits.') - - return response - - self.checkErrorStatus(response) - - return None - - response = polling.poll( - lambda: self.session.post( - '{}/user'.format(self.host), - headers={'Accept': 'application/json'}, - data={ - 'username': self.username, - 'password': self.password - } - ), - check_success=_checkRequest, - step=10, - timeout=120 - ) - - self.debugRequest(response) - - # ------------------------------------------------------------------------------- # - - def reportJob(self, jobID): - if not jobID: - raise reCaptchaBadJobID( - "DeathByCaptcha: Error bad job id to report failed reCaptcha." - ) - - def _checkRequest(response): - if response.status_code == 200: - return response - - self.checkErrorStatus(response) - - return None - - response = polling.poll( - lambda: self.session.post( - '{}/captcha/{}/report'.format(self.host, jobID), - headers={'Accept': 'application/json'}, - data={ - 'username': self.username, - 'password': self.password - } - ), - check_success=_checkRequest, - step=10, - timeout=180 - ) - - if response: - return True - else: - raise reCaptchaReportError( - "DeathByCaptcha: Error report failed reCaptcha." - ) - - # ------------------------------------------------------------------------------- # - - def requestJob(self, jobID): - if not jobID: - raise reCaptchaBadJobID( - "DeathByCaptcha: Error bad job id to request reCaptcha." - ) - - def _checkRequest(response): - if response.ok and response.json().get('text'): - return response - - self.checkErrorStatus(response) - - return None - - response = polling.poll( - lambda: self.session.get( - '{}/captcha/{}'.format(self.host, jobID), - headers={'Accept': 'application/json'} - ), - check_success=_checkRequest, - step=10, - timeout=180 - ) - - if response: - return response.json().get('text') - else: - raise reCaptchaTimeout( - "DeathByCaptcha: Error failed to solve reCaptcha." - ) - - # ------------------------------------------------------------------------------- # - - def requestSolve(self, url, siteKey): - def _checkRequest(response): - if response.ok and response.json().get("is_correct") and response.json().get('captcha'): - return response - - self.checkErrorStatus(response) - - return None - - response = polling.poll( - lambda: self.session.post( - '{}/captcha'.format(self.host), - headers={'Accept': 'application/json'}, - data={ - 'username': self.username, - 'password': self.password, - 'type': '4', - 'token_params': json.dumps({ - 'googlekey': siteKey, - 'pageurl': url - }) - }, - allow_redirects=False - ), - check_success=_checkRequest, - step=10, - timeout=180 - ) - - if response: - return response.json().get('captcha') - else: - raise reCaptchaBadJobID( - 'DeathByCaptcha: Error no job id was returned.' - ) - - # ------------------------------------------------------------------------------- # - - def getCaptchaAnswer(self, captchaType, url, siteKey, reCaptchaParams): - jobID = None - - for param in ['username', 'password']: - if not reCaptchaParams.get(param): - raise reCaptchaParameter( - "DeathByCaptcha: Missing '{}' parameter.".format(param) - ) - setattr(self, param, reCaptchaParams.get(param)) - - if captchaType == 'hCaptcha': - raise reCaptchaException( - 'Provider does not support hCaptcha.' - ) - - if reCaptchaParams.get('proxy'): - self.session.proxies = reCaptchaParams.get('proxies') - - try: - jobID = self.requestSolve(url, siteKey) - return self.requestJob(jobID) - except polling.TimeoutException: - try: - if jobID: - self.reportJob(jobID) - except polling.TimeoutException: - raise reCaptchaTimeout( - "DeathByCaptcha: reCaptcha solve took to long and also failed reporting the job id {}.".format(jobID) - ) - - raise reCaptchaTimeout( - "DeathByCaptcha: reCaptcha solve took to long to execute job id {}, aborting.".format(jobID) - ) - - -# ------------------------------------------------------------------------------- # - -captchaSolver() diff --git a/lib/cloudscraper/exceptions.py b/lib/cloudscraper/exceptions.py deleted file mode 100644 index 1ed0b236..00000000 --- a/lib/cloudscraper/exceptions.py +++ /dev/null @@ -1,111 +0,0 @@ -# -*- coding: utf-8 -*- - -# ------------------------------------------------------------------------------- # - -""" -cloudscraper.exceptions -~~~~~~~~~~~~~~~~~~~ -This module contains the set of cloudscraper exceptions. -""" - -# ------------------------------------------------------------------------------- # - - -class CloudflareException(Exception): - """ - Base exception class for cloudscraper for Cloudflare - """ - - -class CloudflareLoopProtection(CloudflareException): - """ - Raise an exception for recursive depth protection - """ - - -class CloudflareCode1020(CloudflareException): - """ - Raise an exception for Cloudflare code 1020 block - """ - - -class CloudflareIUAMError(CloudflareException): - """ - Raise an error for problem extracting IUAM paramters - from Cloudflare payload - """ - - -class CloudflareChallengeError(CloudflareException): - """ - Raise an error when detected new Cloudflare challenge - """ - - -class CloudflareSolveError(CloudflareException): - """ - Raise an error when issue with solving Cloudflare challenge - """ - - -class CloudflareCaptchaError(CloudflareException): - """ - Raise an error for problem extracting Captcha paramters - from Cloudflare payload - """ - - -class CloudflareCaptchaProvider(CloudflareException): - """ - Raise an exception for no Captcha provider loaded for Cloudflare. - """ - -# ------------------------------------------------------------------------------- # - - -class CaptchaException(Exception): - """ - Base exception class for cloudscraper captcha Providers - """ - - -class CaptchaServiceUnavailable(CaptchaException): - """ - Raise an exception for external services that cannot be reached - """ - - -class CaptchaAPIError(CaptchaException): - """ - Raise an error for error from API response. - """ - - -class CaptchaAccountError(CaptchaException): - """ - Raise an error for captcha provider account problem. - """ - - -class CaptchaTimeout(CaptchaException): - """ - Raise an exception for captcha provider taking too long. - """ - - -class CaptchaParameter(CaptchaException): - """ - Raise an exception for bad or missing Parameter. - """ - - -class CaptchaBadJobID(CaptchaException): - """ - Raise an exception for invalid job id. - """ - - -class CaptchaReportError(CaptchaException): - """ - Raise an error for captcha provider unable to report bad solve. - """ diff --git a/lib/cloudscraper/help.py b/lib/cloudscraper/help.py deleted file mode 100644 index 24d72e29..00000000 --- a/lib/cloudscraper/help.py +++ /dev/null @@ -1,79 +0,0 @@ -import json -import platform -import requests -import ssl -import sys -import urllib3 - -from collections import OrderedDict -from . import __version__ as cloudscraper_version - -# ------------------------------------------------------------------------------- # - - -def getPossibleCiphers(): - try: - context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) - context.set_ciphers('ALL') - return sorted([cipher['name'] for cipher in context.get_ciphers()]) - except AttributeError: - return 'get_ciphers() is unsupported' - -# ------------------------------------------------------------------------------- # - - -def _pythonVersion(): - interpreter = platform.python_implementation() - interpreter_version = platform.python_version() - - if interpreter == 'PyPy': - interpreter_version = '{}.{}.{}'.format( - sys.pypy_version_info.major, - sys.pypy_version_info.minor, - sys.pypy_version_info.micro - ) - if sys.pypy_version_info.releaselevel != 'final': - interpreter_version = '{}{}'.format( - interpreter_version, - sys.pypy_version_info.releaselevel - ) - - return { - 'name': interpreter, - 'version': interpreter_version - } - -# ------------------------------------------------------------------------------- # - - -def systemInfo(): - try: - platform_info = { - 'system': platform.system(), - 'release': platform.release(), - } - except IOError: - platform_info = { - 'system': 'Unknown', - 'release': 'Unknown', - } - - return OrderedDict([ - ('platform', platform_info), - ('interpreter', _pythonVersion()), - ('cloudscraper', cloudscraper_version), - ('requests', requests.__version__), - ('urllib3', urllib3.__version__), - ('OpenSSL', OrderedDict( - [ - ('version', ssl.OPENSSL_VERSION), - ('ciphers', getPossibleCiphers()) - ] - )) - ]) - -# ------------------------------------------------------------------------------- # - - -if __name__ == '__main__': - print(json.dumps(systemInfo(), indent=4)) diff --git a/lib/cloudscraper/interpreters/__init__.py b/lib/cloudscraper/interpreters/__init__.py deleted file mode 100644 index af937b4a..00000000 --- a/lib/cloudscraper/interpreters/__init__.py +++ /dev/null @@ -1,56 +0,0 @@ -import sys -import logging -import abc - -from ..exceptions import CloudflareSolveError - -if sys.version_info >= (3, 4): - ABC = abc.ABC # noqa -else: - ABC = abc.ABCMeta('ABC', (), {}) - -# ------------------------------------------------------------------------------- # - -interpreters = {} - -# ------------------------------------------------------------------------------- # - - -class JavaScriptInterpreter(ABC): - - # ------------------------------------------------------------------------------- # - - @abc.abstractmethod - def __init__(self, name): - interpreters[name] = self - - # ------------------------------------------------------------------------------- # - - @classmethod - def dynamicImport(cls, name): - if name not in interpreters: - try: - __import__('{}.{}'.format(cls.__module__, name)) - if not isinstance(interpreters.get(name), JavaScriptInterpreter): - raise ImportError('The interpreter was not initialized.') - except ImportError: - logging.error('Unable to load {} interpreter'.format(name)) - raise - - return interpreters[name] - - # ------------------------------------------------------------------------------- # - - @abc.abstractmethod - def eval(self, jsEnv, js): - pass - - # ------------------------------------------------------------------------------- # - - def solveChallenge(self, body, domain): - try: - return '{0:.10f}'.format(float(self.eval(body, domain))) - except Exception: - raise CloudflareSolveError( - 'Error trying to solve Cloudflare IUAM Javascript, they may have changed their technique.' - ) diff --git a/lib/cloudscraper/interpreters/chakracore.py b/lib/cloudscraper/interpreters/chakracore.py deleted file mode 100644 index 2ff56867..00000000 --- a/lib/cloudscraper/interpreters/chakracore.py +++ /dev/null @@ -1,103 +0,0 @@ -from __future__ import absolute_import - -import os -import sys -import ctypes.util - -from ctypes import c_void_p, c_size_t, byref, create_string_buffer, CDLL - -from . import JavaScriptInterpreter -from .encapsulated import template - -# ------------------------------------------------------------------------------- # - - -class ChallengeInterpreter(JavaScriptInterpreter): - - # ------------------------------------------------------------------------------- # - - def __init__(self): - super(ChallengeInterpreter, self).__init__('chakracore') - - # ------------------------------------------------------------------------------- # - - def eval(self, body, domain): - chakraCoreLibrary = None - - # check current working directory. - for _libraryFile in ['libChakraCore.so', 'libChakraCore.dylib', 'ChakraCore.dll']: - if os.path.isfile(os.path.join(os.getcwd(), _libraryFile)): - chakraCoreLibrary = os.path.join(os.getcwd(), _libraryFile) - continue - - if not chakraCoreLibrary: - chakraCoreLibrary = ctypes.util.find_library('ChakraCore') - - if not chakraCoreLibrary: - sys.tracebacklimit = 0 - raise RuntimeError( - 'ChakraCore library not found in current path or any of your system library paths, ' - 'please download from https://www.github.com/VeNoMouS/cloudscraper/tree/ChakraCore/, ' - 'or https://github.com/Microsoft/ChakraCore/' - ) - - try: - chakraCore = CDLL(chakraCoreLibrary) - except OSError: - sys.tracebacklimit = 0 - raise RuntimeError('There was an error loading the ChakraCore library {}'.format(chakraCoreLibrary)) - - if sys.platform != 'win32': - chakraCore.DllMain(0, 1, 0) - chakraCore.DllMain(0, 2, 0) - - script = create_string_buffer(template(body, domain).encode('utf-16')) - - runtime = c_void_p() - chakraCore.JsCreateRuntime(0, 0, byref(runtime)) - - context = c_void_p() - chakraCore.JsCreateContext(runtime, byref(context)) - chakraCore.JsSetCurrentContext(context) - - fname = c_void_p() - chakraCore.JsCreateString( - 'iuam-challenge.js', - len('iuam-challenge.js'), - byref(fname) - ) - - scriptSource = c_void_p() - chakraCore.JsCreateExternalArrayBuffer( - script, - len(script), - 0, - 0, - byref(scriptSource) - ) - - jsResult = c_void_p() - chakraCore.JsRun(scriptSource, 0, fname, 0x02, byref(jsResult)) - - resultJSString = c_void_p() - chakraCore.JsConvertValueToString(jsResult, byref(resultJSString)) - - stringLength = c_size_t() - chakraCore.JsCopyString(resultJSString, 0, 0, byref(stringLength)) - - resultSTR = create_string_buffer(stringLength.value + 1) - chakraCore.JsCopyString( - resultJSString, - byref(resultSTR), - stringLength.value + 1, - 0 - ) - - chakraCore.JsDisposeRuntime(runtime) - - return resultSTR.value - - -# ------------------------------------------------------------------------------- # - -ChallengeInterpreter() diff --git a/lib/cloudscraper/interpreters/encapsulated.py b/lib/cloudscraper/interpreters/encapsulated.py deleted file mode 100644 index d98fa236..00000000 --- a/lib/cloudscraper/interpreters/encapsulated.py +++ /dev/null @@ -1,62 +0,0 @@ -import logging -import re - -# ------------------------------------------------------------------------------- # - - -def template(body, domain): - BUG_REPORT = 'Cloudflare may have changed their technique, or there may be a bug in the script.' - - try: - js = re.search( - r'setTimeout\(function\(\){\s+(.*?a\.value\s*=\s*\S+toFixed\(10\);)', - body, - re.M | re.S - ).group(1) - except Exception: - raise ValueError('Unable to identify Cloudflare IUAM Javascript on website. {}'.format(BUG_REPORT)) - - jsEnv = '''String.prototype.italics=function(str) {{return "" + this + "";}}; - var subVars= {{{subVars}}}; - var document = {{ - createElement: function () {{ - return {{ firstChild: {{ href: "https://{domain}/" }} }} - }}, - getElementById: function (str) {{ - return {{"innerHTML": subVars[str]}}; - }} - }}; - ''' - - try: - js = js.replace( - r"(setInterval(function(){}, 100),t.match(/https?:\/\//)[0]);", - r"t.match(/https?:\/\//)[0];" - ) - - k = re.search(r" k\s*=\s*'(?P\S+)';", body).group('k') - r = re.compile(r'
\s*(?P[^<>]*)
'.format(k)) - - subVars = '' - for m in r.finditer(body): - subVars = '{}\n\t\t{}{}: {},\n'.format(subVars, k, m.group('id'), m.group('jsfuck')) - subVars = subVars[:-2] - - except: # noqa - logging.error('Error extracting Cloudflare IUAM Javascript. {}'.format(BUG_REPORT)) - raise - - return '{}{}'.format( - re.sub( - r'\s{2,}', - ' ', - jsEnv.format( - domain=domain, - subVars=subVars - ), - re.MULTILINE | re.DOTALL - ), - js - ) - -# ------------------------------------------------------------------------------- # diff --git a/lib/cloudscraper/interpreters/js2py.py b/lib/cloudscraper/interpreters/js2py.py deleted file mode 100644 index 409500a2..00000000 --- a/lib/cloudscraper/interpreters/js2py.py +++ /dev/null @@ -1,44 +0,0 @@ -from __future__ import absolute_import - -import js2py -import logging -import base64 - -from . import JavaScriptInterpreter - -from .encapsulated import template -from .jsunfuck import jsunfuck - -# ------------------------------------------------------------------------------- # - - -class ChallengeInterpreter(JavaScriptInterpreter): - - # ------------------------------------------------------------------------------- # - - def __init__(self): - super(ChallengeInterpreter, self).__init__('js2py') - - # ------------------------------------------------------------------------------- # - - def eval(self, body, domain): - - jsPayload = template(body, domain) - - if js2py.eval_js('(+(+!+[]+[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+[!+[]+!+[]]+[+[]])+[])[+!+[]]') == '1': - logging.warning('WARNING - Please upgrade your js2py https://github.com/PiotrDabkowski/Js2Py, applying work around for the meantime.') - jsPayload = jsunfuck(jsPayload) - - def atob(s): - return base64.b64decode('{}'.format(s)).decode('utf-8') - - js2py.disable_pyimport() - context = js2py.EvalJs({'atob': atob}) - result = context.eval(jsPayload) - - return result - - -# ------------------------------------------------------------------------------- # - -ChallengeInterpreter() diff --git a/lib/cloudscraper/interpreters/jsunfuck.py b/lib/cloudscraper/interpreters/jsunfuck.py deleted file mode 100644 index 9b149cc2..00000000 --- a/lib/cloudscraper/interpreters/jsunfuck.py +++ /dev/null @@ -1,97 +0,0 @@ -MAPPING = { - 'a': '(false+"")[1]', - 'b': '([]["entries"]()+"")[2]', - 'c': '([]["fill"]+"")[3]', - 'd': '(undefined+"")[2]', - 'e': '(true+"")[3]', - 'f': '(false+"")[0]', - 'g': '(false+[0]+String)[20]', - 'h': '(+(101))["to"+String["name"]](21)[1]', - 'i': '([false]+undefined)[10]', - 'j': '([]["entries"]()+"")[3]', - 'k': '(+(20))["to"+String["name"]](21)', - 'l': '(false+"")[2]', - 'm': '(Number+"")[11]', - 'n': '(undefined+"")[1]', - 'o': '(true+[]["fill"])[10]', - 'p': '(+(211))["to"+String["name"]](31)[1]', - 'q': '(+(212))["to"+String["name"]](31)[1]', - 'r': '(true+"")[1]', - 's': '(false+"")[3]', - 't': '(true+"")[0]', - 'u': '(undefined+"")[0]', - 'v': '(+(31))["to"+String["name"]](32)', - 'w': '(+(32))["to"+String["name"]](33)', - 'x': '(+(101))["to"+String["name"]](34)[1]', - 'y': '(NaN+[Infinity])[10]', - 'z': '(+(35))["to"+String["name"]](36)', - 'A': '(+[]+Array)[10]', - 'B': '(+[]+Boolean)[10]', - 'C': 'Function("return escape")()(("")["italics"]())[2]', - 'D': 'Function("return escape")()([]["fill"])["slice"]("-1")', - 'E': '(RegExp+"")[12]', - 'F': '(+[]+Function)[10]', - 'G': '(false+Function("return Date")()())[30]', - 'I': '(Infinity+"")[0]', - 'M': '(true+Function("return Date")()())[30]', - 'N': '(NaN+"")[0]', - 'O': '(NaN+Function("return{}")())[11]', - 'R': '(+[]+RegExp)[10]', - 'S': '(+[]+String)[10]', - 'T': '(NaN+Function("return Date")()())[30]', - 'U': '(NaN+Function("return{}")()["to"+String["name"]]["call"]())[11]', - ' ': '(NaN+[]["fill"])[11]', - '"': '("")["fontcolor"]()[12]', - '%': 'Function("return escape")()([]["fill"])[21]', - '&': '("")["link"](0+")[10]', - '(': '(undefined+[]["fill"])[22]', - ')': '([0]+false+[]["fill"])[20]', - '+': '(+(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+[+!+[]]+[+[]]+[+[]])+[])[2]', - ',': '([]["slice"]["call"](false+"")+"")[1]', - '-': '(+(.+[0000000001])+"")[2]', - '.': '(+(+!+[]+[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+[!+[]+!+[]]+[+[]])+[])[+!+[]]', - '/': '(false+[0])["italics"]()[10]', - ':': '(RegExp()+"")[3]', - ';': '("")["link"](")[14]', - '<': '("")["italics"]()[0]', - '=': '("")["fontcolor"]()[11]', - '>': '("")["italics"]()[2]', - '?': '(RegExp()+"")[2]', - '[': '([]["entries"]()+"")[0]', - ']': '([]["entries"]()+"")[22]', - '{': '(true+[]["fill"])[20]', - '}': '([]["fill"]+"")["slice"]("-1")' -} - -SIMPLE = { - 'false': '![]', - 'true': '!![]', - 'undefined': '[][[]]', - 'NaN': '+[![]]', - 'Infinity': '+(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+[+!+[]]+[+[]]+[+[]]+[+[]])' # +"1e1000" -} - -CONSTRUCTORS = { - 'Array': '[]', - 'Number': '(+[])', - 'String': '([]+[])', - 'Boolean': '(![])', - 'Function': '[]["fill"]', - 'RegExp': 'Function("return/"+false+"/")()' -} - - -def jsunfuck(jsfuckString): - for key in sorted(MAPPING, key=lambda k: len(MAPPING[k]), reverse=True): - if MAPPING.get(key) in jsfuckString: - jsfuckString = jsfuckString.replace(MAPPING.get(key), '"{}"'.format(key)) - - for key in sorted(SIMPLE, key=lambda k: len(SIMPLE[k]), reverse=True): - if SIMPLE.get(key) in jsfuckString: - jsfuckString = jsfuckString.replace(SIMPLE.get(key), '{}'.format(key)) - - # for key in sorted(CONSTRUCTORS, key=lambda k: len(CONSTRUCTORS[k]), reverse=True): - # if CONSTRUCTORS.get(key) in jsfuckString: - # jsfuckString = jsfuckString.replace(CONSTRUCTORS.get(key), '{}'.format(key)) - - return jsfuckString diff --git a/lib/cloudscraper/interpreters/native.py b/lib/cloudscraper/interpreters/native.py deleted file mode 100644 index f71474cf..00000000 --- a/lib/cloudscraper/interpreters/native.py +++ /dev/null @@ -1,233 +0,0 @@ -from __future__ import absolute_import - -import ast -import re -import operator as op -import pyparsing - -from ..exceptions import CloudflareSolveError -from . import JavaScriptInterpreter - -# ------------------------------------------------------------------------------- # - -_OP_MAP = { - ast.Add: op.add, - ast.Sub: op.sub, - ast.Mult: op.mul, - ast.Div: op.truediv, - ast.Invert: op.neg, -} - -# ------------------------------------------------------------------------------- # - - -class Calc(ast.NodeVisitor): - - def visit_BinOp(self, node): - return _OP_MAP[type(node.op)](self.visit(node.left), self.visit(node.right)) - - # ------------------------------------------------------------------------------- # - - def visit_Num(self, node): - return node.n - - # ------------------------------------------------------------------------------- # - - def visit_Expr(self, node): - return self.visit(node.value) - - # ------------------------------------------------------------------------------- # - - @classmethod - def doMath(cls, expression): - tree = ast.parse(expression) - calc = cls() - return calc.visit(tree.body[0]) - -# ------------------------------------------------------------------------------- # - - -class Parentheses(object): - - def fix(self, s): - res = [] - self.visited = set([s]) - self.dfs(s, self.invalid(s), res) - return res - - # ------------------------------------------------------------------------------- # - - def dfs(self, s, n, res): - if n == 0: - res.append(s) - return - for i in range(len(s)): - if s[i] in ['(', ')']: - s_new = s[:i] + s[i + 1:] - if s_new not in self.visited and self.invalid(s_new) < n: - self.visited.add(s_new) - self.dfs(s_new, self.invalid(s_new), res) - - # ------------------------------------------------------------------------------- # - - def invalid(self, s): - plus = minus = 0 - memo = {"(": 1, ")": -1} - for c in s: - plus += memo.get(c, 0) - minus += 1 if plus < 0 else 0 - plus = max(0, plus) - return plus + minus - -# ------------------------------------------------------------------------------- # - - -class ChallengeInterpreter(JavaScriptInterpreter): - - def __init__(self): - super(ChallengeInterpreter, self).__init__('native') - - # ------------------------------------------------------------------------------- # - - def eval(self, body, domain): - - operators = { - '+': op.add, - '-': op.sub, - '*': op.mul, - '/': op.truediv - } - - # ------------------------------------------------------------------------------- # - - def flatten(lists): - return sum(map(flatten, lists), []) if isinstance(lists, list) else [lists] - - # ------------------------------------------------------------------------------- # - - def jsfuckToNumber(jsFuck): - # "Clean Up" JSFuck - jsFuck = jsFuck.replace('!+[]', '1').replace('!![]', '1').replace('[]', '0') - jsFuck = jsFuck.lstrip('+').replace('(+', '(').replace(' ', '') - jsFuck = Parentheses().fix(jsFuck)[0] - - # Hackery Parser for Math - stack = [] - bstack = [] - - for i in flatten(pyparsing.nestedExpr().parseString(jsFuck).asList()): - if i == '+': - stack.append(bstack) - bstack = [] - continue - bstack.append(i) - stack.append(bstack) - - return int(''.join([str(Calc.doMath(''.join(i))) for i in stack])) - - # ------------------------------------------------------------------------------- # - - def divisorMath(payload, needle, domain): - jsfuckMath = payload.split('/') - if needle in jsfuckMath[1]: - expression = re.findall(r"^(.*?)(.)\(function", jsfuckMath[1])[0] - - expression_value = operators[expression[1]]( - float(jsfuckToNumber(expression[0])), - float(ord(domain[jsfuckToNumber(jsfuckMath[1][ - jsfuckMath[1].find('"("+p+")")}') + len('"("+p+")")}'):-2 - ])])) - ) - else: - expression_value = jsfuckToNumber(jsfuckMath[1]) - - expression_value = jsfuckToNumber(jsfuckMath[0]) / float(expression_value) - - return expression_value - - # ------------------------------------------------------------------------------- # - - def challengeSolve(body, domain): - jschl_answer = 0 - - try: - jsfuckChallenge = re.search( - r"setTimeout\(function\(\){\s+var.*?f,\s*(?P\w+).*?:(?P\S+)};" - r".*?\('challenge-form'\);.*?;(?P.*?a\.value)\s*=\s*\S+\.toFixed\(10\);", - body, - re.DOTALL | re.MULTILINE - ).groupdict() - except AttributeError: - raise CloudflareSolveError('There was an issue extracting "jsfuckChallenge" from the Cloudflare challenge.') - - kJSFUCK = re.search(r'(;|)\s*k.=(?P\S+);', jsfuckChallenge['challenge'], re.S | re.M) - if kJSFUCK: - try: - kJSFUCK = jsfuckToNumber(kJSFUCK.group('kJSFUCK')) - except IndexError: - raise CloudflareSolveError('There was an issue extracting "kJSFUCK" from the Cloudflare challenge.') - - try: - kID = re.search(r"\s*k\s*=\s*'(?P\S+)';", body).group('kID') - except IndexError: - raise CloudflareSolveError('There was an issue extracting "kID" from the Cloudflare challenge.') - - try: - r = re.compile(r'
\s*(?P[^<>]*)
'.format(kID)) - - kValues = {} - for m in r.finditer(body): - kValues[int(m.group('id'))] = m.group('jsfuck') - - jsfuckChallenge['k'] = kValues[kJSFUCK] - except (AttributeError, IndexError): - raise CloudflareSolveError('There was an issue extracting "kValues" from the Cloudflare challenge.') - - jsfuckChallenge['challenge'] = re.finditer( - r'{}.*?([+\-*/])=(.*?);(?=a\.value|{})'.format( - jsfuckChallenge['variable'], - jsfuckChallenge['variable'] - ), - jsfuckChallenge['challenge'] - ) - - # ------------------------------------------------------------------------------- # - - if '/' in jsfuckChallenge['init']: - val = jsfuckChallenge['init'].split('/') - jschl_answer = jsfuckToNumber(val[0]) / float(jsfuckToNumber(val[1])) - else: - jschl_answer = jsfuckToNumber(jsfuckChallenge['init']) - - # ------------------------------------------------------------------------------- # - - for expressionMatch in jsfuckChallenge['challenge']: - oper, expression = expressionMatch.groups() - - if '/' in expression: - expression_value = divisorMath(expression, 'function(p)', domain) - else: - if 'Element' in expression: - expression_value = divisorMath(jsfuckChallenge['k'], '"("+p+")")}', domain) - else: - expression_value = jsfuckToNumber(expression) - - jschl_answer = operators[oper](jschl_answer, expression_value) - - # ------------------------------------------------------------------------------- # - - # if not jsfuckChallenge['k'] and '+ t.length' in body: - # jschl_answer += len(domain) - - # ------------------------------------------------------------------------------- # - - return '{0:.10f}'.format(jschl_answer) - - # ------------------------------------------------------------------------------- # - - return challengeSolve(body, domain) - -# ------------------------------------------------------------------------------- # - - -ChallengeInterpreter() diff --git a/lib/cloudscraper/interpreters/nodejs.py b/lib/cloudscraper/interpreters/nodejs.py deleted file mode 100644 index bafab288..00000000 --- a/lib/cloudscraper/interpreters/nodejs.py +++ /dev/null @@ -1,49 +0,0 @@ -import base64 -import subprocess -import sys - -from . import JavaScriptInterpreter -from .encapsulated import template - -# ------------------------------------------------------------------------------- # - - -class ChallengeInterpreter(JavaScriptInterpreter): - - # ------------------------------------------------------------------------------- # - - def __init__(self): - super(ChallengeInterpreter, self).__init__('nodejs') - - # ------------------------------------------------------------------------------- # - - def eval(self, body, domain): - try: - js = 'var atob = function(str) {return Buffer.from(str, "base64").toString("binary");};' \ - 'var challenge = atob("%s");' \ - 'var context = {atob: atob};' \ - 'var options = {filename: "iuam-challenge.js", timeout: 4000};' \ - 'var answer = require("vm").runInNewContext(challenge, context, options);' \ - 'process.stdout.write(String(answer));' \ - % base64.b64encode(template(body, domain).encode('UTF-8')).decode('ascii') - - return subprocess.check_output(['node', '-e', js]) - - except OSError as e: - if e.errno == 2: - raise EnvironmentError( - 'Missing Node.js runtime. Node is required and must be in the PATH (check with `node -v`).\n\n' - 'Your Node binary may be called `nodejs` rather than `node`, ' - 'in which case you may need to run `apt-get install nodejs-legacy` on some Debian-based systems.\n\n' - '(Please read the cloudscraper README\'s Dependencies section: ' - 'https://github.com/VeNoMouS/cloudscraper#dependencies.)' - ) - raise - except Exception: - sys.tracebacklimit = 0 - raise RuntimeError('Error executing Cloudflare IUAM Javascript in nodejs') - - -# ------------------------------------------------------------------------------- # - -ChallengeInterpreter() diff --git a/lib/cloudscraper/interpreters/v8.py b/lib/cloudscraper/interpreters/v8.py deleted file mode 100644 index 5d00fb40..00000000 --- a/lib/cloudscraper/interpreters/v8.py +++ /dev/null @@ -1,33 +0,0 @@ -from __future__ import absolute_import - -import sys - -try: - import v8eval -except ImportError: - sys.tracebacklimit = 0 - raise RuntimeError('Please install the python module v8eval either via pip or download it from https://github.com/sony/v8eval') - -from . import JavaScriptInterpreter -from .encapsulated import template - -# ------------------------------------------------------------------------------- # - - -class ChallengeInterpreter(JavaScriptInterpreter): - - def __init__(self): - super(ChallengeInterpreter, self).__init__('v8') - - # ------------------------------------------------------------------------------- # - - def eval(self, body, domain): - try: - return v8eval.V8().eval(template(body, domain)) - except (TypeError, v8eval.V8Error): - RuntimeError('We encountered an error running the V8 Engine.') - - -# ------------------------------------------------------------------------------- # - -ChallengeInterpreter() diff --git a/lib/cloudscraper/user_agent/__init__.py b/lib/cloudscraper/user_agent/__init__.py deleted file mode 100644 index 80231f3f..00000000 --- a/lib/cloudscraper/user_agent/__init__.py +++ /dev/null @@ -1,124 +0,0 @@ -import json -import os -import random -import re -import sys -import ssl - -from collections import OrderedDict - -# ------------------------------------------------------------------------------- # - - -class User_Agent(): - - # ------------------------------------------------------------------------------- # - - def __init__(self, *args, **kwargs): - self.headers = None - self.cipherSuite = [] - self.loadUserAgent(*args, **kwargs) - - # ------------------------------------------------------------------------------- # - - def filterAgents(self, user_agents): - filtered = {} - - if self.mobile: - if self.platform in user_agents['mobile'] and user_agents['mobile'][self.platform]: - filtered.update(user_agents['mobile'][self.platform]) - - if self.desktop: - if self.platform in user_agents['desktop'] and user_agents['desktop'][self.platform]: - filtered.update(user_agents['desktop'][self.platform]) - - return filtered - - # ------------------------------------------------------------------------------- # - - def tryMatchCustom(self, user_agents): - for device_type in user_agents['user_agents']: - for platform in user_agents['user_agents'][device_type]: - for browser in user_agents['user_agents'][device_type][platform]: - if re.search(re.escape(self.custom), ' '.join(user_agents['user_agents'][device_type][platform][browser])): - self.headers = user_agents['headers'][browser] - self.headers['User-Agent'] = self.custom - self.cipherSuite = user_agents['cipherSuite'][browser] - return True - return False - - # ------------------------------------------------------------------------------- # - - def loadUserAgent(self, *args, **kwargs): - self.browser = kwargs.pop('browser', None) - - self.platforms = ['linux', 'windows', 'darwin', 'android', 'ios'] - self.browsers = ['chrome', 'firefox'] - - if isinstance(self.browser, dict): - self.custom = self.browser.get('custom', None) - self.platform = self.browser.get('platform', None) - self.desktop = self.browser.get('desktop', True) - self.mobile = self.browser.get('mobile', True) - self.browser = self.browser.get('browser', None) - else: - self.custom = kwargs.pop('custom', None) - self.platform = kwargs.pop('platform', None) - self.desktop = kwargs.pop('desktop', True) - self.mobile = kwargs.pop('mobile', True) - - if not self.desktop and not self.mobile: - sys.tracebacklimit = 0 - raise RuntimeError("Sorry you can't have mobile and desktop disabled at the same time.") - - with open(os.path.join(os.path.dirname(__file__), 'browsers.json'), 'r') as fp: - user_agents = json.load( - fp, - object_pairs_hook=OrderedDict - ) - - if self.custom: - if not self.tryMatchCustom(user_agents): - self.cipherSuite = [ - ssl._DEFAULT_CIPHERS, - '!AES128-SHA', - '!ECDHE-RSA-AES256-SHA', - ] - self.headers = OrderedDict([ - ('User-Agent', self.custom), - ('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'), - ('Accept-Language', 'en-US,en;q=0.9'), - ('Accept-Encoding', 'gzip, deflate, br') - ]) - else: - if self.browser and self.browser not in self.browsers: - sys.tracebacklimit = 0 - raise RuntimeError('Sorry "{}" browser is not valid, valid browsers are [{}].'.format(self.browser, ', '.join(self.browsers))) - - if not self.platform: - self.platform = random.SystemRandom().choice(self.platforms) - - if self.platform not in self.platforms: - sys.tracebacklimit = 0 - raise RuntimeError('Sorry the platform "{}" is not valid, valid platforms are [{}]'.format(self.platform, ', '.join(self.platforms))) - - filteredAgents = self.filterAgents(user_agents['user_agents']) - - if not self.browser: - # has to be at least one in there... - while not filteredAgents.get(self.browser): - self.browser = random.SystemRandom().choice(list(filteredAgents.keys())) - - if not filteredAgents[self.browser]: - sys.tracebacklimit = 0 - raise RuntimeError('Sorry "{}" browser was not found with a platform of "{}".'.format(self.browser, self.platform)) - - self.cipherSuite = user_agents['cipherSuite'][self.browser] - self.headers = user_agents['headers'][self.browser] - - self.headers['User-Agent'] = random.SystemRandom().choice(filteredAgents[self.browser]) - - if not kwargs.get('allow_brotli', False) and 'br' in self.headers['Accept-Encoding']: - self.headers['Accept-Encoding'] = ','.join([ - encoding for encoding in self.headers['Accept-Encoding'].split(',') if encoding.strip() != 'br' - ]).strip() diff --git a/lib/cloudscraper/user_agent/browsers.json b/lib/cloudscraper/user_agent/browsers.json deleted file mode 100644 index 1caff339..00000000 --- a/lib/cloudscraper/user_agent/browsers.json +++ /dev/null @@ -1,7922 +0,0 @@ -{ - "headers": { - "chrome": { - "User-Agent": null, - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", - "Accept-Language": "en-US,en;q=0.9", - "Accept-Encoding": "gzip, deflate, br" - }, - "firefox": { - "User-Agent": null, - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", - "Accept-Language": "en-US,en;q=0.5", - "Accept-Encoding": "gzip, deflate, br" - } - }, - "cipherSuite": { - "chrome": [ - "TLS_AES_128_GCM_SHA256", - "TLS_AES_256_GCM_SHA384", - "TLS_CHACHA20_POLY1305_SHA256", - "ECDHE-ECDSA-AES128-GCM-SHA256", - "ECDHE-RSA-AES128-GCM-SHA256", - "ECDHE-ECDSA-AES256-GCM-SHA384", - "ECDHE-RSA-AES256-GCM-SHA384", - "ECDHE-ECDSA-CHACHA20-POLY1305", - "ECDHE-RSA-CHACHA20-POLY1305", - "ECDHE-RSA-AES128-SHA", - "ECDHE-RSA-AES256-SHA", - "AES128-GCM-SHA256", - "AES256-GCM-SHA384", - "AES128-SHA", - "AES256-SHA", - "DES-CBC3-SHA" - ], - "firefox": [ - "TLS_AES_128_GCM_SHA256", - "TLS_CHACHA20_POLY1305_SHA256", - "TLS_AES_256_GCM_SHA384", - "ECDHE-ECDSA-AES128-GCM-SHA256", - "ECDHE-RSA-AES128-GCM-SHA256", - "ECDHE-ECDSA-CHACHA20-POLY1305", - "ECDHE-RSA-CHACHA20-POLY1305", - "ECDHE-ECDSA-AES256-GCM-SHA384", - "ECDHE-RSA-AES256-GCM-SHA384", - "ECDHE-ECDSA-AES256-SHA", - "ECDHE-ECDSA-AES128-SHA", - "ECDHE-RSA-AES128-SHA", - "ECDHE-RSA-AES256-SHA", - "DHE-RSA-AES128-SHA", - "DHE-RSA-AES256-SHA", - "AES128-SHA", - "AES256-SHA", - "DES-CBC3-SHA" - ] - }, - "user_agents": { - "desktop": { - "windows": { - "chrome": [ - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.1331.54 Safari/537.36", - "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.1.2909.1022 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.1.2909.1022 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.0.1471.813 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.1.2015.1007 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.1.2107.204 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.1.2909.1213 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.0.1308.1016 Safari/420815", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.1.2015.1007 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.1.2909.1022 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.1.2015.1007 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.0.1471.914 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.1.2015.1007 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 UBrowser/6.1.2909.1022 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.18 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.95 Safari/537.36 Core/1.50.1659.400 QQBrowser/9.5.9570.400", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.95 Safari/537.36 Core/1.50.1659.400 QQBrowser/9.5.9769.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2683.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2683.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2683.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.47 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.63 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.63 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.63 Safari/537.36 OPR/38.0.2220.29", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 (https://shrinktheweb.com)", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Vivaldi/1.2.490.39", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Vivaldi/1.3.501.6", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Vivaldi/1.2.490.39", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Vivaldi/1.3.501.6", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Vivaldi/1.2.490.39", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Vivaldi/1.2.490.39", - "Mozilla/5.0 (Windows NT 10.0; ARM; Lumia 535) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Vivaldi/1.2.490.39", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Vivaldi/1.3.501.6", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Vivaldi/1.2.490.39", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Vivaldi/1.3.501.6", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2741.70 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 OPR/39.0.2256.71", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 YaBrowser/16.9.1.1131 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.14987", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; WebView/3.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 OPR/39.0.2256.71", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 YaBrowser/16.9.1.1192 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.42 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.43", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.42 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.43", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.43", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.42 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.43", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.40 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.42 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.43", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.2743.82 Safari/537.36 OPR/39.0.2256.43", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.0.11780 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.0.11780 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.52 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.54", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.62", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 YaBrowser/16.10.0.1807 (beta) Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.52 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.54", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.62", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 YaBrowser/16.10.0.1807 (beta) Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.54", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.52 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.54", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.62", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.62", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.52 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.54", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.62", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.62 (Edition Campaign 34)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 YaBrowser/16.10.0.1807 (beta) Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 YaBrowser/16.10.0.1807 (beta) Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.2057.400 QQBrowser/9.5.10158.400", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.3427.400 QQBrowser/9.6.12449.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.2759.400 QQBrowser/9.6.11266.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.3084.400 QQBrowser/9.6.11346.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.4549.400 QQBrowser/9.7.12900.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.4620.400 QQBrowser/9.7.13014.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.4843.400 QQBrowser/9.7.13021.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.4882.400 QQBrowser/9.7.13036.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.4882.400 QQBrowser/9.7.13076.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.5006.400 QQBrowser/9.7.13080.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.5048.400 QQBrowser/9.7.13114.400", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.1989.400 QQBrowser/9.5.10016.400", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.4620.400 QQBrowser/9.7.13014.400", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.3538.400 QQBrowser/9.7.12954.400", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.4482.400 QQBrowser/9.7.13001.400", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 6; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/F7C8DB", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.21 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.70 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36 009754B0C", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36 OPR/40.0.2308.44 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36 QQBrowser", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36 TSBrowser QQBrowser", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36 OPR/40.0.2308.44 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36 Slimjet/12.0.6.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36 OPR/40.0.2308.44 (Edition beta)", - "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/53.0Safari/532.9", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/535.22.75 (KHTML, like Gecko) Chrome/53.7.2410.8782 Safari/531.83", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2824.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.27 Safari/537.36 OPR/41.0.2353.10 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 OPR/41.0.2353.30 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 OPR/41.0.2353.46", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 OPR/41.0.2353.46 (Edition Yx)", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 Vivaldi/1.5.638.3", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 115Browser/8.3.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 115Browser/8.6.2", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 OPR/41.0.2353.30 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 OPR/41.0.2353.46", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 OPR/41.0.2353.46", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 OPR/41.0.2353.30 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 OPR/41.0.2353.46", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 OPR/41.0.2353.46", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 Edge/38.14393", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 Vivaldi/1.5.638.3", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 OPR/41.0.2353.30 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 OPR/41.0.2353.46", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36 OPR/41.0.2353.56", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36 OPR/41.0.2353.69", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 UBrowser/5.6.12860.7 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36 OPR/41.0.2353.69 (Edition FCI)", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36 OPR/41.0.2353.69", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2878.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.24.2840.71 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.0.12195 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/428.36 (KHTML, like Gecko) Chrome/55.0.2490.80 Safari/428.36 (https://darkbyte.ru/)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/55.0.2883 Safari/535.1", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.105 Safari/537.36 Swing/4.1.0.2", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.11 Safari/537.36", - "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.78 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.85", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.78 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.85", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.78 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.85", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.85", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.85", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.78 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.85", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.78 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.85", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 Slimjet/13.0.9.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.78 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.85", - "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.2.3964.2 Safari/537.36", - "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.2.4094.1 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 ASW/3.55.2393.596", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 OPR/42.0.2393.137", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 OPR/42.0.2393.517", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 OPR/42.0.2393.94", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/5.6.12860.7 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.1.2909.1213 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.2.3964.2 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.2.4094.1 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/7.0.125.1629 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/7.0.185.1002 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.2.4091.2 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/7.0.185.1002 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 OPR/42.0.2393.94", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.2.3964.2 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 7Star/2.0.55.2 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 OPR/42.0.2393.137", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 OPR/42.0.2393.517", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 OPR/42.0.2393.94", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.2.4094.1 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/7.0.125.1629 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/7.0.185.1002 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 YaBrowser/17.1.1.1003 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.96 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.3130.117 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64) AppleWebKit/530.63.10 (KHTML, like Gecko) Chrome/55.0.5138.0866 Safari/532.92 OPR/41.9.4315.9043", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.17.2883.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.19.2883.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.21.2883.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.56 (KHTML, like Gecko) Chrome/56.0.1750.154 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2911.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.28 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.28 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.28 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.51 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.686 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.806", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.806 (Edition 360-1)", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.686 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.806", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.686 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.806", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.806", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.806", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.806", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.806", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.686 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.806", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.686 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.806", - "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 YaBrowser/17.3.0.1785 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 YaBrowser/17.3.1.840 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1144", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 YaBrowser/17.3.1.840 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1144", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1144", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1144 (Edition Yx)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.991", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 YaBrowser/17.3.1.840 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1144", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1144", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1144", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 NetHelper70", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1144", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 YaBrowser/17.3.1.840 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 8.1; Win64; x64) AppleWebKit/603.4.6 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/603.4.6", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1144", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 FirePHP/4Chrome", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1144", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1144", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1144 (Edition Yx)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.991", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 YaBrowser/17.3.0.1785 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 YaBrowser/17.3.1.840 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.90 Safari/537.36 2345Explorer/9.3.2.17331", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.90 Safari/537.36 2345Explorer/9.1.1.16851", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.90 Safari/537.36 2345Explorer/9.3.1.17322", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.90 Safari/537.36 2345Explorer/9.3.2.17331", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.90 Safari/537.36 2345Explorer/9.5.0.17997", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.90 Safari/537.36 2345Explorer/9.6.0.18627", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.90 Safari/537.36 2345Explorer/9.3.2.17331", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2944.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.13.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.15.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.15.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.17.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.3.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.0.12335 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/534.34 (KHTML, like Gecko) Chrome/57.0.2345.113 Safari/534.34", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2945.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0.14393; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2950.4 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2951.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2954.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2960.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2970.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2979.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2979.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2979.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2984.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2985.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2986.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2986.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.0 Safari/537.36", - "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.108 Safari/537.36 MZBrowser/7.5.110-2018110721", - "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.108 Safari/537.36 MZBrowser/7.6.110-2018121017", - "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.108 Safari/537.36 MZBrowser/7.7.110-2019010410", - "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.108 Safari/537.36 MZBrowser/7.8.110-2019031217", - "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36 OPR/44.0.2510.23876 (Edition Campaign ni)", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 YaBrowser/17.4.0.1922 (beta) Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36 OPR/44.0.2510.23876 (Edition Campaign ni)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 YaBrowser/17.4.0.1922 (beta) Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 7Star/2.0.57.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36 FirePHP/0.7.4", - "Mozilla/5.0 (Windows NT 10.0; WOpleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36 OPR/44.0.2510.23876 (Edition Campaign ni)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 YaBrowser/17.4.0.1922 (beta) Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 OPR/44.0.2510.1159", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 OPR/44.0.2510.1218", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 OPR/44.0.2510.1159", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 OPR/44.0.2510.1449", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 OPR/44.0.2510.1449", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 OPR/44.0.2510.1449", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 OPR/44.0.2510.1218", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 OPR/44.0.2510.1449", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 OPR/44.0.2510.1218", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 OPR/44.0.2510.1449", - "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.137 YaBrowser/17.4.0.2461 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.137 YaBrowser/17.4.1.1026 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.137 YaBrowser/17.4.1.919 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.137 YaBrowser/17.4.1.919 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.138 Safari/537.36 Vivaldi/1.8.770.54", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.21 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.74 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.88 Safari/537.36", - "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.849 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.857", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.857 (Edition Yx)", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.857", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.849 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.857", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.857", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.849 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.857", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.849 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.857", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.857 (Edition Campaign 70)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.849 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.857", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.12.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.12.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.14.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.14.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.17.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.22.2987.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.2988.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.2988.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.2988.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.2988.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.2993.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3014.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3018.3 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3018.3 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3022.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 OPR/45.0.2552.888", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 OPR/45.0.2552.898", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 OPR/45.0.2552.881", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 OPR/45.0.2552.898", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 YaBrowser/17.6.1.749 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 YaBrowser/17.6.1.770 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 YaBrowser/17.6.1.749 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 OPR/45.0.2552.881", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16241", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 OPR/45.0.2552.888", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 OPR/45.0.2552.898", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 slurp", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 OPR/45.0.2552.888", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 OPR/45.0.2552.898", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 OPR/45.0.2552.898 (Edition 360)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.114 Safari/537.36 Vivaldi/1.9.818.50", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.19 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.33 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.41 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.54 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.54 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36 OPR/45.0.2552.812", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Iridium/58.0 Safari/537.36 Chrome/58.0.3029.81", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36 OPR/45.0.2552.626 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36 OPR/45.0.2552.812", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36 OPR/45.0.2552.812", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36 OPR/45.0.2552.634 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36 FirePHP/0.7.4", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36 OPR/45.0.2552.812", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36 ASW/4.58.2552.909", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36 OPR/45.0.2552.626 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36 OPR/45.0.2552.812", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.82 Safari/537.36 Vivaldi/1.9.818.44", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.82 Safari/537.36 Vivaldi/1.9.818.40", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.97 Safari/537.36 Vivaldi/1.9.818.49", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3249.33 Safari/537.36", - "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/58.0Safari/532.9", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.5.3029.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3032.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3036.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3041.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3042.4 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3044.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3047.4 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3047.4 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3048.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3051.3 Safari/537.36 slurp", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.112 Safari/537.36 Vivaldi/1.91.867.48", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.112 Safari/537.36 Vivaldi/1.91.867.48", - "Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 NetHelper70", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.57", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.57", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.57", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.57 (Edition Campaign 34)", - "Mozilla/5.0 (Windows NT 6.1; WOW64); AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.46", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.39", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.57", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.46", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.57", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.39", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.39", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.57", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36Connect Us: webauth@cmcm.com", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.39", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.57", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.15 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.29 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.30 Safari/537.36 Core/1.59.3969.400 QQBrowser/10.0.184.400", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.36 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.36 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.47 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.61 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.61 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.71 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36 OPR/46.0.2597.32", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36 OPR/46.0.2597.19 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36 OPR/46.0.2597.32", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36 OPR/46.0.2597.19 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36 OPR/46.0.2597.26374 (Edition Campaign 75)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36 OPR/46.0.2597.32", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36 OPR/46.0.2597.32", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36 OPR/46.0.2597.26", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36 OPR/46.0.2597.19 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36 OPR/46.0.2597.32", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36 OPR/46.0.2597.19 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36 OPR/46.0.2597.32", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.90 Safari/537.36 Vivaldi/1.91.867.38", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.90 Safari/537.36 Vivaldi/1.91.867.38", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.0.1508 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3075.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3095.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3095.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.105 Safari/537.36 Vivaldi/1.92.917.43", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 YaBrowser/17.9.0.2081 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 YaBrowser/17.9.1.768 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 YaBrowser/17.9.1.824 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36 Vivaldi/1.93.947.3", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.50 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.66 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.66 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.72 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.72 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.72 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 OPR/47.0.2631.34 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 OPR/47.0.2631.55", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 Vivaldi/1.92.917.17", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 OPR/47.0.2631.34 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 OPR/47.0.2631.55", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 OPR/47.0.2631.55", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 OPR/47.0.2631.34 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 OPR/47.0.2631.39", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 OPR/47.0.2631.55", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 Vivaldi/1.92.917.17", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 OPR/47.0.2631.39 (Edition Campaign 75)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 OPR/47.0.2631.55", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 OPR/47.0.2631.71", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 OPR/47.0.2631.71 (Edition Campaign 76)", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 OPR/47.0.2631.80", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 OPR/47.0.2631.71", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 OPR/47.0.2631.80", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 Stephen/5b844d6a1d7fa337734eceedfccfdfa168d6cf5c", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 OPR/47.0.2631.71", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 OPR/47.0.2631.71", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 OPR/47.0.2631.71", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 OPR/47.0.2631.80", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 OPR/47.0.2631.71 (Edition Campaign 34)", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 OPR/47.0.2631.71", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 OPR/47.0.2631.80", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 OPR/47.0.2631.71", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 OPR/47.0.2631.71 (Edition Campaign 75)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3113.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3116.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3124.11 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3141.7 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3143.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3147.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3154.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3155.1 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3159.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.35", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.39", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.50", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 YaBrowser/17.10.1.1204 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.35", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.39", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.50", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.52", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.52 (Edition Campaign 76)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.35", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.39", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.52", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 YaBrowser/17.10.0.2017 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 YaBrowser/17.10.1.1204 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.35", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.52", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 FirePHP/4Chrome", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.35", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.50", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.50 (Edition Campaign 76)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.52", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.52 (Edition Campaign 34)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.52 (Edition Campaign 76)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.35", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.35 (Edition Campaign 34)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.50 (Edition Campaign 76)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.52", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.52 (Edition Campaign 75)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 YaBrowser/17.10.0.2017 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 YaBrowser/17.10.1.1204 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.102 Safari/537.36 Vivaldi/1.94.971.8", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.31 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.31 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.39 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.49 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.49 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.59 Safari/537.36", - "Mozilla/5.0 (CVManaged; Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36 OPR/48.0.2685.22 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36 OPR/48.0.2685.26 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36 OPR/48.0.2685.22 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36 OPR/48.0.2685.22 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36 OPR/48.0.2685.22 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36 OPR/48.0.2685.22 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36 OPR/48.0.2685.26 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36 OPR/48.0.2685.22 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36 OPR/48.0.2685.26 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36 OPR/48.0.2685.32 (Edition 360-1)", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36 OPR/48.0.2685.32", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36 OPR/48.0.2685.32", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3167.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3188.4 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3192.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.29 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.38 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.38 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.45 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.45 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.45 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36 OPR/49.0.2725.31 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36 OPR/49.0.2725.31 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36 OPR/49.0.2725.27 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36 OPR/49.0.2725.31 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36 OPR/49.0.2725.27 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; https://liquidrechner.com; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36 https://liquidrechner.com", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) DownloaderChrome/62.0.3202.75 Safari/537.36", - "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36 VivoBrowser/5.5.4.0 Chrome/62.0.3202.84", - "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36 VivoBrowser/5.7.0.2 Chrome/62.0.3202.84", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36 OPR/49.0.2725.47", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36 OPR/49.0.2725.47", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36 OPR/49.0.2725.39", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36 OPR/49.0.2725.47", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36 OPR/49.0.2725.47 (Edition Campaign 34)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36 OPR/49.0.2725.47 (Edition Yx)", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36 OPR/49.0.2725.47", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36 OPR/49.0.2725.47", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36 OPR/49.0.2725.47", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36 OPR/49.0.2725.47", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36 OPR/49.0.2725.47", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36 OPR/49.0.2725.39", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36 OPR/49.0.2725.47", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36 OPR/49.0.2725.47 (Edition 360-1)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.9 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 YaBrowser/17.11.0.2260 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 OPR/49.0.2725.64", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 OPR/49.0.2725.64 (Edition Campaign 76)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 OPR/49.0.0.272531065 (Edition EXP168)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 OPR/49.0.2725.56", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 YaBrowser/17.11.0.2191 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 YaBrowser/17.11.1.988 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 YaBrowser/17.11.0.2191 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 FirePHP/4Chrome", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 OPR/49.0.0.272531065 (Edition EXP168)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 OPR/49.0.2725.64", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 OPR/49.0.2725.64", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 OPR/49.0.2725.64 (Edition Campaign 76)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 YaBrowser/17.11.1.992 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.97 Safari/537.36 Vivaldi/1.94.1008.40", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.97 Safari/537.36 Vivaldi/1.94.1008.40", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3219.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36 OPR/50.0.2762.45", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36", - "Mozilla/5.0 (Windows NT 5.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 OPR/50.0.2762.58", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 YaBrowser/18.2.1.174 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/4B4932", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 OPR/50.0.2762.58", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/479B76", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 OPR/50.0.2762.58", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 OPR/50.0.2762.67", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 YaBrowser/18.1.1.839 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 OPR/50.0.2762.58", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 YaBrowser/18.1.1.840 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 YaBrowser/18.1.1.839 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 YaBrowser/18.2.0.284 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 OPR/50.0.2762.58", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 OPR/50.0.2762.67", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 OPR/50.0.2762.58 (Edition Campaign 75)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.18 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5083.400 QQBrowser/10.0.972.400", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.6788.400 QQBrowser/10.3.2727.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.4737.400 QQBrowser/10.0.654.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5083.400 QQBrowser/10.0.972.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5221.400 QQBrowser/10.0.1125.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5359.400 QQBrowser/10.0.1299.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5383.400 QQBrowser/10.0.1313.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5408.400 QQBrowser/10.1.1408.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5467.400 QQBrowser/10.1.1503.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5478.400 QQBrowser/10.1.1550.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5915.400 LBBROWSER/10.1.3090.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.6726.400 QQBrowser/10.2.2265.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.6776.400 QQBrowser/10.3.2577.400", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.6788.400 QQBrowser/10.3.2843.400", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5083.400 QQBrowser/10.0.972.400", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5514.400 QQBrowser/10.1.1620.400", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.6788.400 QQBrowser/10.3.2714.400", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.52 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.59 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/B85648", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3251.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3255.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36 OPR/51.0.2830.23 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36 OPR/51.0.2830.23 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36 OPR/51.0.2830.23 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36 OPR/51.0.2830.26", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.22 anonymized by Abelssoft 400343057", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36 OPR/51.0.2830.23 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36 OPR/51.0.2830.23 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36 OPR/51.0.2830.23 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36 OPR/51.0.2830.26", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36 OPR/51.0.2830.23 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Chedot/9.0.3 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.167 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.167 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.167 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36 OPR/51.0.2830.55 (Edition Campaign 34)", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 YaBrowser/18.3.1.1232 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 YaBrowser/18.3.1.1232 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 YaBrowser/18.3.1.1232 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.24 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3288.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3298.4 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3298.4 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36 OPR/52.0.2871.20 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36 OPR/52.0.2871.20 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36 OPR/52.0.2871.20 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.40", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.64", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.64 (Edition Campaign 34)", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.99", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.64", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.99", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/986368", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; ; NCLIENT50_AAP38D0BEF49AF) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.40", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.64", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.99", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 YaBrowser/18.4.0.2080 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.40", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.64", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.64 (Edition Campaign 76)", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.99", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 Romash218922romash", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.64", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.99", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.183 Safari/537.36 Vivaldi/1.96.1147.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.183 Safari/537.36 Vivaldi/1.96.1147.42", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.183 Safari/537.36 Vivaldi/1.96.1147.42", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.183 Safari/537.36 Vivaldi/1.96.1147.47", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.19 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.52 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3343.4 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3355.4 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36 OPR/53.0.2907.37", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36 FirePHP/4Chrome", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 YaBrowser/18.6.0.1399 (beta) Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.57", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.99", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 Kinza/4.7.1", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.106", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.57", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.57 (Edition Campaign 34)", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.68", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.99", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 Ionic/2.16.8", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.57", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.57 (Edition Campaign 34)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.57 (Edition Yx)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.99", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.22 anonymized by Abelssoft 616146556", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.57", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.57", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.99", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.57", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.57", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.68", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.99", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.110", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.57", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36 Kinza/4.7.2", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36 XiaoBai/10.0.1521.260", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 YaBrowser/18.6.1.770 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 YaBrowser/18.6.1.770 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.66 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3377.1 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3381.1 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3381.1 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3393.4 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.10 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.10 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.103 YaBrowser/18.7.1.920 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.18 Safari/537.36 OPR/55.0.2962.0 (Edition developer)", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.18 Safari/537.36 OPR/55.0.2955.0 (Edition developer)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.18 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.48 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/7BB8A0", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36 OPR/54.0.2952.17 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36 OPR/54.0.2952.17 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36 OPR/54.0.2952.17 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/4CDC03", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.51", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.54", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.64", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.71", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.64", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.64 (Edition Yx)", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.51", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.54", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.64", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.71", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.64 (Edition Campaign 75)", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36 Kinza/4.8.2", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36 Avast/67.1.664.100", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3409.2 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3416.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3418.2 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3423.2 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3423.2 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3423.2 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3427.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3432.3 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36 Kinza/4.9.1", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36 OPR/55.0.2994.44", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36 OPR/55.0.2994.44 (Edition Yx 02)", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36 OPR/55.0.2994.56", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36 OPR/55.0.2994.61", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36 OPR/55.0.2994.44", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36 OPR/55.0.2994.56", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 YaBrowser/18.9.0.3409 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36 OPR/55.0.2994.44", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36 OPR/55.0.2994.56", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36 OPR/55.0.2994.61", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 YaBrowser/18.9.0.3409 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.17 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.25 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.59 Safari/537.36 Avast/68.0.746.60", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.59 Safari/537.36 AVG/68.0.639.61", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.7 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.7 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36 Slimjet/20.0.4.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) adbeat.com/policy AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36 OPR/55.0.2994.29 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) adbeat.com/policy AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) adbeat.com/policy AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36 OPR/55.0.2994.29 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; Tesseract/1.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36 OPR/55.0.2994.29 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.2343.52 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3449.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3463.1 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 Avast/69.1.867.101", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 OPR/56.0.3051.104", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 OPR/56.0.3051.99", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 Avast/69.1.867.100", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 OPR/56.0.3051.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 OPR/56.0.3051.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 OPR/56.0.3051.52", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 OPR/56.0.3051.52 (Edition Campaign 76)", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 ADG/11.0.2163 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 OPR/56.0.3051.116 (Edition Yx)", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.12 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.32 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.42 Safari/537.36 OPR/56.0.3051.10 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36 Avast/69.0.792.81", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36 Avast/69.0.792.82", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36 Avast/69.0.792.82", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36 Avast/69.0.792.81", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36 Avast/69.0.792.82", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.82 Safari/537.36 Vivaldi/2.0.1295.3", - "Mozilla/5.0 (CVManaged; Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36 Ionic/2.16.8", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36 Ionic/2.16.8", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3535.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 OPR/57.0.3098.106", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 OPR/57.0.3098.106", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18865", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 OPR/57.0.3098.106", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 OPR/57.0.3098.116", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 YaBrowser/18.11.1.805 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.113 Safari/537.36 Vivaldi/2.1.1337.51", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3641.400 QQBrowser/10.4.3284.400", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3676.400 QQBrowser/10.4.3505.400", - "Mozilla/5.0 ( Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 OPR/58.0.3135.132 (Edition Campaign 34)", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 OPR/58.0.3135.117", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 OPR/58.0.3135.132", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 OPR/58.0.3135.132", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 OPR/58.0.3135.127 (Edition Campaign 76)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 Kinza/5.2.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 OPR/58.0.3135.107", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 OPR/58.0.3135.127", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 OPR/58.0.3135.132", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 Avast/71.0.1037.99", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 OPR/58.0.3135.132", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.104 Safari/537.36 OPR/58.0.3195.110", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36 ygWA0Qm54YGF44mVBz8P/1.1", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36/null", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3.9600; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/6D6A5C", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36 FirePHP/4Chrome", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36 PolycomVVX-VVX_301-UA/2.31.1535989787", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36/null", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36/RbXQjqLc-54", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36/zK3yLGsE-53", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.110 Safari/537.36 Vivaldi/2.3.1440.48", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.122 Safari/537.36 Vivaldi/2.3.1440.61", - "Mozilla/5.0 (Windows NT 5.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36/null", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36 Avast/72.0.1151.82", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 YaBrowser/19.3.0.1994 (beta) Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.22 anonymized by Abelssoft 669580698", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36 AVG/72.0.718.83", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36 Avast/72.0.1151.82", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36/null", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36 Avast/72.0.1151.82", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 OPR/60.0.3255.95", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 OPR/60.0.3255.95", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 TSTTLF SergiGrossi DATALAYER", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36 FirePHP/4Chrome", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36 OPR/60.0.3255.15 (Edition beta)", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36 OPR/60.0.3255.27", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36 OPR/60.0.3255.15 (Edition beta)", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36 OPR/60.0.3255.27", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36/null", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36/WxBHdekp-51", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36/XJdO3eX0-29", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 YaBrowser/19.6.0.1226 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.91 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3739.0 Safari/537.36 Edg/75.0.109.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.66 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3788.1 Safari/537.36" - ], - "firefox": [ - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/52.15.25.665 Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/52.15.25.664 Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/52.15.25.665 Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/52.15.25.664 Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/55.0.2883.58 Chrome/55.0.2883.52 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/57.0.2987.93 Chrome/57.0.2987.88 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/57.0.2987.93 Chrome/57.0.2987.88 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/58.0.3029.113 Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/58.0.3029.113 Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 5.1; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Windows NT 5.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Windows NT 6.0; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Windows NT 6.0; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Windows NT 6.1; MNCache; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Windows NT 6.1; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Windows NT 6.1; rv:50.0) Gecko/20100101 Firefox/50.0 Cyberfox/50.0", - "Mozilla/5.0 (Windows NT 6.1; rv:50.0) Gecko/20100101 Firefox/50.0 IceDragon/50.0.0.2", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/50.0 slurp", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0 IceDragon/50.0.0.2", - "Mozilla/5.0 (Windows NT 6.2; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Windows NT 10.0; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0 FirePHP/0.7.4", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0 IceDragon/50.0.0.2", - "Mozilla/5.0 (Windows; U; Windows NT 6.1; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0.2", - "Mozilla/5.0 (Windows NT 5.1; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Windows NT 5.2; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Windows NT 6.0; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Windows NT 6.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Windows NT 6.1; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Windows NT 6.1; rv:51.0) Gecko/20100101 Goanna/2.2 Firefox/51.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0 ColdFire/1.11.208.251", - "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Windows NT 6.3; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Windows NT 10.0; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:51.0) Gecko/20100101 Firefox/51.0.1 Waterfox/51.0.1", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0.1", - "Mozilla/5.0 (Windows NT 4; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Windows NT 5.1; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Windows NT 5.2; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Windows NT 5.2; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Windows NT 6.0; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0 Cyberfox/52.0.4", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0 SeaMonkey/2.49.2", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0 SeaMonkey/2.49.3", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0 SeaMonkey/2.49.4", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20170501 Firefox/52.0 ms1", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Windows NT 10.0; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Windows NT 10.0; rv:52.0) Gecko/20100101 Firefox/52.0 Cyberfox/52.2.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0 SeaMonkey/2.49.4", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0.1 Waterfox/52.0.1", - "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0; Firefox 52.1.1 - 111312-1700920044-1.30", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0; Firefox 52.7.3 - 111512-1801120036-1.44", - "Mozilla/5.0 (Windows NT 6.1; rv:52.9) Gecko/20100101 Firefox/52.9", - "Mozilla/5.0 (Windows NT 6.1; rv:52.9) Gecko/20100101 Goanna/4.1 Firefox/52.9 PaleMoon/28.0.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.8.1", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.9.2", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.9.4", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:52.9) Gecko/20100101 Goanna/4.1 Firefox/52.9 PaleMoon/28.0.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:52.9) Gecko/20100101 Goanna/4.1 Firefox/52.9 PaleMoon/28.1.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.9.4", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.9) Gecko/20100101 Goanna/4.1 Firefox/52.9 PaleMoon/28.0.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.9) Gecko/20100101 Goanna/4.1 Firefox/52.9 PaleMoon/28.0.0b5", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:52.9) Gecko/20100101 Goanna/3.3 Firefox/52.9 PaleMoon/27.5.1", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.9.0", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:52.9) Gecko/20100101 Goanna/4.1 Firefox/52.9 Basilisk/20180905", - "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.7.1", - "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.9.4", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.9) Gecko/20100101 Goanna/3.3 Firefox/52.9 PaleMoon/27.5.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.6.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.6.2", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.7.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.9.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.9) Gecko/20100101 Goanna/4.1 Firefox/52.9 Basilisk/20180905", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.9) Gecko/20100101 Goanna/4.1 Firefox/52.9 PaleMoon/28.0.0", - "Mozilla/5.0 (Windows NT 5.1; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (Windows NT 6.1; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (Windows NT 6.3; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0 WV", - "Mozilla/5.0 (Windows NT 10.0; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (Windows NT 5.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (Windows NT 6.1; rv:54.0) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:54.0) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (Windows NT 6.3; rv:54.0) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:54.0) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (Windows NT 10.0; rv:54.0) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:54.0) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:54.0) Gecko/20100101 Firefox/54.0.0.1 Waterfox/54.0.0.1", - "Mozilla/5.0 (Windows NT 5.1; rv:55.0) Gecko/20100101 Firefox/55.0", - "Mozilla/5.0 (Windows NT 6.1; rv:55.0) Gecko/20100101 Firefox/55.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0", - "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0", - "Mozilla/5.0 (Windows NT 10.0; rv:55.0) Gecko/20100101 Firefox/55.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Goanna/4.0 Firefox/55.0 Basilisk/20171112", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.2.2 Waterfox/55.2.2", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.2.2 Waterfox/55.2.2", - "Mozilla/5.0 (Windows NT 6.1; rv:56.0) Gecko/20100101 Firefox/56.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0 Waterfox/56.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0", - "Mozilla/5.0 (Windows NT 6.3; rv:56.0) Gecko/20100101 Firefox/56.0", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0", - "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0", - "Mozilla/5.0 (Windows NT 10.0; rv:56.0) Gecko/20100101 Firefox/56.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0.3 Waterfox/56.0.3", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:56.0; Waterfox) Gecko/20100101 Firefox/56.2.3", - "Mozilla/5.0 (Windows NT 6.1; rv:57.0) Gecko/20100101 Firefox/57.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0", - "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0", - "Mozilla/5.0 (Windows NT 10.0; rv:57.0) Gecko/20100101 Firefox/57.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0", - "Mozilla/5.0 (Windows NT 6.1; rv:58.0) Gecko/20100101 Firefox/58.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0", - "Mozilla/5.0 (Windows NT 10.0; rv:58.0) Gecko/20100101 Firefox/58.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0", - "Mozilla/5.0 (Windows NT 6.1; rv:59.0) Gecko/20100101 Firefox/59.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:59.0) Gecko/20100101 Firefox/59.0", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0", - "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:59.0) Gecko/20100101 Firefox/59.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:59.0) Gecko/20100101 Firefox/59.0", - "Mozilla/5.0 (Windows NT 10.0; rv:59.0) Gecko/20100101 Firefox/59.0.2", - "Mozilla/5.0 (Windows NT 6.1; rv:60.0) Gecko/20100101 Firefox/60.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:60.0) Gecko/20100101 Firefox/60.0", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0", - "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:60.0) Gecko/20100101 Firefox/60.0", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0", - "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:60.0) Gecko/20100101 Firefox/60.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:60.0) Gecko/20100101 Firefox/60.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.6.3) Gecko/20100101 Firefox/60.6.3", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.9) Gecko/20100101 Goanna/4.2 Firefox/60.9 PaleMoon/28.5.0", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:60.9) Gecko/20100101 Goanna/4.2 Firefox/60.9 PaleMoon/28.5.0", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:60.9) Gecko/20100101 Goanna/4.2 Firefox/60.9 PaleMoon/28.5.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 Basilisk/20190327", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.2.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.2.1", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.2.2", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.3.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.4.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.9) Gecko/20100101 Goanna/4.2 Firefox/60.9 PaleMoon/28.5.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.4.0", - "Mozilla/5.0 (Windows NT 6.1; rv:61.0) Gecko/20100101 Firefox/61.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:61.0) Gecko/20100101 Firefox/61.0", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0", - "Mozilla/5.0 (Windows NT 10.0; rv:61.0) Gecko/20100101 Firefox/61.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0 IceDragon/61.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:61.0) Gecko/20100101 Firefox/61.0", - "Mozilla/5.0 (Windows NT 6.1; rv:62.0) Gecko/20100101 Firefox/62.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:62.0) Gecko/20100101 Firefox/62.0", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:62.0) Gecko/20100101 Firefox/62.0", - "Mozilla/5.0 (Windows NT 6.1; rv:63.0) Gecko/20100101 Firefox/63.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:63.0) Gecko/20100101 Firefox/63.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0 IceDragon/63.0.4", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:63.0) Gecko/20100101 Firefox/63.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0", - "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0", - "Mozilla/5.0 (Windows NT 10.0; rv:64.0) Gecko/20100101 Firefox/64.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0 IceDragon/64.0.2", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0 Waterfox/56.2.7", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:65.0) Gecko/20100101 Firefox/65.0", - "Mozilla/5.0 (Windows NT 6.1; rv:66.0) Gecko/20100101 Firefox/66.0", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:66.0) Gecko/20100101 Firefox/66.0", - "Mozilla/5.0 (Windows NT 6.2; rv:66.0) Gecko/20100101 Firefox/66.0", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:66.0) Gecko/20100101 Firefox/66.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:66.0.1) Gecko/20100101 Firefox/66.0.1", - "Mozilla/5.0 (Windows NT 6.1; rv:67.0) Gecko/20100101 Firefox/67.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:67.0) Gecko/20100101 Firefox/67.0", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:67.0) Gecko/20100101 Firefox/67.0" - ] - }, - "linux": { - "chrome": [ - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.86 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.2 Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.63 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Vivaldi/1.2.490.39", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Vivaldi/1.3.501.6", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2705.45 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686 on x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2712.8 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2739.0 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.43", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.54", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.52 (Edition beta)", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.54", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/53.0.2785.146 Safari/534.24 XiaoMi/MiuiBrowser/9.5.6", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.148 Safari/537.36 Vivaldi/1.4.589.38", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36 OPR/40.0.2308.44 (Edition beta)", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36 Slimjet/12.0.2.0", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36 Slimjet/12.0.6.0", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.90 Safari/537.36 Vivaldi/1.4.589.11", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.92 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2834.76 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.100 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 OPR/41.0.2353.46", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 Vivaldi/1.5.638.3", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/54.0.2840.68 Safari/537.31", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36 FirePHP/4Chrome", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.90 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.35 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.44 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.85", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.78 (Edition beta)", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.85", - "Mozilla/5.0 (X11; U; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.85", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 FirePHP/4Chrome", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 OPR/42.0.2393.94", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Safari/537.36 OPR/42.7.2246.114996", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Falkon/3.0.0 Chrome/56.0.2924.122 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.51 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.686 (Edition beta)", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.806", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.78 Safari/537.36", - "Mozilla/5.0 (X11; Linux armv7l) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.84 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1144", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.88 Safari/537.36 Vivaldi/1.7.735.46", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2969.89 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2970.0 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.88 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.857", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.849 (Edition beta)", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.857", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3004.3 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.41 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.54 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.57", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 YaBrowser/17.7.1.802 (beta) Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36 FirePHP/4Chrome", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36 Slimjet/15.1.6.0", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.1599.101 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.24 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.40 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.50 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.66 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 OPR/47.0.2631.34 (Edition beta)", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 OPR/47.0.2631.55", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.97 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36(KHTML, like Gecko) Chrome/61.0.3116.0 Safari/537.36 Chrome-Lighthouse", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3141.7 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.35", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.39", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.52", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.102 Safari/537.36 Vivaldi/1.93.955.38", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.102 Safari/537.36 Vivaldi/1.93.955.48", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/61.0.3163.128 Safari/534.24 XiaoMi/MiuiBrowser/9.6.0-Beta", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/61.0.3163.128 Safari/534.24 XiaoMi/MiuiBrowser/9.7.3", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/61.0.3163.128 Safari/534.24 XiaoMi/MiuiBrowser/10.8.1", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Safari/537.36", - "Mozilla/5.0 (X11; U; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3176.54 Safari/537.36 OPR/46.0.2153.299", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.9 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 OPR/49.0.2725.56", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3236.7 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.107 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Safari/537.36 EdgA/41.0.0.1561", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Safari/537.36 OPR/46.0.2246.126998", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/7A69F6", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.71 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.123 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.156 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.167 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36 FirePHP/4Chrome", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.40", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.183 Safari/537.36 Vivaldi/1.96.1137.3", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Falkon/3.0.1 Chrome/65.0.3325.230 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.93 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.106 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36 OPR/53.0.2907.37", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.106", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.57", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686 (x86_64)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3394.0 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686 (x86_64)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.0 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.60", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3398.0 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.70 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36 Slimjet/20.0.2.0", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Brave Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 OPR/56.0.3051.52", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 YaBrowser/18.11.2.501.00 (alpha) Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.17 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.675 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36 Vivaldi/2.1.1337.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (X11; U; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.8d Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 OPR/58.0.3135.79", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Safari/537.36 OPR/50.3.2426.136976", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.120 Safari/537.36 Vivaldi/2.3.1440.57", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36 OPR/51.3.2461.138727", - "Mozilla/5.0 (X11; Linux aarch64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.122 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3666.0 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 OPR/60.0.3255.59", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.84 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36 OPR/60.0.3255.15 (Edition beta)", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Safari/537.36 OPR/52.1.2517.139570", - "Mozilla/5.0 (X11; U; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3690.121 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.112 Safari/537.36 OPT/1.16.62", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36" - ], - "firefox": [ - "Mozilla/5.0 (X11; Linux i686 on x86_64; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (X11; Linux i686; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/50.0", - "Mozilla/5.0 (X11; Linux i686 on x86_64; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (X11; Linux i686; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (X11; Linux; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/52.0", - "Mozilla/5.0 (X11; Linux i686; rv:52.9) Gecko/20100101 Goanna/3.3 Firefox/52.9 PaleMoon/27.5.0", - "Mozilla/5.0 (X11; Linux i686; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.6.0", - "Mozilla/5.0 (X11; Linux i686; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.7.0", - "Mozilla/5.0 (X11; Linux i686; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.8.3", - "Mozilla/5.0 (X11; Linux i686; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.9.0", - "Mozilla/5.0 (X11; Linux i686; rv:52.9) Gecko/20100101 Goanna/4.1 Firefox/52.9 PaleMoon/28.0.0", - "Mozilla/5.0 (X11; Linux i686; rv:52.9) Gecko/20100101 Goanna/4.1 Firefox/52.9 PaleMoon/28.1.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:52.9) Gecko/20100101 Goanna/3.3 Firefox/52.9 PaleMoon/27.5.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.7.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.9.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.9.2", - "Mozilla/5.0 (X11; Linux x86_64; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.9.3", - "Mozilla/5.0 (X11; Linux x86_64; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.9.4", - "Mozilla/5.0 (X11; Linux x86_64; rv:52.9) Gecko/20100101 Goanna/4.1 Firefox/52.9 Basilisk/20181107", - "Mozilla/5.0 (X11; Linux x86_64; rv:52.9) Gecko/20100101 Goanna/4.1 Firefox/52.9 PaleMoon/28.0.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:52.9) Gecko/20100101 Goanna/4.1 Firefox/52.9 PaleMoon/28.0.1", - "Mozilla/5.0 (X11; Linux i686; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:54.0) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:55.0) Gecko/20100101 Firefox/55.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:55.0) Gecko/20100101 Goanna/4.0 Firefox/55.0 Basilisk/20171113", - "Mozilla/5.0 (X11; Linux x86_64; rv:55.0) Gecko/20100101 Goanna/4.0 Firefox/55.0 Basilisk/20171228", - "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/55.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0.4 Waterfox/56.0.4", - "Mozilla/5.0 (X11; Linux x86_64; rv:56.0; Waterfox) Gecko/20100101 Firefox/56.2.4", - "Mozilla/5.0 (X11; Linux i686; rv:57.0) Gecko/20100101 Firefox/57.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0", - "Mozilla/5.0 (X11; Linux i686; rv:58.0) Gecko/20100101 Firefox/58.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0", - "Mozilla/5.0 (X11; Linux i686; rv:59.0) Gecko/20100101 Firefox/59.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:59.0) Gecko/20100101 Firefox/59.0", - "Mozilla/5.0 (X11; Linux i686; rv:60.0) Gecko/20100101 Firefox/60.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0.1", - "Mozilla/5.0 (X11; Linux i686; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.2.0", - "Mozilla/5.0 (X11; Linux i686; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.3.0", - "Mozilla/5.0 (X11; Linux i686; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.4.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 Basilisk/20190327", - "Mozilla/5.0 (X11; Linux x86_64; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.2.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.2.1", - "Mozilla/5.0 (X11; Linux x86_64; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.3.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.4.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.4.1", - "Mozilla/5.0 (X11; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0 Andino/11.6", - "Mozilla/5.0 (X11; Linux x86_64; rv:64.0) Gecko/20100101 Firefox/64.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0", - "Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0" - ] - }, - "darwin": { - "chrome": [ - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36 QQBrowser/4.1.4132.400", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2692.49 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.63 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Vivaldi/1.2.490.39", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Vivaldi/1.2.490.39", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecho) Chrome/51.0.2704.84 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36 OPR/38.0.2220.31", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2716.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.33 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.42 (Edition beta)", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.43", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2777.85 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.52 (Edition beta)", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36 OPR/40.0.2308.54", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 OPR/41.0.2353.30 (Edition beta)", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 OPR/41.0.2353.30 (Edition beta)", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36 OPR/41.0.2353.46", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2844.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36 OPR/42.0.2393.85", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 OPR/42.0.2393.517", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 OPR/42.0.2393.94", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.98 Safari/537.36 Vivaldi/1.6.689.40", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2909.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_22_79) AppleWebKit/531.73.20 (KHTML, like Gecko) Chrome/55.1.6284.1911 Safari/532.03 Edge/36.07338", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_20_77) AppleWebKit/531.71.18 (KHTML, like Gecko) Chrome/55.1.6997.1625 Safari/532.00 Edge/36.04460", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2885.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2913.3 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.14 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.28 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.28 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.806", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36 OPR/43.0.2442.806", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1165", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1165", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1144", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1165", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1165", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 YaBrowser/17.3.1.838 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2986.42 Safari/537.36", - "Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_47_84) AppleWebKit/532.88.35 (KHTML, like Gecko) Chrome/56.2.7798.2426 Safari/533.18 Edge/36.12482", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16.5) AppleWebKit/603.4.8 (KHTML, like Gecko) Chrome/57.0.2844.85 Safari/603.4.8", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2959.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2971.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 Kinza/3.8.2", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/603.1.30 (KHTML, like Gecko) Chrome/57.0.2987.133 Version/10.1 Safari/603.1.30", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.137 YaBrowser/17.4.1.718 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.137 YaBrowser/17.4.1.982 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.88 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 ICFSP KMD", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 OPR/44.0.2510.857", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_30_83) AppleWebKit/532.99.42 (KHTML, like Gecko) Chrome/57.4.0146.5318 Safari/534.59 Edge/34.65970", - "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_45_97) AppleWebKit/533.93.56 (KHTML, like Gecko) Chrome/57.5.0506.6878 Safari/530.64 Edge/34.70475", - "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_46_99) AppleWebKit/533.05.58 (KHTML, like Gecko) Chrome/57.5.0741.6014 Safari/530.65 Edge/34.71925", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.2999.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3019.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 OPR/45.0.2552.898", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.19 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.33 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.41 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.41 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.54 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36 OPR/45.0.2552.812", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/603.1.30 (KHTML, like Gecko) Chrome/58.0.3029.96 Version/10.1 Safari/603.1.30", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3047.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.114 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.57", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.39", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.57", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.134 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.29 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.36 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.47 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.71 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36 OPR/46.0.2597.19 (Edition beta)", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3083.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3084.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3089.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3090.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3108.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3108.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36 QQBrowser/4.3.4986.400", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36 QQBrowser/4.3.4986.400", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.24 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.32 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36 OPR/47.0.2631.55", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 OPR/47.0.2631.71", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3118.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3129.4 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3147.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.35", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.50", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 OPR/48.0.2685.39", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.39 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.49 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36 OPR/48.0.2685.22 (Edition beta)", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.12; en-US) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3192.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.45 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36 OPR/49.0.2725.31 (Edition beta)", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3086.96 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3218.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 YaBrowser/18.1.1.841 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.59 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.70 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/E58566", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/62BFE7", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.90 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3253.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36 OPR/51.0.2830.26", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.167 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36 OPR/51.0.2830.55", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.71 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3309.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3309.6 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3322.3 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3323.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3324.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36 OPR/52.0.2871.27 (Edition beta)", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.64", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 UserAgent-Cube", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.64", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.99", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.183 Safari/537.36 Vivaldi/1.96.1147.42", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.88 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/608.1.10 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.57", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.57", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36 OPR/53.0.2907.68", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.66 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3393.4 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3393.4 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.10 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.103 YaBrowser/18.7.1.855 Yowser/2.5 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.40 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.71", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.64", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.64", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.7", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3415.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3422.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3432.3 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3432.3 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36 OPR/55.0.2994.44", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36 OPR/55.0.2994.61", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.15 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) adbeat.com/policy AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) adbeat.com/policy AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36 OPR/55.0.2994.29 (Edition beta)", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3444.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3451.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3451.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3480.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 OPR/56.0.3051.104", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36 FirePHP/4Chrome", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3563.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.27 Safari/537.36 Vivaldi/2.2.1360.4", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.53 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13.6; U; en-NZ) AppleWebKit/605.1.15 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/605.1.15 OPR/54.0.2952.71", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 OPR/58.0.3135.53", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 OPR/58.0.3135.132", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3606.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36 FirePHP/4Chrome", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36 encors/0.0.6", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36 (prophototech)pp_dev", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 OPR/60.0.3255.83", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 OPR/60.0.3255.59", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.142 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.46 Safari/537.36 OPR/60.0.3254.0 (Edition developer)", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36 OPR/60.0.3255.15 (Edition beta)", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36 OPR/60.0.3255.27", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.28 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3783.0 Safari/537.36" - ], - "firefox": [ - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:51.0) Gecko/20100101 Firefox/51.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:52.0) Gecko/20100101 Firefox/52.0 SeaMonkey/2.49.4", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:52.0) Gecko/20100101 Firefox/52.0 SeaMonkey/2.49.5", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:52.0) Gecko/20100101 Firefox/52.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:52.9) Gecko/20100101 Goanna/3.4 Firefox/52.9 PaleMoon/27.9.4", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:52.9) Gecko/20100101 Goanna/4.1 Firefox/52.9 PaleMoon/28.0.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:53.0) Gecko/20100101 Firefox/53.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6; rv:54.0) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:54.0) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:54.0) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:54.0) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:54.0) Gecko/20100101 Firefox/54.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:55.0) Gecko/20100101 Firefox/55.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:55.0) Gecko/20100101 Firefox/55.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:55.0) Gecko/20100101 Firefox/55.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:55.0) Gecko/20100101 Firefox/55.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:55.0) Gecko/20100101 Firefox/55.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:55.0) Gecko/20100101 Firefox/55.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:56.0) Gecko/20100101 Firefox/56.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:56.0) Gecko/20100101 Firefox/56.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:56.0) Gecko/20100101 Firefox/56.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:56.0) Gecko/20100101 Firefox/56.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:56.0) Gecko/20100101 Firefox/56.0.4 Waterfox/56.0.4", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:57.0) Gecko/20100101 Firefox/57.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:57.0) Gecko/20100101 Firefox/57.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:57.0) Gecko/20100101 Firefox/57.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:57.0) Gecko/20100101 Firefox/57.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:57.0) Gecko/20100101 Firefox/57.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:58.0) Gecko/20100101 Firefox/58.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:58.0) Gecko/20100101 Firefox/58.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:58.0) Gecko/20100101 Firefox/58.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:59.0) Gecko/20100101 Firefox/59.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:59.0) Gecko/20100101 Firefox/59.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:59.0) Gecko/20100101 Firefox/59.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:60.0) Gecko/20100101 Firefox/60.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:60.0) Gecko/20100101 Firefox/60.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:60.0) Gecko/20100101 Firefox/60.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.2.2", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.3.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.4.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:60.9) Gecko/20100101 Goanna/4.1 Firefox/60.9 PaleMoon/28.4.1", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:61.0) Gecko/20100101 Firefox/61.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:61.0) Gecko/20100101 Firefox/61.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:61.0) Gecko/20100101 Firefox/61.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:61.0) Gecko/20100101 Firefox/61.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:62.0) Gecko/20100101 Firefox/62.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:62.0) Gecko/20100101 Firefox/62.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:62.0) Gecko/20100101 Firefox/62.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:62.0) Gecko/20100101 Firefox/62.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:63.0) Gecko/20100101 Firefox/63.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:63.0) Gecko/20100101 Firefox/63.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:64.0) Gecko/20100101 Firefox/64.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:64.0) Gecko/20100101 Firefox/64.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:65.0) Gecko/20100101 Firefox/65.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:65.0) Gecko/20100101 Firefox/65.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:65.0) Gecko/20100101 Firefox/65.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:65.0) Gecko/20100101 Firefox/65.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:66.0) Gecko/20100101 Firefox/66.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:66.0) Gecko/20100101 Firefox/66.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:66.0) Gecko/20100101 Firefox/66.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:66.0) Gecko/20100101 Firefox/66.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:67.0) Gecko/20100101 Firefox/67.0", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:67.0) Gecko/20100101 Firefox/67.0" - ] - } - }, - "mobile": { - "android": { - "chrome": [ - "Mozilla/5.0 (Linux; U; Android 5.1; zh-cn; Build/LMY47D ) AppleWebKit/534.30 (KHTML,like Gecko) Version/4.0 Chrome/50.0.0.0 Mobile Safari/534.30 GIONEE-GN9010/GN9010 RV/5.0.16", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-cn; Build/MRA58K ) AppleWebKit/534.30 (KHTML,like Gecko) Version/4.0 Chrome/50.0.0.0 Mobile Safari/534.30 GIONEE-S9/S9 RV/5.0.17", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.1276.852 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2005.618 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; F5 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/50.0.2661.86 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; F100L Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/50.0.2661.86 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.1; Micromax A110Q Build/JOP40D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-T230NU Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; SCH-I545 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; SM-N915F Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; 6045O Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-S920L Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-T535 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; C6743 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LG-K330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGLS675 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGMS330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-E700F Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320M Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J500FN Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; VS425PP Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A1601 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI CUN-L22 Build/HUAWEICUN-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI LUA-U22 Build/HUAWEILUA-U22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI LYO-L01 Build/HUAWEILYO-L01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Lenovo A1010a20 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Z958 Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 4060W Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5056N Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Alcatel_5098O Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; HTC Desire 530 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-K220 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS450 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGMS428 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G930A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A800F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T2 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920T Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G930V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G935F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J320F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J320VPP Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S120VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-T800 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Wileyfox Spark + Build/MMB29X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1609 Build/MPI24.241-2.35-1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1609 Build/MPIS24.241-2.35-1-17) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1609 Build/MPIS24.241-2.35-1-13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1609 Build/MPIS24.241-2.35-1-3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; ZTE Blade V770 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ALE-L21 Build/HuaweiALE-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; H60-L04 Build/HDH60-L04) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo A7020a48 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-H810 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A1601 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Mobile Safari/537.36 OPR/37.0.2192.112031", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.5586.214 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.8814.926 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.9067.698 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.9370.394 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.1345.464 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.1785.251 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.1948.189 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; LG-D605 Build/KTU84Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2693.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SAMSUNG SM-G850F/G850FXXS2CQE3 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-G531H Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-J105B Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-J120F Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-J200GU Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-J320FN Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-J700F Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SAMSUNG-SM-J320A Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-A520W Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G550T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G550T Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G610F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G900F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G920F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G920T Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.0 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G935A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-J510FN Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-J700F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-J700T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-N910C Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-N920V Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G935A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.0 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-A710F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.2 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G920F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G920R4 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G920T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.0 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G925F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.0 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G930F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G930P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.0 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G930T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.0 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G930T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G930VL Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G935F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.0 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G935F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G935T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G955U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J327A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.2 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J327AZ Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.2 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.2 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J530F/J530FXXU1AQF5 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.2 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J530F/J530FXXU1AQF5 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J727P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.0 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J727T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.2 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-N920I Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-P585M Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.2 Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G891A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.0 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G925A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.0 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G935A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.0 Chrome/51.0.2704.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; HUAWEI Y330-U01 Build/HuaweiY330-U01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-T230NU Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; E2053 Build/25.0.A.2.31) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; LGL22C Build/LRX21Y) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-S920L Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGMS330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LS-5014 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Nexus 9 Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G360G Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J700M Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; VS880 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Y538 Build/HuaweiY538) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Z959 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; 0PM92 Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; MotoG3 Build/MPI24.107-55) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G920A Build/MMB29K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G930VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G930VL Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo Y66L Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36 lite baiduboxapp/3.6.5.11 (Baidu; P1 6.0.1)", - "Mozilla/5.0 (Linux; Android 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Focus/1.3 Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Focus/4.0.1 Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo K10a40 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-H735 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LGMS631 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.3803.648 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.6700.709 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.1349.850 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Build/R62-9901.77.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2706.0 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; M6SPlus Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/52.0.2743.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; GT-P5210 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; ara Build/KTU84Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-S820L Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900V Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; 5054N Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGLS751 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGMS330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGMS631 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-N910A Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-T337A Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J500FN Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Z828 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M153 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGL58VL Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGL58VL Build/MXB48T; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGMS428 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MTC20F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920V Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G935T Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700T Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N920T Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1254 Build/MCG24.251-5-5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; CRO-U00 Build/HUAWEICRO-U00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LGLS770 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; S9 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; SOV32 Build/32.1.C.0.364) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGUS992 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Nexus 6P Build/NRD90T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; D6503 Build/17.1.1.A.0.402) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; vivo X3S Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; Che2-L11 Build/HonorChe2-L11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; RCT6773W22 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; HUAWEI H892L Build/HuaweiH892L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; XT1080 Build/SU6-7.7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; LGL22C Build/LRX21Y) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; HTC One_M8 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-S978L Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900F Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGMS330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G530T1 Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J200GU Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; 4017X Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI ALE-L04 Build/HuaweiALE-L04) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; ZTE Blade L5 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 0PM92 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-K540 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M151 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M153 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS450 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS676 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G930A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G935A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900T Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900W8 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920R4 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo 1603 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; VS835 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z798BL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z837VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; EVA-L09 Build/HUAWEIEVA-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-K350 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 4.4.4; zh-cn; OPPO R7 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.9.3", - "Mozilla/5.0 (Linux; U; Android 4.4.4; zh-cn; R8107 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.4.9", - "Mozilla/5.0 (Linux; U; Android 5.0; zh-cn; OPPO R7Plus Build/LRX21M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.7.1", - "Mozilla/5.0 (Linux; U; Android 5.1.1; zh-cn; OPPO A33 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.7.2", - "Mozilla/5.0 (Linux; U; Android 5.1.1; zh-cn; OPPO A33m Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.4.9", - "Mozilla/5.0 (Linux; U; Android 5.1.1; zh-cn; OPPO R7sm Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.3.9", - "Mozilla/5.0 (Linux; U; Android 5.1.1; zh-cn; R7Plusm Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.4.9", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-cn; OPPO A37m Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.4.9", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-cn; OPPO A59m Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.4.9", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-cn; OPPO A59s Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.3.9", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-cn; OPPO A59s Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.8.4", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-cn; OPPO R9m Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.3.9", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-cn; OPPO R9m Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.4.9", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-cn; OPPO R9tm Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.5.2beta", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-cn; OPPO R9tm Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.9.3", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; OPPO A57 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.6.5.3", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; OPPO A57t Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.6.5.3", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; OPPO A57t Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.7.1", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; OPPO A57t Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/10.5.0.1", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; OPPO R9s Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.4.9", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; OPPO R9s Plus Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.4.9", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; OPPO R9sk Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.4.9", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; OPPO R9st Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.4.9", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-cn; OPPO A73 Build/N6F26Q) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.4.1", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-cn; OPPO A77t Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.3.9", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-cn; OPPO A79 Build/N6F26Q) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.6.5.3", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-cn; OPPO A83 Build/N6F26Q) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.8.4", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-cn; OPPO R11 Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.3.8", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-cn; OPPO R11 Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.4.9", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-cn; OPPO R11s Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/10.5.0.1", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-cn; OPPO R11st Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.8.1", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-cn; OPPO R11t Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.6.5.3", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-tw; OPPO A83t Build/N6F26Q) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.6.5.3", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; OPPO PACM00 Build/O11019) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.7.1", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; PBAT00 Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/10.5.0.1", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; PBCM30 Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.9.2", - "Mozilla/5.0 (Linux; U; Android 4.4.4; zh-cn; 2014812 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.3.10", - "Mozilla/5.0 (Linux; U; Android 4.4.4; zh-cn; 2014813 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.3.2", - "Mozilla/5.0 (Linux; U; Android 4.4.4; zh-cn; HM 1S Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/8.7.7", - "Mozilla/5.0 (Linux; U; Android 4.4.4; zh-cn; HM 2A Build/KTU84Q) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.3.10", - "Mozilla/5.0 (Linux; U; Android 4.4.4; zh-cn; MI 3 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/8.5.7", - "Mozilla/5.0 (Linux; U; Android 5.0.2; it-it; Redmi Note 2 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/8.5.9", - "Mozilla/5.0 (Linux; U; Android 5.1.1; en-us; Redmi 3 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/8.5.14", - "Mozilla/5.0 (Linux; U; Android 5.1.1; zh-cn; Redmi 3 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/8.5.14", - "Mozilla/5.0 (Linux; U; Android 6.0.1; en-us; Redmi Note 4 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/8.5.7", - "Mozilla/5.0 (Linux; U; Android 6.0.1; id-id; Redmi Note 4 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/8.5.7", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; MI NOTE LTE Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/8.8.7", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; Redmi 3S Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/8.9.5", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; Redmi 4X Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.0.3 tae_sdk_a_2.1.0 AliApp(BC/2.1.0)", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; Redmi Note 3 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.0.3", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; Redmi Note 4X Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.0.3", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-cn; Redmi Note 4 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.3.10", - "Mozilla/5.0 (Linux; U; Android 7.0; en-us; MI 5 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.0.3", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; MI 5 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/8.7.8", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; MI 5 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.3.10", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; MI 5s Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.2.5", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; Redmi Note 4X Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.3.10", - "Mozilla/5.0 (Linux; U; Android 7.1.1; en-us; MI MAX 2 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.2.8", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-cn) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 QuickCast", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-cn; Mi Note 3 Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.4.12", - "Mozilla/5.0 (Linux; U; Android 8.1.0; en-us; Redmi Note 5 Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.146 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.4.13", - "Mozilla/5.0 (Linux; Android 5.1.1; Redmi Note 3 Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.49 Mobile MQQBrowser/6.2 TBS/043613 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; PRO 6 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.49 Mobile MQQBrowser/6.2 TBS/043128 Safari/537.36 MicroMessenger/6.5.7.1041 NetType/WIFI Language/zh_CN", - "Mozilla/5.0 (Linux; Android 7.1.1; TA-1000 Build/NMF26F; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.49 Mobile MQQBrowser/6.2 TBS/043128 Safari/537.36 MicroMessenger/6.5.7.1041 NetType/WIFI Language/zh_CN", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.4328.512 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.6160.171 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.7483.442 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.7889.219 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.3; GT-I9300 Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; DROID RAZR HD Build/KDA20.62-15.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; GT-N7100 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; Lenovo A328 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; Winmax TX5 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; 6039A Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Coolpad 3622A Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LG-K330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGMS330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI CUN-L21 Build/HUAWEICUN-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; D5803 Build/23.5.A.1.291) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; HTC Desire 626s Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGMS428 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A300FU Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G935F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G935V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; HUAWEI GRA-L09 Build/HUAWEIGRA-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.1.2; LG-E425f Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; Che2-L11 Build/HonorChe2-L11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; LG-D958 Build/KOT49I.D95820c) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; VF685 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; N817 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; XT1080 Build/SU6-7.7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; GT-I9506 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36 OPR/41.2.2246.111806", - "Mozilla/5.0 (Linux; Android 5.0.1; LG-H326 Build/LRX21Y) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; LGL22C Build/LRX21Y) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; SCH-I545 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-A300H Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LG-K330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL62VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGLS675 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGMS330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Mi-4c Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J120H Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J700M Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; vivo V3 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; C6740N Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI CUN-L21 Build/HUAWEICUN-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI LYO-L02 Build/HUAWEILYO-L02) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; XT1049 Build/LPA23.12-39-R-19) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; H1611 Build/HUAWEIH1611) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; HTC Desire 530 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGMS428 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; ONE E1003 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Redmi Note 4 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G920AZ Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G930A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920K Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G930F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G930V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700T Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36 OPR/41.2.2246.111806", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N920T Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S903VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1635-01 Build/MCOS24.104-35-1-9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; CPH1609 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; EVA-L09 Build/HUAWEIEVA-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Redmi Note 4 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1; Pixel Build/NDE63V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.4393.791 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.5729.588 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.8292.280 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.9938.657 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; VFD 500 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.77 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; VFD 500 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.77 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Mobile Sa fari/537.36", - "Mozilla/5.0 (Linux; Android 4.1.2; GT-I8190 Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.1.2; SCH-S968C Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.1; HUAWEI G700-U10 Build/HuaweiG700-U10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; GT-P5113 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; GT-S7580 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.3; GT-I9300 Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; 4009E Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; A464BG Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; ASUS_T00J-D Build/KVT49L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; Blade L2 Plus Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; D2203 Build/18.4.C.2.12) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; GT-I9301I Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; HTC Desire 510 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; InFocus M530 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; Lenovo A536 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SCH-I545 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-G900W8 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-T230NU Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-N910G Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-T560 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; Z970 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4; LGL34C Build/KRT16S.L34CV10c) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; ALE-L23 Build/HuaweiALE-L23) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; GT-I9500 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; SCH-I545 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; Lenovo S90-A Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-G850FQ Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-S920L Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900I Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; 5054N Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A37f Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A571VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Aquaris E5 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; C6743 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; C6903 Build/14.6.A.1.236) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LG-K330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL61AL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL82VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGMS330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-G530AZ Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G360T1 Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G530T Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G925K Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J120F Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J120H Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J120ZN Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J120ZN Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36 OPR/42.7.2246.114996", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J200G Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J200GU Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320FN Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320M Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-T285 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-T677V Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; VS425PP Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Z828 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Z959 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A33w Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; GN5001S Build/LMY47D; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HTC Desire 626s Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HTCD100LVWPP Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI CUN-L21 Build/HUAWEICUN-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI LUA-L21 Build/HUAWEILUA-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI TAG-L01 Build/HUAWEITAG-L01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; iris 750 Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Lenovo P1ma40 Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; VFD 200 Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36 OPR/42.7.2246.114996", - "Mozilla/5.0 (Linux; Android 5.1; XT1254 Build/SU4TL-49) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Z958 Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 0PM92 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5056I Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5056N Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; ASUS_Z010D Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; D5803 Build/23.5.A.1.291) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; HTC 10 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; HTCD160LVWPP Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; HUAWEI RIO-AL00 Build/HuaweiRIO-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Le X526 Build/IIXOSOP5801910121S) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-H820 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS676 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS775 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGMS428 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGMS550 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGUS110 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; MI 5 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; MI MAX Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Moto G (4) Build/MPJ24.139-64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; MotoG3 Build/MPIS24.107-55-2-5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 6 Build/MOB31S) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; OPPO A57t Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36 rabbit/1.0 baiduboxapp/7.1 (Baidu; P1 6.0.1)", - "Mozilla/5.0 (Linux; Android 6.0.1; Redmi Note 3 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G900A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G920A Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G920AZ Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G935A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A300FU Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A500F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A520F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36 OPR/42.7.2246.114996", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532F Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532G Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532G Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36 OPT/1.10.37", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G570Y Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G610F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G610F Build/MMB29K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900I Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900T Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900W8 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920I Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920T Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920V Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G925F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G930V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G935F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G935P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G935P Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36 BingWeb/6.5.25183290", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G935V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J320VPP Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500H Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500H Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J510FN Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700F Build/MMB29K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700T Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J710F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J710MN Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N920P Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N920T Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S120VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-T550 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-T815 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; VS500PP Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Wileyfox Spark + Build/MMB29X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36 OPR/42.7.2246.114996", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1635-02 Build/MPNS24.104-49-4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z956 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; ZTE Blade A462 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; 5045T Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; A75 MAX Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ALE-L21 Build/HuaweiALE-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ASUS_X008DA Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; F100S Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; GN5005L Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; GN8003 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; HTC One M9 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; HTC One_M8 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; HUAWEI CAZ-TL20 Build/HUAWEICAZ-TL20; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36 rabbit/1.0 baiduboxapp/7.1 (Baidu; P1 6.0)", - "Mozilla/5.0 (Linux; Android 6.0; HUAWEI MLA-TL10 Build/HUAWEIMLA-TL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; HUAWEI VNS-L21 Build/HUAWEIVNS-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-H343 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-K350 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LGUS991 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Telenor_Smart_4G Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-H918 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M150 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M150 Build/NRD90U; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36 BingWeb/8.8.26218802", - "Mozilla/5.0 (Linux; Android 7.0; LG-M210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M257 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M430 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL63BL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL83BL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGLS775 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP450 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS550 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS550 Build/NRD90U; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGUS215 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGUS997 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; MI MAX Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto G (4) Build/NPJ25.93-14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto G (4) Build/NPJS25.93-14-13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto G (5) Build/NPP25.137-33) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Nexus 6 Build/NBD90Z) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; PRA-LA1 Build/HUAWEIPRA-LA1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G928C Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G950F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-N920P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VS835 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; A574BL Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; A574BL Build/NMF26F; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Coolpad 3632A Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; F5121 Build/N4F26I12) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N9560 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; ONEPLUS A3003 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; OPPO A77 Build/NMF26F; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36 baiduboxapp/8.1 (Baidu; P1 7.1.1)", - "Mozilla/5.0 (Linux; Android 7.1.1; Pixel XL Build/NOF27B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 YaBrowser/17.1.0.412.00 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.3364.543 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.4704.451 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; Lenovo P70-t Build/KOT49H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/56.0.2924.116 Mobile Safari/537.36 SogouMSE,SogouMobileBrowser/5.12.12", - "Mozilla/5.0 (Linux; Android 5.1.1; vivo X7 Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/56.0.2924.116 Mobile Safari/537.36 SogouMSE,SogouMobileBrowser/5.16.8", - "Mozilla/5.0 (Linux; Android 6.0; Redmi Note 4 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/56.0.2924.116 Mobile Safari/537.36 SogouMSE,SogouMobileBrowser/5.13.5", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-T560 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.78 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 7041X Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.3; ZTE Grand S II LTE Build/JLS36C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; ASUS_T00J Build/KVT49L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; GT-I9195 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; GT-I9301I Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; GT-P5210 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; Lenovo A536 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; LGLS660 Build/KOT49I.LS660ZV6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-G313MU Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SPH-L900 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; VK810 4G Build/KOT49I.VK81024A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; XT907 Build/KDA20.62-15.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; GT-I9060I Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; GT-I9300I Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; N817 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-J110H Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-S820L Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-T116NY Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; LG-D838 Build/LRX21Y) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; Lenovo A5000 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; Lenovo A6000 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; NX511J Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; S455 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SAMSUNG SM-A7000 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SAMSUNG SM-G920F Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-G530H Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SAMSUNG SM-N900A Build/LRX21V) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-N9005 Build/LRX21V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A37f Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A571VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; C6743 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; C6902 Build/14.6.A.1.236) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Coolpad 3622A Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; GT-I9301I Build/LMY48Y) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; KYOCERA-C6742A Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Lenovo A2020a40 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL44VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGLS675 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGMS330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-G530R4 Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-J120FN Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-J200GU Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-J320FN Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-G530AZ Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-J3119 Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-A8000 Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G530T Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G800F Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J100VPP Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J105B Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J200GU Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J200M Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320FN Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J500FN Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J700F Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; VS880PP Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Y538 Build/HuaweiY538) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Z959 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; BRAVIS_TREND Build/LMY47D; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HTC Desire 626 Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI CUN-L21 Build/HUAWEICUN-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; SAMSUNG HUAWEI CUN-L21 Build/HUAWEICUN-L21) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; XT1058 Build/LPAS23.12-21.7-1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Z812 Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; ZTE C880A Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5056N Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; A0001 Build/MHC19Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Aquaris M5 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; ASUS_T00N Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; ASUS_Z00ED Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; HTC Desire 530 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; HTC Desire 626s Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-K520 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS450 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGMS428 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; MI 5s Plus Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Moto G Play Build/MPIS24.241-15.3-16) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; MotoG3 Build/MPIS24.107-55-2-17) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; N9519 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; RCT6873W42 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-A500F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G532F Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G532G Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G532M Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G900R6 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G900T Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-J500F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-J500M Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G930A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-J120AZ Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SHV35 Build/S6020) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A300FU Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A500FU Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A520F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A520W Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A710F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A9000 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532F Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G570F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920S Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920V Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G925F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G928G Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G928V Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G930F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G930V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G935F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G935F Build/MMB29K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G935V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J320VPP Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500H Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J510FN Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J710F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J710GN Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S727VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S727VL Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S727VL Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/56.0.2924.87 Mobile Safari/537.36 SamsungBrowser/CrossApp/0.1.89", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1254 Build/MCG24.251-5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z832 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z956 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z981 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ALE-L21 Build/HuaweiALE-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ELUGA Prim Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; EVA-L09 Build/HUAWEIEVA-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; H60-L12 Build/HDH60-L12) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; HUAWEI CRR-TL00 Build/HUAWEICRR-TL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; HUAWEI VNS-L21 Build/HUAWEIVNS-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; HUAWEI VNS-L31 Build/HUAWEIVNS-L31) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Le X507 Build/DHXOSOP5801911241S) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo A7000-a Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo TB3-730F Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-D855 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-X230 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; VFD 1100 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ZTE BLADE A510 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; 5049Z Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; 5058 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Alcatel 5085C Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; F8331 Build/39.2.A.0.417) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-H918 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-K428 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-LS777 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL158VL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Nexus 6 Build/NBD92D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-A320F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-A510F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-A520W Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G610M Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G891A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G892U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G903W Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G920F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G925A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G925F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G925F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G928A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G928F/G928FXXU3CQF3 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G930V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G935A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G935F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G935F/XXS1DQIM Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G935P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G955U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G955W Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G9350 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J710GN Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J710MN Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J727T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J727T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-N920V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-S737TL Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-T815Y Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-J327A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-J327AZ Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930T Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327VPP Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J530F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VS987 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; WAS-LX1 Build/HUAWEIWAS-LX1) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; XT1650 Build/NCL25.86-11-4-6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; GIONEE S10C Build/NMF26F; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQ26.69-64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQ26.69-46) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NDQ26.69-64-11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NDQ26.69-64-9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NDQS26.69-64-11-2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NDQS26.69-64-8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NDQS26.69-64-2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 5X Build/N4F26I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 5X Build/N4F26T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Pixel XL Build/NOF27B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SAMSUNG SM-J320AZ Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SAMSUNG SM-N950U Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.4 Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z835 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z899VL Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z971 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z982 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.1.1; en-us; Moto E (4) Build/NCQ26.69-64) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/56.0.2924.87 Mobile Safari/537.36 Hawk/QuickBrowser/2.3.0.22166", - "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.3334.705 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.5400.45 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.1.1; M040 Build/JRO03H) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/57.0.2987.108 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-S920L Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.108 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 4.4.4; zh-CN; SM-G7200 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.0.2.982 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1.1; en-US; SM-N910C Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.10.5.1171 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1.1; zh-CN; OPPO R7sm Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/11.8.3.963 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1.1; zh-CN; vivo X7 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/11.9.7.977 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-m1 note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.7.110-2019010410 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-m1 note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.8.110-2019031217 UWS/2.15.0.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-m2 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.5.110-2018110721 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-m2 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.6.110-2018121017 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-m2 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.7.110-2019010410 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-m2 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.8.110-2019031217 UWS/2.15.0.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-m2 note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.5.110-2018110721 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-m2 note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.7.110-2019010410 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-m2 note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.8.110-2019031217 UWS/2.15.0.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-m3 note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.5.110-2018110721 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-m3 note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.6.110-2018121017 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-m3 note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.7.110-2019010410 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-m3 note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.8.110-2019031217 UWS/2.15.0.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-M3s Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.5.110-2018110721 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-M3s Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.6.110-2018121017 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-M3s Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.7.110-2019010410 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-M3s Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.8.110-2019031217 UWS/2.15.0.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-M3s Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.9.7 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-MX4 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.7.110-2019010410 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; MZ-MX5 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.5.110-2018110721 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; OPPO R9m Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.0.3.983 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; OPPO R9tm Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.2.5.1005 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-CN; vivo X6D Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/11.8.3.963 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0.1; en-US; SM-G532G Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.9.3.1144 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-CN; MZ-PRO 6 Plus Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.8.110-2019031217 UWS/2.15.0.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-CN; NX569H Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.0.3.983 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-CN; OPPO R9s Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/11.8.4.964 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-CN; Redmi 4 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/11.8.2.962 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; en-US; M5c Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.8.8.1140 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-M3 Max Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.7.110-2019010410 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-M3 Max Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.8.110-2019031217 UWS/2.15.0.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-M5 Note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.5.110-2018110721 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-M5 Note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.6.110-2018121017 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-M5 Note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.7.110-2019010410 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-M5 Note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.8.110-2019031217 UWS/2.15.0.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-M5c Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.5.110-2018110721 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-M5c Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.6.110-2018121017 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-M5c Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.7.110-2019010410 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-M5c Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.8.110-2019031217 UWS/2.15.0.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-M5s Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.5.110-2018110721 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-M5s Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.6.110-2018121017 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-M5s Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.7.110-2019010410 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-M5s Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.8.110-2019031217 UWS/2.15.0.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-MEIZU_M5 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.5.110-2018110721 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-MEIZU_M5 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.6.110-2018121017 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-MEIZU_M5 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.7.110-2019010410 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-MEIZU_M5 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.8.110-2019031217 UWS/2.15.0.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-MX6 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.7.110-2019010410 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-PRO 6 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.8.110-2019031217 UWS/2.15.0.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-U10 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.5.110-2018110721 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-U10 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.6.110-2018121017 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-U10 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.7.110-2019010410 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-U10 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.8.110-2019031217 UWS/2.15.0.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-U20 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.5.110-2018110721 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-U20 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.6.110-2018121017 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; MZ-U20 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.7.110-2019010410 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; Redmi Note 4X Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/11.8.2.962 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.0.0; zh-CN; MZ-PRO 6 Plus Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.5.110-2018110721 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.0; en-US; Moto C Plus Build/NRD90M.03.045) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.10.3.1199 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.0; en-US; Redmi Note 4 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.10.2.1164 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.0; en-US; SM-G610F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.9.3.1144 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-CN; Mi-4c Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/11.8.2.962 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-CN; MZ-M5 Note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.5.110-2018110721 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-CN; MZ-M5 Note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.6.110-2018121017 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-CN; MZ-M5 Note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.7.110-2019010410 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-CN; MZ-M5 Note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.8.110-2019031217 UWS/2.15.0.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-CN; MZ-M5 Note Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.9.6 UWS/2.15.0.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.1.1; en-US; Z851M Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.5.0.1109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.1.1; en-US; Z899VL Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.5.0.1109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-CN; Mi Note 3 Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.1.4.994 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-CN; MZ-MX6 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 MZBrowser/7.8.110-2019031217 UWS/2.15.0.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.0.0; en-US; SM-G950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.9.7.1158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.0.0; zh-CN; BLN-AL10 Build/HONORBLN-AL10) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.2.4.1004 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.1.0; en-US; Redmi Note 5 Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.11.5.1185 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.1.0; en-US; SM-J730G Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.10.0.1163 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.1.0; en-US; SM-J730G Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.11.2.1184 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-CN; ALP-AL00 Build/HUAWEIALP-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/11.8.3.963 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 9; zh-CN; COL-AL10 Build/HUAWEICOL-AL10) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.4.3.1023 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 9; zh-CN; ONEPLUS A5000 Build/PKQ1.180716.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 Quark/3.0.0.942 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Pixel XL Build/NPG05E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.1.2; LG-D680 Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; GT-I8200 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; HTC Desire 310 dual sim Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; HTC One mini 2 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SIGMA Build/KVT49L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-T210R Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; A462C Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; E2104 Build/24.0.A.5.14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; GT-I9060I Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-S820L Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; LG-D337 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-G530H Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; VK810 4G Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; RCT6303W87DK Build/LRX21M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Alcatel_4060A Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Lenovo A6020a40 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Lenovo A6020a46 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LG-H634 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL82VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGLS675 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Redmi 3 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Redmi 3 Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G531H Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J100VPP Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J200GU Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J500F Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Y538 Build/HuaweiY538) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A1601 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HTC Desire 626s Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI TAG-L22 Build/HUAWEITAG-L22; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 Mobile Safari/537.36 MicroMessenger/6.5.7.1041 NetType/4G Language/en", - "Mozilla/5.0 (Linux; Android 5.1; N9521 Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Z812 Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5056N Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; D6653 Build/23.5.A.1.291) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGMS428 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; MotoG3 Build/MPIS24.107-55-2-5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Redmi Note 3 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Redmi Note 4 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-N920A Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A310F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920I Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G925F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500M Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910C Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910T3 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N920V Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S120VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-T715Y Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-T810 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; STV100-2 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z956 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z981 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; ZTE A2017G Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; F3111 Build/33.2.A.4.70) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo A7020a48 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo K10a40 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-H815 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; VFD 1100 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; vivo 1601 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; XT1069 Build/MPB24.65-34-3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; XT1706 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-K520 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; ONEPLUS A3000 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G935A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G925F Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VS995 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Plus Build/NDRS26.58-33-2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto G (5S) Build/NPPS26.102-49-11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto G (5S) Plus Build/NPSS26.116-64-11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 5X Build/N4F26T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Nexus 5X Build/N2G47F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 4.2.1; zh-cn; HUAWEI G610-U00 Build/HuaweiG610-U00) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 4.4.2; zh-cn; V861 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.5 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.0.2; zh-cn; Redmi Note 2 Build/LRX22B) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.5 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.0.2; zh-cn; vivo Y51A Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.1 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-cn; M3s Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.9 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-cn; OPPO A37m Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; zh-cn; OPPO A59m Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.7 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; ATH-AL00 Build/HONORATH-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.5 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; KIW-AL10 Build/HONORKIW-AL10) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/9.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; OPPO A57 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.3 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; OPPO R9s Plus Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.9 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; Redmi 4 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.9 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; SM-G9350 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.6 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; vivo X9i Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.5 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; vivo Y66 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/9.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-cn; MEIZU_M5 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.3 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-cn; OPPO R9m Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-cn; Redmi Note 4 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.5 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-cn; vivo Y67 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.9 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0zh-cn; CAM-TL00 Build/HONORCAM-TL00) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.1 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; DUK-AL20 Build/HUAWEIDUK-AL20) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.1 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; FRD-AL00 Build/HUAWEIFRD-AL00) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.1 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; FRD-AL10 Build/HUAWEIFRD-AL10) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.6 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; M5 Note Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.9 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; M760 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/9.1 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; STF-AL10 Build/HUAWEISTF-AL10) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.1 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; TRT-AL00 Build/HUAWEITRT-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.9 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-cn; OPPO A83 Build/N6F26Q) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.5 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-cn; OPPO R11t Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.5 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-cn; vivo X20A Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.5 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-cn; vivo Xplay6 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.8 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 7.1.1; zh-tw; MI MAX 2 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.0.0; zh-cn; ANE-TL00 Build/HUAWEIANE-TL00) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/9.1 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.0.0; zh-cn; BKL-TL10 Build/HUAWEIBKL-TL10) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.9 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.0.0; zh-cn; DUK-AL20 Build/HUAWEIDUK-AL20) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.9 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.0.0; zh-cn; HWI-AL00 Build/HUAWEIHWI-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/9.0 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.0.0; zh-cn; LDN-AL20 Build/HUAWEILDN-AL20) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/9.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.0.0; zh-cn; SM-G9500 Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/9.0 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.0.0;zh-cn; FRD-AL10 Build/HUAWEIFRD-AL10) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.1 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.0zh-cn; ONEPLUS A6000 Build/PKQ1.180716.001) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.1 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; COL-AL10 Build/HUAWEICOL-AL10) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.9 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; MI 8 SE Build/OPM1.171019.019) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.8 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; PACM00 Build/O11019) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.8 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; PADM00 Build/O11019) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.8 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; PADM00 Build/O11019) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.9 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; PBAM00 Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/9.0 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; PBCM30 Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/9.0 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; V1813BT Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/9.0 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; vivo X21i A Build/O11019) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.8 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; vivo Y83A Build/O11019) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.7 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; vivo Y85 Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.8 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.1.0;zh-cn; INE-AL00 Build/HUAWEIINE-AL00) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.1 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.1.0;zh-cn; SNE-AL00 Build/HUAWEISNE-AL00) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.1 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 9; zh-cn; BKL-AL20 Build/HUAWEIBKL-AL20) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/9.0 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 9; zh-cn; MI 8 Build/PKQ1.180729.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/9.1 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 9; zh-cn; MI 8 Build/PKQ1.180729.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/9.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 9; zh-cn; PAR-AL00 Build/HUAWEIPAR-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/9.0 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 9; zh-cn; PAR-AL00 Build/HUAWEIPAR-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/9.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 9zh-cn; VCE-AL00 Build/HUAWEIVCE-AL00) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.1 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo K50a40 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.137 YaBrowser/17.4.1.352.00 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.146 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.19 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; HTC Desire 820 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.54 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.5712.263 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.9816.482 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.1850.227 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; LG-V400 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3019.3 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.145 Mobile Safari/537.36 EdgA/41.0.0.1270", - "Mozilla/5.0 (Linux; Android 7.0; LGLS775 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.145 Mobile Safari/537.36 EdgA/41.0.0.1270", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900T Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.33 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.1.2; VS870 4G Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; HP Slate 7 Plus Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.3; GT-I9300 Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.3; MediaPad T1 8.0 Build/HuaweiMediaPad) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; 7040T Build/KVT49L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; DASH C MUSIC Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; GT-P5210 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; HTC One mini 2 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; ILIUM S106 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; Lenovo A536 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; LG-D165AR Build/KOT49I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; LGLS990 Build/KVT49L.LS990ZV4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; Tab2A7-20F Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; GT-I9060I Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-J100FN Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-T113NU Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-T560 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; GT-I9500 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; GT-I9505 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; Lenovo TB3-710F Build/LRX21M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; SCH-I545 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; LG-D722AR Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-A300H Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-G530BT Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-S920L Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-T535 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SO-01G Build/23.1.B.1.317) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900F Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900V Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-N900U Build/LRX21V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; 9020A Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A37f Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A571VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A621BL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Alcatel_4060A Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Alcatel_5056O Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Coolpad 3622A Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; HUAWEI Y560-L03 Build/HUAWEIY560-L03) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; KYOCERA-C6742 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; KYOCERA-E6560 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL62VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-E700H Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G530T Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G531F Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G531H Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J100VPP Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320M Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J500FN Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J3110 Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-N910V Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; vivo V3 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; VS425PP Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; VS820 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; VS880 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; 8050G Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A1601 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A1601 Build/LMY47I; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A1603 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Eluga_A2 Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Fire2 Plus LTE Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI CUN-L01 Build/HUAWEICUN-L01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; iris560 Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; N9521 Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; XT1040 Build/LPBS23.13-35.5-1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; ZTE BLADE A110 Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; ZTE Blade L5 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5027B Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5056N Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; A0001 Build/MHC19Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Alcatel_5098O Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Alcatel_6055U Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; GT-I9300 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; H1611 Build/HUAWEIH1611) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; HTCD160LVWPP Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGL58VL Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS450 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS676 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGMS428 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGMS550 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Moto G (4) Build/MPJ24.139-63) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/M4B30Z) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; ONE A2003 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Redmi Note 3 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G925A Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A320FL Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A500F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A520F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G389F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G610F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900I Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G903W Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920W8 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G925F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G930F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G9208 Build/MMB29K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500FN Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500M Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J510FN Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700M Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J710F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910C Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910T Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N915F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N915P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N930F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S903VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-T350 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo 1610 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1562 Build/MPDS24.107-70-1-5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z831 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z956 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z981 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; ZUK Z2131 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; 5010G Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ALE-L21 Build/HuaweiALE-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ALE-L21 Build/HuaweiALE-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Coolpad E502 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; dtac_Phone_S2 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; HUAWEI VNS-L31 Build/HUAWEIVNS-L31) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; JERRY Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo A7020a48 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo TB3-850F Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-H635 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-K371 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; M20Pro Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; MotoG3 Build/MPI24.65-25) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; RCT6213W87M Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Redmi Note 4 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; VFD 300 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; vivo 1601 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ZTE BLADE A510 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Focus/3.0.2 Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; dtacPhoneX3 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; EVA-L09 Build/HUAWEIEVA-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HTC 10 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI CAN-L11 Build/HUAWEICAN-L11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI NXT-L29 Build/HUAWEINXT-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI VNS-L31 Build/HUAWEIVNS-L31) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-TP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Life M2+ Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; MHA-L29 Build/HUAWEIMHA-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; MI 5 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto C Build/NRD90M.063) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-N920A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SGP712 Build/32.3.A.2.33) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-A520F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-A520W Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G610F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G920F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G925F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G925I Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G928T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G928V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930VC Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930VL Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930W8 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G955F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-N920P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SMART 4G GEN C 5.0 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; TECNO Camon CX Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; XT1585 Build/NCK25.118-10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; ZTE BLADE A602 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N9137 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Nokia 2 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; ONEPLUS A3003 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; REVVLPLUS C3701A Build/143.14.171129.3701A-TMO) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z839 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z851M Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z982 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Nexus 5X Build/N2G47W) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Pixel Build/N2G47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Pixel Build/NHG47N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Pixel Build/NJH47B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Pixel C Build/N2G47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.7956.507 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.8394.739 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.1863.446 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.2117.682 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SGH-T399N Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3062.4 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.1.2; Z930L Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 7047A Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; GT-I9105P Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.3; SM-N9005 Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; 9005X Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; GT-N7100 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-G900T Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-T210 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-T230NU Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; 5042T Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; N817 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; XT1080 Build/SU6-7.7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; GT-I9505 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; GT-I9515 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; Lenovo TB3-710F Build/LRX21M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; LG-D838 Build/LRX21Y) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; SAMSUNG GT-I9505 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; D2502 Build/19.3.A.0.472) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-S920L Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; E5606 Build/30.0.A.1.33) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SAMSUNG SM-N900V Build/LRX21V) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900F Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-N900T Build/LRX21V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; 5054S Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A37f Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Alcatel_4060A Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Coolpad 3622A Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; HUAWEI Y560-L01 Build/HUAWEIY560-L01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; KYOCERA-E6560 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LG-H345 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LG-K330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL44VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL52VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL62VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGMS330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGMS345 Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; PSP5506DUO Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; PULP FAB 4G Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-G5500 Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G531F Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J100VPP Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320FN Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320M Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J500G Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; VS880 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; VS880PP Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Y538 Build/HuaweiY538) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Z828 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Z959 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; 8050E Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A1601 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Archos 50 Power Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; N9521 Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; T03 Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; VFD 200 Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; XT1022 Build/LPC23.13-34.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Z818L Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Z987 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5027B Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5056N Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; D5803 Build/23.5.A.1.291) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; D6603 Build/23.5.A.1.291) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; H1611 Build/HUAWEIH1611) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; HTC 10 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-H831 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-K220 Build/MXB48T; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS676 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; N9136 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; N9519 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; ONE E1003 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Redmi 3S Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Redmi 4A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Redmi Note 3 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-A300FU Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-A510Y Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-A800F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-A8000 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G532G Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G550T Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G900T Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G925F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G925F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-J120AZ Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-J320AZ Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-J500F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-J710GN Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-N910V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-S327VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-S727VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G930A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-J120AZ Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-J320A Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-J320AZ Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A500F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A520F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A520W Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G389F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G610F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G800F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900T Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920I Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920I Build/MMB29K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.125 Mobile Safari/537.36 SamsungBrowser/CrossApp/0.1.103", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G925F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G930F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500M Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700M Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J710MN Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N915F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S907VL Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-T377P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-T377V Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-T805 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; STV100-1 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; TOMMY Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo 1610 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1254 Build/MCG24.251-5-5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z798BL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z832 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z981 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ALE-L21 Build/HuaweiALE-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; B1-780 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; EVA-L09 Build/HUAWEIEVA-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; HTC One_M8 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; HUAWEI GRA-L09 Build/HUAWEIGRA-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo K50a40 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo TB3-730F Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-D855 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; VIVAX TABLET TPC 802 3G Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; vivo 1601 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; XT1092 Build/MPES24.49-18-7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; XT1706 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; EVA-L09 Build/HUAWEIEVA-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI NXT-AL10 Build/HUAWEINXT-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-LS777 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M257 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGLS775 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGLS775 Build/NRD90U; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS550 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-A520F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-A520F/A520FXXU2BQK1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G610F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G610F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G928T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J327AZ Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J327AZ Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J730G Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-N920C Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-N920T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-N920T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-N920V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G891A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G930A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G935A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-A310F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G920F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G920V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G925F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G955F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VKY-L29 Build/HUAWEIVKY-L29) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VKY-L29 Build/HUAWEIVKY-L29) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; XT1635-01 Build/NDN25.137-24.4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; XT1635-01 Build/NDNS25.137-24-1-4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; ONEPLUS A3000 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; ONEPLUS A3003 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SAMSUNG SM-J320AZ Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SAMSUNG SM-J510FN Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SAMSUNG SM-J510FN Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SAMSUNG SM-J700P Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SAMSUNG SM-J700T1 Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SAMSUNG-SM-J320A Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-N950U Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z557BL Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; ZTE A2017U Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210CM Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Moto G4 Plus Build/NJH47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Nexus 5X Build/N2G47Z) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Nexus 5X Build/N2G48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; SM-N900 Build/NJH47F) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-A6050 Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G891A Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G930A Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G930A Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G930F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G930F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G930T Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G930T Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G930T Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G930VL Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G935F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G935F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G950F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G950W Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G950W Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G955F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G955W Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G955W Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G960F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G960U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G960U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G965F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G965F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G9508 Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G9650 Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-J337A Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-J337P Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-J337T Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-N950F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-N950F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-N950F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-N950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-N950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-N950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-J530G Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-J727P Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-J727T1 Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.4 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-J727T Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0.1; es; SM-G532M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Tenta/1.2.0.27 Mobile Safari/537.36 Mobile", - "Mozilla/5.0 (Linux; U; Android 6.0; VFD 300 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.125 Mobile Safari/537.36 OPR/28.0.2254.119213", - "Mozilla/5.0 (Linux; Android 5.0; SM-N900T Build/LRX21V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.25 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z981 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.25 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G935A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.25 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGLS992 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.60 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; 1607-A01 Build/NMF26F; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.82 Mobile Safari/537.36;haowangzhi;ebrowser 2120", - "Mozilla/5.0 (Linux; Android 4.0; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/59.0.3071.92", - "Mozilla/5.0 (Linux; Android 6.0; ALE-L21 Build/HuaweiALE-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.92 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.92 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.6181.470 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.1366.273 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-T210R Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; SCH-I545 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; London Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Alcatel_5056O Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Coolpad 3622A Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J700M Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Z959 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; m1 note Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGL58VL Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A520F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A520W Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T2 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G800F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900R6 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900W8 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G925I Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z798BL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z981 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Archos 55 Helium Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo TB3-850F Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-D852G Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-H812 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; VFD 501 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; VS990 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI CAN-L12 Build/HUAWEICAN-L12) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS550 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-J327AZ Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G892A Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G920F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G955U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; Pixel XL Build/OPR6.170623.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; 7_Plus Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-T211M Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-S820L Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; Redmi Note 2 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36 OPR/44.0.2246.121597", - "Mozilla/5.0 (Linux; Android 5.0; RCT6303W87DK Build/LRX21M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SAMSUNG-SM-G900A Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A37f Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Coolpad 3622A Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; KYOCERA-C6742 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL62VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-G530AZ Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; VS425PP Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Focus/1.3 Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; C6740N Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HTC Desire 520 Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI LUA-L22 Build/HUAWEILUA-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI TAG-L01 Build/HUAWEITAG-L01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; HTC Desire 530 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M153 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Redmi 3S Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G928V Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910C Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S903VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-T377V Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z981 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z988 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; ZUK Z2131 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-K350 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-K373 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-K373 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M327 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-J327AZ Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G928F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G955U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J727T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J727T1 Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; WAS-LX1 Build/HUAWEIWAS-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; GIONEE F6 Build/NMF26F; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z558VL Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; CPH1803 Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36 OPR/44.6.2246.127414", - "Mozilla/5.0 (Linux; Android 5.1.1; VS425PP Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.72 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; GT-N7100 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320FN Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G610F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ASUS_X008D Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; BLL-L22 Build/HUAWEIBLL-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGLS775 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; M1 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.78 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-N935S Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VTR-L29 Build/HUAWEIVTR-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Moto G 2014 Build/NJH47D; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.78 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-T550 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.97 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; vivo 1601 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.97 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.97 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.5241.1275 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.6926.395 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.7705.1187 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; MI 8 Lite Build/PKQ1.181007.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiQuickSearchBox/ XiaoMi/HybridView/", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; MI MAX Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.2.2", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; Redmi 3S Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.0.2", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; Redmi 3S Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.7.3", - "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; Redmi 4A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.5.5", - "Mozilla/5.0 (Linux; U; Android 6.0; en-us; Redmi Pro Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.1.1", - "Mozilla/5.0 (Linux; U; Android 6.0; zh-cn; Redmi Pro Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.5.1", - "Mozilla/5.0 (Linux; U; Android 7.0; cs-cz; Redmi Note 4 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.8.4", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; MI 5 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.7.2", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; MI MAX Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.7.2", - "Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; Redmi Note 4X Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.5.14", - "Mozilla/5.0 (Linux; U; Android 7.1.2; cs-cz; Redmi Note 5A Prime Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.1.2", - "Mozilla/5.0 (Linux; U; Android 7.1.2; en-gb; Redmi 4A Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.5.6-g", - "Mozilla/5.0 (Linux; U; Android 7.1.2; zh-cn; MI 5X Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.5.14", - "Mozilla/5.0 (Linux; U; Android 7.1.2; zh-cn; Redmi 4X Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.5.2", - "Mozilla/5.0 (Linux; U; Android 7.1.2; zh-cn; Redmi 5 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.2.2", - "Mozilla/5.0 (Linux; U; Android 8.0.0; zh-cn; MIX 2 Build/OPR1.170623.027) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.7.2", - "Mozilla/5.0 (Linux; U; Android 8.0.0; zh-cn; MIX 2S Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.3.2", - "Mozilla/5.0 (Linux; U; Android 8.1.0; he-il; Redmi Note 5 Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.1.2", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; MI 6X Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.5.1", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; Redmi Note 5 Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/9.5.14", - "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; Redmi Note 5 Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.7.3", - "Mozilla/5.0 (Linux; U; Android 9; zh-cn; MIX 3 Build/PKQ1.180729.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.5.1", - "Mozilla/5.0 (Linux; U; Android 9; zh-cn; Redmi Note 7 Build/PKQ1.180904.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.6.1", - "Mozilla/5.0 (Linux; Android 4.4.2; Lenovo A5000 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.141 Mobile Safari/537.36 OPR/45.1.2246.125351", - "Mozilla/5.0 (Linux; Android 6.0; Tank Xtreme 5.0 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.141 Mobile Safari/537.36 OPR/45.1.2246.125351", - "Mozilla/5.0 (Linux; Android 7.0; Moto G (5) Build/NPPS25.137-93-4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.141 Mobile Safari/537.36 OPR/45.1.2246.125351", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900R6 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.42 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J700F Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; GT-I8200 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36 OPR/45.0.2246.10", - "Mozilla/5.0 (Linux; Android 4.4.2; 7_Plus Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; GT-N7100 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; GT-P5210 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; HTC Desire 620G dual sim Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; HUAWEI MT7-TL10 Build/HuaweiMT7-TL10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-G730W8 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-T113 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-T116 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-T560 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SO-01G Build/23.0.B.1.59) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; GT-I9500 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; GT-I9515 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; RCT6303W87DK Build/LRX21M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; HUAWEI SCL-L01 Build/HuaweiSCL-L01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; KYOCERA-C6742 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL62VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGMS330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G531F Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J120F Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320FN Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320P Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; VS880 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Z828 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI LYO-L02 Build/HUAWEILYO-L02) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; iris 870 Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; TECNO-L8Plus Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5027B Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M151 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS450 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS676 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGMS428 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Moto G Play Build/MPIS24.241-15.3-26) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; N9136 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; N9519 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A520F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G570M Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G935F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J510FN Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700H Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700M Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910G Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910T Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S903VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-T550 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1609 Build/MPIS24.241-2.35-1-17; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z831 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; HTC One X10 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-H343 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-K373 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; M20Pro Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-H870 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-TP450 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGLS775 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; PLUS Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-A520F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G920V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G925F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G925T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G928F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G928V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G955F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G955U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G955W Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327VPP Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-T580 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-T585 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VS995 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; WAS-LX1A Build/HUAWEIWAS-LX1A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; CPH1725 Build/N6F26Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; CPH1725 Build/N6F26Q; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.98 Mobile Safari/537.36 BingWeb/9.1.26249402", - "Mozilla/5.0 (Linux; Android 7.1.1; CPH1729 Build/N6F26Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; MI MAX 2 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; XT1635-01 Build/NDNS26.118-23-1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z971 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPR5.170623.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 Build/OPD1.170816.018) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Pixel XL Build/OPM1.171019.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A310F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.45 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; VS425PP Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.73 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; HTC Desire 510 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; vivo Y27 Build/KTU84P; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.5.1.2", - "Mozilla/5.0 (Linux; Android 5.0.2; LG-D337 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; vivo Y51 Build/LRX22G; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.6.0.0", - "Mozilla/5.0 (Linux; Android 5.1.1; C6743 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; D2502 Build/19.4.A.0.182) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LG-H634 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL44VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL62VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J100VPP Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J200G Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320M Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J500G Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J700F Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-N750 Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; vivo Y31L Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.7.0.2", - "Mozilla/5.0 (Linux; Android 5.1.1; vivo Y51t L Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/6.2.0.5", - "Mozilla/5.0 (Linux; Android 5.1.1; VS425PP Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A1601 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A1603 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI TAG-L01 Build/HUAWEITAG-L01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI TAG-L23 Build/HUAWEITAG-L23) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Lenovo A2010-a Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Lenovo TAB 2 A8-50L Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; LYO-L21 Build/HUAWEILYO-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Z812 Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; ZTE-Z987 Build/LMY47I; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Focus/2.4 Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5056N Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; CPH1701 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; D6503 Build/23.5.A.1.291) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; HTCD160LVWPP Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M153 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS676 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS755 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGMS428 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; MI 4W Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Moto G Play Build/MPI24.241-2.35-1.5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; N9136 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; RCT6873W42 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G900A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G935A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-J320AZ Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T2 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900I Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G903F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920I Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920V Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700M Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700T Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J710GN Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910C Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910F Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N920T Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S120VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-T550 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo 1606 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.8.0.8", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo 1606 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.5.5", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo 1610 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.5.3", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo Y53 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/6.1.1.1", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo Y55 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/6.1.1.1", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo Y55 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.5.4.2", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo Y66 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.6.3.0", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo Y66 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.6.3.1", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1609 Build/MPIS24.241-2.35-1-17) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z981 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; iris870 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; JERRY Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-H343 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-H812 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-K373 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-X230 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; SGH-I337M Build/MRA58V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; vivo 1609 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.8.0.1", - "Mozilla/5.0 (Linux; Android 6.0; vivo 1609 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.7.0.2", - "Mozilla/5.0 (Linux; Android 6.0; vivo Y67A Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/6.2.0.5", - "Mozilla/5.0 (Linux; Android 6.0; vivo Y67A Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.5.1.1", - "Mozilla/5.0 (Linux; Android 6.0; vivo Y67L Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.6.3.1", - "Mozilla/5.0 (Linux; Android 6.0; XT1068 Build/MPB24.65-34-3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; F3111 Build/33.3.A.1.97) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; FRD-L09 Build/HUAWEIFRD-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI NMO-L22 Build/HUAWEINMO-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; JMM-AL00 Build/HONORJMM-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 SogouSearch Android1.0 version3.0 AppVersion/6002", - "Mozilla/5.0 (Linux; Android 7.0; LG-H831 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-H918 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-LS777 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-TP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGLS775 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS550 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; MHA-L29 Build/HUAWEIMHA-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Redmi Note 4X Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G935A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-J727A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-A310F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-A520F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G610F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G903W Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G920T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G925F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G925I Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G925T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930W8 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G955F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G955U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G9208 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J710F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-N920P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-N920V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-P585M Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; STF-L09 Build/HUAWEISTF-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; vivo 1713 Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.8.0.8", - "Mozilla/5.0 (Linux; Android 7.0; VS835 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VS988 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VTR-L09 Build/HUAWEIVTR-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; WAS-LX1A Build/HUAWEIWAS-LX1A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; A577VL Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Coolpad 3632A Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; L50 Build/L50_01.01.02) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQ26.69-46) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto Z (2) Build/NDX26.183-15) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 5X Build/N4F26T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-J700T1 Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-N950U Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-T377V Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; vivo X9L Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; vivo Y75 Build/N6F26Q; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/6.1.1.1", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210CM Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; MI 5C Build/N2G47J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Redmi 4 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Redmi Y1 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; vivo 1718 Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.6.0.0", - "Mozilla/5.0 (Linux; Android 7.1.2; vivo X9 Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.6.8.5", - "Mozilla/5.0 (Linux; Android 7.1.2; vivo X9 Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/6.2.7.0", - "Mozilla/5.0 (Linux; Android 7.1.2; vivo X9 Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.6.1.1", - "Mozilla/5.0 (Linux; Android 7.1.2; vivo X9i Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.6.8.5", - "Mozilla/5.0 (Linux; Android 7.1.2; vivo X9s Plus L Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.5.2.1", - "Mozilla/5.0 (Linux; Android 8.0.0; MI 6 Build/OPR1.170623.027; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 Build/OPD1.170816.025) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; PAAT00 Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 SogouSearch Android1.0 version3.0 AppVersion/6213", - "Mozilla/5.0 (Linux; Android 8.1.0; PADM00 Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; PBAT00 Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 baiduboxapp/9.2.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PBEM00 Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 lite baiduboxapp/3.9.0.11 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; Redmi 6A Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 baiduboxapp/9.2.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; V1813A Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/6.2.0.6", - "Mozilla/5.0 (Linux; Android 8.1.0; V1813A Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/6.2.7.2", - "Mozilla/5.0 (Linux; Android 8.1.0; V1813A Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 baiduboxapp/9.2.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; V1813T Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/6.2.0.5", - "Mozilla/5.0 (Linux; Android 8.1.0; V1818CA Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/6.2.7.0", - "Mozilla/5.0 (Linux; Android 8.1.0; vivo 1812 Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.8.0.8", - "Mozilla/5.0 (Linux; Android 8.1.0; vivo X20A Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/6.1.1.1", - "Mozilla/5.0 (Linux; Android 8.1.0; vivo Y71A Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.6.3.1", - "Mozilla/5.0 (Linux; Android 8.1.0; vivo Y83A Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.6.3.2", - "Mozilla/5.0 (Linux; Android 8.1.0; vivo Y83A Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/6.1.1.1", - "Mozilla/5.0 (Linux; Android 8.1.0; vivo Y85A Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 baiduboxapp/9.2.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 9; vivo 1819 Build/PPR1.180610.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36 VivoBrowser/5.8.0.8", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; 8676-A01 Build/LMY47D; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.97 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; PRA-AL00 Build/HONORPRA-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.97 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3223.7 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1609 Build/MPIS24.241-2.35-1-17) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3223.7 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1609 Build/MPIS24.241-2.35-1-17) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3236.6 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G920A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3236.6 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J727T Build/M1AJQ.J727TUVS3BRI1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239 Mobile Safari/537.36 MainLauncher/2.2.35", - "Mozilla/5.0 (Linux; Android 6.0.1; HTC Desire 530 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G920A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.107 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 6040A Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.3; C6530N Build/JLS36C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.3; SM-G710 Build/JLS36C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; A1-841 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; CHC-U01 Build/HuaweiCHC-U01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; CHM-U01 Build/HonorCHM-U01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; GT-I9195 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; HM NOTE 1W Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-G7102 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-N900V Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-T520 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; T1 7.0 Build/HuaweiMediaPad) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; TB-713 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; D2303 Build/18.3.1.C.1.13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-G360H Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; TR10RS1 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; LGLK430 Build/LRX21Y) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; SAMSUNG GT-I9505 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; SAMSUNG-SM-N910A Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; SGH-I337M Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; Redmi Note 2 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-G530H Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-G920F Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; RCT6303W87DK Build/LRX21M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-N900T Build/LRX21V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A37f Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A37fw Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Alcatel_4060A Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; C6743 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; F1f Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL82VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGMS330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-G360T1 Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-J111F Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-J320Y Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J100VPP Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-T285 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A1601 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HTC Desire 628 dual sim Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; MotoE2(4G-LTE) Build/LPIS23.29-15.3-7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; SMART_Surf_4G Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5027B Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5056N Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Andromax B26D2H Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; CPH1607 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; HTC_M910x Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-K540 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M153 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS450 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS676 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Moto G Play Build/MPI24.241-2.35-1.5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Moto G Play Build/MPIS24.241-15.3-26) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; N9136 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; RCT6873W42 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G532G Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G532M Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-J500H Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-N910V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-S327VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-S727VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G930A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-J120A Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-J120AZ Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-J120AZ Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36 EdgA/41.0.0.1561", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G800F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900I Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920I Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G930F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500M Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700H Build/MMB29K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910C Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910U Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S120VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; VS500PP Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1609 Build/MPIS24.241-2.35-1-17) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z798BL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z831 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z988 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; A3-A40 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; CAM-L03 Build/HUAWEICAM-L03) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36 OPR/46.0.2246.126998", - "Mozilla/5.0 (Linux; Android 6.0; F103 Pro Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo A2016b30 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LGMS631 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; MotoG3 Build/MPIS24.65-33.1-2-2-11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; R7 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; RCT6K03W13 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Focus/4.0.1 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; EVA-L09 Build/HUAWEIEVA-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Lenovo K33a48 Build/NRD90N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-H831 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-H873 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-H918 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M257 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M430 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-TP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL83BL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGLS775 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP450 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS550 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGUS215 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; MI 5 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto C Build/NRD90M.008) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto G (4) Build/NPJS25.93-14-13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto G (5) Plus Build/NPN25.137-92) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; PRA-LX1 Build/HUAWEIPRA-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Redmi Note 4 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-A510M Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G610F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G920A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G930W8 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G891A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G925A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G930A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G930AZ Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G935A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-A320FL Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-A510F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-A520F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-A520W Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G903W Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G920F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G925F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G955F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G955U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327VPP Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327VPP Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J710FN Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J727P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J727T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J727T1 Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-N920V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; STF-L09 Build/HUAWEISTF-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VS501 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36 EdgA/41.0.0.1561", - "Mozilla/5.0 (Linux; Android 7.0; VS835 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VS987 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Focus/4.0.1 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQ26.69-46-5-4) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQ26.69-46) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Plus Build/NDRS26.58-33-2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; REVVLPLUS C3701A Build/143.02.171026.3701A-TMO) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SAMSUNG SM-J250F Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SAMSUNG SM-J510FN Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-J510FN Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-J700T1 Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-N950F Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-N950U Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; TA-1021 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; XT1710-02 Build/NDSS26.118-23-19-6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36 OPR/46.3.2246.127744", - "Mozilla/5.0 (Linux; Android 7.1.1; Z965 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z982 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LG-SP200 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G) Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G) Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; TA-1021 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; vivo 1718 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; AUM-AL00 Build/HONORAUM-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36 baiduboxapp/9.2.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; FIG-LX1 Build/HUAWEIFIG-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; G8141 Build/47.1.A.8.49) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ONEPLUS A3000 Build/OPR6.170623.013) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-A520F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-A520W Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G892A Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G930F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G930T Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G930W8 Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G935F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G950F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G955F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G960U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G965F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-J337A Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-J737T1 Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.0 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-S367VL Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950F Build/R16NW; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G960U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; CPH1819 Build/O11019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; CPH1859 Build/O11019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Pixel 2 XL Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Pixel XL Build/OPM1.171019.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-G610F Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-G610M Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-J260T1 Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.0 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-J530F Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-J610FN Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-J710F Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.0 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-J710F Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-J727P Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-J727T1 Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-N960F/N960FXXS2ARJ2 Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.0 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-N960U Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.0 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-N960U Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; HMA-AL00 Build/HUAWEIHMA-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 HuaweiBrowser/9.0.2.305 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; MRD-AL00 Build/HUAWEIMRD-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 HuaweiBrowser/9.0.1.335 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G960F Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-N960F Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 6.0; XT1092 Build/MPES24.49-18-7; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36 OPR/32.0.2254.123747", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G930A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.71 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; CHM-TL00 Build/HonorCHM-TL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 4.4.2)", - "Mozilla/5.0 (Linux; Android 4.4.4; E2053 Build/25.0.A.2.31) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; Nexus 9 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; vivo X6A Build/LRX22G; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 5.0.2)", - "Mozilla/5.0 (Linux; Android 5.1.1; OPPO R9 Plusm A Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.1 baiduboxapp/11.1.0.10 (Baidu; P1 5.1.1)", - "Mozilla/5.0 (Linux; Android 5.1.1; OPPO R9 Plusm A Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 5.1.1)", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J500H Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; vivo V3Max A Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/10.10 lite baiduboxapp/3.5.5.10 (Baidu; P1 5.1.1)", - "Mozilla/5.0 (Linux; Android 5.1.1; vivo V3Max A Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 5.1.1)", - "Mozilla/5.0 (Linux; Android 5.1.1; vivo X6S A Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 5.1.1)", - "Mozilla/5.0 (Linux; Android 5.1.1; vivo X6SPlus D Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 5.1.1)", - "Mozilla/5.0 (Linux; Android 5.1.1; vivo X7 Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 5.1.1)", - "Mozilla/5.0 (Linux; Android 5.1.1; vivo X7 Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 5.1.1)", - "Mozilla/5.0 (Linux; Android 5.1.1; vivo X7Plus Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 5.1.1)", - "Mozilla/5.0 (Linux; Android 5.1.1; vivo Y51A Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.0 baiduboxapp/11.0.0.11 (Baidu; P1 5.1.1)", - "Mozilla/5.0 (Linux; Android 5.1; Che1-CL20 Build/Che1-CL20; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 5.1)", - "Mozilla/5.0 (Linux; Android 5.1; CP8298_I00 Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; OPPO A59s Build/LMY47I; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/10.13 baiduboxapp/10.13.0.11 (Baidu; P1 5.1)", - "Mozilla/5.0 (Linux; Android 5.1; OPPO A59s Build/LMY47I; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.6 baiduboxapp/11.6.1.10 (Baidu; P1 5.1)", - "Mozilla/5.0 (Linux; Android 5.1; vivo X6D Build/LMY47I; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.6 baiduboxapp/11.6.1.10 (Baidu; P1 5.1)", - "Mozilla/5.0 (Linux; Android 6.0.1; H1611 Build/HUAWEIH1611) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; HUAWEI RIO-AL00 Build/HuaweiRIO-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 6.0.1)", - "Mozilla/5.0 (Linux; Android 6.0.1; Le X820 Build/FEXCNFN6003009092S; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.0.13 (Baidu; P1 6.0.1)", - "Mozilla/5.0 (Linux; Android 6.0.1; OPPO A57 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.0 baiduboxapp/11.0.0.11 (Baidu; P1 6.0.1)", - "Mozilla/5.0 (Linux; Android 6.0.1; OPPO A57t Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.5 baiduboxapp/11.5.0.10 (Baidu; P1 6.0.1)", - "Mozilla/5.0 (Linux; Android 6.0.1; OPPO R9s Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.1 baiduboxapp/11.1.5.10 (Baidu; P1 6.0.1)", - "Mozilla/5.0 (Linux; Android 6.0.1; OPPO R9s Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 6.0.1)", - "Mozilla/5.0 (Linux; Android 6.0.1; OPPO R9s Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 6.0.1)", - "Mozilla/5.0 (Linux; Android 6.0.1; OPPO R9sk Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/10.12 baiduboxapp/10.12.0.12 (Baidu; P1 6.0.1)", - "Mozilla/5.0 (Linux; Android 6.0.1; OPPO R9sk Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 6.0.1)", - "Mozilla/5.0 (Linux; Android 6.0.1; OPPO R9st Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 6.0.1)", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-J320A Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500FN Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S907VL Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo Y66 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 6.0.1)", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo Y66L Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/10.13 lite baiduboxapp/3.8.0.12 (Baidu; P1 6.0.1)", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo Y66L Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 6.0.1)", - "Mozilla/5.0 (Linux; Android 6.0; DIG-AL00 Build/HUAWEIDIG-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 6.0)", - "Mozilla/5.0 (Linux; Android 6.0; GN8002S Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 6.0)", - "Mozilla/5.0 (Linux; Android 6.0; HUAWEI MLA-AL10 Build/HUAWEIMLA-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.0.13 (Baidu; P1 6.0)", - "Mozilla/5.0 (Linux; Android 6.0; HUAWEI MT7-TL10 Build/HuaweiMT7-TL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 6.0)", - "Mozilla/5.0 (Linux; Android 6.0; KNT-AL10 Build/HUAWEIKNT-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.5 baiduboxapp/11.5.0.10 (Baidu; P1 6.0)", - "Mozilla/5.0 (Linux; Android 6.0; M A5 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 6.0)", - "Mozilla/5.0 (Linux; Android 6.0; NCE-TL10 Build/HUAWEINCE-TL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.2 baiduboxapp/11.2.0.10 (Baidu; P1 6.0)", - "Mozilla/5.0 (Linux; Android 6.0; vivo Y67 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 6.0)", - "Mozilla/5.0 (Linux; Android 7.0; BLN-TL10 Build/HONORBLN-TL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 7.0)", - "Mozilla/5.0 (Linux; Android 7.0; BND-AL10 Build/HONORBND-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.1 baiduboxapp/11.1.0.10 (Baidu; P1 7.0)", - "Mozilla/5.0 (Linux; Android 7.0; CPN-W09 Build/HUAWEICPN-W09; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 7.0)", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI CAZ-TL20 Build/HUAWEICAZ-TL20; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 7.0)", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI MLA-AL10 Build/HUAWEIMLA-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 7.0)", - "Mozilla/5.0 (Linux; Android 7.0; Meizu S6 Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 7.0)", - "Mozilla/5.0 (Linux; Android 7.0; MHA-TL00 Build/HUAWEIMHA-TL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 7.0)", - "Mozilla/5.0 (Linux; Android 7.0; Micromax C1 Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.2 baiduboxapp/11.2.0.10 (Baidu; P1 7.0)", - "Mozilla/5.0 (Linux; Android 7.0; MON-AL19B Build/HUAWEIMON-AL19; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 7.0)", - "Mozilla/5.0 (Linux; Android 7.0; Redmi Note 4X Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 7.0)", - "Mozilla/5.0 (Linux; Android 7.0; SLA-AL00 Build/HUAWEISLA-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/10.13 baiduboxapp/10.13.5.10 (Baidu; P1 7.0)", - "Mozilla/5.0 (Linux; Android 7.0; SM-A520W Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G955F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G9200 Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.5 baiduboxapp/11.5.0.10 (Baidu; P1 7.0)", - "Mozilla/5.0 (Linux; Android 7.0; TRT-AL00 Build/HUAWEITRT-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 7.0)", - "Mozilla/5.0 (Linux; Android 7.1.1; MX6 Build/NMF26O; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 7.1.1)", - "Mozilla/5.0 (Linux; Android 7.1.1; OPPO A73t Build/N6F26Q; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.2 baiduboxapp/11.2.0.10 (Baidu; P1 7.1.1)", - "Mozilla/5.0 (Linux; Android 7.1.1; OPPO A83 Build/N6F26Q; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.0.13 (Baidu; P1 7.1.1)", - "Mozilla/5.0 (Linux; Android 7.1.1; OPPO A83t Build/N6F26Q; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 7.1.1)", - "Mozilla/5.0 (Linux; Android 7.1.1; OPPO A83t Build/N6F26Q; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.6 baiduboxapp/11.6.1.10 (Baidu; P1 7.1.1)", - "Mozilla/5.0 (Linux; Android 7.1.1; OPPO A83t Build/N6F26Q; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 7.1.1)", - "Mozilla/5.0 (Linux; Android 7.1.1; OPPO R11 Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 7.1.1)", - "Mozilla/5.0 (Linux; Android 7.1.1; OPPO R11st Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.2 baiduboxapp/11.2.0.10 (Baidu; P1 7.1.1)", - "Mozilla/5.0 (Linux; Android 7.1.1; OPPO R11st Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.9 baiduboxapp/11.9.0.11 (Baidu; P1 7.1.1)", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-W2018 Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.2 baiduboxapp/11.2.0.10 (Baidu; P1 7.1.1)", - "Mozilla/5.0 (Linux; Android 7.1.1; vivo X20A Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/10.0 lite baiduboxapp/3.2.5.10 (Baidu; P1 7.1.1)", - "Mozilla/5.0 (Linux; Android 7.1.1; vivo Y75A Build/N6F26Q; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.0 baiduboxapp/11.0.0.11 (Baidu; P1 7.1.1)", - "Mozilla/5.0 (Linux; Android 7.1.1; vivo Y75A Build/N6F26Q; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 7.1.1)", - "Mozilla/5.0 (Linux; Android 7.1.1; ZTE V0840 Build/NMF26F; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.5 baiduboxapp/11.5.0.10 (Baidu; P1 7.1.1)", - "Mozilla/5.0 (Linux; Android 7.1.2; HLTE300T Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.1 baiduboxapp/11.1.0.10 (Baidu; P1 7.1.2)", - "Mozilla/5.0 (Linux; Android 7.1.2; HLTE300T Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 7.1.2)", - "Mozilla/5.0 (Linux; Android 7.1.2; Redmi 5 Plus Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/10.13 baiduboxapp/10.13.5.10 (Baidu; P1 7.1.2)", - "Mozilla/5.0 (Linux; Android 7.1.2; SM-G900F Build/NJH47F; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; vivo X9 Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.6 baiduboxapp/11.6.1.10 (Baidu; P1 7.1.2)", - "Mozilla/5.0 (Linux; Android 7.1.2; vivo X9 Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 7.1.2)", - "Mozilla/5.0 (Linux; Android 7.1.2; vivo X9Plus Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 7.1.2)", - "Mozilla/5.0 (Linux; Android 7.1.2; vivo X9Plus Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 7.1.2)", - "Mozilla/5.0 (Linux; Android 7.1.2; XT1095 Build/NJH47F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ALP-AL00 Build/HUAWEIALP-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; ANE-AL00 Build/HUAWEIANE-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; AUM-AL20 Build/HONORAUM-AL20; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; AUM-TL20 Build/HONORAUM-TL20; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; BAC-AL00 Build/HUAWEIBAC-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/10.13 lite baiduboxapp/3.7.5.11 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; BAC-AL00 Build/HUAWEIBAC-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; BKL-AL20 Build/HUAWEIBKL-AL20; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; BND-AL10 Build/HONORBND-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; EVA-AL10 Build/HUAWEIEVA-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/10.13 lite baiduboxapp/3.9.0.11 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; EVA-AL10 Build/HUAWEIEVA-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.0 baiduboxapp/11.0.0.11 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; FIG-AL10 Build/HUAWEIFIG-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.5 baiduboxapp/11.5.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; FRD-AL00 Build/HUAWEIFRD-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; FRD-AL00 Build/HUAWEIFRD-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; FRD-AL10 Build/HUAWEIFRD-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; HWI-AL00 Build/HUAWEIHWI-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.1 baiduboxapp/11.1.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; HWI-AL00 Build/HUAWEIHWI-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; HWI-AL00 Build/HUAWEIHWI-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; KNT-AL10 Build/HUAWEIKNT-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.9 baiduboxapp/11.9.0.11 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; LDN-AL00 Build/HUAWEILDN-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; LLD-AL30 Build/HONORLLD-AL30; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; LND-AL30 Build/HONORLND-AL30; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; LND-AL30 Build/HONORLND-AL30; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.9 baiduboxapp/11.9.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; LON-AL00 Build/HUAWEILON-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; MHA-AL00 Build/HUAWEIMHA-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; MI 6 Build/OPR1.170623.027; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; MI 6 Build/OPR1.170623.027; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; PIC-AL00 Build/HUAWEIPIC-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; PRA-AL00 Build/HONORPRA-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.0.13 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; PRA-AL00X Build/HONORPRA-AL00X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.9 baiduboxapp/11.9.0.11 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; RNE-AL00 Build/HUAWEIRNE-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.2 baiduboxapp/11.2.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; RNE-AL00 Build/HUAWEIRNE-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.0.13 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; RNE-AL00 Build/HUAWEIRNE-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; STF-AL00 Build/HUAWEISTF-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; STF-AL10 Build/HUAWEISTF-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.0.0; VTR-AL00 Build/HUAWEIVTR-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.0.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; 1807-A01 Build/OPM1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.0 baiduboxapp/11.0.5.12 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; AWM-A0 Build/G66T1904190CN00MP4; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; COL-AL10 Build/HUAWEICOL-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/10.12 baiduboxapp/10.12.0.12 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; COR-AL00 Build/HUAWEICOR-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.0 baiduboxapp/11.0.0.11 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; INE-AL00 Build/HUAWEIINE-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; INE-AL00 Build/HUAWEIINE-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; JKM-AL00a Build/HUAWEIJKM-AL00a; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; JKM-AL00b Build/HUAWEIJKM-AL00b; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.6 baiduboxapp/11.6.1.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; JKM-TL00 Build/HUAWEIJKM-TL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; JSN-AL00 Build/HONORJSN-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; JSN-TL00 Build/HONORJSN-TL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; MI 6X Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; MI 8 Lite Build/OPM1.171019.019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; OPPO R11t Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.9 baiduboxapp/11.9.0.11 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PAAM00 Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PAAM00 Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PACM00 Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.0 baiduboxapp/11.0.0.11 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PACM00 Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PACM00 Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PACT00 Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.5 baiduboxapp/11.5.1.1 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PACT00 Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PADM00 Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PADT00 Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PAFM00 Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PBAM00 Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/10.13 lite baiduboxapp/3.7.0.11 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PBAM00 Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PBBM00 Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PBCM10 Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PBCM10 Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PBCM30 Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.9 baiduboxapp/11.9.0.11 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PBEM00 Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; PBEM00 Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; Redmi Note 5 Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; SKR-A0 Build/G66X1904020CN00MPX; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; SNE-AL00 Build/HUAWEISNE-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; V1813A Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; V1816A Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; V1818A Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.6 baiduboxapp/11.6.1.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; V1818CT Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; vivo X9s Plus Build/OPM1.171019.019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; vivo X20A Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; vivo X20Plus Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; vivo X21 Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; vivo X21A Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; vivo X21i Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.1 baiduboxapp/11.1.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; vivo Y71A Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.6 baiduboxapp/11.6.1.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; vivo Y85A Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 8.1.0; vivo Z1 Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 8.1.0)", - "Mozilla/5.0 (Linux; Android 9; ALP-AL00 Build/HUAWEIALP-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.6 baiduboxapp/11.6.1.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; ALP-AL00 Build/HUAWEIALP-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; ALP-AL00 Build/HUAWEIALP-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; ALP-TL00 Build/HUAWEIALP-TL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; BLA-AL00 Build/HUAWEIBLA-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; BLA-AL00 Build/HUAWEIBLA-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; CLT-AL00 Build/HUAWEICLT-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.5 baiduboxapp/11.5.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; CLT-AL01 Build/HUAWEICLT-AL01; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.5 baiduboxapp/11.5.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; CMR-W09 Build/HUAWEICMR-W09; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; COL-AL10 Build/HUAWEICOL-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; COL-AL10 Build/HUAWEICOL-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; COR-TL10 Build/HUAWEICOR-TL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.9 baiduboxapp/11.9.0.11 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; HMA-AL00 Build/HUAWEIHMA-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; HMA-AL00 Build/HUAWEIHMA-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; HMA-AL00 Build/HUAWEIHMA-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.9 baiduboxapp/11.9.0.11 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; HWI-AL00 Build/HUAWEIHWI-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.3 baiduboxapp/11.3.6.11 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; JSN-AL00 Build/HONORJSN-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; LYA-AL00 Build/HUAWEILYA-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; MI 8 Build/PKQ1.180729.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; MI 8 Build/PKQ1.180729.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.9 baiduboxapp/11.9.0.11 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; MI 9 Build/PKQ1.181121.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; ONEPLUS A5010 Build/PKQ1.180716.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; PAR-AL00 Build/HUAWEIPAR-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; PCAM00 Build/PKQ1.190101.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; PCT-AL10 Build/HUAWEIPCT-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; PCT-AL10 Build/HUAWEIPCT-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; Redmi Note 7 Pro Build/PKQ1.181203.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; SM-G9730 Build/PPR1.180610.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; SM-N9600 Build/PPR1.180610.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.7 baiduboxapp/11.7.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; TNY-AL00 Build/HUAWEITNY-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; V1824A Build/PKQ1.181216.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; V1838A Build/PKQ1.181203.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; vivo X21i Build/PPR1.180610.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/11.8 baiduboxapp/11.8.0.10 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1609 Build/MPIS24.241-2.35-1-17) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3261.0 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900T Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.12 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A37fw Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.123 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A51w Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.123 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M153 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.123 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.123 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M150 Build/NRD90U; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/64.0.3282.123 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGLS775 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.123 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.123 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.123 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-J727A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.123 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G925F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.123 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G955U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.123 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.123 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Plus Build/NDRS26.58-33-2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.123 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z982 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.123 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G) Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.123 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A571VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G531H Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J100VPP Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Lenovo P1ma40 Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS676 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGMS428 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; N9136 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36 mCent/0.13.1192", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500FN Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo K50a40 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36 mCent/0.13.1195", - "Mozilla/5.0 (Linux; Android 6.0; LG-H525n Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; BLADE L7A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; FRD-L09 Build/HUAWEIFRD-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI VNS-L21 Build/HUAWEIVNS-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M327 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M430 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-TP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL Build/NRD90U; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGLS992 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP450 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; PRA-LA1 Build/HONORPRA-LA1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Redmi Note 4X Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/64.0.3282.137 Mobile Safari/537.36 lite baiduboxapp/3.5.5.10 (Baidu; P1 7.0)", - "Mozilla/5.0 (Linux; Android 7.0; SM-G610F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327VPP Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VS501 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Coolpad 3632A Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQ26.69-46) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N9560 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-J700T Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-N950U Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Focus/3.2.5 Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; F3JR Build/N2G48H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LG-SP200 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G) Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210CM Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X410(FG) Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/64.0.3282.137 Mobile Safari/537.36 BingWeb/9.5.27157501", - "Mozilla/5.0 (Linux; Android 7.1.2; RC555L Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Redmi 4 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36 mCent/0.13.1208", - "Mozilla/5.0 (Linux; Android 8.0.0; LG-H873 Build/OPR1.170623.032; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play Build/ODP27.91-24-2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930V Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G960F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LML212VL Build/OPM1.171019.019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Redmi Note 5 Pro Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36 mCent/0.13.1176", - "Mozilla/5.0 (Linux; U; Android 8.1.0; en; REVVL 2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Tenta/2.10.7 Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-V405 Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.156 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-T580 Build/PQ1A.190105.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.156 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900T Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3310.3 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-LS777 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3310.3 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-T230NU Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; N817 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-G360H Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; XT1080 Build/SU6-7.7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900V Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; VOYAGER2_DG310 Build/LRX21M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A37f Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-T337A Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G388F Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J100VPP Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320F Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-T365 Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HTC Desire 520 Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI CUN-L01 Build/HUAWEICUN-L01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS676 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910G Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z981 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z988 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; M3 Max Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; R1 PLUS Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; FRD-AL00 Build/HUAWEIFRD-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI NXT-L29 Build/HUAWEINXT-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-H831 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-H872 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M257 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M430 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL164VL Build/NRD90U; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGLS775 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGUS215 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Redmi Note 4 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G930A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-J327A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G570Y Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G925I Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J727T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-T580 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VKY-L29 Build/HUAWEIVKY-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; GM 5 Plus d Build/NNK57) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; K88 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NDQS26.69-64-2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NDQS26.69-64-2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36 EdgA/41.0.0.1921", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Plus Build/NCR26.58-26) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SAMSUNG-SM-J320AZ Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-J700T Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-N950U Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z557BL Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z899VL Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z982 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z983 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G) Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Redmi Note 5A Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG-SM-G891A Build/R16NW; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930VL Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; DRA-L01 Build/HUAWEIDRA-L01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; INE-LX2 Build/HUAWEIINE-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 8.0.0; RNE-L21 Build/HUAWEIRNE-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/65.0.3325.109 Mobile Safari/537.36 OPR/37.1.2254.132401", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-G850F Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VS501 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G) Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; HTC U11 life Build/OPR6.170623.013) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.1.2; GT-I9300 Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.1.2; HTC Desire 500 Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; SCH-I545 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL52VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGMS330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J120ZN Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J200M Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI LUA-L22 Build/HUAWEILUA-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; PULP FAB Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; H710VL Build/HUAWEIH710VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS676 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; N9136 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; N9519 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532F Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J710MN Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z798BL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z837VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; RCT6K03W13 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G920A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-A520W Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G610F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G610M Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930W8 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J727T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J730GM Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VS501 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VS987 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQ26.69-64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQ26.69-46-5-4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQ26.69-46) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SAMSUNG-SM-J320AZ Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G) Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Redmi 5 Plus Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX1 Build/HUAWEIANE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; HTC U11 life Build/OPR6.170623.013) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LDN-LX2 Build/HUAWEILDN-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LG-G710 Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LG-H831 Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play Build/ODP27.91-121) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play Build/ODPS27.91-121-8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play Build/ODPS27.91-121-4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930R4 Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955W Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J737T1 Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J737T1 Build/R16NW; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; VTR-L29 Build/HUAWEIVTR-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; 5041C Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710.FGN Build/OPM1.171019.019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Redmi S2 Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J327VPP Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J727P Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J727T1 Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.126 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J727T1 Build/M1AJQ; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 Mobile Safari/537.36 BingWeb/9.4.26267402", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; 302KC Build/104.0.3020) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; HUAWEI H891L Build/HuaweiH891L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-G530MU Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; Redmi Note 2 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; vivo Y35 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SAMSUNG-SM-N900A Build/LRX21V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; Tab2A7-10F Build/LRX21M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; ASUS_X00BD Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGMS330 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-G928A Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J111F Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J120H Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320FN Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J500G Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J500M Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J700F Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; vivo V3 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; 8050G Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A79 Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; iris560 Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; ZTE Blade L5 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; CPH1607 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; CPH1701 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M151 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS676 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-J320A Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532F Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532G Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900I Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J320VPP Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S120VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S727VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo 1606 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo 1610 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z798BL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z833 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; 5080A Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; CPH1609 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; CRO-L03 Build/HUAWEICRO-L03) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-H343 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-X230 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; MotoG3-TE Build/MPDS24.65-33-1-30) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; 5049Z Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36 OPR/47.1.2249.129326", - "Mozilla/5.0 (Linux; Android 7.0; LG-M320 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL158VL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGUS215 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGUS997 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; MI 5s Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Redmi Note 4 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G925A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G610M Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G925F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G955U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36 OPR/47.1.2249.129326", - "Mozilla/5.0 (Linux; Android 7.0; SM-J727V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-N920V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQ26.69-64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NDQS26.69-64-2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-N950F Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z557BL Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z899VL Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z971 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z982 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z3001S Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ONEPLUS A3000 Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G960F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G960U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; STF-L09 Build/HUAWEISTF-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; VTR-L09 Build/HUAWEIVTR-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Pixel 2 XL Build/PQ2A.190405.003) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ2A.190205.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Pixel Build/PPR2.181005.003) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M430 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 YaBrowser/18.6.0.683.00 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.46 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SAMSUNG-SM-J320AZ Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.82 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI VNS-L23 Build/HUAWEIVNS-L23) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.123 Mobile Safari/537.36 EdgA/42.0.0.2313", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.49 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HTCD100LVWPP Build/LMY47O) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; D6502 Build/23.5.A.1.291) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Le X522 Build/IFXNAOP5802102141S) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS676 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Redmi Note 4 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Focus/5.0 Chrome/67.0.3396.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-LS777 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Coolpad 3632A Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G960U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.68 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; HTC One_M8 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z798BL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-LS777 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Redmi Note 4 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G925F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Coolpad 3632A Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-J510FN Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; XT1710-02 Build/NDSS26.118-23-19-6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z851M Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LLD-L31 Build/HONORLLD-L31) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; MediaPad M1 8.0 Build/HuaweiMediaPad) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.3; SM-S975L Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; GT-N7100 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; HUAWEI G7-L03 Build/HuaweiG7-L03) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; ALE-L02 Build/HuaweiALE-L02) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; vivo Y51 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900V Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A37f Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-J100VPP Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G531F Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J120F Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J200GU Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J200M Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320F Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; vivo V3Max Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; BLU DASH M Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI LUA-L21 Build/HUAWEILUA-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; OPPO R7s Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; SLTDVD9200 Build/LMY47I; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M151 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M153 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGL58VL Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS676 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS755 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-A800F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G532G Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G550T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G900I Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-N910G Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-S327VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500G Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700M Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; TOMMY Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo 1606 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; VS500PP Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z981 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; CRO-L22 Build/HUAWEICRO-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; PLK-L01 Build/HONORPLK-L01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HTC One A9 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-H870 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M250 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M257 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M320 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M327 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M400 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M430 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-TP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL158VL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGUS215 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto C Build/NRD90M.063) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; PRA-LX1 Build/HUAWEIPRA-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G920F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G920F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.4 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G925F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-N920C Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-J327A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-A510F Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-A710F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G920S Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G928F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935P Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J530F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J727T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J727V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SMART 4G GEN C 4.0 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N818S Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N9137 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N9560 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; REVVLPLUS C3701A Build/143.14.171129.3701A-TMO) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SAMSUNG SM-T350 Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-J510FN Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-J700P Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z557BL Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z835 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z899VL Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z982 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G) Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210VPP Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ATU-L42 Build/HUAWEIATU-L42) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LDN-LX2 Build/HUAWEILDN-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LM-G710 Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; MHA-AL00 Build/HUAWEIMHA-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ONEPLUS A3000 Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; PRA-TL10 Build/HONORPRA-TL10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-A520F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-A600FN Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-A720F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G930A Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G930F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G930P Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G930T Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G930W8 Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G960F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-J337A Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-J737P Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-J737T1 Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-S367VL Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-S767VL Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SH-M05 Build/S5221) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-A520F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-A520W Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930V Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G960U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; 5033A Build/O11019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; A502DL Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; H1A1000 Build/H1A1000.007ho.01.01.01r.217) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710(FGN) Build/OPM1.171019.019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LML212VL Build/OPM1.171019.019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; ONEPLUS A5010 Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Pixel 2 Build/OPM2.171026.006.G1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Pixel 2 XL Build/OPM2.171026.006.C1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-G610F Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-J260T1 Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-J701M Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-J701MT Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-J727AZ Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-J727T1 Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-G610F Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Nokia 3.1 Plus Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Pixel 2 XL Build/PQ2A.190405.003) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G950F Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G950U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.0 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G955U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G960F Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G960U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.0 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G960U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G965F Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.0 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G965F Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G965U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.0 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G965U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-N950U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.0 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-N950U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-N960F Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-N960U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.0 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-N960U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.2 Chrome/67.0.3396.87 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G) Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3400.0 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z851M Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3430.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z899VL Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3430.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.40 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; ALCATEL ONE TOUCH 7047A Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.70 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J500F Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.70 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; U2 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.70 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.70 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; VS500PP Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.70 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-J327A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.70 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.70 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J727T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.70 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.70 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.70 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.70 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1; SM-N960F Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.70 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; JERRY Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.8 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; GT-I9060 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-T113 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Lenovo A2020a40 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LG-K420 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J120G Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J200GU Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; CPH1701 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Le X821 Build/FGXOSOP5801910121S) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-A500FU Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N915F Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S727VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1254 Build/MCG24.251-5-5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; 5080X Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Infinix Zero 3 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo K50a40 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-H818 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; RCT6773W22BM Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Redmi Note 4 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; vivo 1609 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI VNS-L21 Build/HUAWEIVNS-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M250 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M257 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto G (4) Build/NPJS25.93-14-18) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto G (5) Plus Build/NPNS25.137-93-14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G925A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G570Y Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J701F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J727P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J730F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J730F Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Lenovo K8 Note Build/NMB26.54-94) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Nokia 2 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-C710F Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-C9000 Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z851M Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G) Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ATU-L21 Build/HUAWEIATU-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ATU-L22 Build/HUAWEIATU-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; BND-AL10 Build/HONORBND-AL10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; MHA-L09 Build/HUAWEIMHA-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ONEPLUS A3000 Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; PRA-LX1 Build/HONORPRA-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-A720F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-A730F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930P Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930V Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935V Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; WAS-LX1 Build/HUAWEIWAS-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Mi A1 Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; ONEPLUS A5000 Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Redmi Note 5 Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; TA-1053 Build/OPR1.170623.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.85 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; GT-I9505 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; GT-N5100 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SCH-I535 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-G355M Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-G7102 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-T520 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SPH-L900 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-T113 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; GT-I9505 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; SHV-E330L Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-G530H Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; F1f Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Lenovo A6020a40 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL52VL Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; M1092R Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G531H Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J100VPP Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J111F Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320FN Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-T285 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; vivo X7 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; 8050G Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A1601 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A1603 Build/LMY47I; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; es-us; 8050G Build/LMY47I; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; MotoE2(4G-LTE) Build/LPIS23.29-18.9-6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; MotoE2(4G-LTE) Build/LPIS23.29-18.9-2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; ZTE Blade L5 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5056N Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M151 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M153 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGL58VL Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS676 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGUS110 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; RCT6873W42 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Redmi 3S Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Redmi 4A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G900A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G930A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-J120A Build/MMB29K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-J120AZ Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532F Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532G Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532MT Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700H Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S120VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S727VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo 1606 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo 1610 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; VS500PP Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; 5010G Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ALE-L21 Build/HuaweiALE-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; BLL-L23 Build/HUAWEIBLL-L23) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; CAM-L23 Build/HUAWEICAM-L23) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; CRO-L22 Build/HUAWEICRO-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; EVA-L19 Build/HUAWEIEVA-L19) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-X230 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Redmi Note 4X Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; SMART 4G MAX 5.0 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; VIE-L09 Build/HUAWEIVIE-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; 5049Z Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; BLL-L22 Build/HUAWEIBLL-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; DUK-L09 Build/HUAWEIDUK-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; iris80 Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-LS777 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M150 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M250 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M257 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M430 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL83BL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL158VL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL164VL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGLS775 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP450 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGUS215 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; MI MAX Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto G (5) Plus Build/NPN25.137-93) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; PRA-LX1 Build/HUAWEIPRA-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-J327A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SC-02H Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-A520F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G570M Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G610F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G615F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G920V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J710F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J710MN Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J727T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; A574BL Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Coolpad 3632A Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; CPH1729 Build/N6F26Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; LG-M700 Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQ26.69-64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NDQ26.69-64-9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NDQS26.69-64-8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto G (5S) Build/NPPS26.102-49-11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N818S Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N9560 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SAMSUNG-SM-J320AZ Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-J510FN Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-J700T1 Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-J700T Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-N9005 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; XT1710-02 Build/NDSS26.118-23-19-6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z557BL Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z835 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z851M Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z899VL Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z965 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z982 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z983 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LG-SP200 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G) Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Redmi 5 Plus Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Redmi Note 5A Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Focus/6.1.1 Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX1 Build/HUAWEIANE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; AUM-L29 Build/HONORAUM-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; HWI-AL00 Build/HUAWEIHWI-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LDN-L21 Build/HUAWEILDN-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LGM-G600L Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; MI 5 Build/OPR1.170623.032; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 cruise Build/OCP27.91-157) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play Build/OCP27.91-150-5-1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play Build/OCPS27.91-150-5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play Build/OCPS27.91-150-2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 plus Build/OCP27.91-150-8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 plus Build/OCPS27.91-150-2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto g(6) Build/OPS27.82-72) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto g(6) play Build/OPP27.91-140) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; Moto Z (2) Build/OCXS27.109-51-7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ONEPLUS A3003 Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; PRA-LX1 Build/HUAWEIPRA-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; PRA-LX2 Build/HUAWEIPRA-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; RNE-L21 Build/HUAWEIRNE-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG-SM-G891A Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG-SM-G930A Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G892U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930T Build/R16NW; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930V Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935V Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950W Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G960F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G960U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J337AZ Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; VS988 Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; VS995 Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; WAS-LX1 Build/HUAWEIWAS-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; WAS-LX1A Build/HUAWEIWAS-LX1A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; 5041C Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Alcatel_5059R Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; INE-LX2 Build/HUAWEIINE-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LG-Q710AL Build/O11019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q610(FGN) Build/OPM1.171019.019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710(FGN) Build/OPM1.171019.019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210 Build/OPM1.171019.019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210(G) Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X212(G) Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X410(FG) Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X410.FG Build/OPM1.171019.019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LML212VL Build/OPM1.171019.019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Nokia 3.1 Plus Build/O11019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Nokia 5.1 Plus Build/O11019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; ONEPLUS A5000 Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Redmi 6A Build/O11019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Redmi Note 5 Pro Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-G610F Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J530F Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J727T1 Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-N960U Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Z559DL Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Pixel 2 Build/PPR1.180610.009) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Pixel Build/PPR1.180610.009) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; JERRY Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3464.0 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; JERRY Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3475.0 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J710F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3475.0 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.3; GT-I9300 Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; LGLS740 Build/KOT49I.LS740ZV5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-G355H Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; GT-I9060I Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-J100H Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-T116 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-T561 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; XT1025 Build/KXC21.5-40) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; GT-I9506 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; HTC One_M8 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; Lenovo A5000 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; vivo Y35 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A37f Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A37fw Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G531H Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J120ZN Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; VS425PP Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A1601 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; es-us; 8050G Build/LMY47I; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI CUN-L21 Build/HUAWEICUN-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; iris560 Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; m3 note Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; P8_Energy Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5056E Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Lenovo TB-X103F Build/LenovoTB-X103F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M151 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M153 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGL58VL Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGUS110 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; N9136 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; RCT6873W42 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Redmi 4A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G930A Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532MT Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T1 Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900T Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S120VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36 OPR/48.1.2331.132804", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S727VL Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; XT1254 Build/MCG24.251-5-5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z981 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ALE-L21 Build/HuaweiALE-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; CRO-U00 Build/HUAWEICRO-U00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; HUAWEI GRA-L09 Build/HUAWEIGRA-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; JERRY Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-X230 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; RCT6K03W13 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Focus/6.1.1 Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; BLL-L22 Build/HUAWEIBLL-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI VNS-L23 Build/HUAWEIVNS-L23) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-LS777 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M320 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M327 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M430 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL Build/NRD90U; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL158VL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP450 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto G (4) Build/NPJS25.93-14-10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; PGN528 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G925A Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SLA-L22 Build/HUAWEISLA-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G570M Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G610F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G920W8 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J727P Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-S737TL Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-T815Y Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; TRT-LX2 Build/HUAWEITRT-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Focus/6.1.1 Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; A574BL Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Coolpad 3632A Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; CPH1729 Build/N6F26Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; GM 5 Plus Build/NNJ34) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; MI MAX 2 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NDQS26.69-64-5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Plus Build/NPRS26.58-47-6; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N818S Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N9560 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N9560 Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36 OPR/48.2.2331.133274", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-J700T Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-T377V Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; XT1710-02 Build/NDSS26.118-23-19-6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z899VL Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z965 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z982 Build/NMF26V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G) Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210CM Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X212(G) Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX1 Build/HUAWEIANE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX2 Build/HUAWEIANE-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ATU-L22 Build/HUAWEIATU-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; BND-L21 Build/HONORBND-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; HTC U11 Build/OPR6.170623.013; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LM-G710VM Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 cruise Build/OCPS27.91-32-5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto g(6) play Build/OPP27.91-87) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; RNE-L21 Build/HUAWEIRNE-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG-SM-G930A Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SHT-AL09 Build/HUAWEISHT-AL09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950W Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G960U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J337AZ Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U1 Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-S367VL Build/R16NW; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.100 Mobile Safari/537.36 BingWeb/9.9.27198701", - "Mozilla/5.0 (Linux; Android 8.0.0; VS995 Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; VS995 Build/OPR1.170623.032; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; WAS-LX1 Build/HUAWEIWAS-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; CPH1909 Build/O11019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; INE-LX2 Build/HUAWEIINE-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LG-Q710AL Build/O11019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710(FGN) Build/OPM1.171019.019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710(FGN) Build/OPM1.171019.019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210 Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210(G) Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X220 Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; MI Mix 2 Build/OPM2.171019.029) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 YaBrowser/18.10.2.119.00 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Redmi Note 5 Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J260F Build/M1AJB) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J327V Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; INE-LX2 Build/HUAWEIINE-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Pixel XL Build/PPR2.181005.003) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G965U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-N950U Build/PPR1.180610.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; A1 Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.128 Mobile Safari/537.36 (Ecosia android@69.0.3497.128)", - "Mozilla/5.0 (Linux; Android 6.0; JERRY Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.24 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo TB3-730F Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.76 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Redmi Note 4X Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500FN Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.86 Mobile Safari/537.36 EdgA/42.0.0.2804", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI NXT-AL10 Build/HUAWEINXT-AL10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.86 Mobile Safari/537.36 EdgA/42.0.0.2741", - "Mozilla/5.0 (Linux; Android 7.0; LGL164VL Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.86 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto C Build/NRD90M.063) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.86 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J710F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.86 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.86 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.86 Mobile Safari/537.36 EdgA/42.0.0.2741", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.86 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.86 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Pixel XL Build/PPR1.180610.009) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.86 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; Blade V6 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.9 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; JERRY Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.9 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; VK810 4G Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J700H Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5056I Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M153 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS676 Build/MXB48T) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.91 Mobile Safari/537.36 OPT/1.10.33", - "Mozilla/5.0 (Linux; Android 6.0.1; RCT6873W42 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; 5049W Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI NXT-L09 Build/HUAWEINXT-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI VNS-L31 Build/HUAWEIVNS-L31) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP450 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J727T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4) Build/NCQS26.69-64-3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX1 Build/HUAWEIANE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; Moto Z (2) Build/OCXS27.109-51-7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-A520F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935V Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Redmi 5 Plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 YaBrowser/18.11.2.501.00 (alpha) Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; C6730) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; XT1080) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; D2303) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G360G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J100VPP) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-T235) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5056I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M151) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGUS110) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; N9136) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-J120A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z981) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Blade V6 Plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Dash XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo TB3-730F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; M5s) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; 5049Z) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M327) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Life M2+ Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SMART 4G GEN C 5.5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; TRT-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VS501) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; CPH1725) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; LG-M703) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z835) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z899VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z965) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LG-SP200 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/70.0.3538.110 Mobile Safari/537.36 OPT/1.13.48", - "Mozilla/5.0 (Linux; Android 7.1.2; LG-SP200) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ATU-L31) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LLD-AL20) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 cruise) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto g(6)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG-SM-G930A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG-SM-G935A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-A320FL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G892A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930W8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U Build/R16NW; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-S367VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; A502DL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LG-Q710AL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710(FGN)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-V405) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X410(FG)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Moto G (5S)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Nokia 3.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Redmi Note 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG-SM-J727AZ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J530F Build/M1AJQ; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J727P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-T580) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; HMA-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; INE-LX2 Build/HUAWEIINE-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36 OPR/49.2.2361.134358", - "Mozilla/5.0 (Linux; Android 9; INE-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Pixel) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.17 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.21257 Mobile Safari/537.36 Sparrow/0.1", - "Mozilla/5.0 (Linux; Android 5.1; MotoE2(4G-LTE)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Z987) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; CPH1701) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S120VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; FRD-L04) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J530F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J710K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-T580) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Focus/7.0.12 Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Coolpad 3632A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; XT1609) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG-SM-G891A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J337AZ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; VTR-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710(FGN)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J727T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.3; C6603) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-T230) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; GT-I9505) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; LG-V410) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-A300H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-S978L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; ALE-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SAMSUNG-SM-G900A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-E700H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J120ZN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; es-us; 8050G Build/LMY47I; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI CUN-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M151) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M153) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G900A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-N910A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S727VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Dash XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; HTC One_M8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Alcatel 5085C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; ASUS_X008DA) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; BLL-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Lenovo K33a48) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-H960) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGLS992 Build/NRD90U; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGLS992) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; PRA-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G610F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G925T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J530F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J710MN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Coolpad 3632A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; L50) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-J510FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-T350) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z839) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z982) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LG-SP200) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X212(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; SM-N900) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ATU-L11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ATU-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LDN-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LG-H870) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 cruise) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; RNE-L03) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; RNE-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG-SM-G935A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-A520W) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955F Build/R16NW; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; TA-1032) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; WAS-LX1A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LG-M250) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710(FGN)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J327V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J727T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J727T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J730G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Pixel 2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; JERRY) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3555.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; HTC One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; D2303) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL44VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Lenovo K33a48) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Lenovo TB-X103F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; CRO-U00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; HUAWEI CRR-UL00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; BLL-L23) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M250) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M327) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930W8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710.FG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J727P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.83 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; HTC One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI LUA-U22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-K350) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VKY-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Coolpad 3632A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z558VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z835) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z839) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; Nokia 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LG-Q710AL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710.FG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J727P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; GT-P5113) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; Le Pan TC802A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.2.2; SM-T110) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.3; GT-I9300) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; ASUS_T00J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-G730W8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-G7102) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; HUAWEI H891L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; N817) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; XT1080) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; LG-V410) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-A500F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; vivo Y51) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-G900V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A33f Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A33f) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A37fw Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36 OPR/50.3.2426.136976", - "Mozilla/5.0 (Linux; Android 5.1.1; A37fw) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGLS675) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320Y) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J500FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J3110) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-T280) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-T285) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A33w) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI LUA-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; iris 810) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Lenovo TB3-710I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; PRO 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M153) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS676) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Redmi 3S) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Redmi Note 3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-J120A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G920V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G928T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N910V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S727VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; VS500PP) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; BLL-L23) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo A7020a48) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-K350) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; vivo 1609 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; vivo 1609) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; 5049Z) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Alcatel 5085C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; DLI-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; EVA-L19) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI NXT-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI VNS-L31) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-LS777) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M210 Build/NRD90U; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 BingWeb/9.4.26268401", - "Mozilla/5.0 (Linux; Android 7.0; LG-M210) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M250) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M327) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M430 Build/NRD90U; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 BingWeb/9.5.27159402", - "Mozilla/5.0 (Linux; Android 7.0; LG-M430) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260 Build/NRD90U; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Life M2+ Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G920A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-A520F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G935V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-N920C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-T815) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SMART Champ 4.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; XT1585) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; A574BL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; CPH1725) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; MI MAX 2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N818S) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N9560) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Redmi Note 5 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; REVVLPLUS C3701A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-J510FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-J700T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z558VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z971) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z3001S) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; E6810) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LG-SP200) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; M6 Note) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Focus/8.0.6 Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ATU-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LDN-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LG-G710) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LGUS997) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LM-G710) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LM-G710VM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 cruise) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto g(6) play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; PRA-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G892U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930W8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G960F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G9650) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J337A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J737R4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U Build/R16NW; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; VS988) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; VS995) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; VTR-L09 Build/HUAWEIVTR-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36 OPR/50.3.2426.136976", - "Mozilla/5.0 (Linux; Android 8.0.0; XT1650) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; CPH1803) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; CPH1823) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; FIG-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LG-Q710AL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710(FGN)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X410PM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LML212VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; moto e5 play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Moto G (5) Plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; moto z3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Redmi Note 5 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-G610F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-G610M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J327V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J327VPP) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J530F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J727P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J727T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J727T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J730G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-N960F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-N960U Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36 OPR/50.3.2426.136976", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-N960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-N960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36 EdgA/42.0.92.3327", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-S737TL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SNE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; vivo 1812) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; CLT-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; CLT-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; EML-AL00 Build/HUAWEIEML-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 JsSdk/2 NewsArticle/7.2.0 NetType/wifi TTPreload", - "Mozilla/5.0 (Linux; Android 9; Nokia 5.1 Plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Pixel 2 XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Redmi Note 7 Build/PKQ1.180904.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 baiduboxapp/11.9.0.11 (Baidu; P1 9)", - "Mozilla/5.0 (Linux; Android 9; SM-G950F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G955W) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G965F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G965U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-N960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SMART 4G GEN C 5.5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3610.2 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; LG-V410) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-T230NU) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; XT1060) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.1; ALE-L23) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-A300H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0; SM-N9005) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A37f) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL62VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-N910A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-T337A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G531H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J100VPP) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; Z828) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; X9009) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; HTC Desire 626s) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; HUAWEI RIO-L01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z956) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Dash XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; HUAWEI GRA-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LGLS991) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; MotoG3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; VFD 300) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ZTE BLADE V0720) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; 5049Z) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI MLA-L03) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; HUAWEI VNS-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M150) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M327) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M430) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL83BL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL158VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS428) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; NUU_A3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G925A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G903W) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G925I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J710MN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-N920V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VS501) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Coolpad 3632A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; MI MAX 2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto Z2 Play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N818S) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N9137) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N9560) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; XT1562) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z557BL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z558VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z835) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z839) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z851M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z899VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z982) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LG-SP200) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210CM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Redmi 4X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; FIG-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; FIG-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LDN-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LM-G710) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 cruise) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto g(6) play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-A730F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G570Y) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G892A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; 6062W) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; A502DL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Alcatel_5059R) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; DRA-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LG-Q710AL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710(FGN) Build/OPM1.171019.019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/72.0.3626.105 Mobile Safari/537.36 BingWeb/9.5.27159402", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710(FGN)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710.FG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X212(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X220) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X410(FG)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LML212VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; moto e5 (XT1920DL)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; moto z3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Redmi 5 Plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-G610M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-N960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; TECNO KA7 Build/O11019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; vivo 1812) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Pixel 2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Pixel 3 XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G950F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G960F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-N960F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.105 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; HUAWEI H891L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-T113) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; KYOCERA-C6742) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-T677A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M153) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N920C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S907VL Build/MMB29K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/72.0.3626.121 Mobile Safari/537.36 BingWeb/9.7.27178401", - "Mozilla/5.0 (Linux; Android 6.0.1; VS500PP) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z981) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-H343) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Micromax Q4260) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; vivo 1601) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; 5026D Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36 OPR/51.2.2461.137690", - "Mozilla/5.0 (Linux; Android 7.0; LG-M150) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M250) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-TP260) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL158VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-J327A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G920V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; VS501) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; A574BL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; MI MAX 2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z835) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z3001S) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; E6810) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210VPP) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; FIG-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LM-G710VM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 cruise) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto g(6) play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto g(6)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950W) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J337AZ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J600G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J737T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-S367VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; 5041C Build/OPM1.171019.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36 OPR/51.2.2461.137690", - "Mozilla/5.0 (Linux; Android 8.1.0; A502DL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; CPH1803) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; i120) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; JSN-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LG-Q710AL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710(FGN)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X212(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X410.FGN Build/OPM1.171019.019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36 OPR/51.2.2461.137690", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X410PM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LML212VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LML413DL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LML713DL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Nokia 2 V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Redmi 5 Plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-G610F Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36 OPR/51.2.2461.137690", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-G610F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J701M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-N960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-T580) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; INE-LX2 Build/HUAWEIINE-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36 OPR/51.0.2461.137246", - "Mozilla/5.0 (Linux; Android 9; INE-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Nokia 2.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G960F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G965U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.53 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.64 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A1601) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; M5c) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Alcatel 5085C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z558VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z3001S) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210CM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LGUS997) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; PRA-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G892A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Alcatel_5059R) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LG-Q710AL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710(FGN)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210(G) Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LML212VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; moto e5 play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-N960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; COL-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G965U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; VIVO GO) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.76 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-G730W8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HTC Desire 828 dual sim) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; DG101TB Build/MXC89K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/72.0.3626.96 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; CRO-U00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; vivo 1601) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; TRT-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z899VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210CM Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210CM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; BND-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; CPH1803) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X410.FGN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Nokia 3.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3666.0 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; LG-X220) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.37 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G965F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.37 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-T113NU) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; KFAUWI) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG-SM-T337A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; C6740N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Lenovo TB-X103F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S727VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-T377V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-H811) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-X230) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Lenovo K33a48) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-LS777) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G920V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; CPH1725) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; L50) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-P550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; XT1609) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z971) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210CM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LG-LS993) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LM-G710) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 cruise) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-A605G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935W8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J337P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; A502DL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; CPH1819) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LG-Q710AL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710(FGN)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-V405) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X220) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X410(FG)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X410PM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LML212VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; moto z3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Redmi 5 Plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SNE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Pixel 3 XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G950F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; A1 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Safari/537.36 OPR/52.1.2517.139570", - "Mozilla/5.0 (Linux; Android 4.4.2; LG-V410) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.3; HTC Desire 510) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-S820L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; SM-S920L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; C5503) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G360T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J3110) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; vivo V3Max) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A1601) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; Lenovo A2010-a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; 5056I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LGLS676) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; MotoG3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-J120A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G550T2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900W8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J710F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S327VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-S727VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-T377V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-T378K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; VS500PP) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z981) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ALE-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-H811) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-K350) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ZTE BLADE A510) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ZTE BLADE V0720) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; 5049Z) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Alcatel_5044R Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/73.0.3683.90 Mobile Safari/537.36 BingWeb/9.7.27178401", - "Mozilla/5.0 (Linux; Android 7.0; BLL-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; EVA-L19) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-H918) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-LS777) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M210) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M250) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M327) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M430) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-TP260) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL83BL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL158VL Build/NRD90U; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL158VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP450) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Redmi Note 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G891A Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG-SM-G930A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-A310F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G610M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G925F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-N920P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; TRT-L53) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; CPH1725) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N9137) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; N9560) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; S7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SM-T560NU) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; XT1609) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z557BL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z558VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z835) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z899VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z982) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z3001S) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LG-SP200) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210CM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; RC555L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Redmi 4A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Redmi 4X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX2J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ATU-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; BAC-L21 Build/HUAWEIBAC-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; FIG-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LG-H918) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LG-LS993) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 cruise) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play Build/OCP27.91-150-5-1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36 OPR/52.1.2517.139570", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play Build/OCPS27.91-150-5; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play Build/OCPS27.91-150-5; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/73.0.3683.90 Mobile Safari/537.36 BingWeb/9.7.27178401", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto g(6) play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; Moto Z2 Play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; Moto Z (2)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ONEPLUS A3003) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-A520F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-A520W) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G570M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G611F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J337A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J337P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J337V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J737P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J737T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J737V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-S367VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; VTR-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; WAS-LX1A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; XT1650) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; 5033A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; 5041C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; A502DL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; ASUS_X00TD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; CPH1819) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; CPH1823) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; K500) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LG-Q710AL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710(FGN)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710.FG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710.FGN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-V405) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210(G) Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/73.0.3683.90 Mobile Safari/537.36 OPT/1.16.61", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X220 Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/73.0.3683.90 Mobile Safari/537.36 OPT/1.16.61", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X220) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X410(FG)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X410.FGN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LML212VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LML713DL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; moto e5 (XT1920DL)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Moto G (5) Plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Moto G (5S) Plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J260T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J701M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J727T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J727T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J730F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; VFD 529 Build/O11019) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Z559DL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; COL-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; G8441) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; JAT-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; LON-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; MHA-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; MI 8 Lite) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; moto z3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Nokia 6.1 Plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Pixel 2 XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G950F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G960U Build/PPR1.180610.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G965U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-N960F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-N960U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36 OPR/52.1.2517.139570", - "Mozilla/5.0 (Linux; Android 9; SM-N960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.90 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; U; Android 5.1; HUAWEI LUA-U22 Build/HUAWEILUA-U22; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/73.0.3683.90 Mobile Safari/537.36 OPR/40.1.2254.138129", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3711.0 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; 305SH) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-T113) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; LGL52VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; KIW-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N915G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z833) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Alcatel 5085C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; CPH1725) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; CPH1729) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; SAMSUNG-SM-T377A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z899VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210CM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; FIG-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LDN-L01 Build/HUAWEILDN-L01; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LDN-L01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LG-LS993) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LLD-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J337P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J737T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J737V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; XT1650) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; 5041C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; DRA-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710.FG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; moto e5 (XT1920DL)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J327VPP) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J710F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SNE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; CLT-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; EML-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.112 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G970U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.112 Mobile Safari/537.36 OPT/1.16.62", - "Mozilla/5.0 (Linux; Android 5.0.2; P023) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J320M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M151) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M153) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G900V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J327P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z981) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; LG-H811) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; RCT6K03W13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; 5049W) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; AW790) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M327) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M430) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS210) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; X60L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; A574BL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z835) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z982) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210CM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; FIG-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LG-H873) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto g(6) play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-A520W) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G892U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930W8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J737P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-S767VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; VS987) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; VS988) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; XT1650) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; 5033A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; 9027W) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; A502DL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; CPH1819) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; H1A1000) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; INE-LX2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LG-Q710AL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710(FGN) Build/OPM1.171019.019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710.FG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X212(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X220) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X410(FG)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X410.FGN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J260T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J415FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J610FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; EML-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Pixel 2 XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G955U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G960F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G970U Build/PPR1.180610.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G975U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.136 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.4; SM-T561) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.0.2; P023) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; 5054W) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A37fw) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-G531F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J105B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M151) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; LG-M153) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Redmi Note 3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-N920V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Z798BL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Aquaris M10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; CAM-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; Lenovo A2016b30) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; vivo 1601) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; ZTE BLADE A510) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M327 Build/NRD90U; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M400) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LG-M430) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGL84VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP260) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMP450) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; LGMS550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; MS50L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G920V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G930V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J327T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Focus/8.0.6 Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; CPH1725) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Moto E (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Pixel XL Build/NOF26V) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.157 Safari/537.36 OPT/1.16.62", - "Mozilla/5.0 (Linux; Android 7.1.1; TW801) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z557BL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z851M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z855) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; Z965) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Alpha 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LG-SP200) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; LM-X210CM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; RC555L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ATU-L31) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LDN-L01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; LG-H873 Build/OPR1.170623.032; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.157 Mobile Safari/537.36 BingWeb/9.9.27198102", - "Mozilla/5.0 (Linux; Android 8.0.0; LG-H873) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 cruise) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto g(6) play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G892A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G930W8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J337A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J337AZ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J737P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-N950U1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-S767VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; XT1710-02) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Focus/7.0.10 Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; 5033X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; 5041C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; 6062W) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; A502DL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; Aquaris X Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; ASUS_X00LD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; CPH1819) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; CPH1823) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LG-Q710AL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q610(FGN)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710(FGN)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-Q710.FGN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X210(G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LM-X220) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; LML212VL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-G610F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J260T1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J327VPP) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-J727T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; SM-S737TL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; moto g(7)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; MRD-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; Pixel 2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G950F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G955U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G965F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G965U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G973U1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-G975U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 9; SM-N960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; VS500PP) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.61 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; SM-J737V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.92 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; moto e5 cruise) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.28 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.1.0; QS5509A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.28 Mobile Safari/537.36" - ], - "firefox": [ - "Mozilla/5.0 (Android 3.0; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 3.1; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 3.2.6; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 3.2; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 4.0.4; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 4.0; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 4.1; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 4.2; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 4.3.1; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 4.3; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 4.4.4; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 4.4; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 5.0; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 5.1.1; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 5.1; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 6.0.1; Mobile; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 6.0.1; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 6.0; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 7.0; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 7.1.2; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 7.1; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 8.0; Tablet; rv:50.0) Gecko/50.0 Firefox/50.0", - "Mozilla/5.0 (Android 4.4.3; Mobile; rv:51.0) Gecko/51.0 Firefox/51.0", - "Mozilla/5.0 (Android 5.0.1; Tablet; rv:51.0) Gecko/51.0 Firefox/51.0", - "Mozilla/5.0 (Android 5.0.2; Mobile; rv:51.0) Gecko/51.0 Firefox/51.0", - "Mozilla/5.0 (Android 6.0.1; Mobile; rv:51.0) Gecko/51.0 Firefox/51.0", - "Mozilla/5.0 (Android 7.0; Mobile; rv:51.0) Gecko/51.0 Firefox/51.0", - "Mozilla/5.0 (Android 7.1; Mobile; rv:51.0) Gecko/51.0 Firefox/51.0", - "Mozilla/5.0 (Android 4.2.2; Mobile; rv:52.0) Gecko/52.0 Firefox/52.0", - "Mozilla/5.0 (Android 4.4.2; Mobile; rv:52.0) Gecko/52.0 Firefox/52.0", - "Mozilla/5.0 (Android 4.4.4; Tablet; rv:52.0) Gecko/52.0 Firefox/52.0", - "Mozilla/5.0 (Android 6.0.1; Mobile; rv:52.0) Gecko/52.0 Firefox/52.0", - "Mozilla/5.0 (Android 7.0; Mobile; LG-M150; rv:52.0) Gecko/52.0 Firefox/52.0", - "Mozilla/5.0 (Android 4.4.2; Mobile; rv:53.0) Gecko/53.0 Firefox/53.0", - "Mozilla/5.0 (Android 6.0.1; Mobile; rv:53.0) Gecko/53.0 Firefox/53.0", - "Mozilla/5.0 (Android 6.0.1; Tablet; rv:53.0) Gecko/53.0 Firefox/53.0", - "Mozilla/5.0 (Android 6.0; Mobile; rv:53.0) Gecko/53.0 Firefox/53.0", - "Mozilla/5.0 (Android 7.0; Mobile; rv:53.0) Gecko/53.0 Firefox/53.0", - "Mozilla/5.0 (Android 7.1.2; Mobile; rv:53.0) Gecko/53.0 Firefox/53.0", - "Mozilla/5.0 (Android 4.2.2; Tablet; rv:54.0) Gecko/54.0 Firefox/54.0", - "Mozilla/5.0 (Android 4.3; Tablet; rv:54.0) Gecko/54.0 Firefox/54.0", - "Mozilla/5.0 (Android 4.4.2; Mobile; rv:54.0) Gecko/54.0 Firefox/54.0", - "Mozilla/5.0 (Android 4.4.4; Tablet; rv:54.0) Gecko/54.0 Firefox/54.0", - "Mozilla/5.0 (Android 6.0.1; Mobile; rv:54.0) Gecko/54.0 Firefox/54.0", - "Mozilla/5.0 (Android 6.0.1; Tablet; rv:54.0) Gecko/54.0 Firefox/54.0", - "Mozilla/5.0 (Android 6.0; Mobile; rv:54.0) Gecko/54.0 Firefox/54.0", - "Mozilla/5.0 (Android 7.0; Mobile; rv:54.0) Gecko/54.0 Firefox/54.0", - "Mozilla/5.0 (Android 4.0.4; Mobile; rv:55.0) Gecko/55.0 Firefox/55.0", - "Mozilla/5.0 (Android 7.0; Mobile; rv:55.0) Gecko/55.0 Firefox/55.0", - "Mozilla/5.0 (Android 8.0.0; Tablet; rv:55.0) Gecko/55.0 Firefox/55.0", - "Mozilla/5.0 (Android 4.4.4; Tablet; rv:56.0) Gecko/56.0 Firefox/56.0", - "Mozilla/5.0 (Android 5.0.2; Mobile; rv:56.0) Gecko/56.0 Firefox/56.0", - "Mozilla/5.0 (Android 6.0.1; Mobile; rv:56.0) Gecko/56.0 Firefox/56.0", - "Mozilla/5.0 (Android 7.0; Mobile; rv:56.0) Gecko/56.0 Firefox/56.0", - "Mozilla/5.0 (Android 7.1.1; Mobile; rv:56.0) Gecko/56.0 Firefox/56.0", - "Mozilla/5.0 (Android 7.1.2; Mobile; rv:56.0) Gecko/56.0 Firefox/56.0", - "Mozilla/5.0 (Android 8.0.0; Mobile; rv:56.0) Gecko/56.0 Firefox/56.0", - "Mozilla/5.0 (Android 4.4.2; Mobile; rv:57.0) Gecko/57.0 Firefox/57.0", - "Mozilla/5.0 (Android 4.4.4; Tablet; rv:57.0) Gecko/57.0 Firefox/57.0", - "Mozilla/5.0 (Android 5.1; Mobile; rv:57.0) Gecko/57.0 Firefox/57.0", - "Mozilla/5.0 (Android 6.0.1; Mobile; rv:57.0) Gecko/57.0 Firefox/57.0", - "Mozilla/5.0 (Android 7.0; Mobile; rv:57.0) Gecko/57.0 Firefox/57.0", - "Mozilla/5.0 (Android 8.0.0; Mobile; rv:57.0) Gecko/57.0 Firefox/57.0", - "Mozilla/5.0 (Android 6.0.1; Mobile; rv:58.0) Gecko/58.0 Firefox/58.0", - "Mozilla/5.0 (Android 7.0; Mobile; rv:58.0) Gecko/58.0 Firefox/58.0", - "Mozilla/5.0 (Android 5.1.1; Mobile; rv:59.0) Gecko/59.0 Firefox/59.0", - "Mozilla/5.0 (Android 7.0; Mobile; rv:59.0) Gecko/59.0 Firefox/59.0", - "Mozilla/5.0 (Android 3.0; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 3.1; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 3.2.6; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 3.2; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 4.0.4; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 4.0; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 4.1; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 4.2; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 4.3.1; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 4.3; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 4.4.2; Mobile; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 4.4.4; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 4.4; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 5.0; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 5.1.1; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 5.1; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 6.0.1; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 6.0; Mobile; rv:60.0) Gecko/20100101 Firefox/60.0", - "Mozilla/5.0 (Android 6.0; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 7.0; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 7.1.1; Mobile; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 7.1.2; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 7.1; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 8.0; Tablet; rv:60.0) Gecko/60.0 Firefox/60.0", - "Mozilla/5.0 (Android 6.0.1; Mobile; rv:61.0) Gecko/61.0 Firefox/61.0", - "Mozilla/5.0 (Android 7.0; Mobile; rv:61.0) Gecko/61.0 Firefox/61.0", - "Mozilla/5.0 (Android 7.1.1; Mobile; rv:61.0) Gecko/61.0 Firefox/61.0", - "Mozilla/5.0 (Android 8.0.0; Mobile; rv:61.0) Gecko/61.0 Firefox/61.0", - "Mozilla/5.0 (Android 8.0.0; Mobile; rv:62.0) Gecko/62.0 Firefox/62.0", - "Mozilla/5.0 (Android 6.0.1; Mobile; rv:63.0) Gecko/63.0 Firefox/63.0", - "Mozilla/5.0 (Android 8.0.0; Mobile; rv:63.0) Gecko/63.0 Firefox/63.0", - "Mozilla/5.0 (Android 8.1.0; Mobile; rv:63.0) Gecko/63.0 Firefox/63.0", - "Mozilla/5.0 (Android 6.0; Mobile; rv:64.0) Gecko/64.0 Firefox/64.0", - "Mozilla/5.0 (Android 8.0.0; Mobile; rv:64.0) Gecko/64.0 Firefox/64.0", - "Mozilla/5.0 (Android 5.1.1; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0", - "Mozilla/5.0 (Android 6.0; Mobile; rv:65.0) Gecko/65.0 Firefox/65.0", - "Mozilla/5.0 (Android 7.0; Mobile; rv:65.0) Gecko/65.0 Firefox/65.0", - "Mozilla/5.0 (Android 7.1.1; Mobile; rv:65.0) Gecko/65.0 Firefox/65.0", - "Mozilla/5.0 (Android 8.0.0; Mobile; rv:65.0) Gecko/65.0 Firefox/65.0", - "Mozilla/5.0 (Android 8.1.0; Mobile; rv:65.0) Gecko/65.0 Firefox/65.0", - "Mozilla/5.0 (Android 9; Mobile; rv:65.0) Gecko/65.0 Firefox/65.0", - "Mozilla/5.0 (Android 4.4.2; Tablet; rv:66.0) Gecko/66.0 Firefox/66.0", - "Mozilla/5.0 (Android 7.0; Mobile; rv:66.0) Gecko/66.0 Firefox/66.0", - "Mozilla/5.0 (Android 8.0.0; Mobile; rv:66.0) Gecko/66.0 Firefox/66.0", - "Mozilla/5.0 (Android 8.1.0; Mobile; rv:66.0) Gecko/66.0 Firefox/66.0", - "Mozilla/5.0 (Android 9; Mobile; rv:66.0) Gecko/66.0 Firefox/66.0", - "Mozilla/5.0 (Android 4.4.2; Tablet; rv:67.0) Gecko/67.0 Firefox/67.0", - "Mozilla/5.0 (Android 6.0.1; Mobile; rv:67.0) Gecko/67.0 Firefox/67.0", - "Mozilla/5.0 (Android 8.0.0; Mobile; rv:67.0) Gecko/67.0 Firefox/67.0", - "Mozilla/5.0 (Android 8.1.0; Mobile; rv:67.0) Gecko/67.0 Firefox/67.0", - "Mozilla/5.0 (Android 4.4.2; Tablet; rv:68.0) Gecko/68.0 Firefox/68.0", - "Mozilla/5.0 (Android 7.1.1; Mobile; rv:68.0) Gecko/68.0 Firefox/68.0", - "Mozilla/5.0 (Android 7.1.1; Tablet; rv:68.0) Gecko/68.0 Firefox/68.0" - ] - }, - "ios": { - "chrome": [ - "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.5277.764 Mobile Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.7610.461 Mobile Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.3018.705 Mobile Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.3973.707 Mobile Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.7001.568 Mobile Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.9149.622 Mobile Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.7278.552 Mobile Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.4495.540 Mobile Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.4587.173 Mobile Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.4636.164 Mobile Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.7090.120 Mobile Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.4592.513 Mobile Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.1914.847 Mobile Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.4712.445 Mobile Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.7982.469 Mobile Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.1502.79 Mobile Safari/537.36" - ], - "firefox": [] - } - } - } -} \ No newline at end of file diff --git a/lib/pyasn1/__init__.py b/lib/pyasn1/__init__.py new file mode 100644 index 00000000..c67f6620 --- /dev/null +++ b/lib/pyasn1/__init__.py @@ -0,0 +1,7 @@ +import sys + +# https://www.python.org/dev/peps/pep-0396/ +__version__ = '0.4.9' + +if sys.version_info[:2] < (2, 7): + raise RuntimeError('PyASN1 requires Python 2.7 or later') diff --git a/lib/sambatools/pyasn1/codec/__init__.py b/lib/pyasn1/codec/__init__.py similarity index 100% rename from lib/sambatools/pyasn1/codec/__init__.py rename to lib/pyasn1/codec/__init__.py diff --git a/lib/sambatools/pyasn1/codec/ber/__init__.py b/lib/pyasn1/codec/ber/__init__.py similarity index 100% rename from lib/sambatools/pyasn1/codec/ber/__init__.py rename to lib/pyasn1/codec/ber/__init__.py diff --git a/lib/pyasn1/codec/ber/decoder.py b/lib/pyasn1/codec/ber/decoder.py new file mode 100644 index 00000000..f5605c29 --- /dev/null +++ b/lib/pyasn1/codec/ber/decoder.py @@ -0,0 +1,2066 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import os + +from pyasn1 import debug +from pyasn1 import error +from pyasn1.codec.ber import eoo +from pyasn1.codec.streaming import asSeekableStream +from pyasn1.codec.streaming import isEndOfStream +from pyasn1.codec.streaming import peekIntoStream +from pyasn1.codec.streaming import readFromStream +from pyasn1.compat.integer import from_bytes +from pyasn1.compat.octets import oct2int, octs2ints, ints2octs, null +from pyasn1.error import PyAsn1Error +from pyasn1.type import base +from pyasn1.type import char +from pyasn1.type import tag +from pyasn1.type import tagmap +from pyasn1.type import univ +from pyasn1.type import useful + +__all__ = ['StreamingDecoder', 'Decoder', 'decode'] + +LOG = debug.registerLoggee(__name__, flags=debug.DEBUG_DECODER) + +noValue = base.noValue + +SubstrateUnderrunError = error.SubstrateUnderrunError + + +class AbstractPayloadDecoder(object): + protoComponent = None + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + """Decode value with fixed byte length. + + The decoder is allowed to consume as many bytes as necessary. + """ + raise error.PyAsn1Error('SingleItemDecoder not implemented for %s' % (tagSet,)) # TODO: Seems more like an NotImplementedError? + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + """Decode value with undefined length. + + The decoder is allowed to consume as many bytes as necessary. + """ + raise error.PyAsn1Error('Indefinite length mode decoder not implemented for %s' % (tagSet,)) # TODO: Seems more like an NotImplementedError? + + @staticmethod + def _passAsn1Object(asn1Object, options): + if 'asn1Object' not in options: + options['asn1Object'] = asn1Object + + return options + + +class AbstractSimplePayloadDecoder(AbstractPayloadDecoder): + @staticmethod + def substrateCollector(asn1Object, substrate, length, options): + for chunk in readFromStream(substrate, length, options): + yield chunk + + def _createComponent(self, asn1Spec, tagSet, value, **options): + if options.get('native'): + return value + elif asn1Spec is None: + return self.protoComponent.clone(value, tagSet=tagSet) + elif value is noValue: + return asn1Spec + else: + return asn1Spec.clone(value) + + +class RawPayloadDecoder(AbstractSimplePayloadDecoder): + protoComponent = univ.Any('') + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if substrateFun: + asn1Object = self._createComponent(asn1Spec, tagSet, '', **options) + + for chunk in substrateFun(asn1Object, substrate, length, options): + yield chunk + + return + + for value in decodeFun(substrate, asn1Spec, tagSet, length, **options): + yield value + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if substrateFun: + asn1Object = self._createComponent(asn1Spec, tagSet, '', **options) + + for chunk in substrateFun(asn1Object, substrate, length, options): + yield chunk + + return + + while True: + for value in decodeFun( + substrate, asn1Spec, tagSet, length, + allowEoo=True, **options): + + if value is eoo.endOfOctets: + return + + yield value + + +rawPayloadDecoder = RawPayloadDecoder() + + +class IntegerPayloadDecoder(AbstractSimplePayloadDecoder): + protoComponent = univ.Integer(0) + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + + if tagSet[0].tagFormat != tag.tagFormatSimple: + raise error.PyAsn1Error('Simple tag format expected') + + for chunk in readFromStream(substrate, length, options): + if isinstance(chunk, SubstrateUnderrunError): + yield chunk + + if chunk: + value = from_bytes(chunk, signed=True) + + else: + value = 0 + + yield self._createComponent(asn1Spec, tagSet, value, **options) + + +class BooleanPayloadDecoder(IntegerPayloadDecoder): + protoComponent = univ.Boolean(0) + + def _createComponent(self, asn1Spec, tagSet, value, **options): + return IntegerPayloadDecoder._createComponent( + self, asn1Spec, tagSet, value and 1 or 0, **options) + + +class BitStringPayloadDecoder(AbstractSimplePayloadDecoder): + protoComponent = univ.BitString(()) + supportConstructedForm = True + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + + if substrateFun: + asn1Object = self._createComponent(asn1Spec, tagSet, noValue, **options) + + for chunk in substrateFun(asn1Object, substrate, length, options): + yield chunk + + return + + if not length: + raise error.PyAsn1Error('Empty BIT STRING substrate') + + for chunk in isEndOfStream(substrate): + if isinstance(chunk, SubstrateUnderrunError): + yield chunk + + if chunk: + raise error.PyAsn1Error('Empty BIT STRING substrate') + + if tagSet[0].tagFormat == tag.tagFormatSimple: # XXX what tag to check? + + for trailingBits in readFromStream(substrate, 1, options): + if isinstance(trailingBits, SubstrateUnderrunError): + yield trailingBits + + trailingBits = ord(trailingBits) + if trailingBits > 7: + raise error.PyAsn1Error( + 'Trailing bits overflow %s' % trailingBits + ) + + for chunk in readFromStream(substrate, length - 1, options): + if isinstance(chunk, SubstrateUnderrunError): + yield chunk + + value = self.protoComponent.fromOctetString( + chunk, internalFormat=True, padding=trailingBits) + + yield self._createComponent(asn1Spec, tagSet, value, **options) + + return + + if not self.supportConstructedForm: + raise error.PyAsn1Error('Constructed encoding form prohibited ' + 'at %s' % self.__class__.__name__) + + if LOG: + LOG('assembling constructed serialization') + + # All inner fragments are of the same type, treat them as octet string + substrateFun = self.substrateCollector + + bitString = self.protoComponent.fromOctetString(null, internalFormat=True) + + current_position = substrate.tell() + + while substrate.tell() - current_position < length: + for component in decodeFun( + substrate, self.protoComponent, substrateFun=substrateFun, + **options): + if isinstance(component, SubstrateUnderrunError): + yield component + + trailingBits = oct2int(component[0]) + if trailingBits > 7: + raise error.PyAsn1Error( + 'Trailing bits overflow %s' % trailingBits + ) + + bitString = self.protoComponent.fromOctetString( + component[1:], internalFormat=True, + prepend=bitString, padding=trailingBits + ) + + yield self._createComponent(asn1Spec, tagSet, bitString, **options) + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + + if substrateFun: + asn1Object = self._createComponent(asn1Spec, tagSet, noValue, **options) + + for chunk in substrateFun(asn1Object, substrate, length, options): + yield chunk + + return + + # All inner fragments are of the same type, treat them as octet string + substrateFun = self.substrateCollector + + bitString = self.protoComponent.fromOctetString(null, internalFormat=True) + + while True: # loop over fragments + + for component in decodeFun( + substrate, self.protoComponent, substrateFun=substrateFun, + allowEoo=True, **options): + + if component is eoo.endOfOctets: + break + + if isinstance(component, SubstrateUnderrunError): + yield component + + if component is eoo.endOfOctets: + break + + trailingBits = oct2int(component[0]) + if trailingBits > 7: + raise error.PyAsn1Error( + 'Trailing bits overflow %s' % trailingBits + ) + + bitString = self.protoComponent.fromOctetString( + component[1:], internalFormat=True, + prepend=bitString, padding=trailingBits + ) + + yield self._createComponent(asn1Spec, tagSet, bitString, **options) + + +class OctetStringPayloadDecoder(AbstractSimplePayloadDecoder): + protoComponent = univ.OctetString('') + supportConstructedForm = True + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if substrateFun: + asn1Object = self._createComponent(asn1Spec, tagSet, noValue, **options) + + for chunk in substrateFun(asn1Object, substrate, length, options): + yield chunk + + return + + if tagSet[0].tagFormat == tag.tagFormatSimple: # XXX what tag to check? + for chunk in readFromStream(substrate, length, options): + if isinstance(chunk, SubstrateUnderrunError): + yield chunk + + yield self._createComponent(asn1Spec, tagSet, chunk, **options) + + return + + if not self.supportConstructedForm: + raise error.PyAsn1Error('Constructed encoding form prohibited at %s' % self.__class__.__name__) + + if LOG: + LOG('assembling constructed serialization') + + # All inner fragments are of the same type, treat them as octet string + substrateFun = self.substrateCollector + + header = null + + original_position = substrate.tell() + # head = popSubstream(substrate, length) + while substrate.tell() - original_position < length: + for component in decodeFun( + substrate, self.protoComponent, substrateFun=substrateFun, + **options): + if isinstance(component, SubstrateUnderrunError): + yield component + + header += component + + yield self._createComponent(asn1Spec, tagSet, header, **options) + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if substrateFun and substrateFun is not self.substrateCollector: + asn1Object = self._createComponent(asn1Spec, tagSet, noValue, **options) + + for chunk in substrateFun(asn1Object, substrate, length, options): + yield chunk + + return + + # All inner fragments are of the same type, treat them as octet string + substrateFun = self.substrateCollector + + header = null + + while True: # loop over fragments + + for component in decodeFun( + substrate, self.protoComponent, substrateFun=substrateFun, + allowEoo=True, **options): + + if isinstance(component, SubstrateUnderrunError): + yield component + + if component is eoo.endOfOctets: + break + + if component is eoo.endOfOctets: + break + + header += component + + yield self._createComponent(asn1Spec, tagSet, header, **options) + + +class NullPayloadDecoder(AbstractSimplePayloadDecoder): + protoComponent = univ.Null('') + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + + if tagSet[0].tagFormat != tag.tagFormatSimple: + raise error.PyAsn1Error('Simple tag format expected') + + for chunk in readFromStream(substrate, length, options): + if isinstance(chunk, SubstrateUnderrunError): + yield chunk + + component = self._createComponent(asn1Spec, tagSet, '', **options) + + if chunk: + raise error.PyAsn1Error('Unexpected %d-octet substrate for Null' % length) + + yield component + + +class ObjectIdentifierPayloadDecoder(AbstractSimplePayloadDecoder): + protoComponent = univ.ObjectIdentifier(()) + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if tagSet[0].tagFormat != tag.tagFormatSimple: + raise error.PyAsn1Error('Simple tag format expected') + + for chunk in readFromStream(substrate, length, options): + if isinstance(chunk, SubstrateUnderrunError): + yield chunk + + if not chunk: + raise error.PyAsn1Error('Empty substrate') + + chunk = octs2ints(chunk) + + oid = () + index = 0 + substrateLen = len(chunk) + while index < substrateLen: + subId = chunk[index] + index += 1 + if subId < 128: + oid += (subId,) + elif subId > 128: + # Construct subid from a number of octets + nextSubId = subId + subId = 0 + while nextSubId >= 128: + subId = (subId << 7) + (nextSubId & 0x7F) + if index >= substrateLen: + raise error.SubstrateUnderrunError( + 'Short substrate for sub-OID past %s' % (oid,) + ) + nextSubId = chunk[index] + index += 1 + oid += ((subId << 7) + nextSubId,) + elif subId == 128: + # ASN.1 spec forbids leading zeros (0x80) in OID + # encoding, tolerating it opens a vulnerability. See + # https://www.esat.kuleuven.be/cosic/publications/article-1432.pdf + # page 7 + raise error.PyAsn1Error('Invalid octet 0x80 in OID encoding') + + # Decode two leading arcs + if 0 <= oid[0] <= 39: + oid = (0,) + oid + elif 40 <= oid[0] <= 79: + oid = (1, oid[0] - 40) + oid[1:] + elif oid[0] >= 80: + oid = (2, oid[0] - 80) + oid[1:] + else: + raise error.PyAsn1Error('Malformed first OID octet: %s' % chunk[0]) + + yield self._createComponent(asn1Spec, tagSet, oid, **options) + + +class RealPayloadDecoder(AbstractSimplePayloadDecoder): + protoComponent = univ.Real() + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if tagSet[0].tagFormat != tag.tagFormatSimple: + raise error.PyAsn1Error('Simple tag format expected') + + for chunk in readFromStream(substrate, length, options): + if isinstance(chunk, SubstrateUnderrunError): + yield chunk + + if not chunk: + yield self._createComponent(asn1Spec, tagSet, 0.0, **options) + return + + fo = oct2int(chunk[0]) + chunk = chunk[1:] + if fo & 0x80: # binary encoding + if not chunk: + raise error.PyAsn1Error("Incomplete floating-point value") + + if LOG: + LOG('decoding binary encoded REAL') + + n = (fo & 0x03) + 1 + + if n == 4: + n = oct2int(chunk[0]) + chunk = chunk[1:] + + eo, chunk = chunk[:n], chunk[n:] + + if not eo or not chunk: + raise error.PyAsn1Error('Real exponent screwed') + + e = oct2int(eo[0]) & 0x80 and -1 or 0 + + while eo: # exponent + e <<= 8 + e |= oct2int(eo[0]) + eo = eo[1:] + + b = fo >> 4 & 0x03 # base bits + + if b > 2: + raise error.PyAsn1Error('Illegal Real base') + + if b == 1: # encbase = 8 + e *= 3 + + elif b == 2: # encbase = 16 + e *= 4 + p = 0 + + while chunk: # value + p <<= 8 + p |= oct2int(chunk[0]) + chunk = chunk[1:] + + if fo & 0x40: # sign bit + p = -p + + sf = fo >> 2 & 0x03 # scale bits + p *= 2 ** sf + value = (p, 2, e) + + elif fo & 0x40: # infinite value + if LOG: + LOG('decoding infinite REAL') + + value = fo & 0x01 and '-inf' or 'inf' + + elif fo & 0xc0 == 0: # character encoding + if not chunk: + raise error.PyAsn1Error("Incomplete floating-point value") + + if LOG: + LOG('decoding character encoded REAL') + + try: + if fo & 0x3 == 0x1: # NR1 + value = (int(chunk), 10, 0) + + elif fo & 0x3 == 0x2: # NR2 + value = float(chunk) + + elif fo & 0x3 == 0x3: # NR3 + value = float(chunk) + + else: + raise error.SubstrateUnderrunError( + 'Unknown NR (tag %s)' % fo + ) + + except ValueError: + raise error.SubstrateUnderrunError( + 'Bad character Real syntax' + ) + + else: + raise error.SubstrateUnderrunError( + 'Unknown encoding (tag %s)' % fo + ) + + yield self._createComponent(asn1Spec, tagSet, value, **options) + + +class AbstractConstructedPayloadDecoder(AbstractPayloadDecoder): + protoComponent = None + + +class ConstructedPayloadDecoderBase(AbstractConstructedPayloadDecoder): + protoRecordComponent = None + protoSequenceComponent = None + + def _getComponentTagMap(self, asn1Object, idx): + raise NotImplementedError() + + def _getComponentPositionByType(self, asn1Object, tagSet, idx): + raise NotImplementedError() + + def _decodeComponentsSchemaless( + self, substrate, tagSet=None, decodeFun=None, + length=None, **options): + + asn1Object = None + + components = [] + componentTypes = set() + + original_position = substrate.tell() + + while length == -1 or substrate.tell() < original_position + length: + for component in decodeFun(substrate, **options): + if isinstance(component, SubstrateUnderrunError): + yield component + + if length == -1 and component is eoo.endOfOctets: + break + + components.append(component) + componentTypes.add(component.tagSet) + + # Now we have to guess is it SEQUENCE/SET or SEQUENCE OF/SET OF + # The heuristics is: + # * 1+ components of different types -> likely SEQUENCE/SET + # * otherwise -> likely SEQUENCE OF/SET OF + if len(componentTypes) > 1: + protoComponent = self.protoRecordComponent + + else: + protoComponent = self.protoSequenceComponent + + asn1Object = protoComponent.clone( + # construct tagSet from base tag from prototype ASN.1 object + # and additional tags recovered from the substrate + tagSet=tag.TagSet(protoComponent.tagSet.baseTag, *tagSet.superTags) + ) + + if LOG: + LOG('guessed %r container type (pass `asn1Spec` to guide the ' + 'decoder)' % asn1Object) + + for idx, component in enumerate(components): + asn1Object.setComponentByPosition( + idx, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False + ) + + yield asn1Object + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if tagSet[0].tagFormat != tag.tagFormatConstructed: + raise error.PyAsn1Error('Constructed tag format expected') + + original_position = substrate.tell() + + if substrateFun: + if asn1Spec is not None: + asn1Object = asn1Spec.clone() + + elif self.protoComponent is not None: + asn1Object = self.protoComponent.clone(tagSet=tagSet) + + else: + asn1Object = self.protoRecordComponent, self.protoSequenceComponent + + for chunk in substrateFun(asn1Object, substrate, length, options): + yield chunk + + return + + if asn1Spec is None: + for asn1Object in self._decodeComponentsSchemaless( + substrate, tagSet=tagSet, decodeFun=decodeFun, + length=length, **options): + if isinstance(asn1Object, SubstrateUnderrunError): + yield asn1Object + + if substrate.tell() < original_position + length: + if LOG: + for trailing in readFromStream(substrate, context=options): + if isinstance(trailing, SubstrateUnderrunError): + yield trailing + + LOG('Unused trailing %d octets encountered: %s' % ( + len(trailing), debug.hexdump(trailing))) + + yield asn1Object + + return + + asn1Object = asn1Spec.clone() + asn1Object.clear() + + options = self._passAsn1Object(asn1Object, options) + + if asn1Spec.typeId in (univ.Sequence.typeId, univ.Set.typeId): + + namedTypes = asn1Spec.componentType + + isSetType = asn1Spec.typeId == univ.Set.typeId + isDeterministic = not isSetType and not namedTypes.hasOptionalOrDefault + + if LOG: + LOG('decoding %sdeterministic %s type %r chosen by type ID' % ( + not isDeterministic and 'non-' or '', isSetType and 'SET' or '', + asn1Spec)) + + seenIndices = set() + idx = 0 + while substrate.tell() - original_position < length: + if not namedTypes: + componentType = None + + elif isSetType: + componentType = namedTypes.tagMapUnique + + else: + try: + if isDeterministic: + componentType = namedTypes[idx].asn1Object + + elif namedTypes[idx].isOptional or namedTypes[idx].isDefaulted: + componentType = namedTypes.getTagMapNearPosition(idx) + + else: + componentType = namedTypes[idx].asn1Object + + except IndexError: + raise error.PyAsn1Error( + 'Excessive components decoded at %r' % (asn1Spec,) + ) + + for component in decodeFun(substrate, componentType, **options): + if isinstance(component, SubstrateUnderrunError): + yield component + + if not isDeterministic and namedTypes: + if isSetType: + idx = namedTypes.getPositionByType(component.effectiveTagSet) + + elif namedTypes[idx].isOptional or namedTypes[idx].isDefaulted: + idx = namedTypes.getPositionNearType(component.effectiveTagSet, idx) + + asn1Object.setComponentByPosition( + idx, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False + ) + + seenIndices.add(idx) + idx += 1 + + if LOG: + LOG('seen component indices %s' % seenIndices) + + if namedTypes: + if not namedTypes.requiredComponents.issubset(seenIndices): + raise error.PyAsn1Error( + 'ASN.1 object %s has uninitialized ' + 'components' % asn1Object.__class__.__name__) + + if namedTypes.hasOpenTypes: + + openTypes = options.get('openTypes', {}) + + if LOG: + LOG('user-specified open types map:') + + for k, v in openTypes.items(): + LOG('%s -> %r' % (k, v)) + + if openTypes or options.get('decodeOpenTypes', False): + + for idx, namedType in enumerate(namedTypes.namedTypes): + if not namedType.openType: + continue + + if namedType.isOptional and not asn1Object.getComponentByPosition(idx).isValue: + continue + + governingValue = asn1Object.getComponentByName( + namedType.openType.name + ) + + try: + openType = openTypes[governingValue] + + except KeyError: + + if LOG: + LOG('default open types map of component ' + '"%s.%s" governed by component "%s.%s"' + ':' % (asn1Object.__class__.__name__, + namedType.name, + asn1Object.__class__.__name__, + namedType.openType.name)) + + for k, v in namedType.openType.items(): + LOG('%s -> %r' % (k, v)) + + try: + openType = namedType.openType[governingValue] + + except KeyError: + if LOG: + LOG('failed to resolve open type by governing ' + 'value %r' % (governingValue,)) + continue + + if LOG: + LOG('resolved open type %r by governing ' + 'value %r' % (openType, governingValue)) + + containerValue = asn1Object.getComponentByPosition(idx) + + if containerValue.typeId in ( + univ.SetOf.typeId, univ.SequenceOf.typeId): + + for pos, containerElement in enumerate( + containerValue): + + stream = asSeekableStream(containerValue[pos].asOctets()) + + for component in decodeFun(stream, asn1Spec=openType, **options): + if isinstance(component, SubstrateUnderrunError): + yield component + + containerValue[pos] = component + + else: + stream = asSeekableStream(asn1Object.getComponentByPosition(idx).asOctets()) + + for component in decodeFun(stream, asn1Spec=openType, **options): + if isinstance(component, SubstrateUnderrunError): + yield component + + asn1Object.setComponentByPosition(idx, component) + + else: + inconsistency = asn1Object.isInconsistent + if inconsistency: + raise inconsistency + + else: + componentType = asn1Spec.componentType + + if LOG: + LOG('decoding type %r chosen by given `asn1Spec`' % componentType) + + idx = 0 + + while substrate.tell() - original_position < length: + for component in decodeFun(substrate, componentType, **options): + if isinstance(component, SubstrateUnderrunError): + yield component + + asn1Object.setComponentByPosition( + idx, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False + ) + + idx += 1 + + yield asn1Object + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if tagSet[0].tagFormat != tag.tagFormatConstructed: + raise error.PyAsn1Error('Constructed tag format expected') + + if substrateFun is not None: + if asn1Spec is not None: + asn1Object = asn1Spec.clone() + + elif self.protoComponent is not None: + asn1Object = self.protoComponent.clone(tagSet=tagSet) + + else: + asn1Object = self.protoRecordComponent, self.protoSequenceComponent + + for chunk in substrateFun(asn1Object, substrate, length, options): + yield chunk + + return + + if asn1Spec is None: + for asn1Object in self._decodeComponentsSchemaless( + substrate, tagSet=tagSet, decodeFun=decodeFun, + length=length, **dict(options, allowEoo=True)): + if isinstance(asn1Object, SubstrateUnderrunError): + yield asn1Object + + yield asn1Object + + return + + asn1Object = asn1Spec.clone() + asn1Object.clear() + + options = self._passAsn1Object(asn1Object, options) + + if asn1Spec.typeId in (univ.Sequence.typeId, univ.Set.typeId): + + namedTypes = asn1Object.componentType + + isSetType = asn1Object.typeId == univ.Set.typeId + isDeterministic = not isSetType and not namedTypes.hasOptionalOrDefault + + if LOG: + LOG('decoding %sdeterministic %s type %r chosen by type ID' % ( + not isDeterministic and 'non-' or '', isSetType and 'SET' or '', + asn1Spec)) + + seenIndices = set() + + idx = 0 + + while True: # loop over components + if len(namedTypes) <= idx: + asn1Spec = None + + elif isSetType: + asn1Spec = namedTypes.tagMapUnique + + else: + try: + if isDeterministic: + asn1Spec = namedTypes[idx].asn1Object + + elif namedTypes[idx].isOptional or namedTypes[idx].isDefaulted: + asn1Spec = namedTypes.getTagMapNearPosition(idx) + + else: + asn1Spec = namedTypes[idx].asn1Object + + except IndexError: + raise error.PyAsn1Error( + 'Excessive components decoded at %r' % (asn1Object,) + ) + + for component in decodeFun(substrate, asn1Spec, allowEoo=True, **options): + + if isinstance(component, SubstrateUnderrunError): + yield component + + if component is eoo.endOfOctets: + break + + if component is eoo.endOfOctets: + break + + if not isDeterministic and namedTypes: + if isSetType: + idx = namedTypes.getPositionByType(component.effectiveTagSet) + + elif namedTypes[idx].isOptional or namedTypes[idx].isDefaulted: + idx = namedTypes.getPositionNearType(component.effectiveTagSet, idx) + + asn1Object.setComponentByPosition( + idx, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False + ) + + seenIndices.add(idx) + idx += 1 + + if LOG: + LOG('seen component indices %s' % seenIndices) + + if namedTypes: + if not namedTypes.requiredComponents.issubset(seenIndices): + raise error.PyAsn1Error( + 'ASN.1 object %s has uninitialized ' + 'components' % asn1Object.__class__.__name__) + + if namedTypes.hasOpenTypes: + + openTypes = options.get('openTypes', {}) + + if LOG: + LOG('user-specified open types map:') + + for k, v in openTypes.items(): + LOG('%s -> %r' % (k, v)) + + if openTypes or options.get('decodeOpenTypes', False): + + for idx, namedType in enumerate(namedTypes.namedTypes): + if not namedType.openType: + continue + + if namedType.isOptional and not asn1Object.getComponentByPosition(idx).isValue: + continue + + governingValue = asn1Object.getComponentByName( + namedType.openType.name + ) + + try: + openType = openTypes[governingValue] + + except KeyError: + + if LOG: + LOG('default open types map of component ' + '"%s.%s" governed by component "%s.%s"' + ':' % (asn1Object.__class__.__name__, + namedType.name, + asn1Object.__class__.__name__, + namedType.openType.name)) + + for k, v in namedType.openType.items(): + LOG('%s -> %r' % (k, v)) + + try: + openType = namedType.openType[governingValue] + + except KeyError: + if LOG: + LOG('failed to resolve open type by governing ' + 'value %r' % (governingValue,)) + continue + + if LOG: + LOG('resolved open type %r by governing ' + 'value %r' % (openType, governingValue)) + + containerValue = asn1Object.getComponentByPosition(idx) + + if containerValue.typeId in ( + univ.SetOf.typeId, univ.SequenceOf.typeId): + + for pos, containerElement in enumerate( + containerValue): + + stream = asSeekableStream(containerValue[pos].asOctets()) + + for component in decodeFun(stream, asn1Spec=openType, + **dict(options, allowEoo=True)): + if isinstance(component, SubstrateUnderrunError): + yield component + + if component is eoo.endOfOctets: + break + + containerValue[pos] = component + + else: + stream = asSeekableStream(asn1Object.getComponentByPosition(idx).asOctets()) + for component in decodeFun(stream, asn1Spec=openType, + **dict(options, allowEoo=True)): + if isinstance(component, SubstrateUnderrunError): + yield component + + if component is eoo.endOfOctets: + break + + asn1Object.setComponentByPosition(idx, component) + + else: + inconsistency = asn1Object.isInconsistent + if inconsistency: + raise inconsistency + + else: + componentType = asn1Spec.componentType + + if LOG: + LOG('decoding type %r chosen by given `asn1Spec`' % componentType) + + idx = 0 + + while True: + + for component in decodeFun( + substrate, componentType, allowEoo=True, **options): + + if isinstance(component, SubstrateUnderrunError): + yield component + + if component is eoo.endOfOctets: + break + + if component is eoo.endOfOctets: + break + + asn1Object.setComponentByPosition( + idx, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False + ) + + idx += 1 + + yield asn1Object + + +class SequenceOrSequenceOfPayloadDecoder(ConstructedPayloadDecoderBase): + protoRecordComponent = univ.Sequence() + protoSequenceComponent = univ.SequenceOf() + + +class SequencePayloadDecoder(SequenceOrSequenceOfPayloadDecoder): + protoComponent = univ.Sequence() + + +class SequenceOfPayloadDecoder(SequenceOrSequenceOfPayloadDecoder): + protoComponent = univ.SequenceOf() + + +class SetOrSetOfPayloadDecoder(ConstructedPayloadDecoderBase): + protoRecordComponent = univ.Set() + protoSequenceComponent = univ.SetOf() + + +class SetPayloadDecoder(SetOrSetOfPayloadDecoder): + protoComponent = univ.Set() + + +class SetOfPayloadDecoder(SetOrSetOfPayloadDecoder): + protoComponent = univ.SetOf() + + +class ChoicePayloadDecoder(ConstructedPayloadDecoderBase): + protoComponent = univ.Choice() + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if asn1Spec is None: + asn1Object = self.protoComponent.clone(tagSet=tagSet) + + else: + asn1Object = asn1Spec.clone() + + if substrateFun: + for chunk in substrateFun(asn1Object, substrate, length, options): + yield chunk + + return + + options = self._passAsn1Object(asn1Object, options) + + if asn1Object.tagSet == tagSet: + if LOG: + LOG('decoding %s as explicitly tagged CHOICE' % (tagSet,)) + + for component in decodeFun( + substrate, asn1Object.componentTagMap, **options): + if isinstance(component, SubstrateUnderrunError): + yield component + + else: + if LOG: + LOG('decoding %s as untagged CHOICE' % (tagSet,)) + + for component in decodeFun( + substrate, asn1Object.componentTagMap, tagSet, length, + state, **options): + if isinstance(component, SubstrateUnderrunError): + yield component + + effectiveTagSet = component.effectiveTagSet + + if LOG: + LOG('decoded component %s, effective tag set %s' % (component, effectiveTagSet)) + + asn1Object.setComponentByType( + effectiveTagSet, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False, + innerFlag=False + ) + + yield asn1Object + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if asn1Spec is None: + asn1Object = self.protoComponent.clone(tagSet=tagSet) + + else: + asn1Object = asn1Spec.clone() + + if substrateFun: + for chunk in substrateFun(asn1Object, substrate, length, options): + yield chunk + + return + + options = self._passAsn1Object(asn1Object, options) + + isTagged = asn1Object.tagSet == tagSet + + if LOG: + LOG('decoding %s as %stagged CHOICE' % ( + tagSet, isTagged and 'explicitly ' or 'un')) + + while True: + + if isTagged: + iterator = decodeFun( + substrate, asn1Object.componentType.tagMapUnique, + **dict(options, allowEoo=True)) + + else: + iterator = decodeFun( + substrate, asn1Object.componentType.tagMapUnique, + tagSet, length, state, **dict(options, allowEoo=True)) + + for component in iterator: + + if isinstance(component, SubstrateUnderrunError): + yield component + + if component is eoo.endOfOctets: + break + + effectiveTagSet = component.effectiveTagSet + + if LOG: + LOG('decoded component %s, effective tag set ' + '%s' % (component, effectiveTagSet)) + + asn1Object.setComponentByType( + effectiveTagSet, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False, + innerFlag=False + ) + + if not isTagged: + break + + if not isTagged or component is eoo.endOfOctets: + break + + yield asn1Object + + +class AnyPayloadDecoder(AbstractSimplePayloadDecoder): + protoComponent = univ.Any() + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if asn1Spec is None: + isUntagged = True + + elif asn1Spec.__class__ is tagmap.TagMap: + isUntagged = tagSet not in asn1Spec.tagMap + + else: + isUntagged = tagSet != asn1Spec.tagSet + + if isUntagged: + fullPosition = substrate.markedPosition + currentPosition = substrate.tell() + + substrate.seek(fullPosition, os.SEEK_SET) + length += currentPosition - fullPosition + + if LOG: + for chunk in peekIntoStream(substrate, length): + if isinstance(chunk, SubstrateUnderrunError): + yield chunk + LOG('decoding as untagged ANY, substrate ' + '%s' % debug.hexdump(chunk)) + + if substrateFun: + for chunk in substrateFun( + self._createComponent(asn1Spec, tagSet, noValue, **options), + substrate, length, options): + yield chunk + + return + + for chunk in readFromStream(substrate, length, options): + if isinstance(chunk, SubstrateUnderrunError): + yield chunk + + yield self._createComponent(asn1Spec, tagSet, chunk, **options) + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if asn1Spec is None: + isTagged = False + + elif asn1Spec.__class__ is tagmap.TagMap: + isTagged = tagSet in asn1Spec.tagMap + + else: + isTagged = tagSet == asn1Spec.tagSet + + if isTagged: + # tagged Any type -- consume header substrate + chunk = null + + if LOG: + LOG('decoding as tagged ANY') + + else: + # TODO: Seems not to be tested + fullPosition = substrate.markedPosition + currentPosition = substrate.tell() + + substrate.seek(fullPosition, os.SEEK_SET) + for chunk in readFromStream(substrate, currentPosition - fullPosition, options): + if isinstance(chunk, SubstrateUnderrunError): + yield chunk + + if LOG: + LOG('decoding as untagged ANY, header substrate %s' % debug.hexdump(chunk)) + + # Any components do not inherit initial tag + asn1Spec = self.protoComponent + + if substrateFun and substrateFun is not self.substrateCollector: + asn1Object = self._createComponent( + asn1Spec, tagSet, noValue, **options) + + for chunk in substrateFun( + asn1Object, chunk + substrate, length + len(chunk), options): + yield chunk + + return + + if LOG: + LOG('assembling constructed serialization') + + # All inner fragments are of the same type, treat them as octet string + substrateFun = self.substrateCollector + + while True: # loop over fragments + + for component in decodeFun( + substrate, asn1Spec, substrateFun=substrateFun, + allowEoo=True, **options): + + if isinstance(component, SubstrateUnderrunError): + yield component + + if component is eoo.endOfOctets: + break + + if component is eoo.endOfOctets: + break + + chunk += component + + if substrateFun: + yield chunk # TODO: Weird + + else: + yield self._createComponent(asn1Spec, tagSet, chunk, **options) + + +# character string types +class UTF8StringPayloadDecoder(OctetStringPayloadDecoder): + protoComponent = char.UTF8String() + + +class NumericStringPayloadDecoder(OctetStringPayloadDecoder): + protoComponent = char.NumericString() + + +class PrintableStringPayloadDecoder(OctetStringPayloadDecoder): + protoComponent = char.PrintableString() + + +class TeletexStringPayloadDecoder(OctetStringPayloadDecoder): + protoComponent = char.TeletexString() + + +class VideotexStringPayloadDecoder(OctetStringPayloadDecoder): + protoComponent = char.VideotexString() + + +class IA5StringPayloadDecoder(OctetStringPayloadDecoder): + protoComponent = char.IA5String() + + +class GraphicStringPayloadDecoder(OctetStringPayloadDecoder): + protoComponent = char.GraphicString() + + +class VisibleStringPayloadDecoder(OctetStringPayloadDecoder): + protoComponent = char.VisibleString() + + +class GeneralStringPayloadDecoder(OctetStringPayloadDecoder): + protoComponent = char.GeneralString() + + +class UniversalStringPayloadDecoder(OctetStringPayloadDecoder): + protoComponent = char.UniversalString() + + +class BMPStringPayloadDecoder(OctetStringPayloadDecoder): + protoComponent = char.BMPString() + + +# "useful" types +class ObjectDescriptorPayloadDecoder(OctetStringPayloadDecoder): + protoComponent = useful.ObjectDescriptor() + + +class GeneralizedTimePayloadDecoder(OctetStringPayloadDecoder): + protoComponent = useful.GeneralizedTime() + + +class UTCTimePayloadDecoder(OctetStringPayloadDecoder): + protoComponent = useful.UTCTime() + + +TAG_MAP = { + univ.Integer.tagSet: IntegerPayloadDecoder(), + univ.Boolean.tagSet: BooleanPayloadDecoder(), + univ.BitString.tagSet: BitStringPayloadDecoder(), + univ.OctetString.tagSet: OctetStringPayloadDecoder(), + univ.Null.tagSet: NullPayloadDecoder(), + univ.ObjectIdentifier.tagSet: ObjectIdentifierPayloadDecoder(), + univ.Enumerated.tagSet: IntegerPayloadDecoder(), + univ.Real.tagSet: RealPayloadDecoder(), + univ.Sequence.tagSet: SequenceOrSequenceOfPayloadDecoder(), # conflicts with SequenceOf + univ.Set.tagSet: SetOrSetOfPayloadDecoder(), # conflicts with SetOf + univ.Choice.tagSet: ChoicePayloadDecoder(), # conflicts with Any + # character string types + char.UTF8String.tagSet: UTF8StringPayloadDecoder(), + char.NumericString.tagSet: NumericStringPayloadDecoder(), + char.PrintableString.tagSet: PrintableStringPayloadDecoder(), + char.TeletexString.tagSet: TeletexStringPayloadDecoder(), + char.VideotexString.tagSet: VideotexStringPayloadDecoder(), + char.IA5String.tagSet: IA5StringPayloadDecoder(), + char.GraphicString.tagSet: GraphicStringPayloadDecoder(), + char.VisibleString.tagSet: VisibleStringPayloadDecoder(), + char.GeneralString.tagSet: GeneralStringPayloadDecoder(), + char.UniversalString.tagSet: UniversalStringPayloadDecoder(), + char.BMPString.tagSet: BMPStringPayloadDecoder(), + # useful types + useful.ObjectDescriptor.tagSet: ObjectDescriptorPayloadDecoder(), + useful.GeneralizedTime.tagSet: GeneralizedTimePayloadDecoder(), + useful.UTCTime.tagSet: UTCTimePayloadDecoder() +} + +# Type-to-codec map for ambiguous ASN.1 types +TYPE_MAP = { + univ.Set.typeId: SetPayloadDecoder(), + univ.SetOf.typeId: SetOfPayloadDecoder(), + univ.Sequence.typeId: SequencePayloadDecoder(), + univ.SequenceOf.typeId: SequenceOfPayloadDecoder(), + univ.Choice.typeId: ChoicePayloadDecoder(), + univ.Any.typeId: AnyPayloadDecoder() +} + +# Put in non-ambiguous types for faster codec lookup +for typeDecoder in TAG_MAP.values(): + if typeDecoder.protoComponent is not None: + typeId = typeDecoder.protoComponent.__class__.typeId + if typeId is not None and typeId not in TYPE_MAP: + TYPE_MAP[typeId] = typeDecoder + + +(stDecodeTag, + stDecodeLength, + stGetValueDecoder, + stGetValueDecoderByAsn1Spec, + stGetValueDecoderByTag, + stTryAsExplicitTag, + stDecodeValue, + stDumpRawValue, + stErrorCondition, + stStop) = [x for x in range(10)] + + +EOO_SENTINEL = ints2octs((0, 0)) + + +class SingleItemDecoder(object): + defaultErrorState = stErrorCondition + #defaultErrorState = stDumpRawValue + defaultRawDecoder = AnyPayloadDecoder() + + supportIndefLength = True + + TAG_MAP = TAG_MAP + TYPE_MAP = TYPE_MAP + + def __init__(self, **options): + self._tagMap = options.get('tagMap', self.TAG_MAP) + self._typeMap = options.get('typeMap', self.TYPE_MAP) + + # Tag & TagSet objects caches + self._tagCache = {} + self._tagSetCache = {} + + def __call__(self, substrate, asn1Spec=None, + tagSet=None, length=None, state=stDecodeTag, + decodeFun=None, substrateFun=None, + **options): + + allowEoo = options.pop('allowEoo', False) + + if LOG: + LOG('decoder called at scope %s with state %d, working with up ' + 'to %s octets of substrate: ' + '%s' % (debug.scope, state, length, substrate)) + + # Look for end-of-octets sentinel + if allowEoo and self.supportIndefLength: + + for eoo_candidate in readFromStream(substrate, 2, options): + if isinstance(eoo_candidate, SubstrateUnderrunError): + yield eoo_candidate + + if eoo_candidate == EOO_SENTINEL: + if LOG: + LOG('end-of-octets sentinel found') + yield eoo.endOfOctets + return + + else: + substrate.seek(-2, os.SEEK_CUR) + + tagMap = self._tagMap + typeMap = self._typeMap + tagCache = self._tagCache + tagSetCache = self._tagSetCache + + value = noValue + + substrate.markedPosition = substrate.tell() + + while state is not stStop: + + if state is stDecodeTag: + # Decode tag + isShortTag = True + + for firstByte in readFromStream(substrate, 1, options): + if isinstance(firstByte, SubstrateUnderrunError): + yield firstByte + + firstOctet = ord(firstByte) + + try: + lastTag = tagCache[firstOctet] + + except KeyError: + integerTag = firstOctet + tagClass = integerTag & 0xC0 + tagFormat = integerTag & 0x20 + tagId = integerTag & 0x1F + + if tagId == 0x1F: + isShortTag = False + lengthOctetIdx = 0 + tagId = 0 + + while True: + for integerByte in readFromStream(substrate, 1, options): + if isinstance(integerByte, SubstrateUnderrunError): + yield integerByte + + if not integerByte: + raise error.SubstrateUnderrunError( + 'Short octet stream on long tag decoding' + ) + + integerTag = ord(integerByte) + lengthOctetIdx += 1 + tagId <<= 7 + tagId |= (integerTag & 0x7F) + + if not integerTag & 0x80: + break + + lastTag = tag.Tag( + tagClass=tagClass, tagFormat=tagFormat, tagId=tagId + ) + + if isShortTag: + # cache short tags + tagCache[firstOctet] = lastTag + + if tagSet is None: + if isShortTag: + try: + tagSet = tagSetCache[firstOctet] + + except KeyError: + # base tag not recovered + tagSet = tag.TagSet((), lastTag) + tagSetCache[firstOctet] = tagSet + else: + tagSet = tag.TagSet((), lastTag) + + else: + tagSet = lastTag + tagSet + + state = stDecodeLength + + if LOG: + LOG('tag decoded into %s, decoding length' % tagSet) + + if state is stDecodeLength: + # Decode length + for firstOctet in readFromStream(substrate, 1, options): + if isinstance(firstOctet, SubstrateUnderrunError): + yield firstOctet + + firstOctet = ord(firstOctet) + + if firstOctet < 128: + length = firstOctet + + elif firstOctet > 128: + size = firstOctet & 0x7F + # encoded in size bytes + for encodedLength in readFromStream(substrate, size, options): + if isinstance(encodedLength, SubstrateUnderrunError): + yield encodedLength + encodedLength = list(encodedLength) + # missing check on maximum size, which shouldn't be a + # problem, we can handle more than is possible + if len(encodedLength) != size: + raise error.SubstrateUnderrunError( + '%s<%s at %s' % (size, len(encodedLength), tagSet) + ) + + length = 0 + for lengthOctet in encodedLength: + length <<= 8 + length |= oct2int(lengthOctet) + size += 1 + + else: # 128 means indefinite + length = -1 + + if length == -1 and not self.supportIndefLength: + raise error.PyAsn1Error('Indefinite length encoding not supported by this codec') + + state = stGetValueDecoder + + if LOG: + LOG('value length decoded into %d' % length) + + if state is stGetValueDecoder: + if asn1Spec is None: + state = stGetValueDecoderByTag + + else: + state = stGetValueDecoderByAsn1Spec + # + # There're two ways of creating subtypes in ASN.1 what influences + # decoder operation. These methods are: + # 1) Either base types used in or no IMPLICIT tagging has been + # applied on subtyping. + # 2) Subtype syntax drops base type information (by means of + # IMPLICIT tagging. + # The first case allows for complete tag recovery from substrate + # while the second one requires original ASN.1 type spec for + # decoding. + # + # In either case a set of tags (tagSet) is coming from substrate + # in an incremental, tag-by-tag fashion (this is the case of + # EXPLICIT tag which is most basic). Outermost tag comes first + # from the wire. + # + if state is stGetValueDecoderByTag: + try: + concreteDecoder = tagMap[tagSet] + + except KeyError: + concreteDecoder = None + + if concreteDecoder: + state = stDecodeValue + + else: + try: + concreteDecoder = tagMap[tagSet[:1]] + + except KeyError: + concreteDecoder = None + + if concreteDecoder: + state = stDecodeValue + else: + state = stTryAsExplicitTag + + if LOG: + LOG('codec %s chosen by a built-in type, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "", state is stDecodeValue and 'value' or 'as explicit tag')) + debug.scope.push(concreteDecoder is None and '?' or concreteDecoder.protoComponent.__class__.__name__) + + if state is stGetValueDecoderByAsn1Spec: + + if asn1Spec.__class__ is tagmap.TagMap: + try: + chosenSpec = asn1Spec[tagSet] + + except KeyError: + chosenSpec = None + + if LOG: + LOG('candidate ASN.1 spec is a map of:') + + for firstOctet, v in asn1Spec.presentTypes.items(): + LOG(' %s -> %s' % (firstOctet, v.__class__.__name__)) + + if asn1Spec.skipTypes: + LOG('but neither of: ') + for firstOctet, v in asn1Spec.skipTypes.items(): + LOG(' %s -> %s' % (firstOctet, v.__class__.__name__)) + LOG('new candidate ASN.1 spec is %s, chosen by %s' % (chosenSpec is None and '' or chosenSpec.prettyPrintType(), tagSet)) + + elif tagSet == asn1Spec.tagSet or tagSet in asn1Spec.tagMap: + chosenSpec = asn1Spec + if LOG: + LOG('candidate ASN.1 spec is %s' % asn1Spec.__class__.__name__) + + else: + chosenSpec = None + + if chosenSpec is not None: + try: + # ambiguous type or just faster codec lookup + concreteDecoder = typeMap[chosenSpec.typeId] + + if LOG: + LOG('value decoder chosen for an ambiguous type by type ID %s' % (chosenSpec.typeId,)) + + except KeyError: + # use base type for codec lookup to recover untagged types + baseTagSet = tag.TagSet(chosenSpec.tagSet.baseTag, chosenSpec.tagSet.baseTag) + try: + # base type or tagged subtype + concreteDecoder = tagMap[baseTagSet] + + if LOG: + LOG('value decoder chosen by base %s' % (baseTagSet,)) + + except KeyError: + concreteDecoder = None + + if concreteDecoder: + asn1Spec = chosenSpec + state = stDecodeValue + + else: + state = stTryAsExplicitTag + + else: + concreteDecoder = None + state = stTryAsExplicitTag + + if LOG: + LOG('codec %s chosen by ASN.1 spec, decoding %s' % (state is stDecodeValue and concreteDecoder.__class__.__name__ or "", state is stDecodeValue and 'value' or 'as explicit tag')) + debug.scope.push(chosenSpec is None and '?' or chosenSpec.__class__.__name__) + + if state is stDecodeValue: + if not options.get('recursiveFlag', True) and not substrateFun: # deprecate this + substrateFun = lambda a, b, c: (a, b[:c]) + + original_position = substrate.tell() + + if length == -1: # indef length + for value in concreteDecoder.indefLenValueDecoder( + substrate, asn1Spec, + tagSet, length, stGetValueDecoder, + self, substrateFun, **options): + if isinstance(value, SubstrateUnderrunError): + yield value + + else: + for value in concreteDecoder.valueDecoder( + substrate, asn1Spec, + tagSet, length, stGetValueDecoder, + self, substrateFun, **options): + if isinstance(value, SubstrateUnderrunError): + yield value + + bytesRead = substrate.tell() - original_position + if bytesRead != length: + raise PyAsn1Error( + "Read %s bytes instead of expected %s." % (bytesRead, length)) + + if LOG: + LOG('codec %s yields type %s, value:\n%s\n...' % ( + concreteDecoder.__class__.__name__, value.__class__.__name__, + isinstance(value, base.Asn1Item) and value.prettyPrint() or value)) + + state = stStop + break + + if state is stTryAsExplicitTag: + if (tagSet and + tagSet[0].tagFormat == tag.tagFormatConstructed and + tagSet[0].tagClass != tag.tagClassUniversal): + # Assume explicit tagging + concreteDecoder = rawPayloadDecoder + state = stDecodeValue + + else: + concreteDecoder = None + state = self.defaultErrorState + + if LOG: + LOG('codec %s chosen, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "", state is stDecodeValue and 'value' or 'as failure')) + + if state is stDumpRawValue: + concreteDecoder = self.defaultRawDecoder + + if LOG: + LOG('codec %s chosen, decoding value' % concreteDecoder.__class__.__name__) + + state = stDecodeValue + + if state is stErrorCondition: + raise error.PyAsn1Error( + '%s not in asn1Spec: %r' % (tagSet, asn1Spec) + ) + + if LOG: + debug.scope.pop() + LOG('decoder left scope %s, call completed' % debug.scope) + + yield value + + +class StreamingDecoder(object): + """Create an iterator that turns BER/CER/DER byte stream into ASN.1 objects. + + On each iteration, consume whatever BER/CER/DER serialization is + available in the `substrate` stream-like object and turns it into + one or more, possibly nested, ASN.1 objects. + + Parameters + ---------- + substrate: :py:class:`file`, :py:class:`io.BytesIO` + BER/CER/DER serialization in form of a byte stream + + Keyword Args + ------------ + asn1Spec: :py:class:`~pyasn1.type.base.PyAsn1Item` + A pyasn1 type object to act as a template guiding the decoder. + Depending on the ASN.1 structure being decoded, `asn1Spec` may + or may not be required. One of the reasons why `asn1Spec` may + me required is that ASN.1 structure is encoded in the *IMPLICIT* + tagging mode. + + Yields + ------ + : :py:class:`~pyasn1.type.base.PyAsn1Item`, :py:class:`~pyasn1.error.SubstrateUnderrunError` + Decoded ASN.1 object (possibly, nested) or + :py:class:`~pyasn1.error.SubstrateUnderrunError` object indicating + insufficient BER/CER/DER serialization on input to fully recover ASN.1 + objects from it. + + In the latter case the caller is advised to ensure some more data in + the input stream, then call the iterator again. The decoder will resume + the decoding process using the newly arrived data. + + The `context` property of :py:class:`~pyasn1.error.SubstrateUnderrunError` + object might hold a reference to the partially populated ASN.1 object + being reconstructed. + + Raises + ------ + ~pyasn1.error.PyAsn1Error, ~pyasn1.error.EndOfStreamError + `PyAsn1Error` on deserialization error, `EndOfStreamError` on + premature stream closure. + + Examples + -------- + Decode BER serialisation without ASN.1 schema + + .. code-block:: pycon + + >>> stream = io.BytesIO( + ... b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03') + >>> + >>> for asn1Object in StreamingDecoder(stream): + ... print(asn1Object) + >>> + SequenceOf: + 1 2 3 + + Decode BER serialisation with ASN.1 schema + + .. code-block:: pycon + + >>> stream = io.BytesIO( + ... b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03') + >>> + >>> schema = SequenceOf(componentType=Integer()) + >>> + >>> decoder = StreamingDecoder(stream, asn1Spec=schema) + >>> for asn1Object in decoder: + ... print(asn1Object) + >>> + SequenceOf: + 1 2 3 + """ + + SINGLE_ITEM_DECODER = SingleItemDecoder + + def __init__(self, substrate, asn1Spec=None, **options): + self._singleItemDecoder = self.SINGLE_ITEM_DECODER(**options) + self._substrate = asSeekableStream(substrate) + self._asn1Spec = asn1Spec + self._options = options + + def __iter__(self): + while True: + for asn1Object in self._singleItemDecoder( + self._substrate, self._asn1Spec, **self._options): + yield asn1Object + + for chunk in isEndOfStream(self._substrate): + if isinstance(chunk, SubstrateUnderrunError): + yield + + break + + if chunk: + break + + +class Decoder(object): + """Create a BER decoder object. + + Parse BER/CER/DER octet-stream into one, possibly nested, ASN.1 object. + """ + STREAMING_DECODER = StreamingDecoder + + @classmethod + def __call__(cls, substrate, asn1Spec=None, **options): + """Turns BER/CER/DER octet stream into an ASN.1 object. + + Takes BER/CER/DER octet-stream in form of :py:class:`bytes` (Python 3) + or :py:class:`str` (Python 2) and decode it into an ASN.1 object + (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which + may be a scalar or an arbitrary nested structure. + + Parameters + ---------- + substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) + BER/CER/DER octet-stream to parse + + Keyword Args + ------------ + asn1Spec: :py:class:`~pyasn1.type.base.PyAsn1Item` + A pyasn1 type object (:py:class:`~pyasn1.type.base.PyAsn1Item` + derivative) to act as a template guiding the decoder. + Depending on the ASN.1 structure being decoded, `asn1Spec` may or + may not be required. Most common reason for it to require is that + ASN.1 structure is encoded in *IMPLICIT* tagging mode. + + Returns + ------- + : :py:class:`tuple` + A tuple of :py:class:`~pyasn1.type.base.PyAsn1Item` object + recovered from BER/CER/DER substrate and the unprocessed trailing + portion of the `substrate` (may be empty) + + Raises + ------ + : :py:class:`~pyasn1.error.PyAsn1Error` + :py:class:`~pyasn1.error.SubstrateUnderrunError` on insufficient + input or :py:class:`~pyasn1.error.PyAsn1Error` on decoding error. + + Examples + -------- + Decode BER/CER/DER serialisation without ASN.1 schema + + .. code-block:: pycon + + >>> s, unprocessed = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03') + >>> str(s) + SequenceOf: + 1 2 3 + + Decode BER/CER/DER serialisation with ASN.1 schema + + .. code-block:: pycon + + >>> seq = SequenceOf(componentType=Integer()) + >>> s, unprocessed = decode( + b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03', asn1Spec=seq) + >>> str(s) + SequenceOf: + 1 2 3 + + """ + substrate = asSeekableStream(substrate) + + streamingDecoder = cls.STREAMING_DECODER( + substrate, asn1Spec, **options) + + for asn1Object in streamingDecoder: + if isinstance(asn1Object, SubstrateUnderrunError): + raise error.SubstrateUnderrunError('Short substrate on input') + + try: + tail = next(readFromStream(substrate)) + + except error.EndOfStreamError: + tail = null + + return asn1Object, tail + + +#: Turns BER octet stream into an ASN.1 object. +#: +#: Takes BER octet-stream and decode it into an ASN.1 object +#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which +#: may be a scalar or an arbitrary nested structure. +#: +#: Parameters +#: ---------- +#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) +#: BER octet-stream +#: +#: Keyword Args +#: ------------ +#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure +#: being decoded, *asn1Spec* may or may not be required. Most common reason for +#: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode. +#: +#: Returns +#: ------- +#: : :py:class:`tuple` +#: A tuple of pyasn1 object recovered from BER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: and the unprocessed trailing portion of the *substrate* (may be empty) +#: +#: Raises +#: ------ +#: ~pyasn1.error.PyAsn1Error, ~pyasn1.error.SubstrateUnderrunError +#: On decoding errors +#: +#: Notes +#: ----- +#: This function is deprecated. Please use :py:class:`Decoder` or +#: :py:class:`StreamingDecoder` class instance. +#: +#: Examples +#: -------- +#: Decode BER serialisation without ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03') +#: >>> str(s) +#: SequenceOf: +#: 1 2 3 +#: +#: Decode BER serialisation with ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03', asn1Spec=seq) +#: >>> str(s) +#: SequenceOf: +#: 1 2 3 +#: +decode = Decoder() diff --git a/lib/pyasn1/codec/ber/encoder.py b/lib/pyasn1/codec/ber/encoder.py new file mode 100644 index 00000000..6cce134a --- /dev/null +++ b/lib/pyasn1/codec/ber/encoder.py @@ -0,0 +1,910 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import sys + +from pyasn1 import debug +from pyasn1 import error +from pyasn1.codec.ber import eoo +from pyasn1.compat.integer import to_bytes +from pyasn1.compat.octets import (int2oct, oct2int, ints2octs, null, + str2octs, isOctetsType) +from pyasn1.type import char +from pyasn1.type import tag +from pyasn1.type import univ +from pyasn1.type import useful + +__all__ = ['Encoder', 'encode'] + +LOG = debug.registerLoggee(__name__, flags=debug.DEBUG_ENCODER) + + +class AbstractItemEncoder(object): + supportIndefLenMode = True + + # An outcome of otherwise legit call `encodeFun(eoo.endOfOctets)` + eooIntegerSubstrate = (0, 0) + eooOctetsSubstrate = ints2octs(eooIntegerSubstrate) + + # noinspection PyMethodMayBeStatic + def encodeTag(self, singleTag, isConstructed): + tagClass, tagFormat, tagId = singleTag + encodedTag = tagClass | tagFormat + if isConstructed: + encodedTag |= tag.tagFormatConstructed + + if tagId < 31: + return encodedTag | tagId, + + else: + substrate = tagId & 0x7f, + + tagId >>= 7 + + while tagId: + substrate = (0x80 | (tagId & 0x7f),) + substrate + tagId >>= 7 + + return (encodedTag | 0x1F,) + substrate + + def encodeLength(self, length, defMode): + if not defMode and self.supportIndefLenMode: + return (0x80,) + + if length < 0x80: + return length, + + else: + substrate = () + while length: + substrate = (length & 0xff,) + substrate + length >>= 8 + + substrateLen = len(substrate) + + if substrateLen > 126: + raise error.PyAsn1Error('Length octets overflow (%d)' % substrateLen) + + return (0x80 | substrateLen,) + substrate + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + raise error.PyAsn1Error('Not implemented') + + def encode(self, value, asn1Spec=None, encodeFun=None, **options): + + if asn1Spec is None: + tagSet = value.tagSet + else: + tagSet = asn1Spec.tagSet + + # untagged item? + if not tagSet: + substrate, isConstructed, isOctets = self.encodeValue( + value, asn1Spec, encodeFun, **options + ) + return substrate + + defMode = options.get('defMode', True) + + substrate = null + + for idx, singleTag in enumerate(tagSet.superTags): + + defModeOverride = defMode + + # base tag? + if not idx: + try: + substrate, isConstructed, isOctets = self.encodeValue( + value, asn1Spec, encodeFun, **options + ) + + except error.PyAsn1Error: + exc = sys.exc_info() + raise error.PyAsn1Error( + 'Error encoding %r: %s' % (value, exc[1])) + + if LOG: + LOG('encoded %svalue %s into %s' % ( + isConstructed and 'constructed ' or '', value, substrate + )) + + if not substrate and isConstructed and options.get('ifNotEmpty', False): + return substrate + + if not isConstructed: + defModeOverride = True + + if LOG: + LOG('overridden encoding mode into definitive for primitive type') + + header = self.encodeTag(singleTag, isConstructed) + + if LOG: + LOG('encoded %stag %s into %s' % ( + isConstructed and 'constructed ' or '', + singleTag, debug.hexdump(ints2octs(header)))) + + header += self.encodeLength(len(substrate), defModeOverride) + + if LOG: + LOG('encoded %s octets (tag + payload) into %s' % ( + len(substrate), debug.hexdump(ints2octs(header)))) + + if isOctets: + substrate = ints2octs(header) + substrate + + if not defModeOverride: + substrate += self.eooOctetsSubstrate + + else: + substrate = header + substrate + + if not defModeOverride: + substrate += self.eooIntegerSubstrate + + if not isOctets: + substrate = ints2octs(substrate) + + return substrate + + +class EndOfOctetsEncoder(AbstractItemEncoder): + def encodeValue(self, value, asn1Spec, encodeFun, **options): + return null, False, True + + +class BooleanEncoder(AbstractItemEncoder): + supportIndefLenMode = False + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + return value and (1,) or (0,), False, False + + +class IntegerEncoder(AbstractItemEncoder): + supportIndefLenMode = False + supportCompactZero = False + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + if value == 0: + if LOG: + LOG('encoding %spayload for zero INTEGER' % ( + self.supportCompactZero and 'no ' or '' + )) + + # de-facto way to encode zero + if self.supportCompactZero: + return (), False, False + else: + return (0,), False, False + + return to_bytes(int(value), signed=True), False, True + + +class BitStringEncoder(AbstractItemEncoder): + def encodeValue(self, value, asn1Spec, encodeFun, **options): + if asn1Spec is not None: + # TODO: try to avoid ASN.1 schema instantiation + value = asn1Spec.clone(value) + + valueLength = len(value) + if valueLength % 8: + alignedValue = value << (8 - valueLength % 8) + else: + alignedValue = value + + maxChunkSize = options.get('maxChunkSize', 0) + if not maxChunkSize or len(alignedValue) <= maxChunkSize * 8: + substrate = alignedValue.asOctets() + return int2oct(len(substrate) * 8 - valueLength) + substrate, False, True + + if LOG: + LOG('encoding into up to %s-octet chunks' % maxChunkSize) + + baseTag = value.tagSet.baseTag + + # strip off explicit tags + if baseTag: + tagSet = tag.TagSet(baseTag, baseTag) + + else: + tagSet = tag.TagSet() + + alignedValue = alignedValue.clone(tagSet=tagSet) + + stop = 0 + substrate = null + while stop < valueLength: + start = stop + stop = min(start + maxChunkSize * 8, valueLength) + substrate += encodeFun(alignedValue[start:stop], asn1Spec, **options) + + return substrate, True, True + + +class OctetStringEncoder(AbstractItemEncoder): + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + + if asn1Spec is None: + substrate = value.asOctets() + + elif not isOctetsType(value): + substrate = asn1Spec.clone(value).asOctets() + + else: + substrate = value + + maxChunkSize = options.get('maxChunkSize', 0) + + if not maxChunkSize or len(substrate) <= maxChunkSize: + return substrate, False, True + + if LOG: + LOG('encoding into up to %s-octet chunks' % maxChunkSize) + + # strip off explicit tags for inner chunks + + if asn1Spec is None: + baseTag = value.tagSet.baseTag + + # strip off explicit tags + if baseTag: + tagSet = tag.TagSet(baseTag, baseTag) + + else: + tagSet = tag.TagSet() + + asn1Spec = value.clone(tagSet=tagSet) + + elif not isOctetsType(value): + baseTag = asn1Spec.tagSet.baseTag + + # strip off explicit tags + if baseTag: + tagSet = tag.TagSet(baseTag, baseTag) + + else: + tagSet = tag.TagSet() + + asn1Spec = asn1Spec.clone(tagSet=tagSet) + + pos = 0 + substrate = null + + while True: + chunk = value[pos:pos + maxChunkSize] + if not chunk: + break + + substrate += encodeFun(chunk, asn1Spec, **options) + pos += maxChunkSize + + return substrate, True, True + + +class NullEncoder(AbstractItemEncoder): + supportIndefLenMode = False + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + return null, False, True + + +class ObjectIdentifierEncoder(AbstractItemEncoder): + supportIndefLenMode = False + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + if asn1Spec is not None: + value = asn1Spec.clone(value) + + oid = value.asTuple() + + # Build the first pair + try: + first = oid[0] + second = oid[1] + + except IndexError: + raise error.PyAsn1Error('Short OID %s' % (value,)) + + if 0 <= second <= 39: + if first == 1: + oid = (second + 40,) + oid[2:] + elif first == 0: + oid = (second,) + oid[2:] + elif first == 2: + oid = (second + 80,) + oid[2:] + else: + raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,)) + + elif first == 2: + oid = (second + 80,) + oid[2:] + + else: + raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,)) + + octets = () + + # Cycle through subIds + for subOid in oid: + if 0 <= subOid <= 127: + # Optimize for the common case + octets += (subOid,) + + elif subOid > 127: + # Pack large Sub-Object IDs + res = (subOid & 0x7f,) + subOid >>= 7 + + while subOid: + res = (0x80 | (subOid & 0x7f),) + res + subOid >>= 7 + + # Add packed Sub-Object ID to resulted Object ID + octets += res + + else: + raise error.PyAsn1Error('Negative OID arc %s at %s' % (subOid, value)) + + return octets, False, False + + +class RealEncoder(AbstractItemEncoder): + supportIndefLenMode = 0 + binEncBase = 2 # set to None to choose encoding base automatically + + @staticmethod + def _dropFloatingPoint(m, encbase, e): + ms, es = 1, 1 + if m < 0: + ms = -1 # mantissa sign + + if e < 0: + es = -1 # exponent sign + + m *= ms + + if encbase == 8: + m *= 2 ** (abs(e) % 3 * es) + e = abs(e) // 3 * es + + elif encbase == 16: + m *= 2 ** (abs(e) % 4 * es) + e = abs(e) // 4 * es + + while True: + if int(m) != m: + m *= encbase + e -= 1 + continue + break + + return ms, int(m), encbase, e + + def _chooseEncBase(self, value): + m, b, e = value + encBase = [2, 8, 16] + if value.binEncBase in encBase: + return self._dropFloatingPoint(m, value.binEncBase, e) + + elif self.binEncBase in encBase: + return self._dropFloatingPoint(m, self.binEncBase, e) + + # auto choosing base 2/8/16 + mantissa = [m, m, m] + exponent = [e, e, e] + sign = 1 + encbase = 2 + e = float('inf') + + for i in range(3): + (sign, + mantissa[i], + encBase[i], + exponent[i]) = self._dropFloatingPoint(mantissa[i], encBase[i], exponent[i]) + + if abs(exponent[i]) < abs(e) or (abs(exponent[i]) == abs(e) and mantissa[i] < m): + e = exponent[i] + m = int(mantissa[i]) + encbase = encBase[i] + + if LOG: + LOG('automatically chosen REAL encoding base %s, sign %s, mantissa %s, ' + 'exponent %s' % (encbase, sign, m, e)) + + return sign, m, encbase, e + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + if asn1Spec is not None: + value = asn1Spec.clone(value) + + if value.isPlusInf: + return (0x40,), False, False + + if value.isMinusInf: + return (0x41,), False, False + + m, b, e = value + + if not m: + return null, False, True + + if b == 10: + if LOG: + LOG('encoding REAL into character form') + + return str2octs('\x03%dE%s%d' % (m, e == 0 and '+' or '', e)), False, True + + elif b == 2: + fo = 0x80 # binary encoding + ms, m, encbase, e = self._chooseEncBase(value) + + if ms < 0: # mantissa sign + fo |= 0x40 # sign bit + + # exponent & mantissa normalization + if encbase == 2: + while m & 0x1 == 0: + m >>= 1 + e += 1 + + elif encbase == 8: + while m & 0x7 == 0: + m >>= 3 + e += 1 + fo |= 0x10 + + else: # encbase = 16 + while m & 0xf == 0: + m >>= 4 + e += 1 + fo |= 0x20 + + sf = 0 # scale factor + + while m & 0x1 == 0: + m >>= 1 + sf += 1 + + if sf > 3: + raise error.PyAsn1Error('Scale factor overflow') # bug if raised + + fo |= sf << 2 + eo = null + if e == 0 or e == -1: + eo = int2oct(e & 0xff) + + else: + while e not in (0, -1): + eo = int2oct(e & 0xff) + eo + e >>= 8 + + if e == 0 and eo and oct2int(eo[0]) & 0x80: + eo = int2oct(0) + eo + + if e == -1 and eo and not (oct2int(eo[0]) & 0x80): + eo = int2oct(0xff) + eo + + n = len(eo) + if n > 0xff: + raise error.PyAsn1Error('Real exponent overflow') + + if n == 1: + pass + + elif n == 2: + fo |= 1 + + elif n == 3: + fo |= 2 + + else: + fo |= 3 + eo = int2oct(n & 0xff) + eo + + po = null + + while m: + po = int2oct(m & 0xff) + po + m >>= 8 + + substrate = int2oct(fo) + eo + po + + return substrate, False, True + + else: + raise error.PyAsn1Error('Prohibited Real base %s' % b) + + +class SequenceEncoder(AbstractItemEncoder): + omitEmptyOptionals = False + + # TODO: handling three flavors of input is too much -- split over codecs + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + + substrate = null + + omitEmptyOptionals = options.get( + 'omitEmptyOptionals', self.omitEmptyOptionals) + + if LOG: + LOG('%sencoding empty OPTIONAL components' % ( + omitEmptyOptionals and 'not ' or '')) + + if asn1Spec is None: + # instance of ASN.1 schema + inconsistency = value.isInconsistent + if inconsistency: + raise inconsistency + + namedTypes = value.componentType + + for idx, component in enumerate(value.values()): + if namedTypes: + namedType = namedTypes[idx] + + if namedType.isOptional and not component.isValue: + if LOG: + LOG('not encoding OPTIONAL component %r' % (namedType,)) + continue + + if namedType.isDefaulted and component == namedType.asn1Object: + if LOG: + LOG('not encoding DEFAULT component %r' % (namedType,)) + continue + + if omitEmptyOptionals: + options.update(ifNotEmpty=namedType.isOptional) + + # wrap open type blob if needed + if namedTypes and namedType.openType: + + wrapType = namedType.asn1Object + + if wrapType.typeId in ( + univ.SetOf.typeId, univ.SequenceOf.typeId): + + substrate += encodeFun( + component, asn1Spec, + **dict(options, wrapType=wrapType.componentType)) + + else: + chunk = encodeFun(component, asn1Spec, **options) + + if wrapType.isSameTypeWith(component): + substrate += chunk + + else: + substrate += encodeFun(chunk, wrapType, **options) + + if LOG: + LOG('wrapped with wrap type %r' % (wrapType,)) + + else: + substrate += encodeFun(component, asn1Spec, **options) + + else: + # bare Python value + ASN.1 schema + for idx, namedType in enumerate(asn1Spec.componentType.namedTypes): + + try: + component = value[namedType.name] + + except KeyError: + raise error.PyAsn1Error('Component name "%s" not found in %r' % ( + namedType.name, value)) + + if namedType.isOptional and namedType.name not in value: + if LOG: + LOG('not encoding OPTIONAL component %r' % (namedType,)) + continue + + if namedType.isDefaulted and component == namedType.asn1Object: + if LOG: + LOG('not encoding DEFAULT component %r' % (namedType,)) + continue + + if omitEmptyOptionals: + options.update(ifNotEmpty=namedType.isOptional) + + componentSpec = namedType.asn1Object + + # wrap open type blob if needed + if namedType.openType: + + if componentSpec.typeId in ( + univ.SetOf.typeId, univ.SequenceOf.typeId): + + substrate += encodeFun( + component, componentSpec, + **dict(options, wrapType=componentSpec.componentType)) + + else: + chunk = encodeFun(component, componentSpec, **options) + + if componentSpec.isSameTypeWith(component): + substrate += chunk + + else: + substrate += encodeFun(chunk, componentSpec, **options) + + if LOG: + LOG('wrapped with wrap type %r' % (componentSpec,)) + + else: + substrate += encodeFun(component, componentSpec, **options) + + return substrate, True, True + + +class SequenceOfEncoder(AbstractItemEncoder): + def _encodeComponents(self, value, asn1Spec, encodeFun, **options): + + if asn1Spec is None: + inconsistency = value.isInconsistent + if inconsistency: + raise inconsistency + + else: + asn1Spec = asn1Spec.componentType + + chunks = [] + + wrapType = options.pop('wrapType', None) + + for idx, component in enumerate(value): + chunk = encodeFun(component, asn1Spec, **options) + + if (wrapType is not None and + not wrapType.isSameTypeWith(component)): + # wrap encoded value with wrapper container (e.g. ANY) + chunk = encodeFun(chunk, wrapType, **options) + + if LOG: + LOG('wrapped with wrap type %r' % (wrapType,)) + + chunks.append(chunk) + + return chunks + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + chunks = self._encodeComponents( + value, asn1Spec, encodeFun, **options) + + return null.join(chunks), True, True + + +class ChoiceEncoder(AbstractItemEncoder): + def encodeValue(self, value, asn1Spec, encodeFun, **options): + if asn1Spec is None: + component = value.getComponent() + else: + names = [namedType.name for namedType in asn1Spec.componentType.namedTypes + if namedType.name in value] + if len(names) != 1: + raise error.PyAsn1Error('%s components for Choice at %r' % (len(names) and 'Multiple ' or 'None ', value)) + + name = names[0] + + component = value[name] + asn1Spec = asn1Spec[name] + + return encodeFun(component, asn1Spec, **options), True, True + + +class AnyEncoder(OctetStringEncoder): + def encodeValue(self, value, asn1Spec, encodeFun, **options): + if asn1Spec is None: + value = value.asOctets() + elif not isOctetsType(value): + value = asn1Spec.clone(value).asOctets() + + return value, not options.get('defMode', True), True + + +TAG_MAP = { + eoo.endOfOctets.tagSet: EndOfOctetsEncoder(), + univ.Boolean.tagSet: BooleanEncoder(), + univ.Integer.tagSet: IntegerEncoder(), + univ.BitString.tagSet: BitStringEncoder(), + univ.OctetString.tagSet: OctetStringEncoder(), + univ.Null.tagSet: NullEncoder(), + univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(), + univ.Enumerated.tagSet: IntegerEncoder(), + univ.Real.tagSet: RealEncoder(), + # Sequence & Set have same tags as SequenceOf & SetOf + univ.SequenceOf.tagSet: SequenceOfEncoder(), + univ.SetOf.tagSet: SequenceOfEncoder(), + univ.Choice.tagSet: ChoiceEncoder(), + # character string types + char.UTF8String.tagSet: OctetStringEncoder(), + char.NumericString.tagSet: OctetStringEncoder(), + char.PrintableString.tagSet: OctetStringEncoder(), + char.TeletexString.tagSet: OctetStringEncoder(), + char.VideotexString.tagSet: OctetStringEncoder(), + char.IA5String.tagSet: OctetStringEncoder(), + char.GraphicString.tagSet: OctetStringEncoder(), + char.VisibleString.tagSet: OctetStringEncoder(), + char.GeneralString.tagSet: OctetStringEncoder(), + char.UniversalString.tagSet: OctetStringEncoder(), + char.BMPString.tagSet: OctetStringEncoder(), + # useful types + useful.ObjectDescriptor.tagSet: OctetStringEncoder(), + useful.GeneralizedTime.tagSet: OctetStringEncoder(), + useful.UTCTime.tagSet: OctetStringEncoder() +} + +# Put in ambiguous & non-ambiguous types for faster codec lookup +TYPE_MAP = { + univ.Boolean.typeId: BooleanEncoder(), + univ.Integer.typeId: IntegerEncoder(), + univ.BitString.typeId: BitStringEncoder(), + univ.OctetString.typeId: OctetStringEncoder(), + univ.Null.typeId: NullEncoder(), + univ.ObjectIdentifier.typeId: ObjectIdentifierEncoder(), + univ.Enumerated.typeId: IntegerEncoder(), + univ.Real.typeId: RealEncoder(), + # Sequence & Set have same tags as SequenceOf & SetOf + univ.Set.typeId: SequenceEncoder(), + univ.SetOf.typeId: SequenceOfEncoder(), + univ.Sequence.typeId: SequenceEncoder(), + univ.SequenceOf.typeId: SequenceOfEncoder(), + univ.Choice.typeId: ChoiceEncoder(), + univ.Any.typeId: AnyEncoder(), + # character string types + char.UTF8String.typeId: OctetStringEncoder(), + char.NumericString.typeId: OctetStringEncoder(), + char.PrintableString.typeId: OctetStringEncoder(), + char.TeletexString.typeId: OctetStringEncoder(), + char.VideotexString.typeId: OctetStringEncoder(), + char.IA5String.typeId: OctetStringEncoder(), + char.GraphicString.typeId: OctetStringEncoder(), + char.VisibleString.typeId: OctetStringEncoder(), + char.GeneralString.typeId: OctetStringEncoder(), + char.UniversalString.typeId: OctetStringEncoder(), + char.BMPString.typeId: OctetStringEncoder(), + # useful types + useful.ObjectDescriptor.typeId: OctetStringEncoder(), + useful.GeneralizedTime.typeId: OctetStringEncoder(), + useful.UTCTime.typeId: OctetStringEncoder() +} + + +class SingleItemEncoder(object): + fixedDefLengthMode = None + fixedChunkSize = None + + TAG_MAP = TAG_MAP + TYPE_MAP = TYPE_MAP + + def __init__(self, **options): + self._tagMap = options.get('tagMap', self.TAG_MAP) + self._typeMap = options.get('typeMap', self.TYPE_MAP) + + def __call__(self, value, asn1Spec=None, **options): + try: + if asn1Spec is None: + typeId = value.typeId + else: + typeId = asn1Spec.typeId + + except AttributeError: + raise error.PyAsn1Error('Value %r is not ASN.1 type instance ' + 'and "asn1Spec" not given' % (value,)) + + if LOG: + LOG('encoder called in %sdef mode, chunk size %s for type %s, ' + 'value:\n%s' % (not options.get('defMode', True) and 'in' or '', + options.get('maxChunkSize', 0), + asn1Spec is None and value.prettyPrintType() or + asn1Spec.prettyPrintType(), value)) + + if self.fixedDefLengthMode is not None: + options.update(defMode=self.fixedDefLengthMode) + + if self.fixedChunkSize is not None: + options.update(maxChunkSize=self.fixedChunkSize) + + try: + concreteEncoder = self._typeMap[typeId] + + if LOG: + LOG('using value codec %s chosen by type ID ' + '%s' % (concreteEncoder.__class__.__name__, typeId)) + + except KeyError: + if asn1Spec is None: + tagSet = value.tagSet + else: + tagSet = asn1Spec.tagSet + + # use base type for codec lookup to recover untagged types + baseTagSet = tag.TagSet(tagSet.baseTag, tagSet.baseTag) + + try: + concreteEncoder = self._tagMap[baseTagSet] + + except KeyError: + raise error.PyAsn1Error('No encoder for %r (%s)' % (value, tagSet)) + + if LOG: + LOG('using value codec %s chosen by tagSet ' + '%s' % (concreteEncoder.__class__.__name__, tagSet)) + + substrate = concreteEncoder.encode(value, asn1Spec, self, **options) + + if LOG: + LOG('codec %s built %s octets of substrate: %s\nencoder ' + 'completed' % (concreteEncoder, len(substrate), + debug.hexdump(substrate))) + + return substrate + + +class Encoder(object): + SINGLE_ITEM_ENCODER = SingleItemEncoder + + def __init__(self, **options): + self._singleItemEncoder = self.SINGLE_ITEM_ENCODER(**options) + + def __call__(self, pyObject, asn1Spec=None, **options): + return self._singleItemEncoder( + pyObject, asn1Spec=asn1Spec, **options) + + +#: Turns ASN.1 object into BER octet stream. +#: +#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: walks all its components recursively and produces a BER octet stream. +#: +#: Parameters +#: ---------- +#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: A Python or pyasn1 object to encode. If Python object is given, `asnSpec` +#: parameter is required to guide the encoding process. +#: +#: Keyword Args +#: ------------ +#: asn1Spec: +#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: +#: defMode: :py:class:`bool` +#: If :obj:`False`, produces indefinite length encoding +#: +#: maxChunkSize: :py:class:`int` +#: Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size) +#: +#: Returns +#: ------- +#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) +#: Given ASN.1 object encoded into BER octetstream +#: +#: Raises +#: ------ +#: ~pyasn1.error.PyAsn1Error +#: On encoding errors +#: +#: Examples +#: -------- +#: Encode Python value into BER with ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> encode([1, 2, 3], asn1Spec=seq) +#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03' +#: +#: Encode ASN.1 value object into BER +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> seq.extend([1, 2, 3]) +#: >>> encode(seq) +#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03' +#: +encode = Encoder() diff --git a/lib/pyasn1/codec/ber/eoo.py b/lib/pyasn1/codec/ber/eoo.py new file mode 100644 index 00000000..ca5c5066 --- /dev/null +++ b/lib/pyasn1/codec/ber/eoo.py @@ -0,0 +1,28 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1.type import base +from pyasn1.type import tag + +__all__ = ['endOfOctets'] + + +class EndOfOctets(base.SimpleAsn1Type): + defaultValue = 0 + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x00) + ) + + _instance = None + + def __new__(cls, *args, **kwargs): + if cls._instance is None: + cls._instance = object.__new__(cls, *args, **kwargs) + + return cls._instance + + +endOfOctets = EndOfOctets() diff --git a/lib/sambatools/pyasn1/codec/cer/__init__.py b/lib/pyasn1/codec/cer/__init__.py similarity index 100% rename from lib/sambatools/pyasn1/codec/cer/__init__.py rename to lib/pyasn1/codec/cer/__init__.py diff --git a/lib/pyasn1/codec/cer/decoder.py b/lib/pyasn1/codec/cer/decoder.py new file mode 100644 index 00000000..52dd455b --- /dev/null +++ b/lib/pyasn1/codec/cer/decoder.py @@ -0,0 +1,142 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1 import error +from pyasn1.codec.streaming import readFromStream +from pyasn1.codec.ber import decoder +from pyasn1.compat.octets import oct2int +from pyasn1.type import univ + +__all__ = ['decode', 'StreamingDecoder'] + +SubstrateUnderrunError = error.SubstrateUnderrunError + + +class BooleanPayloadDecoder(decoder.AbstractSimplePayloadDecoder): + protoComponent = univ.Boolean(0) + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + + if length != 1: + raise error.PyAsn1Error('Not single-octet Boolean payload') + + for chunk in readFromStream(substrate, length, options): + if isinstance(chunk, SubstrateUnderrunError): + yield chunk + + byte = oct2int(chunk[0]) + + # CER/DER specifies encoding of TRUE as 0xFF and FALSE as 0x0, while + # BER allows any non-zero value as TRUE; cf. sections 8.2.2. and 11.1 + # in https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + if byte == 0xff: + value = 1 + + elif byte == 0x00: + value = 0 + + else: + raise error.PyAsn1Error('Unexpected Boolean payload: %s' % byte) + + yield self._createComponent(asn1Spec, tagSet, value, **options) + + +# TODO: prohibit non-canonical encoding +BitStringPayloadDecoder = decoder.BitStringPayloadDecoder +OctetStringPayloadDecoder = decoder.OctetStringPayloadDecoder +RealPayloadDecoder = decoder.RealPayloadDecoder + +TAG_MAP = decoder.TAG_MAP.copy() +TAG_MAP.update( + {univ.Boolean.tagSet: BooleanPayloadDecoder(), + univ.BitString.tagSet: BitStringPayloadDecoder(), + univ.OctetString.tagSet: OctetStringPayloadDecoder(), + univ.Real.tagSet: RealPayloadDecoder()} +) + +TYPE_MAP = decoder.TYPE_MAP.copy() + +# Put in non-ambiguous types for faster codec lookup +for typeDecoder in TAG_MAP.values(): + if typeDecoder.protoComponent is not None: + typeId = typeDecoder.protoComponent.__class__.typeId + if typeId is not None and typeId not in TYPE_MAP: + TYPE_MAP[typeId] = typeDecoder + + +class SingleItemDecoder(decoder.SingleItemDecoder): + __doc__ = decoder.SingleItemDecoder.__doc__ + + TAG_MAP = TAG_MAP + TYPE_MAP = TYPE_MAP + + +class StreamingDecoder(decoder.StreamingDecoder): + __doc__ = decoder.StreamingDecoder.__doc__ + + SINGLE_ITEM_DECODER = SingleItemDecoder + + +class Decoder(decoder.Decoder): + __doc__ = decoder.Decoder.__doc__ + + STREAMING_DECODER = StreamingDecoder + + +#: Turns CER octet stream into an ASN.1 object. +#: +#: Takes CER octet-stream and decode it into an ASN.1 object +#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which +#: may be a scalar or an arbitrary nested structure. +#: +#: Parameters +#: ---------- +#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) +#: CER octet-stream +#: +#: Keyword Args +#: ------------ +#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure +#: being decoded, *asn1Spec* may or may not be required. Most common reason for +#: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode. +#: +#: Returns +#: ------- +#: : :py:class:`tuple` +#: A tuple of pyasn1 object recovered from CER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: and the unprocessed trailing portion of the *substrate* (may be empty) +#: +#: Raises +#: ------ +#: ~pyasn1.error.PyAsn1Error, ~pyasn1.error.SubstrateUnderrunError +#: On decoding errors +#: +#: Examples +#: -------- +#: Decode CER serialisation without ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> s, _ = decode(b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00') +#: >>> str(s) +#: SequenceOf: +#: 1 2 3 +#: +#: Decode CER serialisation with ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> s, _ = decode(b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00', asn1Spec=seq) +#: >>> str(s) +#: SequenceOf: +#: 1 2 3 +#: +decode = Decoder() diff --git a/lib/pyasn1/codec/cer/encoder.py b/lib/pyasn1/codec/cer/encoder.py new file mode 100644 index 00000000..21366091 --- /dev/null +++ b/lib/pyasn1/codec/cer/encoder.py @@ -0,0 +1,323 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1 import error +from pyasn1.codec.ber import encoder +from pyasn1.compat.octets import str2octs, null +from pyasn1.type import univ +from pyasn1.type import useful + +__all__ = ['Encoder', 'encode'] + + +class BooleanEncoder(encoder.IntegerEncoder): + def encodeValue(self, value, asn1Spec, encodeFun, **options): + if value == 0: + substrate = (0,) + else: + substrate = (255,) + return substrate, False, False + + +class RealEncoder(encoder.RealEncoder): + def _chooseEncBase(self, value): + m, b, e = value + return self._dropFloatingPoint(m, b, e) + + +# specialized GeneralStringEncoder here + +class TimeEncoderMixIn(object): + Z_CHAR = ord('Z') + PLUS_CHAR = ord('+') + MINUS_CHAR = ord('-') + COMMA_CHAR = ord(',') + DOT_CHAR = ord('.') + ZERO_CHAR = ord('0') + + MIN_LENGTH = 12 + MAX_LENGTH = 19 + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + # CER encoding constraints: + # - minutes are mandatory, seconds are optional + # - sub-seconds must NOT be zero / no meaningless zeros + # - no hanging fraction dot + # - time in UTC (Z) + # - only dot is allowed for fractions + + if asn1Spec is not None: + value = asn1Spec.clone(value) + + numbers = value.asNumbers() + + if self.PLUS_CHAR in numbers or self.MINUS_CHAR in numbers: + raise error.PyAsn1Error('Must be UTC time: %r' % value) + + if numbers[-1] != self.Z_CHAR: + raise error.PyAsn1Error('Missing "Z" time zone specifier: %r' % value) + + if self.COMMA_CHAR in numbers: + raise error.PyAsn1Error('Comma in fractions disallowed: %r' % value) + + if self.DOT_CHAR in numbers: + + isModified = False + + numbers = list(numbers) + + searchIndex = min(numbers.index(self.DOT_CHAR) + 4, len(numbers) - 1) + + while numbers[searchIndex] != self.DOT_CHAR: + if numbers[searchIndex] == self.ZERO_CHAR: + del numbers[searchIndex] + isModified = True + + searchIndex -= 1 + + searchIndex += 1 + + if searchIndex < len(numbers): + if numbers[searchIndex] == self.Z_CHAR: + # drop hanging comma + del numbers[searchIndex - 1] + isModified = True + + if isModified: + value = value.clone(numbers) + + if not self.MIN_LENGTH < len(numbers) < self.MAX_LENGTH: + raise error.PyAsn1Error('Length constraint violated: %r' % value) + + options.update(maxChunkSize=1000) + + return encoder.OctetStringEncoder.encodeValue( + self, value, asn1Spec, encodeFun, **options + ) + + +class GeneralizedTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder): + MIN_LENGTH = 12 + MAX_LENGTH = 20 + + +class UTCTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder): + MIN_LENGTH = 10 + MAX_LENGTH = 14 + + +class SetOfEncoder(encoder.SequenceOfEncoder): + def encodeValue(self, value, asn1Spec, encodeFun, **options): + chunks = self._encodeComponents( + value, asn1Spec, encodeFun, **options) + + # sort by serialised and padded components + if len(chunks) > 1: + zero = str2octs('\x00') + maxLen = max(map(len, chunks)) + paddedChunks = [ + (x.ljust(maxLen, zero), x) for x in chunks + ] + paddedChunks.sort(key=lambda x: x[0]) + + chunks = [x[1] for x in paddedChunks] + + return null.join(chunks), True, True + + +class SequenceOfEncoder(encoder.SequenceOfEncoder): + def encodeValue(self, value, asn1Spec, encodeFun, **options): + + if options.get('ifNotEmpty', False) and not len(value): + return null, True, True + + chunks = self._encodeComponents( + value, asn1Spec, encodeFun, **options) + + return null.join(chunks), True, True + + +class SetEncoder(encoder.SequenceEncoder): + @staticmethod + def _componentSortKey(componentAndType): + """Sort SET components by tag + + Sort regardless of the Choice value (static sort) + """ + component, asn1Spec = componentAndType + + if asn1Spec is None: + asn1Spec = component + + if asn1Spec.typeId == univ.Choice.typeId and not asn1Spec.tagSet: + if asn1Spec.tagSet: + return asn1Spec.tagSet + else: + return asn1Spec.componentType.minTagSet + else: + return asn1Spec.tagSet + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + + substrate = null + + comps = [] + compsMap = {} + + if asn1Spec is None: + # instance of ASN.1 schema + inconsistency = value.isInconsistent + if inconsistency: + raise inconsistency + + namedTypes = value.componentType + + for idx, component in enumerate(value.values()): + if namedTypes: + namedType = namedTypes[idx] + + if namedType.isOptional and not component.isValue: + continue + + if namedType.isDefaulted and component == namedType.asn1Object: + continue + + compsMap[id(component)] = namedType + + else: + compsMap[id(component)] = None + + comps.append((component, asn1Spec)) + + else: + # bare Python value + ASN.1 schema + for idx, namedType in enumerate(asn1Spec.componentType.namedTypes): + + try: + component = value[namedType.name] + + except KeyError: + raise error.PyAsn1Error('Component name "%s" not found in %r' % (namedType.name, value)) + + if namedType.isOptional and namedType.name not in value: + continue + + if namedType.isDefaulted and component == namedType.asn1Object: + continue + + compsMap[id(component)] = namedType + comps.append((component, asn1Spec[idx])) + + for comp, compType in sorted(comps, key=self._componentSortKey): + namedType = compsMap[id(comp)] + + if namedType: + options.update(ifNotEmpty=namedType.isOptional) + + chunk = encodeFun(comp, compType, **options) + + # wrap open type blob if needed + if namedType and namedType.openType: + wrapType = namedType.asn1Object + if wrapType.tagSet and not wrapType.isSameTypeWith(comp): + chunk = encodeFun(chunk, wrapType, **options) + + substrate += chunk + + return substrate, True, True + + +class SequenceEncoder(encoder.SequenceEncoder): + omitEmptyOptionals = True + + +TAG_MAP = encoder.TAG_MAP.copy() + +TAG_MAP.update({ + univ.Boolean.tagSet: BooleanEncoder(), + univ.Real.tagSet: RealEncoder(), + useful.GeneralizedTime.tagSet: GeneralizedTimeEncoder(), + useful.UTCTime.tagSet: UTCTimeEncoder(), + # Sequence & Set have same tags as SequenceOf & SetOf + univ.SetOf.tagSet: SetOfEncoder(), + univ.Sequence.typeId: SequenceEncoder() +}) + +TYPE_MAP = encoder.TYPE_MAP.copy() + +TYPE_MAP.update({ + univ.Boolean.typeId: BooleanEncoder(), + univ.Real.typeId: RealEncoder(), + useful.GeneralizedTime.typeId: GeneralizedTimeEncoder(), + useful.UTCTime.typeId: UTCTimeEncoder(), + # Sequence & Set have same tags as SequenceOf & SetOf + univ.Set.typeId: SetEncoder(), + univ.SetOf.typeId: SetOfEncoder(), + univ.Sequence.typeId: SequenceEncoder(), + univ.SequenceOf.typeId: SequenceOfEncoder() +}) + + +class SingleItemEncoder(encoder.SingleItemEncoder): + fixedDefLengthMode = False + fixedChunkSize = 1000 + + TAG_MAP = TAG_MAP + TYPE_MAP = TYPE_MAP + + +class Encoder(encoder.Encoder): + SINGLE_ITEM_ENCODER = SingleItemEncoder + + +#: Turns ASN.1 object into CER octet stream. +#: +#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: walks all its components recursively and produces a CER octet stream. +#: +#: Parameters +#: ---------- +#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: A Python or pyasn1 object to encode. If Python object is given, `asnSpec` +#: parameter is required to guide the encoding process. +#: +#: Keyword Args +#: ------------ +#: asn1Spec: +#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: +#: Returns +#: ------- +#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) +#: Given ASN.1 object encoded into BER octet-stream +#: +#: Raises +#: ------ +#: ~pyasn1.error.PyAsn1Error +#: On encoding errors +#: +#: Examples +#: -------- +#: Encode Python value into CER with ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> encode([1, 2, 3], asn1Spec=seq) +#: b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00' +#: +#: Encode ASN.1 value object into CER +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> seq.extend([1, 2, 3]) +#: >>> encode(seq) +#: b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00' +#: +encode = Encoder() + +# EncoderFactory queries class instance and builds a map of tags -> encoders diff --git a/lib/sambatools/pyasn1/codec/der/__init__.py b/lib/pyasn1/codec/der/__init__.py similarity index 100% rename from lib/sambatools/pyasn1/codec/der/__init__.py rename to lib/pyasn1/codec/der/__init__.py diff --git a/lib/pyasn1/codec/der/decoder.py b/lib/pyasn1/codec/der/decoder.py new file mode 100644 index 00000000..06f90957 --- /dev/null +++ b/lib/pyasn1/codec/der/decoder.py @@ -0,0 +1,112 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1.codec.cer import decoder +from pyasn1.type import univ + +__all__ = ['decode', 'StreamingDecoder'] + + +class BitStringPayloadDecoder(decoder.BitStringPayloadDecoder): + supportConstructedForm = False + + +class OctetStringPayloadDecoder(decoder.OctetStringPayloadDecoder): + supportConstructedForm = False + + +# TODO: prohibit non-canonical encoding +RealPayloadDecoder = decoder.RealPayloadDecoder + +TAG_MAP = decoder.TAG_MAP.copy() +TAG_MAP.update( + {univ.BitString.tagSet: BitStringPayloadDecoder(), + univ.OctetString.tagSet: OctetStringPayloadDecoder(), + univ.Real.tagSet: RealPayloadDecoder()} +) + +TYPE_MAP = decoder.TYPE_MAP.copy() + +# Put in non-ambiguous types for faster codec lookup +for typeDecoder in TAG_MAP.values(): + if typeDecoder.protoComponent is not None: + typeId = typeDecoder.protoComponent.__class__.typeId + if typeId is not None and typeId not in TYPE_MAP: + TYPE_MAP[typeId] = typeDecoder + + +class SingleItemDecoder(decoder.SingleItemDecoder): + __doc__ = decoder.SingleItemDecoder.__doc__ + + TAG_MAP = TAG_MAP + TYPE_MAP = TYPE_MAP + + supportIndefLength = False + + +class StreamingDecoder(decoder.StreamingDecoder): + __doc__ = decoder.StreamingDecoder.__doc__ + + SINGLE_ITEM_DECODER = SingleItemDecoder + + +class Decoder(decoder.Decoder): + __doc__ = decoder.Decoder.__doc__ + + STREAMING_DECODER = StreamingDecoder + + +#: Turns DER octet stream into an ASN.1 object. +#: +#: Takes DER octet-stream and decode it into an ASN.1 object +#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which +#: may be a scalar or an arbitrary nested structure. +#: +#: Parameters +#: ---------- +#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) +#: DER octet-stream +#: +#: Keyword Args +#: ------------ +#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure +#: being decoded, *asn1Spec* may or may not be required. Most common reason for +#: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode. +#: +#: Returns +#: ------- +#: : :py:class:`tuple` +#: A tuple of pyasn1 object recovered from DER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: and the unprocessed trailing portion of the *substrate* (may be empty) +#: +#: Raises +#: ------ +#: ~pyasn1.error.PyAsn1Error, ~pyasn1.error.SubstrateUnderrunError +#: On decoding errors +#: +#: Examples +#: -------- +#: Decode DER serialisation without ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03') +#: >>> str(s) +#: SequenceOf: +#: 1 2 3 +#: +#: Decode DER serialisation with ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03', asn1Spec=seq) +#: >>> str(s) +#: SequenceOf: +#: 1 2 3 +#: +decode = Decoder() diff --git a/lib/pyasn1/codec/der/encoder.py b/lib/pyasn1/codec/der/encoder.py new file mode 100644 index 00000000..510c5dd8 --- /dev/null +++ b/lib/pyasn1/codec/der/encoder.py @@ -0,0 +1,118 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1 import error +from pyasn1.codec.cer import encoder +from pyasn1.type import univ + +__all__ = ['Encoder', 'encode'] + + +class SetEncoder(encoder.SetEncoder): + @staticmethod + def _componentSortKey(componentAndType): + """Sort SET components by tag + + Sort depending on the actual Choice value (dynamic sort) + """ + component, asn1Spec = componentAndType + + if asn1Spec is None: + compType = component + else: + compType = asn1Spec + + if compType.typeId == univ.Choice.typeId and not compType.tagSet: + if asn1Spec is None: + return component.getComponent().tagSet + else: + # TODO: move out of sorting key function + names = [namedType.name for namedType in asn1Spec.componentType.namedTypes + if namedType.name in component] + if len(names) != 1: + raise error.PyAsn1Error( + '%s components for Choice at %r' % (len(names) and 'Multiple ' or 'None ', component)) + + # TODO: support nested CHOICE ordering + return asn1Spec[names[0]].tagSet + + else: + return compType.tagSet + + +TAG_MAP = encoder.TAG_MAP.copy() + +TAG_MAP.update({ + # Set & SetOf have same tags + univ.Set.tagSet: SetEncoder() +}) + +TYPE_MAP = encoder.TYPE_MAP.copy() + +TYPE_MAP.update({ + # Set & SetOf have same tags + univ.Set.typeId: SetEncoder() +}) + + +class SingleItemEncoder(encoder.SingleItemEncoder): + fixedDefLengthMode = True + fixedChunkSize = 0 + + TAG_MAP = TAG_MAP + TYPE_MAP = TYPE_MAP + + +class Encoder(encoder.Encoder): + SINGLE_ITEM_ENCODER = SingleItemEncoder + + +#: Turns ASN.1 object into DER octet stream. +#: +#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: walks all its components recursively and produces a DER octet stream. +#: +#: Parameters +#: ---------- +#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: A Python or pyasn1 object to encode. If Python object is given, `asnSpec` +#: parameter is required to guide the encoding process. +#: +#: Keyword Args +#: ------------ +#: asn1Spec: +#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: +#: Returns +#: ------- +#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) +#: Given ASN.1 object encoded into BER octet-stream +#: +#: Raises +#: ------ +#: ~pyasn1.error.PyAsn1Error +#: On encoding errors +#: +#: Examples +#: -------- +#: Encode Python value into DER with ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> encode([1, 2, 3], asn1Spec=seq) +#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03' +#: +#: Encode ASN.1 value object into DER +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> seq.extend([1, 2, 3]) +#: >>> encode(seq) +#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03' +#: +encode = Encoder() diff --git a/lib/sambatools/pyasn1/compat/__init__.py b/lib/pyasn1/codec/native/__init__.py similarity index 100% rename from lib/sambatools/pyasn1/compat/__init__.py rename to lib/pyasn1/codec/native/__init__.py diff --git a/lib/pyasn1/codec/native/decoder.py b/lib/pyasn1/codec/native/decoder.py new file mode 100644 index 00000000..4dca0d04 --- /dev/null +++ b/lib/pyasn1/codec/native/decoder.py @@ -0,0 +1,233 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1 import debug +from pyasn1 import error +from pyasn1.type import base +from pyasn1.type import char +from pyasn1.type import tag +from pyasn1.type import univ +from pyasn1.type import useful + +__all__ = ['decode'] + +LOG = debug.registerLoggee(__name__, flags=debug.DEBUG_DECODER) + + +class AbstractScalarPayloadDecoder(object): + def __call__(self, pyObject, asn1Spec, decodeFun=None, **options): + return asn1Spec.clone(pyObject) + + +class BitStringPayloadDecoder(AbstractScalarPayloadDecoder): + def __call__(self, pyObject, asn1Spec, decodeFun=None, **options): + return asn1Spec.clone(univ.BitString.fromBinaryString(pyObject)) + + +class SequenceOrSetPayloadDecoder(object): + def __call__(self, pyObject, asn1Spec, decodeFun=None, **options): + asn1Value = asn1Spec.clone() + + componentsTypes = asn1Spec.componentType + + for field in asn1Value: + if field in pyObject: + asn1Value[field] = decodeFun(pyObject[field], componentsTypes[field].asn1Object, **options) + + return asn1Value + + +class SequenceOfOrSetOfPayloadDecoder(object): + def __call__(self, pyObject, asn1Spec, decodeFun=None, **options): + asn1Value = asn1Spec.clone() + + for pyValue in pyObject: + asn1Value.append(decodeFun(pyValue, asn1Spec.componentType), **options) + + return asn1Value + + +class ChoicePayloadDecoder(object): + def __call__(self, pyObject, asn1Spec, decodeFun=None, **options): + asn1Value = asn1Spec.clone() + + componentsTypes = asn1Spec.componentType + + for field in pyObject: + if field in componentsTypes: + asn1Value[field] = decodeFun(pyObject[field], componentsTypes[field].asn1Object, **options) + break + + return asn1Value + + +TAG_MAP = { + univ.Integer.tagSet: AbstractScalarPayloadDecoder(), + univ.Boolean.tagSet: AbstractScalarPayloadDecoder(), + univ.BitString.tagSet: BitStringPayloadDecoder(), + univ.OctetString.tagSet: AbstractScalarPayloadDecoder(), + univ.Null.tagSet: AbstractScalarPayloadDecoder(), + univ.ObjectIdentifier.tagSet: AbstractScalarPayloadDecoder(), + univ.Enumerated.tagSet: AbstractScalarPayloadDecoder(), + univ.Real.tagSet: AbstractScalarPayloadDecoder(), + univ.Sequence.tagSet: SequenceOrSetPayloadDecoder(), # conflicts with SequenceOf + univ.Set.tagSet: SequenceOrSetPayloadDecoder(), # conflicts with SetOf + univ.Choice.tagSet: ChoicePayloadDecoder(), # conflicts with Any + # character string types + char.UTF8String.tagSet: AbstractScalarPayloadDecoder(), + char.NumericString.tagSet: AbstractScalarPayloadDecoder(), + char.PrintableString.tagSet: AbstractScalarPayloadDecoder(), + char.TeletexString.tagSet: AbstractScalarPayloadDecoder(), + char.VideotexString.tagSet: AbstractScalarPayloadDecoder(), + char.IA5String.tagSet: AbstractScalarPayloadDecoder(), + char.GraphicString.tagSet: AbstractScalarPayloadDecoder(), + char.VisibleString.tagSet: AbstractScalarPayloadDecoder(), + char.GeneralString.tagSet: AbstractScalarPayloadDecoder(), + char.UniversalString.tagSet: AbstractScalarPayloadDecoder(), + char.BMPString.tagSet: AbstractScalarPayloadDecoder(), + # useful types + useful.ObjectDescriptor.tagSet: AbstractScalarPayloadDecoder(), + useful.GeneralizedTime.tagSet: AbstractScalarPayloadDecoder(), + useful.UTCTime.tagSet: AbstractScalarPayloadDecoder() +} + +# Put in ambiguous & non-ambiguous types for faster codec lookup +TYPE_MAP = { + univ.Integer.typeId: AbstractScalarPayloadDecoder(), + univ.Boolean.typeId: AbstractScalarPayloadDecoder(), + univ.BitString.typeId: BitStringPayloadDecoder(), + univ.OctetString.typeId: AbstractScalarPayloadDecoder(), + univ.Null.typeId: AbstractScalarPayloadDecoder(), + univ.ObjectIdentifier.typeId: AbstractScalarPayloadDecoder(), + univ.Enumerated.typeId: AbstractScalarPayloadDecoder(), + univ.Real.typeId: AbstractScalarPayloadDecoder(), + # ambiguous base types + univ.Set.typeId: SequenceOrSetPayloadDecoder(), + univ.SetOf.typeId: SequenceOfOrSetOfPayloadDecoder(), + univ.Sequence.typeId: SequenceOrSetPayloadDecoder(), + univ.SequenceOf.typeId: SequenceOfOrSetOfPayloadDecoder(), + univ.Choice.typeId: ChoicePayloadDecoder(), + univ.Any.typeId: AbstractScalarPayloadDecoder(), + # character string types + char.UTF8String.typeId: AbstractScalarPayloadDecoder(), + char.NumericString.typeId: AbstractScalarPayloadDecoder(), + char.PrintableString.typeId: AbstractScalarPayloadDecoder(), + char.TeletexString.typeId: AbstractScalarPayloadDecoder(), + char.VideotexString.typeId: AbstractScalarPayloadDecoder(), + char.IA5String.typeId: AbstractScalarPayloadDecoder(), + char.GraphicString.typeId: AbstractScalarPayloadDecoder(), + char.VisibleString.typeId: AbstractScalarPayloadDecoder(), + char.GeneralString.typeId: AbstractScalarPayloadDecoder(), + char.UniversalString.typeId: AbstractScalarPayloadDecoder(), + char.BMPString.typeId: AbstractScalarPayloadDecoder(), + # useful types + useful.ObjectDescriptor.typeId: AbstractScalarPayloadDecoder(), + useful.GeneralizedTime.typeId: AbstractScalarPayloadDecoder(), + useful.UTCTime.typeId: AbstractScalarPayloadDecoder() +} + + +class SingleItemDecoder(object): + + TAG_MAP = TAG_MAP + TYPE_MAP = TYPE_MAP + + def __init__(self, **options): + self._tagMap = options.get('tagMap', self.TAG_MAP) + self._typeMap = options.get('typeMap', self.TYPE_MAP) + + def __call__(self, pyObject, asn1Spec, **options): + + if LOG: + debug.scope.push(type(pyObject).__name__) + LOG('decoder called at scope %s, working with ' + 'type %s' % (debug.scope, type(pyObject).__name__)) + + if asn1Spec is None or not isinstance(asn1Spec, base.Asn1Item): + raise error.PyAsn1Error( + 'asn1Spec is not valid (should be an instance of an ASN.1 ' + 'Item, not %s)' % asn1Spec.__class__.__name__) + + try: + valueDecoder = self._typeMap[asn1Spec.typeId] + + except KeyError: + # use base type for codec lookup to recover untagged types + baseTagSet = tag.TagSet(asn1Spec.tagSet.baseTag, asn1Spec.tagSet.baseTag) + + try: + valueDecoder = self._tagMap[baseTagSet] + + except KeyError: + raise error.PyAsn1Error('Unknown ASN.1 tag %s' % asn1Spec.tagSet) + + if LOG: + LOG('calling decoder %s on Python type %s ' + '<%s>' % (type(valueDecoder).__name__, + type(pyObject).__name__, repr(pyObject))) + + value = valueDecoder(pyObject, asn1Spec, self, **options) + + if LOG: + LOG('decoder %s produced ASN.1 type %s ' + '<%s>' % (type(valueDecoder).__name__, + type(value).__name__, repr(value))) + debug.scope.pop() + + return value + + +class Decoder(object): + SINGLE_ITEM_DECODER = SingleItemDecoder + + def __init__(self, **options): + self._singleItemDecoder = self.SINGLE_ITEM_DECODER(**options) + + def __call__(self, pyObject, asn1Spec=None, **kwargs): + return self._singleItemDecoder(pyObject, asn1Spec=asn1Spec, **kwargs) + + +#: Turns Python objects of built-in types into ASN.1 objects. +#: +#: Takes Python objects of built-in types and turns them into a tree of +#: ASN.1 objects (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which +#: may be a scalar or an arbitrary nested structure. +#: +#: Parameters +#: ---------- +#: pyObject: :py:class:`object` +#: A scalar or nested Python objects +#: +#: Keyword Args +#: ------------ +#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: A pyasn1 type object to act as a template guiding the decoder. It is required +#: for successful interpretation of Python objects mapping into their ASN.1 +#: representations. +#: +#: Returns +#: ------- +#: : :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: A scalar or constructed pyasn1 object +#: +#: Raises +#: ------ +#: ~pyasn1.error.PyAsn1Error +#: On decoding errors +#: +#: Examples +#: -------- +#: Decode native Python object into ASN.1 objects with ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> s, _ = decode([1, 2, 3], asn1Spec=seq) +#: >>> str(s) +#: SequenceOf: +#: 1 2 3 +#: +decode = Decoder() diff --git a/lib/pyasn1/codec/native/encoder.py b/lib/pyasn1/codec/native/encoder.py new file mode 100644 index 00000000..6fbedb6d --- /dev/null +++ b/lib/pyasn1/codec/native/encoder.py @@ -0,0 +1,269 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from collections import OrderedDict + +from pyasn1 import debug +from pyasn1 import error +from pyasn1.type import base +from pyasn1.type import char +from pyasn1.type import tag +from pyasn1.type import univ +from pyasn1.type import useful + +__all__ = ['encode'] + +LOG = debug.registerLoggee(__name__, flags=debug.DEBUG_ENCODER) + + +class AbstractItemEncoder(object): + def encode(self, value, encodeFun, **options): + raise error.PyAsn1Error('Not implemented') + + +class BooleanEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return bool(value) + + +class IntegerEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return int(value) + + +class BitStringEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return str(value) + + +class OctetStringEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return value.asOctets() + + +class TextStringEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return str(value) + + +class NullEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return None + + +class ObjectIdentifierEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return str(value) + + +class RealEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return float(value) + + +class SetEncoder(AbstractItemEncoder): + protoDict = dict + + def encode(self, value, encodeFun, **options): + inconsistency = value.isInconsistent + if inconsistency: + raise inconsistency + + namedTypes = value.componentType + substrate = self.protoDict() + + for idx, (key, subValue) in enumerate(value.items()): + if namedTypes and namedTypes[idx].isOptional and not value[idx].isValue: + continue + substrate[key] = encodeFun(subValue, **options) + return substrate + + +class SequenceEncoder(SetEncoder): + protoDict = OrderedDict + + +class SequenceOfEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + inconsistency = value.isInconsistent + if inconsistency: + raise inconsistency + return [encodeFun(x, **options) for x in value] + + +class ChoiceEncoder(SequenceEncoder): + pass + + +class AnyEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return value.asOctets() + + +TAG_MAP = { + univ.Boolean.tagSet: BooleanEncoder(), + univ.Integer.tagSet: IntegerEncoder(), + univ.BitString.tagSet: BitStringEncoder(), + univ.OctetString.tagSet: OctetStringEncoder(), + univ.Null.tagSet: NullEncoder(), + univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(), + univ.Enumerated.tagSet: IntegerEncoder(), + univ.Real.tagSet: RealEncoder(), + # Sequence & Set have same tags as SequenceOf & SetOf + univ.SequenceOf.tagSet: SequenceOfEncoder(), + univ.SetOf.tagSet: SequenceOfEncoder(), + univ.Choice.tagSet: ChoiceEncoder(), + # character string types + char.UTF8String.tagSet: TextStringEncoder(), + char.NumericString.tagSet: TextStringEncoder(), + char.PrintableString.tagSet: TextStringEncoder(), + char.TeletexString.tagSet: TextStringEncoder(), + char.VideotexString.tagSet: TextStringEncoder(), + char.IA5String.tagSet: TextStringEncoder(), + char.GraphicString.tagSet: TextStringEncoder(), + char.VisibleString.tagSet: TextStringEncoder(), + char.GeneralString.tagSet: TextStringEncoder(), + char.UniversalString.tagSet: TextStringEncoder(), + char.BMPString.tagSet: TextStringEncoder(), + # useful types + useful.ObjectDescriptor.tagSet: OctetStringEncoder(), + useful.GeneralizedTime.tagSet: OctetStringEncoder(), + useful.UTCTime.tagSet: OctetStringEncoder() +} + + +# Put in ambiguous & non-ambiguous types for faster codec lookup +TYPE_MAP = { + univ.Boolean.typeId: BooleanEncoder(), + univ.Integer.typeId: IntegerEncoder(), + univ.BitString.typeId: BitStringEncoder(), + univ.OctetString.typeId: OctetStringEncoder(), + univ.Null.typeId: NullEncoder(), + univ.ObjectIdentifier.typeId: ObjectIdentifierEncoder(), + univ.Enumerated.typeId: IntegerEncoder(), + univ.Real.typeId: RealEncoder(), + # Sequence & Set have same tags as SequenceOf & SetOf + univ.Set.typeId: SetEncoder(), + univ.SetOf.typeId: SequenceOfEncoder(), + univ.Sequence.typeId: SequenceEncoder(), + univ.SequenceOf.typeId: SequenceOfEncoder(), + univ.Choice.typeId: ChoiceEncoder(), + univ.Any.typeId: AnyEncoder(), + # character string types + char.UTF8String.typeId: OctetStringEncoder(), + char.NumericString.typeId: OctetStringEncoder(), + char.PrintableString.typeId: OctetStringEncoder(), + char.TeletexString.typeId: OctetStringEncoder(), + char.VideotexString.typeId: OctetStringEncoder(), + char.IA5String.typeId: OctetStringEncoder(), + char.GraphicString.typeId: OctetStringEncoder(), + char.VisibleString.typeId: OctetStringEncoder(), + char.GeneralString.typeId: OctetStringEncoder(), + char.UniversalString.typeId: OctetStringEncoder(), + char.BMPString.typeId: OctetStringEncoder(), + # useful types + useful.ObjectDescriptor.typeId: OctetStringEncoder(), + useful.GeneralizedTime.typeId: OctetStringEncoder(), + useful.UTCTime.typeId: OctetStringEncoder() +} + + +class SingleItemEncoder(object): + + TAG_MAP = TAG_MAP + TYPE_MAP = TYPE_MAP + + def __init__(self, **options): + self._tagMap = options.get('tagMap', self.TAG_MAP) + self._typeMap = options.get('typeMap', self.TYPE_MAP) + + def __call__(self, value, **options): + if not isinstance(value, base.Asn1Item): + raise error.PyAsn1Error( + 'value is not valid (should be an instance of an ASN.1 Item)') + + if LOG: + debug.scope.push(type(value).__name__) + LOG('encoder called for type %s ' + '<%s>' % (type(value).__name__, value.prettyPrint())) + + tagSet = value.tagSet + + try: + concreteEncoder = self._typeMap[value.typeId] + + except KeyError: + # use base type for codec lookup to recover untagged types + baseTagSet = tag.TagSet( + value.tagSet.baseTag, value.tagSet.baseTag) + + try: + concreteEncoder = self._tagMap[baseTagSet] + + except KeyError: + raise error.PyAsn1Error('No encoder for %s' % (value,)) + + if LOG: + LOG('using value codec %s chosen by ' + '%s' % (concreteEncoder.__class__.__name__, tagSet)) + + pyObject = concreteEncoder.encode(value, self, **options) + + if LOG: + LOG('encoder %s produced: ' + '%s' % (type(concreteEncoder).__name__, repr(pyObject))) + debug.scope.pop() + + return pyObject + + +class Encoder(object): + SINGLE_ITEM_ENCODER = SingleItemEncoder + + def __init__(self, **options): + self._singleItemEncoder = self.SINGLE_ITEM_ENCODER(**options) + + def __call__(self, pyObject, asn1Spec=None, **options): + return self._singleItemEncoder( + pyObject, asn1Spec=asn1Spec, **options) + + +#: Turns ASN.1 object into a Python built-in type object(s). +#: +#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: walks all its components recursively and produces a Python built-in type or a tree +#: of those. +#: +#: One exception is that instead of :py:class:`dict`, the :py:class:`OrderedDict` +#: is used to preserve ordering of the components in ASN.1 SEQUENCE. +#: +#: Parameters +#: ---------- +# asn1Value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: pyasn1 object to encode (or a tree of them) +#: +#: Returns +#: ------- +#: : :py:class:`object` +#: Python built-in type instance (or a tree of them) +#: +#: Raises +#: ------ +#: ~pyasn1.error.PyAsn1Error +#: On encoding errors +#: +#: Examples +#: -------- +#: Encode ASN.1 value object into native Python types +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> seq.extend([1, 2, 3]) +#: >>> encode(seq) +#: [1, 2, 3] +#: +encode = SingleItemEncoder() diff --git a/lib/pyasn1/codec/streaming.py b/lib/pyasn1/codec/streaming.py new file mode 100644 index 00000000..6d0146b9 --- /dev/null +++ b/lib/pyasn1/codec/streaming.py @@ -0,0 +1,243 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import io +import os +import sys + +from pyasn1 import error +from pyasn1.type import univ + +_PY2 = sys.version_info < (3,) + + +class CachingStreamWrapper(io.IOBase): + """Wrapper around non-seekable streams. + + Note that the implementation is tied to the decoder, + not checking for dangerous arguments for the sake + of performance. + + The read bytes are kept in an internal cache until + setting _markedPosition which may reset the cache. + """ + def __init__(self, raw): + self._raw = raw + self._cache = io.BytesIO() + self._markedPosition = 0 + + def peek(self, n): + result = self.read(n) + self._cache.seek(-len(result), os.SEEK_CUR) + return result + + def seekable(self): + return True + + def seek(self, n=-1, whence=os.SEEK_SET): + # Note that this not safe for seeking forward. + return self._cache.seek(n, whence) + + def read(self, n=-1): + read_from_cache = self._cache.read(n) + if n != -1: + n -= len(read_from_cache) + if not n: # 0 bytes left to read + return read_from_cache + + read_from_raw = self._raw.read(n) + + self._cache.write(read_from_raw) + + return read_from_cache + read_from_raw + + @property + def markedPosition(self): + """Position where the currently processed element starts. + + This is used for back-tracking in SingleItemDecoder.__call__ + and (indefLen)ValueDecoder and should not be used for other purposes. + The client is not supposed to ever seek before this position. + """ + return self._markedPosition + + @markedPosition.setter + def markedPosition(self, value): + # By setting the value, we ensure we won't seek back before it. + # `value` should be the same as the current position + # We don't check for this for performance reasons. + self._markedPosition = value + + # Whenever we set _marked_position, we know for sure + # that we will not return back, and thus it is + # safe to drop all cached data. + if self._cache.tell() > io.DEFAULT_BUFFER_SIZE: + self._cache = io.BytesIO(self._cache.read()) + self._markedPosition = 0 + + def tell(self): + return self._cache.tell() + + +def asSeekableStream(substrate): + """Convert object to seekable byte-stream. + + Parameters + ---------- + substrate: :py:class:`bytes` or :py:class:`io.IOBase` or :py:class:`univ.OctetString` + + Returns + ------- + : :py:class:`io.IOBase` + + Raises + ------ + : :py:class:`~pyasn1.error.PyAsn1Error` + If the supplied substrate cannot be converted to a seekable stream. + """ + if isinstance(substrate, io.BytesIO): + return substrate + + elif isinstance(substrate, bytes): + return io.BytesIO(substrate) + + elif isinstance(substrate, univ.OctetString): + return io.BytesIO(substrate.asOctets()) + + try: + # Special case: impossible to set attributes on `file` built-in + if _PY2 and isinstance(substrate, file): + return io.BufferedReader(substrate) + + elif substrate.seekable(): # Will fail for most invalid types + return substrate + + else: + return CachingStreamWrapper(substrate) + + except AttributeError: + raise error.UnsupportedSubstrateError( + "Cannot convert " + substrate.__class__.__name__ + + " to a seekable bit stream.") + + +def isEndOfStream(substrate): + """Check whether we have reached the end of a stream. + + Although it is more effective to read and catch exceptions, this + function + + Parameters + ---------- + substrate: :py:class:`IOBase` + Stream to check + + Returns + ------- + : :py:class:`bool` + """ + if isinstance(substrate, io.BytesIO): + cp = substrate.tell() + substrate.seek(0, os.SEEK_END) + result = substrate.tell() == cp + substrate.seek(cp, os.SEEK_SET) + yield result + + else: + received = substrate.read(1) + if received is None: + yield + + if received: + substrate.seek(-1, os.SEEK_CUR) + + yield not received + + +def peekIntoStream(substrate, size=-1): + """Peek into stream. + + Parameters + ---------- + substrate: :py:class:`IOBase` + Stream to read from. + + size: :py:class:`int` + How many bytes to peek (-1 = all available) + + Returns + ------- + : :py:class:`bytes` or :py:class:`str` + The return type depends on Python major version + """ + if hasattr(substrate, "peek"): + received = substrate.peek(size) + if received is None: + yield + + while len(received) < size: + yield + + yield received + + else: + current_position = substrate.tell() + try: + for chunk in readFromStream(substrate, size): + yield chunk + + finally: + substrate.seek(current_position) + + +def readFromStream(substrate, size=-1, context=None): + """Read from the stream. + + Parameters + ---------- + substrate: :py:class:`IOBase` + Stream to read from. + + Keyword parameters + ------------------ + size: :py:class:`int` + How many bytes to read (-1 = all available) + + context: :py:class:`dict` + Opaque caller context will be attached to exception objects created + by this function. + + Yields + ------ + : :py:class:`bytes` or :py:class:`str` or :py:class:`SubstrateUnderrunError` + Read data or :py:class:`~pyasn1.error.SubstrateUnderrunError` + object if no `size` bytes is readily available in the stream. The + data type depends on Python major version + + Raises + ------ + : :py:class:`~pyasn1.error.EndOfStreamError` + Input stream is exhausted + """ + while True: + # this will block unless stream is non-blocking + received = substrate.read(size) + if received is None: # non-blocking stream can do this + yield error.SubstrateUnderrunError(context=context) + + elif not received and size != 0: # end-of-stream + raise error.EndOfStreamError(context=context) + + elif len(received) < size: + substrate.seek(-len(received), os.SEEK_CUR) + + # behave like a non-blocking stream + yield error.SubstrateUnderrunError(context=context) + + else: + break + + yield received diff --git a/lib/sambatools/pyasn1/type/__init__.py b/lib/pyasn1/compat/__init__.py similarity index 100% rename from lib/sambatools/pyasn1/type/__init__.py rename to lib/pyasn1/compat/__init__.py diff --git a/lib/pyasn1/compat/integer.py b/lib/pyasn1/compat/integer.py new file mode 100644 index 00000000..71a504da --- /dev/null +++ b/lib/pyasn1/compat/integer.py @@ -0,0 +1,103 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import sys +import platform + +from pyasn1.compat.octets import oct2int, null, ensureString + + +implementation = platform.python_implementation() + +if sys.version_info[0] < 3 or implementation != 'CPython': + from binascii import a2b_hex, b2a_hex + + def from_bytes(octets, signed=False): + if not octets: + return 0 + + value = long(b2a_hex(ensureString(octets)), 16) + + if signed and oct2int(octets[0]) & 0x80: + return value - (1 << len(octets) * 8) + + return value + + def to_bytes(value, signed=False, length=0): + if value < 0: + if signed: + bits = bitLength(value) + + # two's complement form + maxValue = 1 << bits + valueToEncode = (value + maxValue) % maxValue + + else: + raise OverflowError('can\'t convert negative int to unsigned') + elif value == 0 and length == 0: + return null + else: + bits = 0 + valueToEncode = value + + hexValue = hex(valueToEncode)[2:] + if hexValue.endswith('L'): + hexValue = hexValue[:-1] + + if len(hexValue) & 1: + hexValue = '0' + hexValue + + # padding may be needed for two's complement encoding + if value != valueToEncode or length: + hexLength = len(hexValue) * 4 + + padLength = max(length, bits) + + if padLength > hexLength: + hexValue = '00' * ((padLength - hexLength - 1) // 8 + 1) + hexValue + elif length and hexLength - length > 7: + raise OverflowError('int too big to convert') + + firstOctet = int(hexValue[:2], 16) + + if signed: + if firstOctet & 0x80: + if value >= 0: + hexValue = '00' + hexValue + elif value < 0: + hexValue = 'ff' + hexValue + + octets_value = a2b_hex(hexValue) + + return octets_value + + def bitLength(number): + # bits in unsigned number + hexValue = hex(abs(number)) + bits = len(hexValue) - 2 + if hexValue.endswith('L'): + bits -= 1 + if bits & 1: + bits += 1 + bits *= 4 + # TODO: strip lhs zeros + return bits + +else: + + def from_bytes(octets, signed=False): + return int.from_bytes(bytes(octets), 'big', signed=signed) + + def to_bytes(value, signed=False, length=0): + length = max(value.bit_length(), length) + + if signed and length % 8 == 0: + length += 1 + + return value.to_bytes(length // 8 + (length % 8 and 1 or 0), 'big', signed=signed) + + def bitLength(number): + return int(number).bit_length() diff --git a/lib/pyasn1/compat/octets.py b/lib/pyasn1/compat/octets.py new file mode 100644 index 00000000..4fcb06dc --- /dev/null +++ b/lib/pyasn1/compat/octets.py @@ -0,0 +1,46 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from sys import version_info + +if version_info[0] <= 2: + int2oct = chr + # noinspection PyPep8 + ints2octs = lambda s: ''.join([int2oct(x) for x in s]) + null = '' + oct2int = ord + # TODO: refactor to return a sequence of ints + # noinspection PyPep8 + octs2ints = lambda s: [oct2int(x) for x in s] + # noinspection PyPep8 + str2octs = lambda x: x + # noinspection PyPep8 + octs2str = lambda x: x + # noinspection PyPep8 + isOctetsType = lambda s: isinstance(s, str) + # noinspection PyPep8 + isStringType = lambda s: isinstance(s, (str, unicode)) + # noinspection PyPep8 + ensureString = str +else: + ints2octs = bytes + # noinspection PyPep8 + int2oct = lambda x: ints2octs((x,)) + null = ints2octs() + # noinspection PyPep8 + oct2int = lambda x: x + # noinspection PyPep8 + octs2ints = lambda x: x + # noinspection PyPep8 + str2octs = lambda x: x.encode('iso-8859-1') + # noinspection PyPep8 + octs2str = lambda x: x.decode('iso-8859-1') + # noinspection PyPep8 + isOctetsType = lambda s: isinstance(s, bytes) + # noinspection PyPep8 + isStringType = lambda s: isinstance(s, str) + # noinspection PyPep8 + ensureString = bytes diff --git a/lib/pyasn1/debug.py b/lib/pyasn1/debug.py new file mode 100644 index 00000000..00f7707b --- /dev/null +++ b/lib/pyasn1/debug.py @@ -0,0 +1,147 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import logging +import sys + +from pyasn1 import __version__ +from pyasn1 import error +from pyasn1.compat.octets import octs2ints + +__all__ = ['Debug', 'setLogger', 'hexdump'] + +DEBUG_NONE = 0x0000 +DEBUG_ENCODER = 0x0001 +DEBUG_DECODER = 0x0002 +DEBUG_ALL = 0xffff + +FLAG_MAP = { + 'none': DEBUG_NONE, + 'encoder': DEBUG_ENCODER, + 'decoder': DEBUG_DECODER, + 'all': DEBUG_ALL +} + +LOGGEE_MAP = {} + + +class Printer(object): + # noinspection PyShadowingNames + def __init__(self, logger=None, handler=None, formatter=None): + if logger is None: + logger = logging.getLogger('pyasn1') + + logger.setLevel(logging.DEBUG) + + if handler is None: + handler = logging.StreamHandler() + + if formatter is None: + formatter = logging.Formatter('%(asctime)s %(name)s: %(message)s') + + handler.setFormatter(formatter) + handler.setLevel(logging.DEBUG) + logger.addHandler(handler) + + self.__logger = logger + + def __call__(self, msg): + self.__logger.debug(msg) + + def __str__(self): + return '' + + +class Debug(object): + defaultPrinter = Printer() + + def __init__(self, *flags, **options): + self._flags = DEBUG_NONE + + if 'loggerName' in options: + # route our logs to parent logger + self._printer = Printer( + logger=logging.getLogger(options['loggerName']), + handler=logging.NullHandler() + ) + + elif 'printer' in options: + self._printer = options.get('printer') + + else: + self._printer = self.defaultPrinter + + self._printer('running pyasn1 %s, debug flags %s' % (__version__, ', '.join(flags))) + + for flag in flags: + inverse = flag and flag[0] in ('!', '~') + if inverse: + flag = flag[1:] + try: + if inverse: + self._flags &= ~FLAG_MAP[flag] + else: + self._flags |= FLAG_MAP[flag] + except KeyError: + raise error.PyAsn1Error('bad debug flag %s' % flag) + + self._printer("debug category '%s' %s" % (flag, inverse and 'disabled' or 'enabled')) + + def __str__(self): + return 'logger %s, flags %x' % (self._printer, self._flags) + + def __call__(self, msg): + self._printer(msg) + + def __and__(self, flag): + return self._flags & flag + + def __rand__(self, flag): + return flag & self._flags + +_LOG = DEBUG_NONE + + +def setLogger(userLogger): + global _LOG + + if userLogger: + _LOG = userLogger + else: + _LOG = DEBUG_NONE + + # Update registered logging clients + for module, (name, flags) in LOGGEE_MAP.items(): + setattr(module, name, _LOG & flags and _LOG or DEBUG_NONE) + + +def registerLoggee(module, name='LOG', flags=DEBUG_NONE): + LOGGEE_MAP[sys.modules[module]] = name, flags + setLogger(_LOG) + return _LOG + + +def hexdump(octets): + return ' '.join( + ['%s%.2X' % (n % 16 == 0 and ('\n%.5d: ' % n) or '', x) + for n, x in zip(range(len(octets)), octs2ints(octets))] + ) + + +class Scope(object): + def __init__(self): + self._list = [] + + def __str__(self): return '.'.join(self._list) + + def push(self, token): + self._list.append(token) + + def pop(self): + return self._list.pop() + + +scope = Scope() diff --git a/lib/pyasn1/error.py b/lib/pyasn1/error.py new file mode 100644 index 00000000..63457706 --- /dev/null +++ b/lib/pyasn1/error.py @@ -0,0 +1,116 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# + + +class PyAsn1Error(Exception): + """Base pyasn1 exception + + `PyAsn1Error` is the base exception class (based on + :class:`Exception`) that represents all possible ASN.1 related + errors. + + Parameters + ---------- + args: + Opaque positional parameters + + Keyword Args + ------------ + kwargs: + Opaque keyword parameters + + """ + def __init__(self, *args, **kwargs): + self._args = args + self._kwargs = kwargs + + @property + def context(self): + """Return exception context + + When exception object is created, the caller can supply some opaque + context for the upper layers to better understand the cause of the + exception. + + Returns + ------- + : :py:class:`dict` + Dict holding context specific data + """ + return self._kwargs.get('context', {}) + + +class ValueConstraintError(PyAsn1Error): + """ASN.1 type constraints violation exception + + The `ValueConstraintError` exception indicates an ASN.1 value + constraint violation. + + It might happen on value object instantiation (for scalar types) or on + serialization (for constructed types). + """ + + +class SubstrateUnderrunError(PyAsn1Error): + """ASN.1 data structure deserialization error + + The `SubstrateUnderrunError` exception indicates insufficient serialised + data on input of a de-serialization codec. + """ + + +class EndOfStreamError(SubstrateUnderrunError): + """ASN.1 data structure deserialization error + + The `EndOfStreamError` exception indicates the condition of the input + stream has been closed. + """ + + +class UnsupportedSubstrateError(PyAsn1Error): + """Unsupported substrate type to parse as ASN.1 data.""" + + +class PyAsn1UnicodeError(PyAsn1Error, UnicodeError): + """Unicode text processing error + + The `PyAsn1UnicodeError` exception is a base class for errors relating to + unicode text de/serialization. + + Apart from inheriting from :class:`PyAsn1Error`, it also inherits from + :class:`UnicodeError` to help the caller catching unicode-related errors. + """ + def __init__(self, message, unicode_error=None): + if isinstance(unicode_error, UnicodeError): + UnicodeError.__init__(self, *unicode_error.args) + PyAsn1Error.__init__(self, message) + + +class PyAsn1UnicodeDecodeError(PyAsn1UnicodeError, UnicodeDecodeError): + """Unicode text decoding error + + The `PyAsn1UnicodeDecodeError` exception represents a failure to + deserialize unicode text. + + Apart from inheriting from :class:`PyAsn1UnicodeError`, it also inherits + from :class:`UnicodeDecodeError` to help the caller catching unicode-related + errors. + """ + + +class PyAsn1UnicodeEncodeError(PyAsn1UnicodeError, UnicodeEncodeError): + """Unicode text encoding error + + The `PyAsn1UnicodeEncodeError` exception represents a failure to + serialize unicode text. + + Apart from inheriting from :class:`PyAsn1UnicodeError`, it also inherits + from :class:`UnicodeEncodeError` to help the caller catching + unicode-related errors. + """ + + diff --git a/lib/pyasn1/type/__init__.py b/lib/pyasn1/type/__init__.py new file mode 100644 index 00000000..8c3066b2 --- /dev/null +++ b/lib/pyasn1/type/__init__.py @@ -0,0 +1 @@ +# This file is necessary to make this directory a package. diff --git a/lib/pyasn1/type/base.py b/lib/pyasn1/type/base.py new file mode 100644 index 00000000..383546e2 --- /dev/null +++ b/lib/pyasn1/type/base.py @@ -0,0 +1,706 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import sys + +from pyasn1 import error +from pyasn1.type import constraint +from pyasn1.type import tag +from pyasn1.type import tagmap + +__all__ = ['Asn1Item', 'Asn1Type', 'SimpleAsn1Type', + 'ConstructedAsn1Type'] + + +class Asn1Item(object): + @classmethod + def getTypeId(cls, increment=1): + try: + Asn1Item._typeCounter += increment + except AttributeError: + Asn1Item._typeCounter = increment + return Asn1Item._typeCounter + + +class Asn1Type(Asn1Item): + """Base class for all classes representing ASN.1 types. + + In the user code, |ASN.1| class is normally used only for telling + ASN.1 objects from others. + + Note + ---- + For as long as ASN.1 is concerned, a way to compare ASN.1 types + is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods. + """ + #: Set or return a :py:class:`~pyasn1.type.tag.TagSet` object representing + #: ASN.1 tag(s) associated with |ASN.1| type. + tagSet = tag.TagSet() + + #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + #: object imposing constraints on initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Disambiguation ASN.1 types identification + typeId = None + + def __init__(self, **kwargs): + readOnly = { + 'tagSet': self.tagSet, + 'subtypeSpec': self.subtypeSpec + } + + readOnly.update(kwargs) + + self.__dict__.update(readOnly) + + self._readOnly = readOnly + + def __setattr__(self, name, value): + if name[0] != '_' and name in self._readOnly: + raise error.PyAsn1Error('read-only instance attribute "%s"' % name) + + self.__dict__[name] = value + + def __str__(self): + return self.prettyPrint() + + @property + def readOnly(self): + return self._readOnly + + @property + def effectiveTagSet(self): + """For |ASN.1| type is equivalent to *tagSet* + """ + return self.tagSet # used by untagged types + + @property + def tagMap(self): + """Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping ASN.1 tags to ASN.1 objects within callee object. + """ + return tagmap.TagMap({self.tagSet: self}) + + def isSameTypeWith(self, other, matchTags=True, matchConstraints=True): + """Examine |ASN.1| type for equality with other ASN.1 type. + + ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints + (:py:mod:`~pyasn1.type.constraint`) are examined when carrying + out ASN.1 types comparison. + + Python class inheritance relationship is NOT considered. + + Parameters + ---------- + other: a pyasn1 type object + Class instance representing ASN.1 type. + + Returns + ------- + : :class:`bool` + :obj:`True` if *other* is |ASN.1| type, + :obj:`False` otherwise. + """ + return (self is other or + (not matchTags or self.tagSet == other.tagSet) and + (not matchConstraints or self.subtypeSpec == other.subtypeSpec)) + + def isSuperTypeOf(self, other, matchTags=True, matchConstraints=True): + """Examine |ASN.1| type for subtype relationship with other ASN.1 type. + + ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints + (:py:mod:`~pyasn1.type.constraint`) are examined when carrying + out ASN.1 types comparison. + + Python class inheritance relationship is NOT considered. + + Parameters + ---------- + other: a pyasn1 type object + Class instance representing ASN.1 type. + + Returns + ------- + : :class:`bool` + :obj:`True` if *other* is a subtype of |ASN.1| type, + :obj:`False` otherwise. + """ + return (not matchTags or + (self.tagSet.isSuperTagSetOf(other.tagSet)) and + (not matchConstraints or self.subtypeSpec.isSuperTypeOf(other.subtypeSpec))) + + @staticmethod + def isNoValue(*values): + for value in values: + if value is not noValue: + return False + return True + + def prettyPrint(self, scope=0): + raise NotImplementedError() + + # backward compatibility + + def getTagSet(self): + return self.tagSet + + def getEffectiveTagSet(self): + return self.effectiveTagSet + + def getTagMap(self): + return self.tagMap + + def getSubtypeSpec(self): + return self.subtypeSpec + + # backward compatibility + def hasValue(self): + return self.isValue + +# Backward compatibility +Asn1ItemBase = Asn1Type + + +class NoValue(object): + """Create a singleton instance of NoValue class. + + The *NoValue* sentinel object represents an instance of ASN.1 schema + object as opposed to ASN.1 value object. + + Only ASN.1 schema-related operations can be performed on ASN.1 + schema objects. + + Warning + ------- + Any operation attempted on the *noValue* object will raise the + *PyAsn1Error* exception. + """ + skipMethods = { + '__slots__', + # attributes + '__getattribute__', + '__getattr__', + '__setattr__', + '__delattr__', + # class instance + '__class__', + '__init__', + '__del__', + '__new__', + '__repr__', + '__qualname__', + '__objclass__', + 'im_class', + '__sizeof__', + # pickle protocol + '__reduce__', + '__reduce_ex__', + '__getnewargs__', + '__getinitargs__', + '__getstate__', + '__setstate__', + } + + _instance = None + + def __new__(cls): + if cls._instance is None: + def getPlug(name): + def plug(self, *args, **kw): + raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % name) + return plug + + op_names = [name + for typ in (str, int, list, dict) + for name in dir(typ) + if (name not in cls.skipMethods and + name.startswith('__') and + name.endswith('__') and + callable(getattr(typ, name)))] + + for name in set(op_names): + setattr(cls, name, getPlug(name)) + + cls._instance = object.__new__(cls) + + return cls._instance + + def __getattr__(self, attr): + if attr in self.skipMethods: + raise AttributeError('Attribute %s not present' % attr) + + raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % attr) + + def __repr__(self): + return '<%s object>' % self.__class__.__name__ + + +noValue = NoValue() + + +class SimpleAsn1Type(Asn1Type): + """Base class for all simple classes representing ASN.1 types. + + ASN.1 distinguishes types by their ability to hold other objects. + Scalar types are known as *simple* in ASN.1. + + In the user code, |ASN.1| class is normally used only for telling + ASN.1 objects from others. + + Note + ---- + For as long as ASN.1 is concerned, a way to compare ASN.1 types + is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods. + """ + #: Default payload value + defaultValue = noValue + + def __init__(self, value=noValue, **kwargs): + Asn1Type.__init__(self, **kwargs) + if value is noValue: + value = self.defaultValue + else: + value = self.prettyIn(value) + try: + self.subtypeSpec(value) + + except error.PyAsn1Error: + exType, exValue, exTb = sys.exc_info() + raise exType('%s at %s' % (exValue, self.__class__.__name__)) + + self._value = value + + def __repr__(self): + representation = '%s %s object' % ( + self.__class__.__name__, self.isValue and 'value' or 'schema') + + for attr, value in self.readOnly.items(): + if value: + representation += ', %s %s' % (attr, value) + + if self.isValue: + value = self.prettyPrint() + if len(value) > 32: + value = value[:16] + '...' + value[-16:] + representation += ', payload [%s]' % value + + return '<%s>' % representation + + def __eq__(self, other): + return self is other and True or self._value == other + + def __ne__(self, other): + return self._value != other + + def __lt__(self, other): + return self._value < other + + def __le__(self, other): + return self._value <= other + + def __gt__(self, other): + return self._value > other + + def __ge__(self, other): + return self._value >= other + + if sys.version_info[0] <= 2: + def __nonzero__(self): + return self._value and True or False + else: + def __bool__(self): + return self._value and True or False + + def __hash__(self): + return hash(self._value) + + @property + def isValue(self): + """Indicate that |ASN.1| object represents ASN.1 value. + + If *isValue* is :obj:`False` then this object represents just + ASN.1 schema. + + If *isValue* is :obj:`True` then, in addition to its ASN.1 schema + features, this object can also be used like a Python built-in object + (e.g. :class:`int`, :class:`str`, :class:`dict` etc.). + + Returns + ------- + : :class:`bool` + :obj:`False` if object represents just ASN.1 schema. + :obj:`True` if object represents ASN.1 schema and can be used as a normal value. + + Note + ---- + There is an important distinction between PyASN1 schema and value objects. + The PyASN1 schema objects can only participate in ASN.1 schema-related + operations (e.g. defining or testing the structure of the data). Most + obvious uses of ASN.1 schema is to guide serialisation codecs whilst + encoding/decoding serialised ASN.1 contents. + + The PyASN1 value objects can **additionally** participate in many operations + involving regular Python objects (e.g. arithmetic, comprehension etc). + """ + return self._value is not noValue + + def clone(self, value=noValue, **kwargs): + """Create a modified version of |ASN.1| schema or value object. + + The `clone()` method accepts the same set arguments as |ASN.1| + class takes on instantiation except that all arguments + of the `clone()` method are optional. + + Whatever arguments are supplied, they are used to create a copy + of `self` taking precedence over the ones used to instantiate `self`. + + Note + ---- + Due to the immutable nature of the |ASN.1| object, if no arguments + are supplied, no new |ASN.1| object will be created and `self` will + be returned instead. + """ + if value is noValue: + if not kwargs: + return self + + value = self._value + + initializers = self.readOnly.copy() + initializers.update(kwargs) + + return self.__class__(value, **initializers) + + def subtype(self, value=noValue, **kwargs): + """Create a specialization of |ASN.1| schema or value object. + + The subtype relationship between ASN.1 types has no correlation with + subtype relationship between Python types. ASN.1 type is mainly identified + by its tag(s) (:py:class:`~pyasn1.type.tag.TagSet`) and value range + constraints (:py:class:`~pyasn1.type.constraint.ConstraintsIntersection`). + These ASN.1 type properties are implemented as |ASN.1| attributes. + + The `subtype()` method accepts the same set arguments as |ASN.1| + class takes on instantiation except that all parameters + of the `subtype()` method are optional. + + With the exception of the arguments described below, the rest of + supplied arguments they are used to create a copy of `self` taking + precedence over the ones used to instantiate `self`. + + The following arguments to `subtype()` create a ASN.1 subtype out of + |ASN.1| type: + + Other Parameters + ---------------- + implicitTag: :py:class:`~pyasn1.type.tag.Tag` + Implicitly apply given ASN.1 tag object to `self`'s + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + explicitTag: :py:class:`~pyasn1.type.tag.Tag` + Explicitly apply given ASN.1 tag object to `self`'s + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Add ASN.1 constraints object to one of the `self`'s, then + use the result as new object's ASN.1 constraints. + + Returns + ------- + : + new instance of |ASN.1| schema or value object + + Note + ---- + Due to the immutable nature of the |ASN.1| object, if no arguments + are supplied, no new |ASN.1| object will be created and `self` will + be returned instead. + """ + if value is noValue: + if not kwargs: + return self + + value = self._value + + initializers = self.readOnly.copy() + + implicitTag = kwargs.pop('implicitTag', None) + if implicitTag is not None: + initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag) + + explicitTag = kwargs.pop('explicitTag', None) + if explicitTag is not None: + initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag) + + for arg, option in kwargs.items(): + initializers[arg] += option + + return self.__class__(value, **initializers) + + def prettyIn(self, value): + return value + + def prettyOut(self, value): + return str(value) + + def prettyPrint(self, scope=0): + return self.prettyOut(self._value) + + def prettyPrintType(self, scope=0): + return '%s -> %s' % (self.tagSet, self.__class__.__name__) + +# Backward compatibility +AbstractSimpleAsn1Item = SimpleAsn1Type + +# +# Constructed types: +# * There are five of them: Sequence, SequenceOf/SetOf, Set and Choice +# * ASN1 types and values are represened by Python class instances +# * Value initialization is made for defaulted components only +# * Primary method of component addressing is by-position. Data model for base +# type is Python sequence. Additional type-specific addressing methods +# may be implemented for particular types. +# * SequenceOf and SetOf types do not implement any additional methods +# * Sequence, Set and Choice types also implement by-identifier addressing +# * Sequence, Set and Choice types also implement by-asn1-type (tag) addressing +# * Sequence and Set types may include optional and defaulted +# components +# * Constructed types hold a reference to component types used for value +# verification and ordering. +# * Component type is a scalar type for SequenceOf/SetOf types and a list +# of types for Sequence/Set/Choice. +# + + +class ConstructedAsn1Type(Asn1Type): + """Base class for all constructed classes representing ASN.1 types. + + ASN.1 distinguishes types by their ability to hold other objects. + Those "nesting" types are known as *constructed* in ASN.1. + + In the user code, |ASN.1| class is normally used only for telling + ASN.1 objects from others. + + Note + ---- + For as long as ASN.1 is concerned, a way to compare ASN.1 types + is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods. + """ + + #: If :obj:`True`, requires exact component type matching, + #: otherwise subtype relation is only enforced + strictConstraints = False + + componentType = None + + # backward compatibility, unused + sizeSpec = constraint.ConstraintsIntersection() + + def __init__(self, **kwargs): + readOnly = { + 'componentType': self.componentType, + # backward compatibility, unused + 'sizeSpec': self.sizeSpec + } + + # backward compatibility: preserve legacy sizeSpec support + kwargs = self._moveSizeSpec(**kwargs) + + readOnly.update(kwargs) + + Asn1Type.__init__(self, **readOnly) + + def _moveSizeSpec(self, **kwargs): + # backward compatibility, unused + sizeSpec = kwargs.pop('sizeSpec', self.sizeSpec) + if sizeSpec: + subtypeSpec = kwargs.pop('subtypeSpec', self.subtypeSpec) + if subtypeSpec: + subtypeSpec = sizeSpec + + else: + subtypeSpec += sizeSpec + + kwargs['subtypeSpec'] = subtypeSpec + + return kwargs + + def __repr__(self): + representation = '%s %s object' % ( + self.__class__.__name__, self.isValue and 'value' or 'schema' + ) + + for attr, value in self.readOnly.items(): + if value is not noValue: + representation += ', %s=%r' % (attr, value) + + if self.isValue and self.components: + representation += ', payload [%s]' % ', '.join( + [repr(x) for x in self.components]) + + return '<%s>' % representation + + def __eq__(self, other): + return self is other or self.components == other + + def __ne__(self, other): + return self.components != other + + def __lt__(self, other): + return self.components < other + + def __le__(self, other): + return self.components <= other + + def __gt__(self, other): + return self.components > other + + def __ge__(self, other): + return self.components >= other + + if sys.version_info[0] <= 2: + def __nonzero__(self): + return bool(self.components) + else: + def __bool__(self): + return bool(self.components) + + @property + def components(self): + raise error.PyAsn1Error('Method not implemented') + + def _cloneComponentValues(self, myClone, cloneValueFlag): + pass + + def clone(self, **kwargs): + """Create a modified version of |ASN.1| schema object. + + The `clone()` method accepts the same set arguments as |ASN.1| + class takes on instantiation except that all arguments + of the `clone()` method are optional. + + Whatever arguments are supplied, they are used to create a copy + of `self` taking precedence over the ones used to instantiate `self`. + + Possible values of `self` are never copied over thus `clone()` can + only create a new schema object. + + Returns + ------- + : + new instance of |ASN.1| type/value + + Note + ---- + Due to the mutable nature of the |ASN.1| object, even if no arguments + are supplied, a new |ASN.1| object will be created and returned. + """ + cloneValueFlag = kwargs.pop('cloneValueFlag', False) + + initializers = self.readOnly.copy() + initializers.update(kwargs) + + clone = self.__class__(**initializers) + + if cloneValueFlag: + self._cloneComponentValues(clone, cloneValueFlag) + + return clone + + def subtype(self, **kwargs): + """Create a specialization of |ASN.1| schema object. + + The `subtype()` method accepts the same set arguments as |ASN.1| + class takes on instantiation except that all parameters + of the `subtype()` method are optional. + + With the exception of the arguments described below, the rest of + supplied arguments they are used to create a copy of `self` taking + precedence over the ones used to instantiate `self`. + + The following arguments to `subtype()` create a ASN.1 subtype out of + |ASN.1| type. + + Other Parameters + ---------------- + implicitTag: :py:class:`~pyasn1.type.tag.Tag` + Implicitly apply given ASN.1 tag object to `self`'s + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + explicitTag: :py:class:`~pyasn1.type.tag.Tag` + Explicitly apply given ASN.1 tag object to `self`'s + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Add ASN.1 constraints object to one of the `self`'s, then + use the result as new object's ASN.1 constraints. + + + Returns + ------- + : + new instance of |ASN.1| type/value + + Note + ---- + Due to the mutable nature of the |ASN.1| object, even if no arguments + are supplied, a new |ASN.1| object will be created and returned. + """ + + initializers = self.readOnly.copy() + + cloneValueFlag = kwargs.pop('cloneValueFlag', False) + + implicitTag = kwargs.pop('implicitTag', None) + if implicitTag is not None: + initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag) + + explicitTag = kwargs.pop('explicitTag', None) + if explicitTag is not None: + initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag) + + for arg, option in kwargs.items(): + initializers[arg] += option + + clone = self.__class__(**initializers) + + if cloneValueFlag: + self._cloneComponentValues(clone, cloneValueFlag) + + return clone + + def getComponentByPosition(self, idx): + raise error.PyAsn1Error('Method not implemented') + + def setComponentByPosition(self, idx, value, verifyConstraints=True): + raise error.PyAsn1Error('Method not implemented') + + def setComponents(self, *args, **kwargs): + for idx, value in enumerate(args): + self[idx] = value + for k in kwargs: + self[k] = kwargs[k] + return self + + # backward compatibility + + def setDefaultComponents(self): + pass + + def getComponentType(self): + return self.componentType + + # backward compatibility, unused + def verifySizeSpec(self): + self.subtypeSpec(self) + + + # Backward compatibility +AbstractConstructedAsn1Item = ConstructedAsn1Type diff --git a/lib/pyasn1/type/char.py b/lib/pyasn1/type/char.py new file mode 100644 index 00000000..58fffb98 --- /dev/null +++ b/lib/pyasn1/type/char.py @@ -0,0 +1,335 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import sys + +from pyasn1 import error +from pyasn1.type import tag +from pyasn1.type import univ + +__all__ = ['NumericString', 'PrintableString', 'TeletexString', 'T61String', 'VideotexString', + 'IA5String', 'GraphicString', 'VisibleString', 'ISO646String', + 'GeneralString', 'UniversalString', 'BMPString', 'UTF8String'] + +NoValue = univ.NoValue +noValue = univ.noValue + + +class AbstractCharacterString(univ.OctetString): + """Creates |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, + its objects are immutable and duck-type Python 2 :class:`str` or Python 3 + :class:`bytes`. When used in octet-stream context, |ASN.1| type assumes + "|encoding|" encoding. + + Keyword Args + ------------ + value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object + :class:`unicode` object (Python 2) or :class:`str` (Python 3), + alternatively :class:`str` (Python 2) or :class:`bytes` (Python 3) + representing octet-stream of serialised unicode string + (note `encoding` parameter) or |ASN.1| class instance. + If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + encoding: :py:class:`str` + Unicode codec ID to encode/decode :class:`unicode` (Python 2) or + :class:`str` (Python 3) the payload when |ASN.1| object is used + in octet-stream context. + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + """ + + if sys.version_info[0] <= 2: + def __str__(self): + try: + # `str` is Py2 text representation + return self._value.encode(self.encoding) + + except UnicodeEncodeError: + exc = sys.exc_info()[1] + raise error.PyAsn1UnicodeEncodeError( + "Can't encode string '%s' with codec " + "%s" % (self._value, self.encoding), exc + ) + + def __unicode__(self): + return unicode(self._value) + + def prettyIn(self, value): + try: + if isinstance(value, unicode): + return value + elif isinstance(value, str): + return value.decode(self.encoding) + elif isinstance(value, (tuple, list)): + return self.prettyIn(''.join([chr(x) for x in value])) + elif isinstance(value, univ.OctetString): + return value.asOctets().decode(self.encoding) + else: + return unicode(value) + + except (UnicodeDecodeError, LookupError): + exc = sys.exc_info()[1] + raise error.PyAsn1UnicodeDecodeError( + "Can't decode string '%s' with codec " + "%s" % (value, self.encoding), exc + ) + + def asOctets(self, padding=True): + return str(self) + + def asNumbers(self, padding=True): + return tuple([ord(x) for x in str(self)]) + + else: + def __str__(self): + # `unicode` is Py3 text representation + return str(self._value) + + def __bytes__(self): + try: + return self._value.encode(self.encoding) + except UnicodeEncodeError: + exc = sys.exc_info()[1] + raise error.PyAsn1UnicodeEncodeError( + "Can't encode string '%s' with codec " + "%s" % (self._value, self.encoding), exc + ) + + def prettyIn(self, value): + try: + if isinstance(value, str): + return value + elif isinstance(value, bytes): + return value.decode(self.encoding) + elif isinstance(value, (tuple, list)): + return self.prettyIn(bytes(value)) + elif isinstance(value, univ.OctetString): + return value.asOctets().decode(self.encoding) + else: + return str(value) + + except (UnicodeDecodeError, LookupError): + exc = sys.exc_info()[1] + raise error.PyAsn1UnicodeDecodeError( + "Can't decode string '%s' with codec " + "%s" % (value, self.encoding), exc + ) + + def asOctets(self, padding=True): + return bytes(self) + + def asNumbers(self, padding=True): + return tuple(bytes(self)) + + # + # See OctetString.prettyPrint() for the explanation + # + + def prettyOut(self, value): + return value + + def prettyPrint(self, scope=0): + # first see if subclass has its own .prettyOut() + value = self.prettyOut(self._value) + + if value is not self._value: + return value + + return AbstractCharacterString.__str__(self) + + def __reversed__(self): + return reversed(self._value) + + +class NumericString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 18) + ) + encoding = 'us-ascii' + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class PrintableString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 19) + ) + encoding = 'us-ascii' + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class TeletexString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 20) + ) + encoding = 'iso-8859-1' + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class T61String(TeletexString): + __doc__ = TeletexString.__doc__ + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class VideotexString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 21) + ) + encoding = 'iso-8859-1' + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class IA5String(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 22) + ) + encoding = 'us-ascii' + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class GraphicString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 25) + ) + encoding = 'iso-8859-1' + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class VisibleString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 26) + ) + encoding = 'us-ascii' + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class ISO646String(VisibleString): + __doc__ = VisibleString.__doc__ + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + +class GeneralString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 27) + ) + encoding = 'iso-8859-1' + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class UniversalString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 28) + ) + encoding = "utf-32-be" + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class BMPString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 30) + ) + encoding = "utf-16-be" + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class UTF8String(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12) + ) + encoding = "utf-8" + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() diff --git a/lib/pyasn1/type/constraint.py b/lib/pyasn1/type/constraint.py new file mode 100644 index 00000000..fa875fa4 --- /dev/null +++ b/lib/pyasn1/type/constraint.py @@ -0,0 +1,756 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +# Original concept and code by Mike C. Fletcher. +# +import sys + +from pyasn1.type import error + +__all__ = ['SingleValueConstraint', 'ContainedSubtypeConstraint', + 'ValueRangeConstraint', 'ValueSizeConstraint', + 'PermittedAlphabetConstraint', 'InnerTypeConstraint', + 'ConstraintsExclusion', 'ConstraintsIntersection', + 'ConstraintsUnion'] + + +class AbstractConstraint(object): + + def __init__(self, *values): + self._valueMap = set() + self._setValues(values) + self.__hash = hash((self.__class__.__name__, self._values)) + + def __call__(self, value, idx=None): + if not self._values: + return + + try: + self._testValue(value, idx) + + except error.ValueConstraintError: + raise error.ValueConstraintError( + '%s failed at: %r' % (self, sys.exc_info()[1]) + ) + + def __repr__(self): + representation = '%s object' % (self.__class__.__name__) + + if self._values: + representation += ', consts %s' % ', '.join( + [repr(x) for x in self._values]) + + return '<%s>' % representation + + def __eq__(self, other): + return self is other and True or self._values == other + + def __ne__(self, other): + return self._values != other + + def __lt__(self, other): + return self._values < other + + def __le__(self, other): + return self._values <= other + + def __gt__(self, other): + return self._values > other + + def __ge__(self, other): + return self._values >= other + + if sys.version_info[0] <= 2: + def __nonzero__(self): + return self._values and True or False + else: + def __bool__(self): + return self._values and True or False + + def __hash__(self): + return self.__hash + + def _setValues(self, values): + self._values = values + + def _testValue(self, value, idx): + raise error.ValueConstraintError(value) + + # Constraints derivation logic + def getValueMap(self): + return self._valueMap + + def isSuperTypeOf(self, otherConstraint): + # TODO: fix possible comparison of set vs scalars here + return (otherConstraint is self or + not self._values or + otherConstraint == self or + self in otherConstraint.getValueMap()) + + def isSubTypeOf(self, otherConstraint): + return (otherConstraint is self or + not self or + otherConstraint == self or + otherConstraint in self._valueMap) + + +class SingleValueConstraint(AbstractConstraint): + """Create a SingleValueConstraint object. + + The SingleValueConstraint satisfies any value that + is present in the set of permitted values. + + Objects of this type are iterable (emitting constraint values) and + can act as operands for some arithmetic operations e.g. addition + and subtraction. The latter can be used for combining multiple + SingleValueConstraint objects into one. + + The SingleValueConstraint object can be applied to + any ASN.1 type. + + Parameters + ---------- + *values: :class:`int` + Full set of values permitted by this constraint object. + + Examples + -------- + .. code-block:: python + + class DivisorOfSix(Integer): + ''' + ASN.1 specification: + + Divisor-Of-6 ::= INTEGER (1 | 2 | 3 | 6) + ''' + subtypeSpec = SingleValueConstraint(1, 2, 3, 6) + + # this will succeed + divisor_of_six = DivisorOfSix(1) + + # this will raise ValueConstraintError + divisor_of_six = DivisorOfSix(7) + """ + def _setValues(self, values): + self._values = values + self._set = set(values) + + def _testValue(self, value, idx): + if value not in self._set: + raise error.ValueConstraintError(value) + + # Constrains can be merged or reduced + + def __contains__(self, item): + return item in self._set + + def __iter__(self): + return iter(self._set) + + def __sub__(self, constraint): + return self.__class__(*(self._set.difference(constraint))) + + def __add__(self, constraint): + return self.__class__(*(self._set.union(constraint))) + + def __sub__(self, constraint): + return self.__class__(*(self._set.difference(constraint))) + + +class ContainedSubtypeConstraint(AbstractConstraint): + """Create a ContainedSubtypeConstraint object. + + The ContainedSubtypeConstraint satisfies any value that + is present in the set of permitted values and also + satisfies included constraints. + + The ContainedSubtypeConstraint object can be applied to + any ASN.1 type. + + Parameters + ---------- + *values: + Full set of values and constraint objects permitted + by this constraint object. + + Examples + -------- + .. code-block:: python + + class DivisorOfEighteen(Integer): + ''' + ASN.1 specification: + + Divisors-of-18 ::= INTEGER (INCLUDES Divisors-of-6 | 9 | 18) + ''' + subtypeSpec = ContainedSubtypeConstraint( + SingleValueConstraint(1, 2, 3, 6), 9, 18 + ) + + # this will succeed + divisor_of_eighteen = DivisorOfEighteen(9) + + # this will raise ValueConstraintError + divisor_of_eighteen = DivisorOfEighteen(10) + """ + def _testValue(self, value, idx): + for constraint in self._values: + if isinstance(constraint, AbstractConstraint): + constraint(value, idx) + elif value not in self._set: + raise error.ValueConstraintError(value) + + +class ValueRangeConstraint(AbstractConstraint): + """Create a ValueRangeConstraint object. + + The ValueRangeConstraint satisfies any value that + falls in the range of permitted values. + + The ValueRangeConstraint object can only be applied + to :class:`~pyasn1.type.univ.Integer` and + :class:`~pyasn1.type.univ.Real` types. + + Parameters + ---------- + start: :class:`int` + Minimum permitted value in the range (inclusive) + + end: :class:`int` + Maximum permitted value in the range (inclusive) + + Examples + -------- + .. code-block:: python + + class TeenAgeYears(Integer): + ''' + ASN.1 specification: + + TeenAgeYears ::= INTEGER (13 .. 19) + ''' + subtypeSpec = ValueRangeConstraint(13, 19) + + # this will succeed + teen_year = TeenAgeYears(18) + + # this will raise ValueConstraintError + teen_year = TeenAgeYears(20) + """ + def _testValue(self, value, idx): + if value < self.start or value > self.stop: + raise error.ValueConstraintError(value) + + def _setValues(self, values): + if len(values) != 2: + raise error.PyAsn1Error( + '%s: bad constraint values' % (self.__class__.__name__,) + ) + self.start, self.stop = values + if self.start > self.stop: + raise error.PyAsn1Error( + '%s: screwed constraint values (start > stop): %s > %s' % ( + self.__class__.__name__, + self.start, self.stop + ) + ) + AbstractConstraint._setValues(self, values) + + +class ValueSizeConstraint(ValueRangeConstraint): + """Create a ValueSizeConstraint object. + + The ValueSizeConstraint satisfies any value for + as long as its size falls within the range of + permitted sizes. + + The ValueSizeConstraint object can be applied + to :class:`~pyasn1.type.univ.BitString`, + :class:`~pyasn1.type.univ.OctetString` (including + all :ref:`character ASN.1 types `), + :class:`~pyasn1.type.univ.SequenceOf` + and :class:`~pyasn1.type.univ.SetOf` types. + + Parameters + ---------- + minimum: :class:`int` + Minimum permitted size of the value (inclusive) + + maximum: :class:`int` + Maximum permitted size of the value (inclusive) + + Examples + -------- + .. code-block:: python + + class BaseballTeamRoster(SetOf): + ''' + ASN.1 specification: + + BaseballTeamRoster ::= SET SIZE (1..25) OF PlayerNames + ''' + componentType = PlayerNames() + subtypeSpec = ValueSizeConstraint(1, 25) + + # this will succeed + team = BaseballTeamRoster() + team.extend(['Jan', 'Matej']) + encode(team) + + # this will raise ValueConstraintError + team = BaseballTeamRoster() + team.extend(['Jan'] * 26) + encode(team) + + Note + ---- + Whenever ValueSizeConstraint is applied to mutable types + (e.g. :class:`~pyasn1.type.univ.SequenceOf`, + :class:`~pyasn1.type.univ.SetOf`), constraint + validation only happens at the serialisation phase rather + than schema instantiation phase (as it is with immutable + types). + """ + def _testValue(self, value, idx): + valueSize = len(value) + if valueSize < self.start or valueSize > self.stop: + raise error.ValueConstraintError(value) + + +class PermittedAlphabetConstraint(SingleValueConstraint): + """Create a PermittedAlphabetConstraint object. + + The PermittedAlphabetConstraint satisfies any character + string for as long as all its characters are present in + the set of permitted characters. + + Objects of this type are iterable (emitting constraint values) and + can act as operands for some arithmetic operations e.g. addition + and subtraction. + + The PermittedAlphabetConstraint object can only be applied + to the :ref:`character ASN.1 types ` such as + :class:`~pyasn1.type.char.IA5String`. + + Parameters + ---------- + *alphabet: :class:`str` + Full set of characters permitted by this constraint object. + + Example + ------- + .. code-block:: python + + class BooleanValue(IA5String): + ''' + ASN.1 specification: + + BooleanValue ::= IA5String (FROM ('T' | 'F')) + ''' + subtypeSpec = PermittedAlphabetConstraint('T', 'F') + + # this will succeed + truth = BooleanValue('T') + truth = BooleanValue('TF') + + # this will raise ValueConstraintError + garbage = BooleanValue('TAF') + + ASN.1 `FROM ... EXCEPT ...` clause can be modelled by combining multiple + PermittedAlphabetConstraint objects into one: + + Example + ------- + .. code-block:: python + + class Lipogramme(IA5String): + ''' + ASN.1 specification: + + Lipogramme ::= + IA5String (FROM (ALL EXCEPT ("e"|"E"))) + ''' + subtypeSpec = ( + PermittedAlphabetConstraint(*string.printable) - + PermittedAlphabetConstraint('e', 'E') + ) + + # this will succeed + lipogramme = Lipogramme('A work of fiction?') + + # this will raise ValueConstraintError + lipogramme = Lipogramme('Eel') + + Note + ---- + Although `ConstraintsExclusion` object could seemingly be used for this + purpose, practically, for it to work, it needs to represent its operand + constraints as sets and intersect one with the other. That would require + the insight into the constraint values (and their types) that are otherwise + hidden inside the constraint object. + + Therefore it's more practical to model `EXCEPT` clause at + `PermittedAlphabetConstraint` level instead. + """ + def _setValues(self, values): + self._values = values + self._set = set(values) + + def _testValue(self, value, idx): + if not self._set.issuperset(value): + raise error.ValueConstraintError(value) + + +class ComponentPresentConstraint(AbstractConstraint): + """Create a ComponentPresentConstraint object. + + The ComponentPresentConstraint is only satisfied when the value + is not `None`. + + The ComponentPresentConstraint object is typically used with + `WithComponentsConstraint`. + + Examples + -------- + .. code-block:: python + + present = ComponentPresentConstraint() + + # this will succeed + present('whatever') + + # this will raise ValueConstraintError + present(None) + """ + def _setValues(self, values): + self._values = ('',) + + if values: + raise error.PyAsn1Error('No arguments expected') + + def _testValue(self, value, idx): + if value is None: + raise error.ValueConstraintError( + 'Component is not present:') + + +class ComponentAbsentConstraint(AbstractConstraint): + """Create a ComponentAbsentConstraint object. + + The ComponentAbsentConstraint is only satisfied when the value + is `None`. + + The ComponentAbsentConstraint object is typically used with + `WithComponentsConstraint`. + + Examples + -------- + .. code-block:: python + + absent = ComponentAbsentConstraint() + + # this will succeed + absent(None) + + # this will raise ValueConstraintError + absent('whatever') + """ + def _setValues(self, values): + self._values = ('',) + + if values: + raise error.PyAsn1Error('No arguments expected') + + def _testValue(self, value, idx): + if value is not None: + raise error.ValueConstraintError( + 'Component is not absent: %r' % value) + + +class WithComponentsConstraint(AbstractConstraint): + """Create a WithComponentsConstraint object. + + The `WithComponentsConstraint` satisfies any mapping object that has + constrained fields present or absent, what is indicated by + `ComponentPresentConstraint` and `ComponentAbsentConstraint` + objects respectively. + + The `WithComponentsConstraint` object is typically applied + to :class:`~pyasn1.type.univ.Set` or + :class:`~pyasn1.type.univ.Sequence` types. + + Parameters + ---------- + *fields: :class:`tuple` + Zero or more tuples of (`field`, `constraint`) indicating constrained + fields. + + Notes + ----- + On top of the primary use of `WithComponentsConstraint` (ensuring presence + or absence of particular components of a :class:`~pyasn1.type.univ.Set` or + :class:`~pyasn1.type.univ.Sequence`), it is also possible to pass any other + constraint objects or their combinations. In case of scalar fields, these + constraints will be verified in addition to the constraints belonging to + scalar components themselves. However, formally, these additional + constraints do not change the type of these ASN.1 objects. + + Examples + -------- + + .. code-block:: python + + class Item(Sequence): # Set is similar + ''' + ASN.1 specification: + + Item ::= SEQUENCE { + id INTEGER OPTIONAL, + name OCTET STRING OPTIONAL + } WITH COMPONENTS id PRESENT, name ABSENT | id ABSENT, name PRESENT + ''' + componentType = NamedTypes( + OptionalNamedType('id', Integer()), + OptionalNamedType('name', OctetString()) + ) + withComponents = ConstraintsUnion( + WithComponentsConstraint( + ('id', ComponentPresentConstraint()), + ('name', ComponentAbsentConstraint()) + ), + WithComponentsConstraint( + ('id', ComponentAbsentConstraint()), + ('name', ComponentPresentConstraint()) + ) + ) + + item = Item() + + # This will succeed + item['id'] = 1 + + # This will succeed + item.reset() + item['name'] = 'John' + + # This will fail (on encoding) + item.reset() + descr['id'] = 1 + descr['name'] = 'John' + """ + def _testValue(self, value, idx): + for field, constraint in self._values: + constraint(value.get(field)) + + def _setValues(self, values): + AbstractConstraint._setValues(self, values) + + +# This is a bit kludgy, meaning two op modes within a single constraint +class InnerTypeConstraint(AbstractConstraint): + """Value must satisfy the type and presence constraints""" + + def _testValue(self, value, idx): + if self.__singleTypeConstraint: + self.__singleTypeConstraint(value) + elif self.__multipleTypeConstraint: + if idx not in self.__multipleTypeConstraint: + raise error.ValueConstraintError(value) + constraint, status = self.__multipleTypeConstraint[idx] + if status == 'ABSENT': # XXX presence is not checked! + raise error.ValueConstraintError(value) + constraint(value) + + def _setValues(self, values): + self.__multipleTypeConstraint = {} + self.__singleTypeConstraint = None + for v in values: + if isinstance(v, tuple): + self.__multipleTypeConstraint[v[0]] = v[1], v[2] + else: + self.__singleTypeConstraint = v + AbstractConstraint._setValues(self, values) + + +# Logic operations on constraints + +class ConstraintsExclusion(AbstractConstraint): + """Create a ConstraintsExclusion logic operator object. + + The ConstraintsExclusion logic operator succeeds when the + value does *not* satisfy the operand constraint. + + The ConstraintsExclusion object can be applied to + any constraint and logic operator object. + + Parameters + ---------- + *constraints: + Constraint or logic operator objects. + + Examples + -------- + .. code-block:: python + + class LuckyNumber(Integer): + subtypeSpec = ConstraintsExclusion( + SingleValueConstraint(13) + ) + + # this will succeed + luckyNumber = LuckyNumber(12) + + # this will raise ValueConstraintError + luckyNumber = LuckyNumber(13) + + Note + ---- + The `FROM ... EXCEPT ...` ASN.1 clause should be modeled by combining + constraint objects into one. See `PermittedAlphabetConstraint` for more + information. + """ + def _testValue(self, value, idx): + for constraint in self._values: + try: + constraint(value, idx) + + except error.ValueConstraintError: + continue + + raise error.ValueConstraintError(value) + + def _setValues(self, values): + AbstractConstraint._setValues(self, values) + + +class AbstractConstraintSet(AbstractConstraint): + + def __getitem__(self, idx): + return self._values[idx] + + def __iter__(self): + return iter(self._values) + + def __add__(self, value): + return self.__class__(*(self._values + (value,))) + + def __radd__(self, value): + return self.__class__(*((value,) + self._values)) + + def __len__(self): + return len(self._values) + + # Constraints inclusion in sets + + def _setValues(self, values): + self._values = values + for constraint in values: + if constraint: + self._valueMap.add(constraint) + self._valueMap.update(constraint.getValueMap()) + + +class ConstraintsIntersection(AbstractConstraintSet): + """Create a ConstraintsIntersection logic operator object. + + The ConstraintsIntersection logic operator only succeeds + if *all* its operands succeed. + + The ConstraintsIntersection object can be applied to + any constraint and logic operator objects. + + The ConstraintsIntersection object duck-types the immutable + container object like Python :py:class:`tuple`. + + Parameters + ---------- + *constraints: + Constraint or logic operator objects. + + Examples + -------- + .. code-block:: python + + class CapitalAndSmall(IA5String): + ''' + ASN.1 specification: + + CapitalAndSmall ::= + IA5String (FROM ("A".."Z"|"a".."z")) + ''' + subtypeSpec = ConstraintsIntersection( + PermittedAlphabetConstraint('A', 'Z'), + PermittedAlphabetConstraint('a', 'z') + ) + + # this will succeed + capital_and_small = CapitalAndSmall('Hello') + + # this will raise ValueConstraintError + capital_and_small = CapitalAndSmall('hello') + """ + def _testValue(self, value, idx): + for constraint in self._values: + constraint(value, idx) + + +class ConstraintsUnion(AbstractConstraintSet): + """Create a ConstraintsUnion logic operator object. + + The ConstraintsUnion logic operator succeeds if + *at least* a single operand succeeds. + + The ConstraintsUnion object can be applied to + any constraint and logic operator objects. + + The ConstraintsUnion object duck-types the immutable + container object like Python :py:class:`tuple`. + + Parameters + ---------- + *constraints: + Constraint or logic operator objects. + + Examples + -------- + .. code-block:: python + + class CapitalOrSmall(IA5String): + ''' + ASN.1 specification: + + CapitalOrSmall ::= + IA5String (FROM ("A".."Z") | FROM ("a".."z")) + ''' + subtypeSpec = ConstraintsUnion( + PermittedAlphabetConstraint('A', 'Z'), + PermittedAlphabetConstraint('a', 'z') + ) + + # this will succeed + capital_or_small = CapitalAndSmall('Hello') + + # this will raise ValueConstraintError + capital_or_small = CapitalOrSmall('hello!') + """ + def _testValue(self, value, idx): + for constraint in self._values: + try: + constraint(value, idx) + except error.ValueConstraintError: + pass + else: + return + + raise error.ValueConstraintError( + 'all of %s failed for "%s"' % (self._values, value) + ) + +# TODO: +# refactor InnerTypeConstraint +# add tests for type check +# implement other constraint types +# make constraint validation easy to skip diff --git a/lib/pyasn1/type/error.py b/lib/pyasn1/type/error.py new file mode 100644 index 00000000..35f80f5c --- /dev/null +++ b/lib/pyasn1/type/error.py @@ -0,0 +1,11 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1.error import PyAsn1Error + + +class ValueConstraintError(PyAsn1Error): + pass diff --git a/lib/pyasn1/type/namedtype.py b/lib/pyasn1/type/namedtype.py new file mode 100644 index 00000000..03aec474 --- /dev/null +++ b/lib/pyasn1/type/namedtype.py @@ -0,0 +1,561 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import sys + +from pyasn1 import error +from pyasn1.type import tag +from pyasn1.type import tagmap + +__all__ = ['NamedType', 'OptionalNamedType', 'DefaultedNamedType', + 'NamedTypes'] + +try: + any + +except NameError: + any = lambda x: bool(filter(bool, x)) + + +class NamedType(object): + """Create named field object for a constructed ASN.1 type. + + The |NamedType| object represents a single name and ASN.1 type of a constructed ASN.1 type. + + |NamedType| objects are immutable and duck-type Python :class:`tuple` objects + holding *name* and *asn1Object* components. + + Parameters + ---------- + name: :py:class:`str` + Field name + + asn1Object: + ASN.1 type object + """ + isOptional = False + isDefaulted = False + + def __init__(self, name, asn1Object, openType=None): + self.__name = name + self.__type = asn1Object + self.__nameAndType = name, asn1Object + self.__openType = openType + + def __repr__(self): + representation = '%s=%r' % (self.name, self.asn1Object) + + if self.openType: + representation += ', open type %r' % self.openType + + return '<%s object, type %s>' % ( + self.__class__.__name__, representation) + + def __eq__(self, other): + return self.__nameAndType == other + + def __ne__(self, other): + return self.__nameAndType != other + + def __lt__(self, other): + return self.__nameAndType < other + + def __le__(self, other): + return self.__nameAndType <= other + + def __gt__(self, other): + return self.__nameAndType > other + + def __ge__(self, other): + return self.__nameAndType >= other + + def __hash__(self): + return hash(self.__nameAndType) + + def __getitem__(self, idx): + return self.__nameAndType[idx] + + def __iter__(self): + return iter(self.__nameAndType) + + @property + def name(self): + return self.__name + + @property + def asn1Object(self): + return self.__type + + @property + def openType(self): + return self.__openType + + # Backward compatibility + + def getName(self): + return self.name + + def getType(self): + return self.asn1Object + + +class OptionalNamedType(NamedType): + __doc__ = NamedType.__doc__ + + isOptional = True + + +class DefaultedNamedType(NamedType): + __doc__ = NamedType.__doc__ + + isDefaulted = True + + +class NamedTypes(object): + """Create a collection of named fields for a constructed ASN.1 type. + + The NamedTypes object represents a collection of named fields of a constructed ASN.1 type. + + *NamedTypes* objects are immutable and duck-type Python :class:`dict` objects + holding *name* as keys and ASN.1 type object as values. + + Parameters + ---------- + *namedTypes: :class:`~pyasn1.type.namedtype.NamedType` + + Examples + -------- + + .. code-block:: python + + class Description(Sequence): + ''' + ASN.1 specification: + + Description ::= SEQUENCE { + surname IA5String, + first-name IA5String OPTIONAL, + age INTEGER DEFAULT 40 + } + ''' + componentType = NamedTypes( + NamedType('surname', IA5String()), + OptionalNamedType('first-name', IA5String()), + DefaultedNamedType('age', Integer(40)) + ) + + descr = Description() + descr['surname'] = 'Smith' + descr['first-name'] = 'John' + """ + def __init__(self, *namedTypes, **kwargs): + self.__namedTypes = namedTypes + self.__namedTypesLen = len(self.__namedTypes) + self.__minTagSet = self.__computeMinTagSet() + self.__nameToPosMap = self.__computeNameToPosMap() + self.__tagToPosMap = self.__computeTagToPosMap() + self.__ambiguousTypes = 'terminal' not in kwargs and self.__computeAmbiguousTypes() or {} + self.__uniqueTagMap = self.__computeTagMaps(unique=True) + self.__nonUniqueTagMap = self.__computeTagMaps(unique=False) + self.__hasOptionalOrDefault = any([True for namedType in self.__namedTypes + if namedType.isDefaulted or namedType.isOptional]) + self.__hasOpenTypes = any([True for namedType in self.__namedTypes + if namedType.openType]) + + self.__requiredComponents = frozenset( + [idx for idx, nt in enumerate(self.__namedTypes) if not nt.isOptional and not nt.isDefaulted] + ) + self.__keys = frozenset([namedType.name for namedType in self.__namedTypes]) + self.__values = tuple([namedType.asn1Object for namedType in self.__namedTypes]) + self.__items = tuple([(namedType.name, namedType.asn1Object) for namedType in self.__namedTypes]) + + def __repr__(self): + representation = ', '.join(['%r' % x for x in self.__namedTypes]) + return '<%s object, types %s>' % ( + self.__class__.__name__, representation) + + def __eq__(self, other): + return self.__namedTypes == other + + def __ne__(self, other): + return self.__namedTypes != other + + def __lt__(self, other): + return self.__namedTypes < other + + def __le__(self, other): + return self.__namedTypes <= other + + def __gt__(self, other): + return self.__namedTypes > other + + def __ge__(self, other): + return self.__namedTypes >= other + + def __hash__(self): + return hash(self.__namedTypes) + + def __getitem__(self, idx): + try: + return self.__namedTypes[idx] + + except TypeError: + return self.__namedTypes[self.__nameToPosMap[idx]] + + def __contains__(self, key): + return key in self.__nameToPosMap + + def __iter__(self): + return (x[0] for x in self.__namedTypes) + + if sys.version_info[0] <= 2: + def __nonzero__(self): + return self.__namedTypesLen > 0 + else: + def __bool__(self): + return self.__namedTypesLen > 0 + + def __len__(self): + return self.__namedTypesLen + + # Python dict protocol + + def values(self): + return self.__values + + def keys(self): + return self.__keys + + def items(self): + return self.__items + + def clone(self): + return self.__class__(*self.__namedTypes) + + class PostponedError(object): + def __init__(self, errorMsg): + self.__errorMsg = errorMsg + + def __getitem__(self, item): + raise error.PyAsn1Error(self.__errorMsg) + + def __computeTagToPosMap(self): + tagToPosMap = {} + for idx, namedType in enumerate(self.__namedTypes): + tagMap = namedType.asn1Object.tagMap + if isinstance(tagMap, NamedTypes.PostponedError): + return tagMap + if not tagMap: + continue + for _tagSet in tagMap.presentTypes: + if _tagSet in tagToPosMap: + return NamedTypes.PostponedError('Duplicate component tag %s at %s' % (_tagSet, namedType)) + tagToPosMap[_tagSet] = idx + + return tagToPosMap + + def __computeNameToPosMap(self): + nameToPosMap = {} + for idx, namedType in enumerate(self.__namedTypes): + if namedType.name in nameToPosMap: + return NamedTypes.PostponedError('Duplicate component name %s at %s' % (namedType.name, namedType)) + nameToPosMap[namedType.name] = idx + + return nameToPosMap + + def __computeAmbiguousTypes(self): + ambiguousTypes = {} + partialAmbiguousTypes = () + for idx, namedType in reversed(tuple(enumerate(self.__namedTypes))): + if namedType.isOptional or namedType.isDefaulted: + partialAmbiguousTypes = (namedType,) + partialAmbiguousTypes + else: + partialAmbiguousTypes = (namedType,) + if len(partialAmbiguousTypes) == len(self.__namedTypes): + ambiguousTypes[idx] = self + else: + ambiguousTypes[idx] = NamedTypes(*partialAmbiguousTypes, **dict(terminal=True)) + return ambiguousTypes + + def getTypeByPosition(self, idx): + """Return ASN.1 type object by its position in fields set. + + Parameters + ---------- + idx: :py:class:`int` + Field index + + Returns + ------- + : + ASN.1 type + + Raises + ------ + ~pyasn1.error.PyAsn1Error + If given position is out of fields range + """ + try: + return self.__namedTypes[idx].asn1Object + + except IndexError: + raise error.PyAsn1Error('Type position out of range') + + def getPositionByType(self, tagSet): + """Return field position by its ASN.1 type. + + Parameters + ---------- + tagSet: :class:`~pysnmp.type.tag.TagSet` + ASN.1 tag set distinguishing one ASN.1 type from others. + + Returns + ------- + : :py:class:`int` + ASN.1 type position in fields set + + Raises + ------ + ~pyasn1.error.PyAsn1Error + If *tagSet* is not present or ASN.1 types are not unique within callee *NamedTypes* + """ + try: + return self.__tagToPosMap[tagSet] + + except KeyError: + raise error.PyAsn1Error('Type %s not found' % (tagSet,)) + + def getNameByPosition(self, idx): + """Return field name by its position in fields set. + + Parameters + ---------- + idx: :py:class:`idx` + Field index + + Returns + ------- + : :py:class:`str` + Field name + + Raises + ------ + ~pyasn1.error.PyAsn1Error + If given field name is not present in callee *NamedTypes* + """ + try: + return self.__namedTypes[idx].name + + except IndexError: + raise error.PyAsn1Error('Type position out of range') + + def getPositionByName(self, name): + """Return field position by filed name. + + Parameters + ---------- + name: :py:class:`str` + Field name + + Returns + ------- + : :py:class:`int` + Field position in fields set + + Raises + ------ + ~pyasn1.error.PyAsn1Error + If *name* is not present or not unique within callee *NamedTypes* + """ + try: + return self.__nameToPosMap[name] + + except KeyError: + raise error.PyAsn1Error('Name %s not found' % (name,)) + + def getTagMapNearPosition(self, idx): + """Return ASN.1 types that are allowed at or past given field position. + + Some ASN.1 serialisation allow for skipping optional and defaulted fields. + Some constructed ASN.1 types allow reordering of the fields. When recovering + such objects it may be important to know which types can possibly be + present at any given position in the field sets. + + Parameters + ---------- + idx: :py:class:`int` + Field index + + Returns + ------- + : :class:`~pyasn1.type.tagmap.TagMap` + Map if ASN.1 types allowed at given field position + + Raises + ------ + ~pyasn1.error.PyAsn1Error + If given position is out of fields range + """ + try: + return self.__ambiguousTypes[idx].tagMap + + except KeyError: + raise error.PyAsn1Error('Type position out of range') + + def getPositionNearType(self, tagSet, idx): + """Return the closest field position where given ASN.1 type is allowed. + + Some ASN.1 serialisation allow for skipping optional and defaulted fields. + Some constructed ASN.1 types allow reordering of the fields. When recovering + such objects it may be important to know at which field position, in field set, + given *tagSet* is allowed at or past *idx* position. + + Parameters + ---------- + tagSet: :class:`~pyasn1.type.tag.TagSet` + ASN.1 type which field position to look up + + idx: :py:class:`int` + Field position at or past which to perform ASN.1 type look up + + Returns + ------- + : :py:class:`int` + Field position in fields set + + Raises + ------ + ~pyasn1.error.PyAsn1Error + If *tagSet* is not present or not unique within callee *NamedTypes* + or *idx* is out of fields range + """ + try: + return idx + self.__ambiguousTypes[idx].getPositionByType(tagSet) + + except KeyError: + raise error.PyAsn1Error('Type position out of range') + + def __computeMinTagSet(self): + minTagSet = None + for namedType in self.__namedTypes: + asn1Object = namedType.asn1Object + + try: + tagSet = asn1Object.minTagSet + + except AttributeError: + tagSet = asn1Object.tagSet + + if minTagSet is None or tagSet < minTagSet: + minTagSet = tagSet + + return minTagSet or tag.TagSet() + + @property + def minTagSet(self): + """Return the minimal TagSet among ASN.1 type in callee *NamedTypes*. + + Some ASN.1 types/serialisation protocols require ASN.1 types to be + arranged based on their numerical tag value. The *minTagSet* property + returns that. + + Returns + ------- + : :class:`~pyasn1.type.tagset.TagSet` + Minimal TagSet among ASN.1 types in callee *NamedTypes* + """ + return self.__minTagSet + + def __computeTagMaps(self, unique): + presentTypes = {} + skipTypes = {} + defaultType = None + for namedType in self.__namedTypes: + tagMap = namedType.asn1Object.tagMap + if isinstance(tagMap, NamedTypes.PostponedError): + return tagMap + for tagSet in tagMap: + if unique and tagSet in presentTypes: + return NamedTypes.PostponedError('Non-unique tagSet %s of %s at %s' % (tagSet, namedType, self)) + presentTypes[tagSet] = namedType.asn1Object + skipTypes.update(tagMap.skipTypes) + + if defaultType is None: + defaultType = tagMap.defaultType + elif tagMap.defaultType is not None: + return NamedTypes.PostponedError('Duplicate default ASN.1 type at %s' % (self,)) + + return tagmap.TagMap(presentTypes, skipTypes, defaultType) + + @property + def tagMap(self): + """Return a *TagMap* object from tags and types recursively. + + Return a :class:`~pyasn1.type.tagmap.TagMap` object by + combining tags from *TagMap* objects of children types and + associating them with their immediate child type. + + Example + ------- + .. code-block:: python + + OuterType ::= CHOICE { + innerType INTEGER + } + + Calling *.tagMap* on *OuterType* will yield a map like this: + + .. code-block:: python + + Integer.tagSet -> Choice + """ + return self.__nonUniqueTagMap + + @property + def tagMapUnique(self): + """Return a *TagMap* object from unique tags and types recursively. + + Return a :class:`~pyasn1.type.tagmap.TagMap` object by + combining tags from *TagMap* objects of children types and + associating them with their immediate child type. + + Example + ------- + .. code-block:: python + + OuterType ::= CHOICE { + innerType INTEGER + } + + Calling *.tagMapUnique* on *OuterType* will yield a map like this: + + .. code-block:: python + + Integer.tagSet -> Choice + + Note + ---- + + Duplicate *TagSet* objects found in the tree of children + types would cause error. + """ + return self.__uniqueTagMap + + @property + def hasOptionalOrDefault(self): + return self.__hasOptionalOrDefault + + @property + def hasOpenTypes(self): + return self.__hasOpenTypes + + @property + def namedTypes(self): + return tuple(self.__namedTypes) + + @property + def requiredComponents(self): + return self.__requiredComponents diff --git a/lib/pyasn1/type/namedval.py b/lib/pyasn1/type/namedval.py new file mode 100644 index 00000000..ef177ca3 --- /dev/null +++ b/lib/pyasn1/type/namedval.py @@ -0,0 +1,192 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +# ASN.1 named integers +# +from pyasn1 import error + +__all__ = ['NamedValues'] + + +class NamedValues(object): + """Create named values object. + + The |NamedValues| object represents a collection of string names + associated with numeric IDs. These objects are used for giving + names to otherwise numerical values. + + |NamedValues| objects are immutable and duck-type Python + :class:`dict` object mapping ID to name and vice-versa. + + Parameters + ---------- + *args: variable number of two-element :py:class:`tuple` + + name: :py:class:`str` + Value label + + value: :py:class:`int` + Numeric value + + Keyword Args + ------------ + name: :py:class:`str` + Value label + + value: :py:class:`int` + Numeric value + + Examples + -------- + + .. code-block:: pycon + + >>> nv = NamedValues('a', 'b', ('c', 0), d=1) + >>> nv + >>> {'c': 0, 'd': 1, 'a': 2, 'b': 3} + >>> nv[0] + 'c' + >>> nv['a'] + 2 + """ + def __init__(self, *args, **kwargs): + self.__names = {} + self.__numbers = {} + + anonymousNames = [] + + for namedValue in args: + if isinstance(namedValue, (tuple, list)): + try: + name, number = namedValue + + except ValueError: + raise error.PyAsn1Error('Not a proper attribute-value pair %r' % (namedValue,)) + + else: + anonymousNames.append(namedValue) + continue + + if name in self.__names: + raise error.PyAsn1Error('Duplicate name %s' % (name,)) + + if number in self.__numbers: + raise error.PyAsn1Error('Duplicate number %s=%s' % (name, number)) + + self.__names[name] = number + self.__numbers[number] = name + + for name, number in kwargs.items(): + if name in self.__names: + raise error.PyAsn1Error('Duplicate name %s' % (name,)) + + if number in self.__numbers: + raise error.PyAsn1Error('Duplicate number %s=%s' % (name, number)) + + self.__names[name] = number + self.__numbers[number] = name + + if anonymousNames: + + number = self.__numbers and max(self.__numbers) + 1 or 0 + + for name in anonymousNames: + + if name in self.__names: + raise error.PyAsn1Error('Duplicate name %s' % (name,)) + + self.__names[name] = number + self.__numbers[number] = name + + number += 1 + + def __repr__(self): + representation = ', '.join(['%s=%d' % x for x in self.items()]) + + if len(representation) > 64: + representation = representation[:32] + '...' + representation[-32:] + + return '<%s object, enums %s>' % ( + self.__class__.__name__, representation) + + def __eq__(self, other): + return dict(self) == other + + def __ne__(self, other): + return dict(self) != other + + def __lt__(self, other): + return dict(self) < other + + def __le__(self, other): + return dict(self) <= other + + def __gt__(self, other): + return dict(self) > other + + def __ge__(self, other): + return dict(self) >= other + + def __hash__(self): + return hash(self.items()) + + # Python dict protocol (read-only) + + def __getitem__(self, key): + try: + return self.__numbers[key] + + except KeyError: + return self.__names[key] + + def __len__(self): + return len(self.__names) + + def __contains__(self, key): + return key in self.__names or key in self.__numbers + + def __iter__(self): + return iter(self.__names) + + def values(self): + return iter(self.__numbers) + + def keys(self): + return iter(self.__names) + + def items(self): + for name in self.__names: + yield name, self.__names[name] + + # support merging + + def __add__(self, namedValues): + return self.__class__(*tuple(self.items()) + tuple(namedValues.items())) + + # XXX clone/subtype? + + def clone(self, *args, **kwargs): + new = self.__class__(*args, **kwargs) + return self + new + + # legacy protocol + + def getName(self, value): + if value in self.__numbers: + return self.__numbers[value] + + def getValue(self, name): + if name in self.__names: + return self.__names[name] + + def getValues(self, *names): + try: + return [self.__names[name] for name in names] + + except KeyError: + raise error.PyAsn1Error( + 'Unknown bit identifier(s): %s' % (set(names).difference(self.__names),) + ) diff --git a/lib/pyasn1/type/opentype.py b/lib/pyasn1/type/opentype.py new file mode 100644 index 00000000..9d2ca25f --- /dev/null +++ b/lib/pyasn1/type/opentype.py @@ -0,0 +1,104 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# + +__all__ = ['OpenType'] + + +class OpenType(object): + """Create ASN.1 type map indexed by a value + + The *OpenType* object models an untyped field of a constructed ASN.1 + type. In ASN.1 syntax it is usually represented by the + `ANY DEFINED BY` for scalars or `SET OF ANY DEFINED BY`, + `SEQUENCE OF ANY DEFINED BY` for container types clauses. Typically + used together with :class:`~pyasn1.type.univ.Any` object. + + OpenType objects duck-type a read-only Python :class:`dict` objects, + however the passed `typeMap` is not copied, but stored by reference. + That means the user can manipulate `typeMap` at run time having this + reflected on *OpenType* object behavior. + + The |OpenType| class models an untyped field of a constructed ASN.1 + type. In ASN.1 syntax it is usually represented by the + `ANY DEFINED BY` for scalars or `SET OF ANY DEFINED BY`, + `SEQUENCE OF ANY DEFINED BY` for container types clauses. Typically + used with :class:`~pyasn1.type.univ.Any` type. + + Parameters + ---------- + name: :py:class:`str` + Field name + + typeMap: :py:class:`dict` + A map of value->ASN.1 type. It's stored by reference and can be + mutated later to register new mappings. + + Examples + -------- + + For untyped scalars: + + .. code-block:: python + + openType = OpenType( + 'id', {1: Integer(), + 2: OctetString()} + ) + Sequence( + componentType=NamedTypes( + NamedType('id', Integer()), + NamedType('blob', Any(), openType=openType) + ) + ) + + For untyped `SET OF` or `SEQUENCE OF` vectors: + + .. code-block:: python + + openType = OpenType( + 'id', {1: Integer(), + 2: OctetString()} + ) + Sequence( + componentType=NamedTypes( + NamedType('id', Integer()), + NamedType('blob', SetOf(componentType=Any()), + openType=openType) + ) + ) + """ + + def __init__(self, name, typeMap=None): + self.__name = name + if typeMap is None: + self.__typeMap = {} + else: + self.__typeMap = typeMap + + @property + def name(self): + return self.__name + + # Python dict protocol + + def values(self): + return self.__typeMap.values() + + def keys(self): + return self.__typeMap.keys() + + def items(self): + return self.__typeMap.items() + + def __contains__(self, key): + return key in self.__typeMap + + def __getitem__(self, key): + return self.__typeMap[key] + + def __iter__(self): + return iter(self.__typeMap) diff --git a/lib/pyasn1/type/tag.py b/lib/pyasn1/type/tag.py new file mode 100644 index 00000000..6ac04c38 --- /dev/null +++ b/lib/pyasn1/type/tag.py @@ -0,0 +1,335 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1 import error + +__all__ = ['tagClassUniversal', 'tagClassApplication', 'tagClassContext', + 'tagClassPrivate', 'tagFormatSimple', 'tagFormatConstructed', + 'tagCategoryImplicit', 'tagCategoryExplicit', + 'tagCategoryUntagged', 'Tag', 'TagSet'] + +#: Identifier for ASN.1 class UNIVERSAL +tagClassUniversal = 0x00 + +#: Identifier for ASN.1 class APPLICATION +tagClassApplication = 0x40 + +#: Identifier for ASN.1 class context-specific +tagClassContext = 0x80 + +#: Identifier for ASN.1 class private +tagClassPrivate = 0xC0 + +#: Identifier for "simple" ASN.1 structure (e.g. scalar) +tagFormatSimple = 0x00 + +#: Identifier for "constructed" ASN.1 structure (e.g. may have inner components) +tagFormatConstructed = 0x20 + +tagCategoryImplicit = 0x01 +tagCategoryExplicit = 0x02 +tagCategoryUntagged = 0x04 + + +class Tag(object): + """Create ASN.1 tag + + Represents ASN.1 tag that can be attached to a ASN.1 type to make + types distinguishable from each other. + + *Tag* objects are immutable and duck-type Python :class:`tuple` objects + holding three integer components of a tag. + + Parameters + ---------- + tagClass: :py:class:`int` + Tag *class* value + + tagFormat: :py:class:`int` + Tag *format* value + + tagId: :py:class:`int` + Tag ID value + """ + def __init__(self, tagClass, tagFormat, tagId): + if tagId < 0: + raise error.PyAsn1Error('Negative tag ID (%s) not allowed' % tagId) + self.__tagClass = tagClass + self.__tagFormat = tagFormat + self.__tagId = tagId + self.__tagClassId = tagClass, tagId + self.__hash = hash(self.__tagClassId) + + def __repr__(self): + representation = '[%s:%s:%s]' % ( + self.__tagClass, self.__tagFormat, self.__tagId) + return '<%s object, tag %s>' % ( + self.__class__.__name__, representation) + + def __eq__(self, other): + return self.__tagClassId == other + + def __ne__(self, other): + return self.__tagClassId != other + + def __lt__(self, other): + return self.__tagClassId < other + + def __le__(self, other): + return self.__tagClassId <= other + + def __gt__(self, other): + return self.__tagClassId > other + + def __ge__(self, other): + return self.__tagClassId >= other + + def __hash__(self): + return self.__hash + + def __getitem__(self, idx): + if idx == 0: + return self.__tagClass + elif idx == 1: + return self.__tagFormat + elif idx == 2: + return self.__tagId + else: + raise IndexError() + + def __iter__(self): + yield self.__tagClass + yield self.__tagFormat + yield self.__tagId + + def __and__(self, otherTag): + return self.__class__(self.__tagClass & otherTag.tagClass, + self.__tagFormat & otherTag.tagFormat, + self.__tagId & otherTag.tagId) + + def __or__(self, otherTag): + return self.__class__(self.__tagClass | otherTag.tagClass, + self.__tagFormat | otherTag.tagFormat, + self.__tagId | otherTag.tagId) + + @property + def tagClass(self): + """ASN.1 tag class + + Returns + ------- + : :py:class:`int` + Tag class + """ + return self.__tagClass + + @property + def tagFormat(self): + """ASN.1 tag format + + Returns + ------- + : :py:class:`int` + Tag format + """ + return self.__tagFormat + + @property + def tagId(self): + """ASN.1 tag ID + + Returns + ------- + : :py:class:`int` + Tag ID + """ + return self.__tagId + + +class TagSet(object): + """Create a collection of ASN.1 tags + + Represents a combination of :class:`~pyasn1.type.tag.Tag` objects + that can be attached to a ASN.1 type to make types distinguishable + from each other. + + *TagSet* objects are immutable and duck-type Python :class:`tuple` objects + holding arbitrary number of :class:`~pyasn1.type.tag.Tag` objects. + + Parameters + ---------- + baseTag: :class:`~pyasn1.type.tag.Tag` + Base *Tag* object. This tag survives IMPLICIT tagging. + + *superTags: :class:`~pyasn1.type.tag.Tag` + Additional *Tag* objects taking part in subtyping. + + Examples + -------- + .. code-block:: python + + class OrderNumber(NumericString): + ''' + ASN.1 specification + + Order-number ::= + [APPLICATION 5] IMPLICIT NumericString + ''' + tagSet = NumericString.tagSet.tagImplicitly( + Tag(tagClassApplication, tagFormatSimple, 5) + ) + + orderNumber = OrderNumber('1234') + """ + def __init__(self, baseTag=(), *superTags): + self.__baseTag = baseTag + self.__superTags = superTags + self.__superTagsClassId = tuple( + [(superTag.tagClass, superTag.tagId) for superTag in superTags] + ) + self.__lenOfSuperTags = len(superTags) + self.__hash = hash(self.__superTagsClassId) + + def __repr__(self): + representation = '-'.join(['%s:%s:%s' % (x.tagClass, x.tagFormat, x.tagId) + for x in self.__superTags]) + if representation: + representation = 'tags ' + representation + else: + representation = 'untagged' + + return '<%s object, %s>' % (self.__class__.__name__, representation) + + def __add__(self, superTag): + return self.__class__(self.__baseTag, *self.__superTags + (superTag,)) + + def __radd__(self, superTag): + return self.__class__(self.__baseTag, *(superTag,) + self.__superTags) + + def __getitem__(self, i): + if i.__class__ is slice: + return self.__class__(self.__baseTag, *self.__superTags[i]) + else: + return self.__superTags[i] + + def __eq__(self, other): + return self.__superTagsClassId == other + + def __ne__(self, other): + return self.__superTagsClassId != other + + def __lt__(self, other): + return self.__superTagsClassId < other + + def __le__(self, other): + return self.__superTagsClassId <= other + + def __gt__(self, other): + return self.__superTagsClassId > other + + def __ge__(self, other): + return self.__superTagsClassId >= other + + def __hash__(self): + return self.__hash + + def __len__(self): + return self.__lenOfSuperTags + + @property + def baseTag(self): + """Return base ASN.1 tag + + Returns + ------- + : :class:`~pyasn1.type.tag.Tag` + Base tag of this *TagSet* + """ + return self.__baseTag + + @property + def superTags(self): + """Return ASN.1 tags + + Returns + ------- + : :py:class:`tuple` + Tuple of :class:`~pyasn1.type.tag.Tag` objects that this *TagSet* contains + """ + return self.__superTags + + def tagExplicitly(self, superTag): + """Return explicitly tagged *TagSet* + + Create a new *TagSet* representing callee *TagSet* explicitly tagged + with passed tag(s). With explicit tagging mode, new tags are appended + to existing tag(s). + + Parameters + ---------- + superTag: :class:`~pyasn1.type.tag.Tag` + *Tag* object to tag this *TagSet* + + Returns + ------- + : :class:`~pyasn1.type.tag.TagSet` + New *TagSet* object + """ + if superTag.tagClass == tagClassUniversal: + raise error.PyAsn1Error("Can't tag with UNIVERSAL class tag") + if superTag.tagFormat != tagFormatConstructed: + superTag = Tag(superTag.tagClass, tagFormatConstructed, superTag.tagId) + return self + superTag + + def tagImplicitly(self, superTag): + """Return implicitly tagged *TagSet* + + Create a new *TagSet* representing callee *TagSet* implicitly tagged + with passed tag(s). With implicit tagging mode, new tag(s) replace the + last existing tag. + + Parameters + ---------- + superTag: :class:`~pyasn1.type.tag.Tag` + *Tag* object to tag this *TagSet* + + Returns + ------- + : :class:`~pyasn1.type.tag.TagSet` + New *TagSet* object + """ + if self.__superTags: + superTag = Tag(superTag.tagClass, self.__superTags[-1].tagFormat, superTag.tagId) + return self[:-1] + superTag + + def isSuperTagSetOf(self, tagSet): + """Test type relationship against given *TagSet* + + The callee is considered to be a supertype of given *TagSet* + tag-wise if all tags in *TagSet* are present in the callee and + they are in the same order. + + Parameters + ---------- + tagSet: :class:`~pyasn1.type.tag.TagSet` + *TagSet* object to evaluate against the callee + + Returns + ------- + : :py:class:`bool` + :obj:`True` if callee is a supertype of *tagSet* + """ + if len(tagSet) < self.__lenOfSuperTags: + return False + return self.__superTags == tagSet[:self.__lenOfSuperTags] + + # Backward compatibility + + def getBaseTag(self): + return self.__baseTag + +def initTagSet(tag): + return TagSet(tag, tag) diff --git a/lib/pyasn1/type/tagmap.py b/lib/pyasn1/type/tagmap.py new file mode 100644 index 00000000..963adf90 --- /dev/null +++ b/lib/pyasn1/type/tagmap.py @@ -0,0 +1,96 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1 import error + +__all__ = ['TagMap'] + + +class TagMap(object): + """Map *TagSet* objects to ASN.1 types + + Create an object mapping *TagSet* object to ASN.1 type. + + *TagMap* objects are immutable and duck-type read-only Python + :class:`dict` objects holding *TagSet* objects as keys and ASN.1 + type objects as values. + + Parameters + ---------- + presentTypes: :py:class:`dict` + Map of :class:`~pyasn1.type.tag.TagSet` to ASN.1 objects considered + as being unconditionally present in the *TagMap*. + + skipTypes: :py:class:`dict` + A collection of :class:`~pyasn1.type.tag.TagSet` objects considered + as absent in the *TagMap* even when *defaultType* is present. + + defaultType: ASN.1 type object + An ASN.1 type object callee *TagMap* returns for any *TagSet* key not present + in *presentTypes* (unless given key is present in *skipTypes*). + """ + def __init__(self, presentTypes=None, skipTypes=None, defaultType=None): + self.__presentTypes = presentTypes or {} + self.__skipTypes = skipTypes or {} + self.__defaultType = defaultType + + def __contains__(self, tagSet): + return (tagSet in self.__presentTypes or + self.__defaultType is not None and tagSet not in self.__skipTypes) + + def __getitem__(self, tagSet): + try: + return self.__presentTypes[tagSet] + except KeyError: + if self.__defaultType is None: + raise KeyError() + elif tagSet in self.__skipTypes: + raise error.PyAsn1Error('Key in negative map') + else: + return self.__defaultType + + def __iter__(self): + return iter(self.__presentTypes) + + def __repr__(self): + representation = '%s object' % self.__class__.__name__ + + if self.__presentTypes: + representation += ', present %s' % repr(self.__presentTypes) + + if self.__skipTypes: + representation += ', skip %s' % repr(self.__skipTypes) + + if self.__defaultType is not None: + representation += ', default %s' % repr(self.__defaultType) + + return '<%s>' % representation + + @property + def presentTypes(self): + """Return *TagSet* to ASN.1 type map present in callee *TagMap*""" + return self.__presentTypes + + @property + def skipTypes(self): + """Return *TagSet* collection unconditionally absent in callee *TagMap*""" + return self.__skipTypes + + @property + def defaultType(self): + """Return default ASN.1 type being returned for any missing *TagSet*""" + return self.__defaultType + + # Backward compatibility + + def getPosMap(self): + return self.presentTypes + + def getNegMap(self): + return self.skipTypes + + def getDef(self): + return self.defaultType diff --git a/lib/pyasn1/type/univ.py b/lib/pyasn1/type/univ.py new file mode 100644 index 00000000..488241fd --- /dev/null +++ b/lib/pyasn1/type/univ.py @@ -0,0 +1,3305 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import math +import sys + +from pyasn1 import error +from pyasn1.codec.ber import eoo +from pyasn1.compat import integer +from pyasn1.compat import octets +from pyasn1.type import base +from pyasn1.type import constraint +from pyasn1.type import namedtype +from pyasn1.type import namedval +from pyasn1.type import tag +from pyasn1.type import tagmap + +NoValue = base.NoValue +noValue = NoValue() + +__all__ = ['Integer', 'Boolean', 'BitString', 'OctetString', 'Null', + 'ObjectIdentifier', 'Real', 'Enumerated', + 'SequenceOfAndSetOfBase', 'SequenceOf', 'SetOf', + 'SequenceAndSetBase', 'Sequence', 'Set', 'Choice', 'Any', + 'NoValue', 'noValue'] + +# "Simple" ASN.1 types (yet incomplete) + + +class Integer(base.SimpleAsn1Type): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its + objects are immutable and duck-type Python :class:`int` objects. + + Keyword Args + ------------ + value: :class:`int`, :class:`str` or |ASN.1| object + Python :class:`int` or :class:`str` literal or |ASN.1| class + instance. If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` + Object representing non-default symbolic aliases for numbers + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + + .. code-block:: python + + class ErrorCode(Integer): + ''' + ASN.1 specification: + + ErrorCode ::= + INTEGER { disk-full(1), no-disk(-1), + disk-not-formatted(2) } + + error ErrorCode ::= disk-full + ''' + namedValues = NamedValues( + ('disk-full', 1), ('no-disk', -1), + ('disk-not-formatted', 2) + ) + + error = ErrorCode('disk-full') + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x02) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object + #: representing symbolic aliases for numbers + namedValues = namedval.NamedValues() + + # Optimization for faster codec lookup + typeId = base.SimpleAsn1Type.getTypeId() + + def __init__(self, value=noValue, **kwargs): + if 'namedValues' not in kwargs: + kwargs['namedValues'] = self.namedValues + + base.SimpleAsn1Type.__init__(self, value, **kwargs) + + def __and__(self, value): + return self.clone(self._value & value) + + def __rand__(self, value): + return self.clone(value & self._value) + + def __or__(self, value): + return self.clone(self._value | value) + + def __ror__(self, value): + return self.clone(value | self._value) + + def __xor__(self, value): + return self.clone(self._value ^ value) + + def __rxor__(self, value): + return self.clone(value ^ self._value) + + def __lshift__(self, value): + return self.clone(self._value << value) + + def __rshift__(self, value): + return self.clone(self._value >> value) + + def __add__(self, value): + return self.clone(self._value + value) + + def __radd__(self, value): + return self.clone(value + self._value) + + def __sub__(self, value): + return self.clone(self._value - value) + + def __rsub__(self, value): + return self.clone(value - self._value) + + def __mul__(self, value): + return self.clone(self._value * value) + + def __rmul__(self, value): + return self.clone(value * self._value) + + def __mod__(self, value): + return self.clone(self._value % value) + + def __rmod__(self, value): + return self.clone(value % self._value) + + def __pow__(self, value, modulo=None): + return self.clone(pow(self._value, value, modulo)) + + def __rpow__(self, value): + return self.clone(pow(value, self._value)) + + def __floordiv__(self, value): + return self.clone(self._value // value) + + def __rfloordiv__(self, value): + return self.clone(value // self._value) + + if sys.version_info[0] <= 2: + def __div__(self, value): + if isinstance(value, float): + return Real(self._value / value) + else: + return self.clone(self._value / value) + + def __rdiv__(self, value): + if isinstance(value, float): + return Real(value / self._value) + else: + return self.clone(value / self._value) + else: + def __truediv__(self, value): + return Real(self._value / value) + + def __rtruediv__(self, value): + return Real(value / self._value) + + def __divmod__(self, value): + return self.clone(divmod(self._value, value)) + + def __rdivmod__(self, value): + return self.clone(divmod(value, self._value)) + + __hash__ = base.SimpleAsn1Type.__hash__ + + def __int__(self): + return int(self._value) + + if sys.version_info[0] <= 2: + def __long__(self): + return long(self._value) + + def __float__(self): + return float(self._value) + + def __abs__(self): + return self.clone(abs(self._value)) + + def __index__(self): + return int(self._value) + + def __pos__(self): + return self.clone(+self._value) + + def __neg__(self): + return self.clone(-self._value) + + def __invert__(self): + return self.clone(~self._value) + + def __round__(self, n=0): + r = round(self._value, n) + if n: + return self.clone(r) + else: + return r + + def __floor__(self): + return math.floor(self._value) + + def __ceil__(self): + return math.ceil(self._value) + + def __trunc__(self): + return self.clone(math.trunc(self._value)) + + def __lt__(self, value): + return self._value < value + + def __le__(self, value): + return self._value <= value + + def __eq__(self, value): + return self._value == value + + def __ne__(self, value): + return self._value != value + + def __gt__(self, value): + return self._value > value + + def __ge__(self, value): + return self._value >= value + + def prettyIn(self, value): + try: + return int(value) + + except ValueError: + try: + return self.namedValues[value] + + except KeyError: + raise error.PyAsn1Error( + 'Can\'t coerce %r into integer: %s' % (value, sys.exc_info()[1]) + ) + + def prettyOut(self, value): + try: + return str(self.namedValues[value]) + + except KeyError: + return str(value) + + # backward compatibility + + def getNamedValues(self): + return self.namedValues + + +class Boolean(Integer): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its + objects are immutable and duck-type Python :class:`int` objects. + + Keyword Args + ------------ + value: :class:`int`, :class:`str` or |ASN.1| object + Python :class:`int` or :class:`str` literal or |ASN.1| class + instance. If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s).Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` + Object representing non-default symbolic aliases for numbers + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + .. code-block:: python + + class RoundResult(Boolean): + ''' + ASN.1 specification: + + RoundResult ::= BOOLEAN + + ok RoundResult ::= TRUE + ko RoundResult ::= FALSE + ''' + ok = RoundResult(True) + ko = RoundResult(False) + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x01), + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = Integer.subtypeSpec + constraint.SingleValueConstraint(0, 1) + + #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object + #: representing symbolic aliases for numbers + namedValues = namedval.NamedValues(('False', 0), ('True', 1)) + + # Optimization for faster codec lookup + typeId = Integer.getTypeId() + +if sys.version_info[0] < 3: + SizedIntegerBase = long +else: + SizedIntegerBase = int + + +class SizedInteger(SizedIntegerBase): + bitLength = leadingZeroBits = None + + def setBitLength(self, bitLength): + self.bitLength = bitLength + self.leadingZeroBits = max(bitLength - integer.bitLength(self), 0) + return self + + def __len__(self): + if self.bitLength is None: + self.setBitLength(integer.bitLength(self)) + + return self.bitLength + + +class BitString(base.SimpleAsn1Type): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its + objects are immutable and duck-type both Python :class:`tuple` (as a tuple + of bits) and :class:`int` objects. + + Keyword Args + ------------ + value: :class:`int`, :class:`str` or |ASN.1| object + Python :class:`int` or :class:`str` literal representing binary + or hexadecimal number or sequence of integer bits or |ASN.1| object. + If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` + Object representing non-default symbolic aliases for numbers + + binValue: :py:class:`str` + Binary string initializer to use instead of the *value*. + Example: '10110011'. + + hexValue: :py:class:`str` + Hexadecimal string initializer to use instead of the *value*. + Example: 'DEADBEEF'. + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + .. code-block:: python + + class Rights(BitString): + ''' + ASN.1 specification: + + Rights ::= BIT STRING { user-read(0), user-write(1), + group-read(2), group-write(3), + other-read(4), other-write(5) } + + group1 Rights ::= { group-read, group-write } + group2 Rights ::= '0011'B + group3 Rights ::= '3'H + ''' + namedValues = NamedValues( + ('user-read', 0), ('user-write', 1), + ('group-read', 2), ('group-write', 3), + ('other-read', 4), ('other-write', 5) + ) + + group1 = Rights(('group-read', 'group-write')) + group2 = Rights('0011') + group3 = Rights(0x3) + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x03) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object + #: representing symbolic aliases for numbers + namedValues = namedval.NamedValues() + + # Optimization for faster codec lookup + typeId = base.SimpleAsn1Type.getTypeId() + + defaultBinValue = defaultHexValue = noValue + + def __init__(self, value=noValue, **kwargs): + if value is noValue: + if kwargs: + try: + value = self.fromBinaryString(kwargs.pop('binValue'), internalFormat=True) + + except KeyError: + pass + + try: + value = self.fromHexString(kwargs.pop('hexValue'), internalFormat=True) + + except KeyError: + pass + + if value is noValue: + if self.defaultBinValue is not noValue: + value = self.fromBinaryString(self.defaultBinValue, internalFormat=True) + + elif self.defaultHexValue is not noValue: + value = self.fromHexString(self.defaultHexValue, internalFormat=True) + + if 'namedValues' not in kwargs: + kwargs['namedValues'] = self.namedValues + + base.SimpleAsn1Type.__init__(self, value, **kwargs) + + def __str__(self): + return self.asBinary() + + def __eq__(self, other): + other = self.prettyIn(other) + return self is other or self._value == other and len(self._value) == len(other) + + def __ne__(self, other): + other = self.prettyIn(other) + return self._value != other or len(self._value) != len(other) + + def __lt__(self, other): + other = self.prettyIn(other) + return len(self._value) < len(other) or len(self._value) == len(other) and self._value < other + + def __le__(self, other): + other = self.prettyIn(other) + return len(self._value) <= len(other) or len(self._value) == len(other) and self._value <= other + + def __gt__(self, other): + other = self.prettyIn(other) + return len(self._value) > len(other) or len(self._value) == len(other) and self._value > other + + def __ge__(self, other): + other = self.prettyIn(other) + return len(self._value) >= len(other) or len(self._value) == len(other) and self._value >= other + + # Immutable sequence object protocol + + def __len__(self): + return len(self._value) + + def __getitem__(self, i): + if i.__class__ is slice: + return self.clone([self[x] for x in range(*i.indices(len(self)))]) + else: + length = len(self._value) - 1 + if i > length or i < 0: + raise IndexError('bit index out of range') + return (self._value >> (length - i)) & 1 + + def __iter__(self): + length = len(self._value) + while length: + length -= 1 + yield (self._value >> length) & 1 + + def __reversed__(self): + return reversed(tuple(self)) + + # arithmetic operators + + def __add__(self, value): + value = self.prettyIn(value) + return self.clone(SizedInteger(self._value << len(value) | value).setBitLength(len(self._value) + len(value))) + + def __radd__(self, value): + value = self.prettyIn(value) + return self.clone(SizedInteger(value << len(self._value) | self._value).setBitLength(len(self._value) + len(value))) + + def __mul__(self, value): + bitString = self._value + while value > 1: + bitString <<= len(self._value) + bitString |= self._value + value -= 1 + return self.clone(bitString) + + def __rmul__(self, value): + return self * value + + def __lshift__(self, count): + return self.clone(SizedInteger(self._value << count).setBitLength(len(self._value) + count)) + + def __rshift__(self, count): + return self.clone(SizedInteger(self._value >> count).setBitLength(max(0, len(self._value) - count))) + + def __int__(self): + return int(self._value) + + def __float__(self): + return float(self._value) + + if sys.version_info[0] < 3: + def __long__(self): + return self._value + + def asNumbers(self): + """Get |ASN.1| value as a sequence of 8-bit integers. + + If |ASN.1| object length is not a multiple of 8, result + will be left-padded with zeros. + """ + return tuple(octets.octs2ints(self.asOctets())) + + def asOctets(self): + """Get |ASN.1| value as a sequence of octets. + + If |ASN.1| object length is not a multiple of 8, result + will be left-padded with zeros. + """ + return integer.to_bytes(self._value, length=len(self)) + + def asInteger(self): + """Get |ASN.1| value as a single integer value. + """ + return self._value + + def asBinary(self): + """Get |ASN.1| value as a text string of bits. + """ + binString = bin(self._value)[2:] + return '0' * (len(self._value) - len(binString)) + binString + + @classmethod + def fromHexString(cls, value, internalFormat=False, prepend=None): + """Create a |ASN.1| object initialized from the hex string. + + Parameters + ---------- + value: :class:`str` + Text string like 'DEADBEEF' + """ + try: + value = SizedInteger(value, 16).setBitLength(len(value) * 4) + + except ValueError: + raise error.PyAsn1Error('%s.fromHexString() error: %s' % (cls.__name__, sys.exc_info()[1])) + + if prepend is not None: + value = SizedInteger( + (SizedInteger(prepend) << len(value)) | value + ).setBitLength(len(prepend) + len(value)) + + if not internalFormat: + value = cls(value) + + return value + + @classmethod + def fromBinaryString(cls, value, internalFormat=False, prepend=None): + """Create a |ASN.1| object initialized from a string of '0' and '1'. + + Parameters + ---------- + value: :class:`str` + Text string like '1010111' + """ + try: + value = SizedInteger(value or '0', 2).setBitLength(len(value)) + + except ValueError: + raise error.PyAsn1Error('%s.fromBinaryString() error: %s' % (cls.__name__, sys.exc_info()[1])) + + if prepend is not None: + value = SizedInteger( + (SizedInteger(prepend) << len(value)) | value + ).setBitLength(len(prepend) + len(value)) + + if not internalFormat: + value = cls(value) + + return value + + @classmethod + def fromOctetString(cls, value, internalFormat=False, prepend=None, padding=0): + """Create a |ASN.1| object initialized from a string. + + Parameters + ---------- + value: :class:`str` (Py2) or :class:`bytes` (Py3) + Text string like '\\\\x01\\\\xff' (Py2) or b'\\\\x01\\\\xff' (Py3) + """ + value = SizedInteger(integer.from_bytes(value) >> padding).setBitLength(len(value) * 8 - padding) + + if prepend is not None: + value = SizedInteger( + (SizedInteger(prepend) << len(value)) | value + ).setBitLength(len(prepend) + len(value)) + + if not internalFormat: + value = cls(value) + + return value + + def prettyIn(self, value): + if isinstance(value, SizedInteger): + return value + elif octets.isStringType(value): + if not value: + return SizedInteger(0).setBitLength(0) + + elif value[0] == '\'': # "'1011'B" -- ASN.1 schema representation (deprecated) + if value[-2:] == '\'B': + return self.fromBinaryString(value[1:-2], internalFormat=True) + elif value[-2:] == '\'H': + return self.fromHexString(value[1:-2], internalFormat=True) + else: + raise error.PyAsn1Error( + 'Bad BIT STRING value notation %s' % (value,) + ) + + elif self.namedValues and not value.isdigit(): # named bits like 'Urgent, Active' + names = [x.strip() for x in value.split(',')] + + try: + + bitPositions = [self.namedValues[name] for name in names] + + except KeyError: + raise error.PyAsn1Error('unknown bit name(s) in %r' % (names,)) + + rightmostPosition = max(bitPositions) + + number = 0 + for bitPosition in bitPositions: + number |= 1 << (rightmostPosition - bitPosition) + + return SizedInteger(number).setBitLength(rightmostPosition + 1) + + elif value.startswith('0x'): + return self.fromHexString(value[2:], internalFormat=True) + + elif value.startswith('0b'): + return self.fromBinaryString(value[2:], internalFormat=True) + + else: # assume plain binary string like '1011' + return self.fromBinaryString(value, internalFormat=True) + + elif isinstance(value, (tuple, list)): + return self.fromBinaryString(''.join([b and '1' or '0' for b in value]), internalFormat=True) + + elif isinstance(value, BitString): + return SizedInteger(value).setBitLength(len(value)) + + elif isinstance(value, intTypes): + return SizedInteger(value) + + else: + raise error.PyAsn1Error( + 'Bad BitString initializer type \'%s\'' % (value,) + ) + + +class OctetString(base.SimpleAsn1Type): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its + objects are immutable and duck-type Python 2 :class:`str` or + Python 3 :class:`bytes`. When used in Unicode context, |ASN.1| type + assumes "|encoding|" serialisation. + + Keyword Args + ------------ + value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object + class:`str` (Python 2) or :class:`bytes` (Python 3), alternatively + class:`unicode` object (Python 2) or :class:`str` (Python 3) + representing character string to be serialised into octets + (note `encoding` parameter) or |ASN.1| object. + If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + encoding: :py:class:`str` + Unicode codec ID to encode/decode :class:`unicode` (Python 2) or + :class:`str` (Python 3) the payload when |ASN.1| object is used + in text string context. + + binValue: :py:class:`str` + Binary string initializer to use instead of the *value*. + Example: '10110011'. + + hexValue: :py:class:`str` + Hexadecimal string initializer to use instead of the *value*. + Example: 'DEADBEEF'. + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + .. code-block:: python + + class Icon(OctetString): + ''' + ASN.1 specification: + + Icon ::= OCTET STRING + + icon1 Icon ::= '001100010011001000110011'B + icon2 Icon ::= '313233'H + ''' + icon1 = Icon.fromBinaryString('001100010011001000110011') + icon2 = Icon.fromHexString('313233') + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x04) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Optimization for faster codec lookup + typeId = base.SimpleAsn1Type.getTypeId() + + defaultBinValue = defaultHexValue = noValue + encoding = 'iso-8859-1' + + def __init__(self, value=noValue, **kwargs): + if kwargs: + if value is noValue: + try: + value = self.fromBinaryString(kwargs.pop('binValue')) + + except KeyError: + pass + + try: + value = self.fromHexString(kwargs.pop('hexValue')) + + except KeyError: + pass + + if value is noValue: + if self.defaultBinValue is not noValue: + value = self.fromBinaryString(self.defaultBinValue) + + elif self.defaultHexValue is not noValue: + value = self.fromHexString(self.defaultHexValue) + + if 'encoding' not in kwargs: + kwargs['encoding'] = self.encoding + + base.SimpleAsn1Type.__init__(self, value, **kwargs) + + if sys.version_info[0] <= 2: + def prettyIn(self, value): + if isinstance(value, str): + return value + + elif isinstance(value, unicode): + try: + return value.encode(self.encoding) + + except (LookupError, UnicodeEncodeError): + exc = sys.exc_info()[1] + raise error.PyAsn1UnicodeEncodeError( + "Can't encode string '%s' with codec " + "%s" % (value, self.encoding), exc + ) + + elif isinstance(value, (tuple, list)): + try: + return ''.join([chr(x) for x in value]) + + except ValueError: + raise error.PyAsn1Error( + "Bad %s initializer '%s'" % (self.__class__.__name__, value) + ) + + else: + return str(value) + + def __str__(self): + return str(self._value) + + def __unicode__(self): + try: + return self._value.decode(self.encoding) + + except UnicodeDecodeError: + exc = sys.exc_info()[1] + raise error.PyAsn1UnicodeDecodeError( + "Can't decode string '%s' with codec " + "%s" % (self._value, self.encoding), exc + ) + + def asOctets(self): + return str(self._value) + + def asNumbers(self): + return tuple([ord(x) for x in self._value]) + + else: + def prettyIn(self, value): + if isinstance(value, bytes): + return value + + elif isinstance(value, str): + try: + return value.encode(self.encoding) + + except UnicodeEncodeError: + exc = sys.exc_info()[1] + raise error.PyAsn1UnicodeEncodeError( + "Can't encode string '%s' with '%s' " + "codec" % (value, self.encoding), exc + ) + elif isinstance(value, OctetString): # a shortcut, bytes() would work the same way + return value.asOctets() + + elif isinstance(value, base.SimpleAsn1Type): # this mostly targets Integer objects + return self.prettyIn(str(value)) + + elif isinstance(value, (tuple, list)): + return self.prettyIn(bytes(value)) + + else: + return bytes(value) + + def __str__(self): + try: + return self._value.decode(self.encoding) + + except UnicodeDecodeError: + exc = sys.exc_info()[1] + raise error.PyAsn1UnicodeDecodeError( + "Can't decode string '%s' with '%s' codec at " + "'%s'" % (self._value, self.encoding, + self.__class__.__name__), exc + ) + + def __bytes__(self): + return bytes(self._value) + + def asOctets(self): + return bytes(self._value) + + def asNumbers(self): + return tuple(self._value) + + # + # Normally, `.prettyPrint()` is called from `__str__()`. Historically, + # OctetString.prettyPrint() used to return hexified payload + # representation in cases when non-printable content is present. At the + # same time `str()` used to produce either octet-stream (Py2) or + # text (Py3) representations. + # + # Therefore `OctetString.__str__()` -> `.prettyPrint()` call chain is + # reversed to preserve the original behaviour. + # + # Eventually we should deprecate `.prettyPrint()` / `.prettyOut()` harness + # and end up with just `__str__()` producing hexified representation while + # both text and octet-stream representation should only be requested via + # the `.asOctets()` method. + # + # Note: ASN.1 OCTET STRING is never mean to contain text! + # + + def prettyOut(self, value): + return value + + def prettyPrint(self, scope=0): + # first see if subclass has its own .prettyOut() + value = self.prettyOut(self._value) + + if value is not self._value: + return value + + numbers = self.asNumbers() + + for x in numbers: + # hexify if needed + if x < 32 or x > 126: + return '0x' + ''.join(('%.2x' % x for x in numbers)) + else: + # this prevents infinite recursion + return OctetString.__str__(self) + + @staticmethod + def fromBinaryString(value): + """Create a |ASN.1| object initialized from a string of '0' and '1'. + + Parameters + ---------- + value: :class:`str` + Text string like '1010111' + """ + bitNo = 8 + byte = 0 + r = [] + for v in value: + if bitNo: + bitNo -= 1 + else: + bitNo = 7 + r.append(byte) + byte = 0 + if v in ('0', '1'): + v = int(v) + else: + raise error.PyAsn1Error( + 'Non-binary OCTET STRING initializer %s' % (v,) + ) + byte |= v << bitNo + + r.append(byte) + + return octets.ints2octs(r) + + @staticmethod + def fromHexString(value): + """Create a |ASN.1| object initialized from the hex string. + + Parameters + ---------- + value: :class:`str` + Text string like 'DEADBEEF' + """ + r = [] + p = [] + for v in value: + if p: + r.append(int(p + v, 16)) + p = None + else: + p = v + if p: + r.append(int(p + '0', 16)) + + return octets.ints2octs(r) + + # Immutable sequence object protocol + + def __len__(self): + return len(self._value) + + def __getitem__(self, i): + if i.__class__ is slice: + return self.clone(self._value[i]) + else: + return self._value[i] + + def __iter__(self): + return iter(self._value) + + def __contains__(self, value): + return value in self._value + + def __add__(self, value): + return self.clone(self._value + self.prettyIn(value)) + + def __radd__(self, value): + return self.clone(self.prettyIn(value) + self._value) + + def __mul__(self, value): + return self.clone(self._value * value) + + def __rmul__(self, value): + return self * value + + def __int__(self): + return int(self._value) + + def __float__(self): + return float(self._value) + + def __reversed__(self): + return reversed(self._value) + + +class Null(OctetString): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its + objects are immutable and duck-type Python :class:`str` objects + (always empty). + + Keyword Args + ------------ + value: :class:`str` or |ASN.1| object + Python empty :class:`str` literal or any object that evaluates to :obj:`False` + If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + .. code-block:: python + + class Ack(Null): + ''' + ASN.1 specification: + + Ack ::= NULL + ''' + ack = Ack('') + """ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x05) + ) + subtypeSpec = OctetString.subtypeSpec + constraint.SingleValueConstraint(octets.str2octs('')) + + # Optimization for faster codec lookup + typeId = OctetString.getTypeId() + + def prettyIn(self, value): + if value: + return value + + return octets.str2octs('') + +if sys.version_info[0] <= 2: + intTypes = (int, long) +else: + intTypes = (int,) + +numericTypes = intTypes + (float,) + + +class ObjectIdentifier(base.SimpleAsn1Type): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its + objects are immutable and duck-type Python :class:`tuple` objects + (tuple of non-negative integers). + + Keyword Args + ------------ + value: :class:`tuple`, :class:`str` or |ASN.1| object + Python sequence of :class:`int` or :class:`str` literal or |ASN.1| object. + If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + .. code-block:: python + + class ID(ObjectIdentifier): + ''' + ASN.1 specification: + + ID ::= OBJECT IDENTIFIER + + id-edims ID ::= { joint-iso-itu-t mhs-motif(6) edims(7) } + id-bp ID ::= { id-edims 11 } + ''' + id_edims = ID('2.6.7') + id_bp = id_edims + (11,) + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x06) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Optimization for faster codec lookup + typeId = base.SimpleAsn1Type.getTypeId() + + def __add__(self, other): + return self.clone(self._value + other) + + def __radd__(self, other): + return self.clone(other + self._value) + + def asTuple(self): + return self._value + + # Sequence object protocol + + def __len__(self): + return len(self._value) + + def __getitem__(self, i): + if i.__class__ is slice: + return self.clone(self._value[i]) + else: + return self._value[i] + + def __iter__(self): + return iter(self._value) + + def __contains__(self, value): + return value in self._value + + def index(self, suboid): + return self._value.index(suboid) + + def isPrefixOf(self, other): + """Indicate if this |ASN.1| object is a prefix of other |ASN.1| object. + + Parameters + ---------- + other: |ASN.1| object + |ASN.1| object + + Returns + ------- + : :class:`bool` + :obj:`True` if this |ASN.1| object is a parent (e.g. prefix) of the other |ASN.1| object + or :obj:`False` otherwise. + """ + l = len(self) + if l <= len(other): + if self._value[:l] == other[:l]: + return True + return False + + def prettyIn(self, value): + if isinstance(value, ObjectIdentifier): + return tuple(value) + elif octets.isStringType(value): + if '-' in value: + raise error.PyAsn1Error( + 'Malformed Object ID %s at %s: %s' % (value, self.__class__.__name__, sys.exc_info()[1]) + ) + try: + return tuple([int(subOid) for subOid in value.split('.') if subOid]) + except ValueError: + raise error.PyAsn1Error( + 'Malformed Object ID %s at %s: %s' % (value, self.__class__.__name__, sys.exc_info()[1]) + ) + + try: + tupleOfInts = tuple([int(subOid) for subOid in value if subOid >= 0]) + + except (ValueError, TypeError): + raise error.PyAsn1Error( + 'Malformed Object ID %s at %s: %s' % (value, self.__class__.__name__, sys.exc_info()[1]) + ) + + if len(tupleOfInts) == len(value): + return tupleOfInts + + raise error.PyAsn1Error('Malformed Object ID %s at %s' % (value, self.__class__.__name__)) + + def prettyOut(self, value): + return '.'.join([str(x) for x in value]) + + +class Real(base.SimpleAsn1Type): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its + objects are immutable and duck-type Python :class:`float` objects. + Additionally, |ASN.1| objects behave like a :class:`tuple` in which case its + elements are mantissa, base and exponent. + + Keyword Args + ------------ + value: :class:`tuple`, :class:`float` or |ASN.1| object + Python sequence of :class:`int` (representing mantissa, base and + exponent) or :class:`float` instance or |ASN.1| object. + If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + .. code-block:: python + + class Pi(Real): + ''' + ASN.1 specification: + + Pi ::= REAL + + pi Pi ::= { mantissa 314159, base 10, exponent -5 } + + ''' + pi = Pi((314159, 10, -5)) + """ + binEncBase = None # binEncBase = 16 is recommended for large numbers + + try: + _plusInf = float('inf') + _minusInf = float('-inf') + _inf = _plusInf, _minusInf + + except ValueError: + # Infinity support is platform and Python dependent + _plusInf = _minusInf = None + _inf = () + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x09) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Optimization for faster codec lookup + typeId = base.SimpleAsn1Type.getTypeId() + + @staticmethod + def __normalizeBase10(value): + m, b, e = value + while m and m % 10 == 0: + m /= 10 + e += 1 + return m, b, e + + def prettyIn(self, value): + if isinstance(value, tuple) and len(value) == 3: + if (not isinstance(value[0], numericTypes) or + not isinstance(value[1], intTypes) or + not isinstance(value[2], intTypes)): + raise error.PyAsn1Error('Lame Real value syntax: %s' % (value,)) + if (isinstance(value[0], float) and + self._inf and value[0] in self._inf): + return value[0] + if value[1] not in (2, 10): + raise error.PyAsn1Error( + 'Prohibited base for Real value: %s' % (value[1],) + ) + if value[1] == 10: + value = self.__normalizeBase10(value) + return value + elif isinstance(value, intTypes): + return self.__normalizeBase10((value, 10, 0)) + elif isinstance(value, float) or octets.isStringType(value): + if octets.isStringType(value): + try: + value = float(value) + except ValueError: + raise error.PyAsn1Error( + 'Bad real value syntax: %s' % (value,) + ) + if self._inf and value in self._inf: + return value + else: + e = 0 + while int(value) != value: + value *= 10 + e -= 1 + return self.__normalizeBase10((int(value), 10, e)) + elif isinstance(value, Real): + return tuple(value) + raise error.PyAsn1Error( + 'Bad real value syntax: %s' % (value,) + ) + + def prettyPrint(self, scope=0): + try: + return self.prettyOut(float(self)) + + except OverflowError: + return '' + + @property + def isPlusInf(self): + """Indicate PLUS-INFINITY object value + + Returns + ------- + : :class:`bool` + :obj:`True` if calling object represents plus infinity + or :obj:`False` otherwise. + + """ + return self._value == self._plusInf + + @property + def isMinusInf(self): + """Indicate MINUS-INFINITY object value + + Returns + ------- + : :class:`bool` + :obj:`True` if calling object represents minus infinity + or :obj:`False` otherwise. + """ + return self._value == self._minusInf + + @property + def isInf(self): + return self._value in self._inf + + def __add__(self, value): + return self.clone(float(self) + value) + + def __radd__(self, value): + return self + value + + def __mul__(self, value): + return self.clone(float(self) * value) + + def __rmul__(self, value): + return self * value + + def __sub__(self, value): + return self.clone(float(self) - value) + + def __rsub__(self, value): + return self.clone(value - float(self)) + + def __mod__(self, value): + return self.clone(float(self) % value) + + def __rmod__(self, value): + return self.clone(value % float(self)) + + def __pow__(self, value, modulo=None): + return self.clone(pow(float(self), value, modulo)) + + def __rpow__(self, value): + return self.clone(pow(value, float(self))) + + if sys.version_info[0] <= 2: + def __div__(self, value): + return self.clone(float(self) / value) + + def __rdiv__(self, value): + return self.clone(value / float(self)) + else: + def __truediv__(self, value): + return self.clone(float(self) / value) + + def __rtruediv__(self, value): + return self.clone(value / float(self)) + + def __divmod__(self, value): + return self.clone(float(self) // value) + + def __rdivmod__(self, value): + return self.clone(value // float(self)) + + def __int__(self): + return int(float(self)) + + if sys.version_info[0] <= 2: + def __long__(self): + return long(float(self)) + + def __float__(self): + if self._value in self._inf: + return self._value + else: + return float( + self._value[0] * pow(self._value[1], self._value[2]) + ) + + def __abs__(self): + return self.clone(abs(float(self))) + + def __pos__(self): + return self.clone(+float(self)) + + def __neg__(self): + return self.clone(-float(self)) + + def __round__(self, n=0): + r = round(float(self), n) + if n: + return self.clone(r) + else: + return r + + def __floor__(self): + return self.clone(math.floor(float(self))) + + def __ceil__(self): + return self.clone(math.ceil(float(self))) + + def __trunc__(self): + return self.clone(math.trunc(float(self))) + + def __lt__(self, value): + return float(self) < value + + def __le__(self, value): + return float(self) <= value + + def __eq__(self, value): + return float(self) == value + + def __ne__(self, value): + return float(self) != value + + def __gt__(self, value): + return float(self) > value + + def __ge__(self, value): + return float(self) >= value + + if sys.version_info[0] <= 2: + def __nonzero__(self): + return bool(float(self)) + else: + def __bool__(self): + return bool(float(self)) + + __hash__ = base.SimpleAsn1Type.__hash__ + + def __getitem__(self, idx): + if self._value in self._inf: + raise error.PyAsn1Error('Invalid infinite value operation') + else: + return self._value[idx] + + # compatibility stubs + + def isPlusInfinity(self): + return self.isPlusInf + + def isMinusInfinity(self): + return self.isMinusInf + + def isInfinity(self): + return self.isInf + + +class Enumerated(Integer): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its + objects are immutable and duck-type Python :class:`int` objects. + + Keyword Args + ------------ + value: :class:`int`, :class:`str` or |ASN.1| object + Python :class:`int` or :class:`str` literal or |ASN.1| object. + If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` + Object representing non-default symbolic aliases for numbers + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + + .. code-block:: python + + class RadioButton(Enumerated): + ''' + ASN.1 specification: + + RadioButton ::= ENUMERATED { button1(0), button2(1), + button3(2) } + + selected-by-default RadioButton ::= button1 + ''' + namedValues = NamedValues( + ('button1', 0), ('button2', 1), + ('button3', 2) + ) + + selected_by_default = RadioButton('button1') + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x0A) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Optimization for faster codec lookup + typeId = Integer.getTypeId() + + #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object + #: representing symbolic aliases for numbers + namedValues = namedval.NamedValues() + + +# "Structured" ASN.1 types + +class SequenceOfAndSetOfBase(base.ConstructedAsn1Type): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.ConstructedAsn1Type`, + its objects are mutable and duck-type Python :class:`list` objects. + + Keyword Args + ------------ + componentType : :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A pyasn1 object representing ASN.1 type allowed within |ASN.1| type + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type can only occur on explicit + `.isInconsistent` call. + + Examples + -------- + + .. code-block:: python + + class LotteryDraw(SequenceOf): # SetOf is similar + ''' + ASN.1 specification: + + LotteryDraw ::= SEQUENCE OF INTEGER + ''' + componentType = Integer() + + lotteryDraw = LotteryDraw() + lotteryDraw.extend([123, 456, 789]) + """ + def __init__(self, *args, **kwargs): + # support positional params for backward compatibility + if args: + for key, value in zip(('componentType', 'tagSet', + 'subtypeSpec'), args): + if key in kwargs: + raise error.PyAsn1Error('Conflicting positional and keyword params!') + kwargs['componentType'] = value + + self._componentValues = noValue + + base.ConstructedAsn1Type.__init__(self, **kwargs) + + # Python list protocol + + def __getitem__(self, idx): + try: + return self.getComponentByPosition(idx) + + except error.PyAsn1Error: + raise IndexError(sys.exc_info()[1]) + + def __setitem__(self, idx, value): + try: + self.setComponentByPosition(idx, value) + + except error.PyAsn1Error: + raise IndexError(sys.exc_info()[1]) + + def append(self, value): + if self._componentValues is noValue: + pos = 0 + + else: + pos = len(self._componentValues) + + self[pos] = value + + def count(self, value): + return list(self._componentValues.values()).count(value) + + def extend(self, values): + for value in values: + self.append(value) + + if self._componentValues is noValue: + self._componentValues = {} + + def index(self, value, start=0, stop=None): + if stop is None: + stop = len(self) + + indices, values = zip(*self._componentValues.items()) + + # TODO: remove when Py2.5 support is gone + values = list(values) + + try: + return indices[values.index(value, start, stop)] + + except error.PyAsn1Error: + raise ValueError(sys.exc_info()[1]) + + def reverse(self): + self._componentValues.reverse() + + def sort(self, key=None, reverse=False): + self._componentValues = dict( + enumerate(sorted(self._componentValues.values(), + key=key, reverse=reverse))) + + def __len__(self): + if self._componentValues is noValue or not self._componentValues: + return 0 + + return max(self._componentValues) + 1 + + def __iter__(self): + for idx in range(0, len(self)): + yield self.getComponentByPosition(idx) + + def _cloneComponentValues(self, myClone, cloneValueFlag): + for idx, componentValue in self._componentValues.items(): + if componentValue is not noValue: + if isinstance(componentValue, base.ConstructedAsn1Type): + myClone.setComponentByPosition( + idx, componentValue.clone(cloneValueFlag=cloneValueFlag) + ) + else: + myClone.setComponentByPosition(idx, componentValue.clone()) + + def getComponentByPosition(self, idx, default=noValue, instantiate=True): + """Return |ASN.1| type component value by position. + + Equivalent to Python sequence subscription operation (e.g. `[]`). + + Parameters + ---------- + idx : :class:`int` + Component index (zero-based). Must either refer to an existing + component or to N+1 component (if *componentType* is set). In the latter + case a new component type gets instantiated and appended to the |ASN.1| + sequence. + + Keyword Args + ------------ + default: :class:`object` + If set and requested component is a schema object, return the `default` + object instead of the requested component. + + instantiate: :class:`bool` + If :obj:`True` (default), inner component will be automatically instantiated. + If :obj:`False` either existing component or the :class:`NoValue` object will be + returned. + + Returns + ------- + : :py:class:`~pyasn1.type.base.PyAsn1Item` + Instantiate |ASN.1| component type or return existing component value + + Examples + -------- + + .. code-block:: python + + # can also be SetOf + class MySequenceOf(SequenceOf): + componentType = OctetString() + + s = MySequenceOf() + + # returns component #0 with `.isValue` property False + s.getComponentByPosition(0) + + # returns None + s.getComponentByPosition(0, default=None) + + s.clear() + + # returns noValue + s.getComponentByPosition(0, instantiate=False) + + # sets component #0 to OctetString() ASN.1 schema + # object and returns it + s.getComponentByPosition(0, instantiate=True) + + # sets component #0 to ASN.1 value object + s.setComponentByPosition(0, 'ABCD') + + # returns OctetString('ABCD') value object + s.getComponentByPosition(0, instantiate=False) + + s.clear() + + # returns noValue + s.getComponentByPosition(0, instantiate=False) + """ + if isinstance(idx, slice): + indices = tuple(range(len(self))) + return [self.getComponentByPosition(subidx, default, instantiate) + for subidx in indices[idx]] + + if idx < 0: + idx = len(self) + idx + if idx < 0: + raise error.PyAsn1Error( + 'SequenceOf/SetOf index is out of range') + + try: + componentValue = self._componentValues[idx] + + except (KeyError, error.PyAsn1Error): + if not instantiate: + return default + + self.setComponentByPosition(idx) + + componentValue = self._componentValues[idx] + + if default is noValue or componentValue.isValue: + return componentValue + else: + return default + + def setComponentByPosition(self, idx, value=noValue, + verifyConstraints=True, + matchTags=True, + matchConstraints=True): + """Assign |ASN.1| type component by position. + + Equivalent to Python sequence item assignment operation (e.g. `[]`) + or list.append() (when idx == len(self)). + + Parameters + ---------- + idx: :class:`int` + Component index (zero-based). Must either refer to existing + component or to N+1 component. In the latter case a new component + type gets instantiated (if *componentType* is set, or given ASN.1 + object is taken otherwise) and appended to the |ASN.1| sequence. + + Keyword Args + ------------ + value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A Python value to initialize |ASN.1| component with (if *componentType* is set) + or ASN.1 value object to assign to |ASN.1| component. + If `value` is not given, schema object will be set as a component. + + verifyConstraints: :class:`bool` + If :obj:`False`, skip constraints validation + + matchTags: :class:`bool` + If :obj:`False`, skip component tags matching + + matchConstraints: :class:`bool` + If :obj:`False`, skip component constraints matching + + Returns + ------- + self + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer + IndexError + When idx > len(self) + """ + if isinstance(idx, slice): + indices = tuple(range(len(self))) + startIdx = indices and indices[idx][0] or 0 + for subIdx, subValue in enumerate(value): + self.setComponentByPosition( + startIdx + subIdx, subValue, verifyConstraints, + matchTags, matchConstraints) + return self + + if idx < 0: + idx = len(self) + idx + if idx < 0: + raise error.PyAsn1Error( + 'SequenceOf/SetOf index is out of range') + + componentType = self.componentType + + if self._componentValues is noValue: + componentValues = {} + + else: + componentValues = self._componentValues + + currentValue = componentValues.get(idx, noValue) + + if value is noValue: + if componentType is not None: + value = componentType.clone() + + elif currentValue is noValue: + raise error.PyAsn1Error('Component type not defined') + + elif not isinstance(value, base.Asn1Item): + if (componentType is not None and + isinstance(componentType, base.SimpleAsn1Type)): + value = componentType.clone(value=value) + + elif (currentValue is not noValue and + isinstance(currentValue, base.SimpleAsn1Type)): + value = currentValue.clone(value=value) + + else: + raise error.PyAsn1Error( + 'Non-ASN.1 value %r and undefined component' + ' type at %r' % (value, self)) + + elif componentType is not None and (matchTags or matchConstraints): + subtypeChecker = ( + self.strictConstraints and + componentType.isSameTypeWith or + componentType.isSuperTypeOf) + + if not subtypeChecker(value, verifyConstraints and matchTags, + verifyConstraints and matchConstraints): + # TODO: we should wrap componentType with UnnamedType to carry + # additional properties associated with componentType + if componentType.typeId != Any.typeId: + raise error.PyAsn1Error( + 'Component value is tag-incompatible: %r vs ' + '%r' % (value, componentType)) + + componentValues[idx] = value + + self._componentValues = componentValues + + return self + + @property + def componentTagMap(self): + if self.componentType is not None: + return self.componentType.tagMap + + @property + def components(self): + return [self._componentValues[idx] + for idx in sorted(self._componentValues)] + + def clear(self): + """Remove all components and become an empty |ASN.1| value object. + + Has the same effect on |ASN.1| object as it does on :class:`list` + built-in. + """ + self._componentValues = {} + return self + + def reset(self): + """Remove all components and become a |ASN.1| schema object. + + See :meth:`isValue` property for more information on the + distinction between value and schema objects. + """ + self._componentValues = noValue + return self + + def prettyPrint(self, scope=0): + scope += 1 + representation = self.__class__.__name__ + ':\n' + + if not self.isValue: + return representation + + for idx, componentValue in enumerate(self): + representation += ' ' * scope + if (componentValue is noValue and + self.componentType is not None): + representation += '' + else: + representation += componentValue.prettyPrint(scope) + + return representation + + def prettyPrintType(self, scope=0): + scope += 1 + representation = '%s -> %s {\n' % (self.tagSet, self.__class__.__name__) + if self.componentType is not None: + representation += ' ' * scope + representation += self.componentType.prettyPrintType(scope) + return representation + '\n' + ' ' * (scope - 1) + '}' + + + @property + def isValue(self): + """Indicate that |ASN.1| object represents ASN.1 value. + + If *isValue* is :obj:`False` then this object represents just ASN.1 schema. + + If *isValue* is :obj:`True` then, in addition to its ASN.1 schema features, + this object can also be used like a Python built-in object + (e.g. :class:`int`, :class:`str`, :class:`dict` etc.). + + Returns + ------- + : :class:`bool` + :obj:`False` if object represents just ASN.1 schema. + :obj:`True` if object represents ASN.1 schema and can be used as a normal value. + + Note + ---- + There is an important distinction between PyASN1 schema and value objects. + The PyASN1 schema objects can only participate in ASN.1 schema-related + operations (e.g. defining or testing the structure of the data). Most + obvious uses of ASN.1 schema is to guide serialisation codecs whilst + encoding/decoding serialised ASN.1 contents. + + The PyASN1 value objects can **additionally** participate in many operations + involving regular Python objects (e.g. arithmetic, comprehension etc). + """ + if self._componentValues is noValue: + return False + + if len(self._componentValues) != len(self): + return False + + for componentValue in self._componentValues.values(): + if componentValue is noValue or not componentValue.isValue: + return False + + return True + + @property + def isInconsistent(self): + """Run necessary checks to ensure |ASN.1| object consistency. + + Default action is to verify |ASN.1| object against constraints imposed + by `subtypeSpec`. + + Raises + ------ + :py:class:`~pyasn1.error.PyAsn1tError` on any inconsistencies found + """ + if self.componentType is noValue or not self.subtypeSpec: + return False + + if self._componentValues is noValue: + return True + + mapping = {} + + for idx, value in self._componentValues.items(): + # Absent fields are not in the mapping + if value is noValue: + continue + + mapping[idx] = value + + try: + # Represent SequenceOf/SetOf as a bare dict to constraints chain + self.subtypeSpec(mapping) + + except error.PyAsn1Error: + exc = sys.exc_info()[1] + return exc + + return False + +class SequenceOf(SequenceOfAndSetOfBase): + __doc__ = SequenceOfAndSetOfBase.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10) + ) + + #: Default :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + #: object representing ASN.1 type allowed within |ASN.1| type + componentType = None + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Disambiguation ASN.1 types identification + typeId = SequenceOfAndSetOfBase.getTypeId() + + +class SetOf(SequenceOfAndSetOfBase): + __doc__ = SequenceOfAndSetOfBase.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) + ) + + #: Default :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + #: object representing ASN.1 type allowed within |ASN.1| type + componentType = None + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Disambiguation ASN.1 types identification + typeId = SequenceOfAndSetOfBase.getTypeId() + + +class SequenceAndSetBase(base.ConstructedAsn1Type): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.ConstructedAsn1Type`, + its objects are mutable and duck-type Python :class:`dict` objects. + + Keyword Args + ------------ + componentType: :py:class:`~pyasn1.type.namedtype.NamedType` + Object holding named ASN.1 types allowed within this collection + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type can only occur on explicit + `.isInconsistent` call. + + Examples + -------- + + .. code-block:: python + + class Description(Sequence): # Set is similar + ''' + ASN.1 specification: + + Description ::= SEQUENCE { + surname IA5String, + first-name IA5String OPTIONAL, + age INTEGER DEFAULT 40 + } + ''' + componentType = NamedTypes( + NamedType('surname', IA5String()), + OptionalNamedType('first-name', IA5String()), + DefaultedNamedType('age', Integer(40)) + ) + + descr = Description() + descr['surname'] = 'Smith' + descr['first-name'] = 'John' + """ + #: Default :py:class:`~pyasn1.type.namedtype.NamedTypes` + #: object representing named ASN.1 types allowed within |ASN.1| type + componentType = namedtype.NamedTypes() + + + class DynamicNames(object): + """Fields names/positions mapping for component-less objects""" + def __init__(self): + self._keyToIdxMap = {} + self._idxToKeyMap = {} + + def __len__(self): + return len(self._keyToIdxMap) + + def __contains__(self, item): + return item in self._keyToIdxMap or item in self._idxToKeyMap + + def __iter__(self): + return (self._idxToKeyMap[idx] for idx in range(len(self._idxToKeyMap))) + + def __getitem__(self, item): + try: + return self._keyToIdxMap[item] + + except KeyError: + return self._idxToKeyMap[item] + + def getNameByPosition(self, idx): + try: + return self._idxToKeyMap[idx] + + except KeyError: + raise error.PyAsn1Error('Type position out of range') + + def getPositionByName(self, name): + try: + return self._keyToIdxMap[name] + + except KeyError: + raise error.PyAsn1Error('Name %s not found' % (name,)) + + def addField(self, idx): + self._keyToIdxMap['field-%d' % idx] = idx + self._idxToKeyMap[idx] = 'field-%d' % idx + + + def __init__(self, **kwargs): + base.ConstructedAsn1Type.__init__(self, **kwargs) + self._componentTypeLen = len(self.componentType) + if self._componentTypeLen: + self._componentValues = [] + else: + self._componentValues = noValue + self._dynamicNames = self._componentTypeLen or self.DynamicNames() + + def __getitem__(self, idx): + if octets.isStringType(idx): + try: + return self.getComponentByName(idx) + + except error.PyAsn1Error: + # duck-typing dict + raise KeyError(sys.exc_info()[1]) + + else: + try: + return self.getComponentByPosition(idx) + + except error.PyAsn1Error: + # duck-typing list + raise IndexError(sys.exc_info()[1]) + + def __setitem__(self, idx, value): + if octets.isStringType(idx): + try: + self.setComponentByName(idx, value) + + except error.PyAsn1Error: + # duck-typing dict + raise KeyError(sys.exc_info()[1]) + + else: + try: + self.setComponentByPosition(idx, value) + + except error.PyAsn1Error: + # duck-typing list + raise IndexError(sys.exc_info()[1]) + + def __contains__(self, key): + if self._componentTypeLen: + return key in self.componentType + else: + return key in self._dynamicNames + + def __len__(self): + return len(self._componentValues) + + def __iter__(self): + return iter(self.componentType or self._dynamicNames) + + # Python dict protocol + + def values(self): + for idx in range(self._componentTypeLen or len(self._dynamicNames)): + yield self[idx] + + def keys(self): + return iter(self) + + def items(self): + for idx in range(self._componentTypeLen or len(self._dynamicNames)): + if self._componentTypeLen: + yield self.componentType[idx].name, self[idx] + else: + yield self._dynamicNames[idx], self[idx] + + def update(self, *iterValue, **mappingValue): + for k, v in iterValue: + self[k] = v + for k in mappingValue: + self[k] = mappingValue[k] + + def clear(self): + """Remove all components and become an empty |ASN.1| value object. + + Has the same effect on |ASN.1| object as it does on :class:`dict` + built-in. + """ + self._componentValues = [] + self._dynamicNames = self.DynamicNames() + return self + + def reset(self): + """Remove all components and become a |ASN.1| schema object. + + See :meth:`isValue` property for more information on the + distinction between value and schema objects. + """ + self._componentValues = noValue + self._dynamicNames = self.DynamicNames() + return self + + @property + def components(self): + return self._componentValues + + def _cloneComponentValues(self, myClone, cloneValueFlag): + if self._componentValues is noValue: + return + + for idx, componentValue in enumerate(self._componentValues): + if componentValue is not noValue: + if isinstance(componentValue, base.ConstructedAsn1Type): + myClone.setComponentByPosition( + idx, componentValue.clone(cloneValueFlag=cloneValueFlag) + ) + else: + myClone.setComponentByPosition(idx, componentValue.clone()) + + def getComponentByName(self, name, default=noValue, instantiate=True): + """Returns |ASN.1| type component by name. + + Equivalent to Python :class:`dict` subscription operation (e.g. `[]`). + + Parameters + ---------- + name: :class:`str` + |ASN.1| type component name + + Keyword Args + ------------ + default: :class:`object` + If set and requested component is a schema object, return the `default` + object instead of the requested component. + + instantiate: :class:`bool` + If :obj:`True` (default), inner component will be automatically + instantiated. + If :obj:`False` either existing component or the :class:`NoValue` + object will be returned. + + Returns + ------- + : :py:class:`~pyasn1.type.base.PyAsn1Item` + Instantiate |ASN.1| component type or return existing + component value + """ + if self._componentTypeLen: + idx = self.componentType.getPositionByName(name) + else: + try: + idx = self._dynamicNames.getPositionByName(name) + + except KeyError: + raise error.PyAsn1Error('Name %s not found' % (name,)) + + return self.getComponentByPosition(idx, default=default, instantiate=instantiate) + + def setComponentByName(self, name, value=noValue, + verifyConstraints=True, + matchTags=True, + matchConstraints=True): + """Assign |ASN.1| type component by name. + + Equivalent to Python :class:`dict` item assignment operation (e.g. `[]`). + + Parameters + ---------- + name: :class:`str` + |ASN.1| type component name + + Keyword Args + ------------ + value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A Python value to initialize |ASN.1| component with (if *componentType* is set) + or ASN.1 value object to assign to |ASN.1| component. + If `value` is not given, schema object will be set as a component. + + verifyConstraints: :class:`bool` + If :obj:`False`, skip constraints validation + + matchTags: :class:`bool` + If :obj:`False`, skip component tags matching + + matchConstraints: :class:`bool` + If :obj:`False`, skip component constraints matching + + Returns + ------- + self + """ + if self._componentTypeLen: + idx = self.componentType.getPositionByName(name) + else: + try: + idx = self._dynamicNames.getPositionByName(name) + + except KeyError: + raise error.PyAsn1Error('Name %s not found' % (name,)) + + return self.setComponentByPosition( + idx, value, verifyConstraints, matchTags, matchConstraints + ) + + def getComponentByPosition(self, idx, default=noValue, instantiate=True): + """Returns |ASN.1| type component by index. + + Equivalent to Python sequence subscription operation (e.g. `[]`). + + Parameters + ---------- + idx: :class:`int` + Component index (zero-based). Must either refer to an existing + component or (if *componentType* is set) new ASN.1 schema object gets + instantiated. + + Keyword Args + ------------ + default: :class:`object` + If set and requested component is a schema object, return the `default` + object instead of the requested component. + + instantiate: :class:`bool` + If :obj:`True` (default), inner component will be automatically + instantiated. + If :obj:`False` either existing component or the :class:`NoValue` + object will be returned. + + Returns + ------- + : :py:class:`~pyasn1.type.base.PyAsn1Item` + a PyASN1 object + + Examples + -------- + + .. code-block:: python + + # can also be Set + class MySequence(Sequence): + componentType = NamedTypes( + NamedType('id', OctetString()) + ) + + s = MySequence() + + # returns component #0 with `.isValue` property False + s.getComponentByPosition(0) + + # returns None + s.getComponentByPosition(0, default=None) + + s.clear() + + # returns noValue + s.getComponentByPosition(0, instantiate=False) + + # sets component #0 to OctetString() ASN.1 schema + # object and returns it + s.getComponentByPosition(0, instantiate=True) + + # sets component #0 to ASN.1 value object + s.setComponentByPosition(0, 'ABCD') + + # returns OctetString('ABCD') value object + s.getComponentByPosition(0, instantiate=False) + + s.clear() + + # returns noValue + s.getComponentByPosition(0, instantiate=False) + """ + try: + if self._componentValues is noValue: + componentValue = noValue + + else: + componentValue = self._componentValues[idx] + + except IndexError: + componentValue = noValue + + if not instantiate: + if componentValue is noValue or not componentValue.isValue: + return default + else: + return componentValue + + if componentValue is noValue: + self.setComponentByPosition(idx) + + componentValue = self._componentValues[idx] + + if default is noValue or componentValue.isValue: + return componentValue + else: + return default + + def setComponentByPosition(self, idx, value=noValue, + verifyConstraints=True, + matchTags=True, + matchConstraints=True): + """Assign |ASN.1| type component by position. + + Equivalent to Python sequence item assignment operation (e.g. `[]`). + + Parameters + ---------- + idx : :class:`int` + Component index (zero-based). Must either refer to existing + component (if *componentType* is set) or to N+1 component + otherwise. In the latter case a new component of given ASN.1 + type gets instantiated and appended to |ASN.1| sequence. + + Keyword Args + ------------ + value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A Python value to initialize |ASN.1| component with (if *componentType* is set) + or ASN.1 value object to assign to |ASN.1| component. + If `value` is not given, schema object will be set as a component. + + verifyConstraints : :class:`bool` + If :obj:`False`, skip constraints validation + + matchTags: :class:`bool` + If :obj:`False`, skip component tags matching + + matchConstraints: :class:`bool` + If :obj:`False`, skip component constraints matching + + Returns + ------- + self + """ + componentType = self.componentType + componentTypeLen = self._componentTypeLen + + if self._componentValues is noValue: + componentValues = [] + + else: + componentValues = self._componentValues + + try: + currentValue = componentValues[idx] + + except IndexError: + currentValue = noValue + if componentTypeLen: + if componentTypeLen < idx: + raise error.PyAsn1Error('component index out of range') + + componentValues = [noValue] * componentTypeLen + + if value is noValue: + if componentTypeLen: + value = componentType.getTypeByPosition(idx) + if isinstance(value, base.ConstructedAsn1Type): + value = value.clone(cloneValueFlag=componentType[idx].isDefaulted) + + elif currentValue is noValue: + raise error.PyAsn1Error('Component type not defined') + + elif not isinstance(value, base.Asn1Item): + if componentTypeLen: + subComponentType = componentType.getTypeByPosition(idx) + if isinstance(subComponentType, base.SimpleAsn1Type): + value = subComponentType.clone(value=value) + + else: + raise error.PyAsn1Error('%s can cast only scalar values' % componentType.__class__.__name__) + + elif currentValue is not noValue and isinstance(currentValue, base.SimpleAsn1Type): + value = currentValue.clone(value=value) + + else: + raise error.PyAsn1Error('%s undefined component type' % componentType.__class__.__name__) + + elif ((verifyConstraints or matchTags or matchConstraints) and + componentTypeLen): + subComponentType = componentType.getTypeByPosition(idx) + if subComponentType is not noValue: + subtypeChecker = (self.strictConstraints and + subComponentType.isSameTypeWith or + subComponentType.isSuperTypeOf) + + if not subtypeChecker(value, verifyConstraints and matchTags, + verifyConstraints and matchConstraints): + if not componentType[idx].openType: + raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType)) + + if componentTypeLen or idx in self._dynamicNames: + componentValues[idx] = value + + elif len(componentValues) == idx: + componentValues.append(value) + self._dynamicNames.addField(idx) + + else: + raise error.PyAsn1Error('Component index out of range') + + self._componentValues = componentValues + + return self + + @property + def isValue(self): + """Indicate that |ASN.1| object represents ASN.1 value. + + If *isValue* is :obj:`False` then this object represents just ASN.1 schema. + + If *isValue* is :obj:`True` then, in addition to its ASN.1 schema features, + this object can also be used like a Python built-in object (e.g. + :class:`int`, :class:`str`, :class:`dict` etc.). + + Returns + ------- + : :class:`bool` + :obj:`False` if object represents just ASN.1 schema. + :obj:`True` if object represents ASN.1 schema and can be used as a + normal value. + + Note + ---- + There is an important distinction between PyASN1 schema and value objects. + The PyASN1 schema objects can only participate in ASN.1 schema-related + operations (e.g. defining or testing the structure of the data). Most + obvious uses of ASN.1 schema is to guide serialisation codecs whilst + encoding/decoding serialised ASN.1 contents. + + The PyASN1 value objects can **additionally** participate in many operations + involving regular Python objects (e.g. arithmetic, comprehension etc). + + It is sufficient for |ASN.1| objects to have all non-optional and non-defaulted + components being value objects to be considered as a value objects as a whole. + In other words, even having one or more optional components not turned into + value objects, |ASN.1| object is still considered as a value object. Defaulted + components are normally value objects by default. + """ + if self._componentValues is noValue: + return False + + componentType = self.componentType + + if componentType: + for idx, subComponentType in enumerate(componentType.namedTypes): + if subComponentType.isDefaulted or subComponentType.isOptional: + continue + + if not self._componentValues: + return False + + componentValue = self._componentValues[idx] + if componentValue is noValue or not componentValue.isValue: + return False + + else: + for componentValue in self._componentValues: + if componentValue is noValue or not componentValue.isValue: + return False + + return True + + @property + def isInconsistent(self): + """Run necessary checks to ensure |ASN.1| object consistency. + + Default action is to verify |ASN.1| object against constraints imposed + by `subtypeSpec`. + + Raises + ------ + :py:class:`~pyasn1.error.PyAsn1tError` on any inconsistencies found + """ + if self.componentType is noValue or not self.subtypeSpec: + return False + + if self._componentValues is noValue: + return True + + mapping = {} + + for idx, value in enumerate(self._componentValues): + # Absent fields are not in the mapping + if value is noValue: + continue + + name = self.componentType.getNameByPosition(idx) + + mapping[name] = value + + try: + # Represent Sequence/Set as a bare dict to constraints chain + self.subtypeSpec(mapping) + + except error.PyAsn1Error: + exc = sys.exc_info()[1] + return exc + + return False + + def prettyPrint(self, scope=0): + """Return an object representation string. + + Returns + ------- + : :class:`str` + Human-friendly object representation. + """ + scope += 1 + representation = self.__class__.__name__ + ':\n' + for idx, componentValue in enumerate(self._componentValues): + if componentValue is not noValue and componentValue.isValue: + representation += ' ' * scope + if self.componentType: + representation += self.componentType.getNameByPosition(idx) + else: + representation += self._dynamicNames.getNameByPosition(idx) + representation = '%s=%s\n' % ( + representation, componentValue.prettyPrint(scope) + ) + return representation + + def prettyPrintType(self, scope=0): + scope += 1 + representation = '%s -> %s {\n' % (self.tagSet, self.__class__.__name__) + for idx, componentType in enumerate(self.componentType.values() or self._componentValues): + representation += ' ' * scope + if self.componentType: + representation += '"%s"' % self.componentType.getNameByPosition(idx) + else: + representation += '"%s"' % self._dynamicNames.getNameByPosition(idx) + representation = '%s = %s\n' % ( + representation, componentType.prettyPrintType(scope) + ) + return representation + '\n' + ' ' * (scope - 1) + '}' + + # backward compatibility + + def setDefaultComponents(self): + return self + + def getComponentType(self): + if self._componentTypeLen: + return self.componentType + + def getNameByPosition(self, idx): + if self._componentTypeLen: + return self.componentType[idx].name + +class Sequence(SequenceAndSetBase): + __doc__ = SequenceAndSetBase.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + #: Default collection of ASN.1 types of component (e.g. :py:class:`~pyasn1.type.namedtype.NamedType`) + #: object imposing size constraint on |ASN.1| objects + componentType = namedtype.NamedTypes() + + # Disambiguation ASN.1 types identification + typeId = SequenceAndSetBase.getTypeId() + + # backward compatibility + + def getComponentTagMapNearPosition(self, idx): + if self.componentType: + return self.componentType.getTagMapNearPosition(idx) + + def getComponentPositionNearType(self, tagSet, idx): + if self.componentType: + return self.componentType.getPositionNearType(tagSet, idx) + else: + return idx + + +class Set(SequenceAndSetBase): + __doc__ = SequenceAndSetBase.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) + ) + + #: Default collection of ASN.1 types of component (e.g. :py:class:`~pyasn1.type.namedtype.NamedType`) + #: object representing ASN.1 type allowed within |ASN.1| type + componentType = namedtype.NamedTypes() + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Disambiguation ASN.1 types identification + typeId = SequenceAndSetBase.getTypeId() + + def getComponent(self, innerFlag=False): + return self + + def getComponentByType(self, tagSet, default=noValue, + instantiate=True, innerFlag=False): + """Returns |ASN.1| type component by ASN.1 tag. + + Parameters + ---------- + tagSet : :py:class:`~pyasn1.type.tag.TagSet` + Object representing ASN.1 tags to identify one of + |ASN.1| object component + + Keyword Args + ------------ + default: :class:`object` + If set and requested component is a schema object, return the `default` + object instead of the requested component. + + instantiate: :class:`bool` + If :obj:`True` (default), inner component will be automatically + instantiated. + If :obj:`False` either existing component or the :class:`noValue` + object will be returned. + + Returns + ------- + : :py:class:`~pyasn1.type.base.PyAsn1Item` + a pyasn1 object + """ + componentValue = self.getComponentByPosition( + self.componentType.getPositionByType(tagSet), + default=default, instantiate=instantiate + ) + if innerFlag and isinstance(componentValue, Set): + # get inner component by inner tagSet + return componentValue.getComponent(innerFlag=True) + else: + # get outer component by inner tagSet + return componentValue + + def setComponentByType(self, tagSet, value=noValue, + verifyConstraints=True, + matchTags=True, + matchConstraints=True, + innerFlag=False): + """Assign |ASN.1| type component by ASN.1 tag. + + Parameters + ---------- + tagSet : :py:class:`~pyasn1.type.tag.TagSet` + Object representing ASN.1 tags to identify one of + |ASN.1| object component + + Keyword Args + ------------ + value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A Python value to initialize |ASN.1| component with (if *componentType* is set) + or ASN.1 value object to assign to |ASN.1| component. + If `value` is not given, schema object will be set as a component. + + verifyConstraints : :class:`bool` + If :obj:`False`, skip constraints validation + + matchTags: :class:`bool` + If :obj:`False`, skip component tags matching + + matchConstraints: :class:`bool` + If :obj:`False`, skip component constraints matching + + innerFlag: :class:`bool` + If :obj:`True`, search for matching *tagSet* recursively. + + Returns + ------- + self + """ + idx = self.componentType.getPositionByType(tagSet) + + if innerFlag: # set inner component by inner tagSet + componentType = self.componentType.getTypeByPosition(idx) + + if componentType.tagSet: + return self.setComponentByPosition( + idx, value, verifyConstraints, matchTags, matchConstraints + ) + else: + componentType = self.getComponentByPosition(idx) + return componentType.setComponentByType( + tagSet, value, verifyConstraints, matchTags, matchConstraints, innerFlag=innerFlag + ) + else: # set outer component by inner tagSet + return self.setComponentByPosition( + idx, value, verifyConstraints, matchTags, matchConstraints + ) + + @property + def componentTagMap(self): + if self.componentType: + return self.componentType.tagMapUnique + + +class Choice(Set): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.ConstructedAsn1Type`, + its objects are mutable and duck-type Python :class:`list` objects. + + Keyword Args + ------------ + componentType: :py:class:`~pyasn1.type.namedtype.NamedType` + Object holding named ASN.1 types allowed within this collection + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type can only occur on explicit + `.isInconsistent` call. + + Examples + -------- + + .. code-block:: python + + class Afters(Choice): + ''' + ASN.1 specification: + + Afters ::= CHOICE { + cheese [0] IA5String, + dessert [1] IA5String + } + ''' + componentType = NamedTypes( + NamedType('cheese', IA5String().subtype( + implicitTag=Tag(tagClassContext, tagFormatSimple, 0) + ), + NamedType('dessert', IA5String().subtype( + implicitTag=Tag(tagClassContext, tagFormatSimple, 1) + ) + ) + + afters = Afters() + afters['cheese'] = 'Mascarpone' + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.TagSet() # untagged + + #: Default collection of ASN.1 types of component (e.g. :py:class:`~pyasn1.type.namedtype.NamedType`) + #: object representing ASN.1 type allowed within |ASN.1| type + componentType = namedtype.NamedTypes() + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection( + constraint.ValueSizeConstraint(1, 1) + ) + + # Disambiguation ASN.1 types identification + typeId = Set.getTypeId() + + _currentIdx = None + + def __eq__(self, other): + if self._componentValues: + return self._componentValues[self._currentIdx] == other + return NotImplemented + + def __ne__(self, other): + if self._componentValues: + return self._componentValues[self._currentIdx] != other + return NotImplemented + + def __lt__(self, other): + if self._componentValues: + return self._componentValues[self._currentIdx] < other + return NotImplemented + + def __le__(self, other): + if self._componentValues: + return self._componentValues[self._currentIdx] <= other + return NotImplemented + + def __gt__(self, other): + if self._componentValues: + return self._componentValues[self._currentIdx] > other + return NotImplemented + + def __ge__(self, other): + if self._componentValues: + return self._componentValues[self._currentIdx] >= other + return NotImplemented + + if sys.version_info[0] <= 2: + def __nonzero__(self): + return self._componentValues and True or False + else: + def __bool__(self): + return self._componentValues and True or False + + def __len__(self): + return self._currentIdx is not None and 1 or 0 + + def __contains__(self, key): + if self._currentIdx is None: + return False + return key == self.componentType[self._currentIdx].getName() + + def __iter__(self): + if self._currentIdx is None: + raise StopIteration + yield self.componentType[self._currentIdx].getName() + + # Python dict protocol + + def values(self): + if self._currentIdx is not None: + yield self._componentValues[self._currentIdx] + + def keys(self): + if self._currentIdx is not None: + yield self.componentType[self._currentIdx].getName() + + def items(self): + if self._currentIdx is not None: + yield self.componentType[self._currentIdx].getName(), self[self._currentIdx] + + def checkConsistency(self): + if self._currentIdx is None: + raise error.PyAsn1Error('Component not chosen') + + def _cloneComponentValues(self, myClone, cloneValueFlag): + try: + component = self.getComponent() + except error.PyAsn1Error: + pass + else: + if isinstance(component, Choice): + tagSet = component.effectiveTagSet + else: + tagSet = component.tagSet + if isinstance(component, base.ConstructedAsn1Type): + myClone.setComponentByType( + tagSet, component.clone(cloneValueFlag=cloneValueFlag) + ) + else: + myClone.setComponentByType(tagSet, component.clone()) + + def getComponentByPosition(self, idx, default=noValue, instantiate=True): + __doc__ = Set.__doc__ + + if self._currentIdx is None or self._currentIdx != idx: + return Set.getComponentByPosition(self, idx, default=default, + instantiate=instantiate) + + return self._componentValues[idx] + + def setComponentByPosition(self, idx, value=noValue, + verifyConstraints=True, + matchTags=True, + matchConstraints=True): + """Assign |ASN.1| type component by position. + + Equivalent to Python sequence item assignment operation (e.g. `[]`). + + Parameters + ---------- + idx: :class:`int` + Component index (zero-based). Must either refer to existing + component or to N+1 component. In the latter case a new component + type gets instantiated (if *componentType* is set, or given ASN.1 + object is taken otherwise) and appended to the |ASN.1| sequence. + + Keyword Args + ------------ + value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A Python value to initialize |ASN.1| component with (if *componentType* is set) + or ASN.1 value object to assign to |ASN.1| component. Once a new value is + set to *idx* component, previous value is dropped. + If `value` is not given, schema object will be set as a component. + + verifyConstraints : :class:`bool` + If :obj:`False`, skip constraints validation + + matchTags: :class:`bool` + If :obj:`False`, skip component tags matching + + matchConstraints: :class:`bool` + If :obj:`False`, skip component constraints matching + + Returns + ------- + self + """ + oldIdx = self._currentIdx + Set.setComponentByPosition(self, idx, value, verifyConstraints, matchTags, matchConstraints) + self._currentIdx = idx + if oldIdx is not None and oldIdx != idx: + self._componentValues[oldIdx] = noValue + return self + + @property + def effectiveTagSet(self): + """Return a :class:`~pyasn1.type.tag.TagSet` object of the currently initialized component or self (if |ASN.1| is tagged).""" + if self.tagSet: + return self.tagSet + else: + component = self.getComponent() + return component.effectiveTagSet + + @property + def tagMap(self): + """"Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping + ASN.1 tags to ASN.1 objects contained within callee. + """ + if self.tagSet: + return Set.tagMap.fget(self) + else: + return self.componentType.tagMapUnique + + def getComponent(self, innerFlag=False): + """Return currently assigned component of the |ASN.1| object. + + Returns + ------- + : :py:class:`~pyasn1.type.base.PyAsn1Item` + a PyASN1 object + """ + if self._currentIdx is None: + raise error.PyAsn1Error('Component not chosen') + else: + c = self._componentValues[self._currentIdx] + if innerFlag and isinstance(c, Choice): + return c.getComponent(innerFlag) + else: + return c + + def getName(self, innerFlag=False): + """Return the name of currently assigned component of the |ASN.1| object. + + Returns + ------- + : :py:class:`str` + |ASN.1| component name + """ + if self._currentIdx is None: + raise error.PyAsn1Error('Component not chosen') + else: + if innerFlag: + c = self._componentValues[self._currentIdx] + if isinstance(c, Choice): + return c.getName(innerFlag) + return self.componentType.getNameByPosition(self._currentIdx) + + @property + def isValue(self): + """Indicate that |ASN.1| object represents ASN.1 value. + + If *isValue* is :obj:`False` then this object represents just ASN.1 schema. + + If *isValue* is :obj:`True` then, in addition to its ASN.1 schema features, + this object can also be used like a Python built-in object (e.g. + :class:`int`, :class:`str`, :class:`dict` etc.). + + Returns + ------- + : :class:`bool` + :obj:`False` if object represents just ASN.1 schema. + :obj:`True` if object represents ASN.1 schema and can be used as a normal + value. + + Note + ---- + There is an important distinction between PyASN1 schema and value objects. + The PyASN1 schema objects can only participate in ASN.1 schema-related + operations (e.g. defining or testing the structure of the data). Most + obvious uses of ASN.1 schema is to guide serialisation codecs whilst + encoding/decoding serialised ASN.1 contents. + + The PyASN1 value objects can **additionally** participate in many operations + involving regular Python objects (e.g. arithmetic, comprehension etc). + """ + if self._currentIdx is None: + return False + + componentValue = self._componentValues[self._currentIdx] + + return componentValue is not noValue and componentValue.isValue + + def clear(self): + self._currentIdx = None + return Set.clear(self) + + # compatibility stubs + + def getMinTagSet(self): + return self.minTagSet + + +class Any(OctetString): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, + its objects are immutable and duck-type Python 2 :class:`str` or Python 3 + :class:`bytes`. When used in Unicode context, |ASN.1| type assumes + "|encoding|" serialisation. + + Keyword Args + ------------ + value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object + :class:`str` (Python 2) or :class:`bytes` (Python 3), alternatively + :class:`unicode` object (Python 2) or :class:`str` (Python 3) + representing character string to be serialised into octets (note + `encoding` parameter) or |ASN.1| object. + If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + encoding: :py:class:`str` + Unicode codec ID to encode/decode :class:`unicode` (Python 2) or + :class:`str` (Python 3) the payload when |ASN.1| object is used + in text string context. + + binValue: :py:class:`str` + Binary string initializer to use instead of the *value*. + Example: '10110011'. + + hexValue: :py:class:`str` + Hexadecimal string initializer to use instead of the *value*. + Example: 'DEADBEEF'. + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + .. code-block:: python + + class Error(Sequence): + ''' + ASN.1 specification: + + Error ::= SEQUENCE { + code INTEGER, + parameter ANY DEFINED BY code -- Either INTEGER or REAL + } + ''' + componentType=NamedTypes( + NamedType('code', Integer()), + NamedType('parameter', Any(), + openType=OpenType('code', {1: Integer(), + 2: Real()})) + ) + + error = Error() + error['code'] = 1 + error['parameter'] = Integer(1234) + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.TagSet() # untagged + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Disambiguation ASN.1 types identification + typeId = OctetString.getTypeId() + + @property + def tagMap(self): + """"Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping + ASN.1 tags to ASN.1 objects contained within callee. + """ + try: + return self._tagMap + + except AttributeError: + self._tagMap = tagmap.TagMap( + {self.tagSet: self}, + {eoo.endOfOctets.tagSet: eoo.endOfOctets}, + self + ) + + return self._tagMap + +# XXX +# coercion rules? diff --git a/lib/pyasn1/type/useful.py b/lib/pyasn1/type/useful.py new file mode 100644 index 00000000..24fac2c4 --- /dev/null +++ b/lib/pyasn1/type/useful.py @@ -0,0 +1,189 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2020, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import datetime + +from pyasn1 import error +from pyasn1.type import char +from pyasn1.type import tag +from pyasn1.type import univ + +__all__ = ['ObjectDescriptor', 'GeneralizedTime', 'UTCTime'] + +NoValue = univ.NoValue +noValue = univ.noValue + + +class ObjectDescriptor(char.GraphicString): + __doc__ = char.GraphicString.__doc__ + + #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects + tagSet = char.GraphicString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 7) + ) + + # Optimization for faster codec lookup + typeId = char.GraphicString.getTypeId() + + +class TimeMixIn(object): + + _yearsDigits = 4 + _hasSubsecond = False + _optionalMinutes = False + _shortTZ = False + + class FixedOffset(datetime.tzinfo): + """Fixed offset in minutes east from UTC.""" + + # defaulted arguments required + # https: // docs.python.org / 2.3 / lib / datetime - tzinfo.html + def __init__(self, offset=0, name='UTC'): + self.__offset = datetime.timedelta(minutes=offset) + self.__name = name + + def utcoffset(self, dt): + return self.__offset + + def tzname(self, dt): + return self.__name + + def dst(self, dt): + return datetime.timedelta(0) + + UTC = FixedOffset() + + @property + def asDateTime(self): + """Create :py:class:`datetime.datetime` object from a |ASN.1| object. + + Returns + ------- + : + new instance of :py:class:`datetime.datetime` object + """ + text = str(self) + if text.endswith('Z'): + tzinfo = TimeMixIn.UTC + text = text[:-1] + + elif '-' in text or '+' in text: + if '+' in text: + text, plusminus, tz = text.partition('+') + else: + text, plusminus, tz = text.partition('-') + + if self._shortTZ and len(tz) == 2: + tz += '00' + + if len(tz) != 4: + raise error.PyAsn1Error('malformed time zone offset %s' % tz) + + try: + minutes = int(tz[:2]) * 60 + int(tz[2:]) + if plusminus == '-': + minutes *= -1 + + except ValueError: + raise error.PyAsn1Error('unknown time specification %s' % self) + + tzinfo = TimeMixIn.FixedOffset(minutes, '?') + + else: + tzinfo = None + + if '.' in text or ',' in text: + if '.' in text: + text, _, ms = text.partition('.') + else: + text, _, ms = text.partition(',') + + try: + ms = int(ms) * 1000 + + except ValueError: + raise error.PyAsn1Error('bad sub-second time specification %s' % self) + + else: + ms = 0 + + if self._optionalMinutes and len(text) - self._yearsDigits == 6: + text += '0000' + elif len(text) - self._yearsDigits == 8: + text += '00' + + try: + dt = datetime.datetime.strptime(text, self._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S') + + except ValueError: + raise error.PyAsn1Error('malformed datetime format %s' % self) + + return dt.replace(microsecond=ms, tzinfo=tzinfo) + + @classmethod + def fromDateTime(cls, dt): + """Create |ASN.1| object from a :py:class:`datetime.datetime` object. + + Parameters + ---------- + dt: :py:class:`datetime.datetime` object + The `datetime.datetime` object to initialize the |ASN.1| object + from + + Returns + ------- + : + new instance of |ASN.1| value + """ + text = dt.strftime(cls._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S') + if cls._hasSubsecond: + text += '.%d' % (dt.microsecond // 1000) + + if dt.utcoffset(): + seconds = dt.utcoffset().seconds + if seconds < 0: + text += '-' + else: + text += '+' + text += '%.2d%.2d' % (seconds // 3600, seconds % 3600) + else: + text += 'Z' + + return cls(text) + + +class GeneralizedTime(char.VisibleString, TimeMixIn): + __doc__ = char.VisibleString.__doc__ + + #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects + tagSet = char.VisibleString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 24) + ) + + # Optimization for faster codec lookup + typeId = char.VideotexString.getTypeId() + + _yearsDigits = 4 + _hasSubsecond = True + _optionalMinutes = True + _shortTZ = True + + +class UTCTime(char.VisibleString, TimeMixIn): + __doc__ = char.VisibleString.__doc__ + + #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects + tagSet = char.VisibleString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 23) + ) + + # Optimization for faster codec lookup + typeId = char.VideotexString.getTypeId() + + _yearsDigits = 2 + _hasSubsecond = False + _optionalMinutes = False + _shortTZ = False diff --git a/lib/sambatools/__init__.py b/lib/sambatools/__init__.py index caa42aef..3e9560c6 100644 --- a/lib/sambatools/__init__.py +++ b/lib/sambatools/__init__.py @@ -3,4 +3,4 @@ import os import sys -sys.path.append(os.path.dirname(__file__)) +sys.path.append(os.path.join(os.path.dirname(__file__), 'python3' if sys.version_info[0] >= 3 else 'python2')) diff --git a/lib/sambatools/libsmb.py b/lib/sambatools/libsmb.py index 4a66385d..8a35f0c8 100644 --- a/lib/sambatools/libsmb.py +++ b/lib/sambatools/libsmb.py @@ -2,13 +2,15 @@ import os import re +import sys +if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int from nmb.NetBIOS import NetBIOS from platformcode import logger from smb.SMBConnection import SMBConnection -GitHub = 'https://github.com/miketeo/pysmb' #buscar aquí de vez en cuando la última versiónde SMB-pysmb, y actualizar en Alfa -vesion_actual_pysmb = '1.1.25' #actualizada el 25/11/2018 +GitHub = 'https://github.com/miketeo/pysmb' # check here from time to time for the latest version of SMB-pysmb +vesion_actual_pysmb = '1.2.6' #updated on 26/12/2020 remote = None @@ -65,11 +67,8 @@ def connect(url): def listdir(url): logger.info("Url: %s" % url) remote, share_name, path = connect(url) - try: - files = [f.filename for f in remote.listPath(share_name, path) if not f.filename in [".", ".."]] - return files - except Exception, e: - raise type(e)(e.message, "") + files = [f.filename for f in remote.listPath(share_name, path) if not f.filename in [".", ".."]] + return files def walk(url, topdown=True, onerror=None): @@ -78,7 +77,7 @@ def walk(url, topdown=True, onerror=None): try: names = remote.listPath(share_name, path) - except Exception, _err: + except Exception as _err: if onerror is not None: onerror(_err) return @@ -107,7 +106,7 @@ def get_attributes(url): remote, share_name, path = connect(url) try: return remote.getAttributes(share_name, path) - except Exception, e: + except Exception as e: raise type(e)(e.message, "") @@ -116,7 +115,7 @@ def mkdir(url): remote, share_name, path = connect(url) try: remote.createDirectory(share_name, path) - except Exception, e: + except Exception as e: raise type(e)(e.message, "") @@ -130,7 +129,7 @@ def isfile(url): remote, share_name, path = connect(url) try: files = [f.filename for f in remote.listPath(share_name, os.path.dirname(path)) if not f.isDirectory] - except Exception, e: + except Exception as e: raise type(e)(e.message, "") return os.path.basename(path) in files @@ -140,7 +139,7 @@ def isdir(url): remote, share_name, path = connect(url) try: folders = [f.filename for f in remote.listPath(share_name, os.path.dirname(path)) if f.isDirectory] - except Exception, e: + except Exception as e: raise type(e)(e.message, "") return os.path.basename(path) in folders or path == "/" @@ -150,7 +149,7 @@ def exists(url): remote, share_name, path = connect(url) try: files = [f.filename for f in remote.listPath(share_name, os.path.dirname(path))] - except Exception, e: + except Exception as e: raise type(e)(e.message, "") return os.path.basename(path) in files or path == "/" @@ -160,7 +159,7 @@ def remove(url): remote, share_name, path = connect(url) try: remote.deleteFiles(share_name, path) - except Exception, e: + except Exception as e: raise type(e)(e.message, "") @@ -169,7 +168,7 @@ def rmdir(url): remote, share_name, path = connect(url) try: remote.deleteDirectory(share_name, path) - except Exception, e: + except Exception as e: raise type(e)(e.message, "") @@ -179,7 +178,7 @@ def rename(url, new_name): _, _, _, new_name, _, _, _ = parse_url(new_name) try: remote.rename(share_name, path, new_name) - except Exception, e: + except Exception as e: raise type(e)(e.message, "") @@ -225,7 +224,7 @@ class SMBFile(object): if "r+" in self.mode: try: attr = self.remote.getAttributes(self.share, self.path) - except Exception, e: + except Exception as e: raise type(e)(e.message, "") self.size = attr.file_size @@ -236,7 +235,7 @@ class SMBFile(object): elif "r" in self.mode: try: attr = self.remote.getAttributes(self.share, self.path) - except Exception, e: + except Exception as e: raise type(e)(e.message, "") self.size = attr.file_size @@ -246,7 +245,7 @@ class SMBFile(object): elif "w+" in self.mode: try: self.remote.storeFileFromOffset(self.share, self.path, self.tmpfile(), 0, truncate=True) - except Exception, e: + except Exception as e: raise type(e)(e.message, "") self.canread = True @@ -256,7 +255,7 @@ class SMBFile(object): elif "w" in self.mode: try: self.remote.storeFileFromOffset(self.share, self.path, self.tmpfile(), 0, truncate=True) - except Exception, e: + except Exception as e: raise type(e)(e.message, "") self.canwrite = True @@ -266,7 +265,7 @@ class SMBFile(object): try: self.remote.storeFileFromOffset(self.share, self.path, self.tmpfile(), 0) attr = self.remote.getAttributes(self.share, self.path) - except Exception, e: + except Exception as e: raise type(e)(e.message, "") self.size = attr.file_size @@ -279,7 +278,7 @@ class SMBFile(object): try: self.remote.storeFileFromOffset(self.share, self.path, self.tmpfile(), 0) attr = self.remote.getAttributes(self.share, self.path) - except Exception, e: + except Exception as e: raise type(e)(e.message, "") self.size = attr.file_size @@ -314,7 +313,7 @@ class SMBFile(object): if self.pos > self.size: self.size = self.pos - def read(self, size=-1L): + def read(self, size=-1): if not self.canread: raise IOError("File not open for reading") f = self.tmpfile() diff --git a/lib/sambatools/pyasn1/__init__.py b/lib/sambatools/pyasn1/__init__.py deleted file mode 100644 index 5f093000..00000000 --- a/lib/sambatools/pyasn1/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -import sys - -# http://www.python.org/dev/peps/pep-0396/ -__version__ = '0.1.9' - -if sys.version_info[:2] < (2, 4): - raise RuntimeError('PyASN1 requires Python 2.4 or later') - diff --git a/lib/sambatools/pyasn1/codec/ber/decoder.py b/lib/sambatools/pyasn1/codec/ber/decoder.py deleted file mode 100644 index f2186825..00000000 --- a/lib/sambatools/pyasn1/codec/ber/decoder.py +++ /dev/null @@ -1,842 +0,0 @@ -# BER decoder -from pyasn1 import debug, error -from pyasn1.codec.ber import eoo -from pyasn1.compat.octets import oct2int, isOctetsType -from pyasn1.type import tag, univ, char, useful, tagmap - - -class AbstractDecoder: - protoComponent = None - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - raise error.PyAsn1Error('Decoder not implemented for %s' % (tagSet,)) - - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - raise error.PyAsn1Error('Indefinite length mode decoder not implemented for %s' % (tagSet,)) - -class AbstractSimpleDecoder(AbstractDecoder): - tagFormats = (tag.tagFormatSimple,) - def _createComponent(self, asn1Spec, tagSet, value=None): - if tagSet[0][1] not in self.tagFormats: - raise error.PyAsn1Error('Invalid tag format %s for %s' % (tagSet[0], self.protoComponent.prettyPrintType())) - if asn1Spec is None: - return self.protoComponent.clone(value, tagSet) - elif value is None: - return asn1Spec - else: - return asn1Spec.clone(value) - -class AbstractConstructedDecoder(AbstractDecoder): - tagFormats = (tag.tagFormatConstructed,) - def _createComponent(self, asn1Spec, tagSet, value=None): - if tagSet[0][1] not in self.tagFormats: - raise error.PyAsn1Error('Invalid tag format %s for %s' % (tagSet[0], self.protoComponent.prettyPrintType())) - if asn1Spec is None: - return self.protoComponent.clone(tagSet) - else: - return asn1Spec.clone() - -class ExplicitTagDecoder(AbstractSimpleDecoder): - protoComponent = univ.Any('') - tagFormats = (tag.tagFormatConstructed,) - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - if substrateFun: - return substrateFun( - self._createComponent(asn1Spec, tagSet, ''), - substrate, length - ) - head, tail = substrate[:length], substrate[length:] - value, _ = decodeFun(head, asn1Spec, tagSet, length) - return value, tail - - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - if substrateFun: - return substrateFun( - self._createComponent(asn1Spec, tagSet, ''), - substrate, length - ) - value, substrate = decodeFun(substrate, asn1Spec, tagSet, length) - terminator, substrate = decodeFun(substrate, allowEoo=True) - if eoo.endOfOctets.isSameTypeWith(terminator) and \ - terminator == eoo.endOfOctets: - return value, substrate - else: - raise error.PyAsn1Error('Missing end-of-octets terminator') - -explicitTagDecoder = ExplicitTagDecoder() - -class IntegerDecoder(AbstractSimpleDecoder): - protoComponent = univ.Integer(0) - precomputedValues = { - '\x00': 0, - '\x01': 1, - '\x02': 2, - '\x03': 3, - '\x04': 4, - '\x05': 5, - '\x06': 6, - '\x07': 7, - '\x08': 8, - '\x09': 9, - '\xff': -1, - '\xfe': -2, - '\xfd': -3, - '\xfc': -4, - '\xfb': -5 - } - - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length, - state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - if not head: - return self._createComponent(asn1Spec, tagSet, 0), tail - if head in self.precomputedValues: - value = self.precomputedValues[head] - else: - firstOctet = oct2int(head[0]) - if firstOctet & 0x80: - value = -1 - else: - value = 0 - for octet in head: - value = value << 8 | oct2int(octet) - return self._createComponent(asn1Spec, tagSet, value), tail - -class BooleanDecoder(IntegerDecoder): - protoComponent = univ.Boolean(0) - def _createComponent(self, asn1Spec, tagSet, value=None): - return IntegerDecoder._createComponent(self, asn1Spec, tagSet, value and 1 or 0) - -class BitStringDecoder(AbstractSimpleDecoder): - protoComponent = univ.BitString(()) - tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed) - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length, - state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - if tagSet[0][1] == tag.tagFormatSimple: # XXX what tag to check? - if not head: - raise error.PyAsn1Error('Empty substrate') - trailingBits = oct2int(head[0]) - if trailingBits > 7: - raise error.PyAsn1Error( - 'Trailing bits overflow %s' % trailingBits - ) - head = head[1:] - lsb = p = 0; l = len(head)-1; b = [] - while p <= l: - if p == l: - lsb = trailingBits - j = 7 - o = oct2int(head[p]) - while j >= lsb: - b.append((o>>j)&0x01) - j = j - 1 - p = p + 1 - return self._createComponent(asn1Spec, tagSet, b), tail - r = self._createComponent(asn1Spec, tagSet, ()) - if substrateFun: - return substrateFun(r, substrate, length) - while head: - component, head = decodeFun(head, self.protoComponent) - r = r + component - return r, tail - - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - r = self._createComponent(asn1Spec, tagSet, '') - if substrateFun: - return substrateFun(r, substrate, length) - while substrate: - component, substrate = decodeFun(substrate, self.protoComponent, - allowEoo=True) - if eoo.endOfOctets.isSameTypeWith(component) and \ - component == eoo.endOfOctets: - break - r = r + component - else: - raise error.SubstrateUnderrunError( - 'No EOO seen before substrate ends' - ) - return r, substrate - -class OctetStringDecoder(AbstractSimpleDecoder): - protoComponent = univ.OctetString('') - tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed) - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length, - state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - if tagSet[0][1] == tag.tagFormatSimple: # XXX what tag to check? - return self._createComponent(asn1Spec, tagSet, head), tail - r = self._createComponent(asn1Spec, tagSet, '') - if substrateFun: - return substrateFun(r, substrate, length) - while head: - component, head = decodeFun(head, self.protoComponent) - r = r + component - return r, tail - - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - r = self._createComponent(asn1Spec, tagSet, '') - if substrateFun: - return substrateFun(r, substrate, length) - while substrate: - component, substrate = decodeFun(substrate, self.protoComponent, - allowEoo=True) - if eoo.endOfOctets.isSameTypeWith(component) and \ - component == eoo.endOfOctets: - break - r = r + component - else: - raise error.SubstrateUnderrunError( - 'No EOO seen before substrate ends' - ) - return r, substrate - -class NullDecoder(AbstractSimpleDecoder): - protoComponent = univ.Null('') - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - r = self._createComponent(asn1Spec, tagSet) - if head: - raise error.PyAsn1Error('Unexpected %d-octet substrate for Null' % length) - return r, tail - -class ObjectIdentifierDecoder(AbstractSimpleDecoder): - protoComponent = univ.ObjectIdentifier(()) - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length, - state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - if not head: - raise error.PyAsn1Error('Empty substrate') - - oid = () - index = 0 - substrateLen = len(head) - while index < substrateLen: - subId = oct2int(head[index]) - index += 1 - if subId < 128: - oid = oid + (subId,) - elif subId > 128: - # Construct subid from a number of octets - nextSubId = subId - subId = 0 - while nextSubId >= 128: - subId = (subId << 7) + (nextSubId & 0x7F) - if index >= substrateLen: - raise error.SubstrateUnderrunError( - 'Short substrate for sub-OID past %s' % (oid,) - ) - nextSubId = oct2int(head[index]) - index += 1 - oid = oid + ((subId << 7) + nextSubId,) - elif subId == 128: - # ASN.1 spec forbids leading zeros (0x80) in OID - # encoding, tolerating it opens a vulnerability. See - # http://www.cosic.esat.kuleuven.be/publications/article-1432.pdf - # page 7 - raise error.PyAsn1Error('Invalid octet 0x80 in OID encoding') - - # Decode two leading arcs - if 0 <= oid[0] <= 39: - oid = (0,) + oid - elif 40 <= oid[0] <= 79: - oid = (1, oid[0]-40) + oid[1:] - elif oid[0] >= 80: - oid = (2, oid[0]-80) + oid[1:] - else: - raise error.PyAsn1Error('Malformed first OID octet: %s' % head[0]) - - return self._createComponent(asn1Spec, tagSet, oid), tail - -class RealDecoder(AbstractSimpleDecoder): - protoComponent = univ.Real() - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - if not head: - return self._createComponent(asn1Spec, tagSet, 0.0), tail - fo = oct2int(head[0]); head = head[1:] - if fo & 0x80: # binary encoding - if not head: - raise error.PyAsn1Error("Incomplete floating-point value") - n = (fo & 0x03) + 1 - if n == 4: - n = oct2int(head[0]) - head = head[1:] - eo, head = head[:n], head[n:] - if not eo or not head: - raise error.PyAsn1Error('Real exponent screwed') - e = oct2int(eo[0]) & 0x80 and -1 or 0 - while eo: # exponent - e <<= 8 - e |= oct2int(eo[0]) - eo = eo[1:] - b = fo >> 4 & 0x03 # base bits - if b > 2: - raise error.PyAsn1Error('Illegal Real base') - if b == 1: # encbase = 8 - e *= 3 - elif b == 2: # encbase = 16 - e *= 4 - p = 0 - while head: # value - p <<= 8 - p |= oct2int(head[0]) - head = head[1:] - if fo & 0x40: # sign bit - p = -p - sf = fo >> 2 & 0x03 # scale bits - p *= 2**sf - value = (p, 2, e) - elif fo & 0x40: # infinite value - value = fo & 0x01 and '-inf' or 'inf' - elif fo & 0xc0 == 0: # character encoding - if not head: - raise error.PyAsn1Error("Incomplete floating-point value") - try: - if fo & 0x3 == 0x1: # NR1 - value = (int(head), 10, 0) - elif fo & 0x3 == 0x2: # NR2 - value = float(head) - elif fo & 0x3 == 0x3: # NR3 - value = float(head) - else: - raise error.SubstrateUnderrunError( - 'Unknown NR (tag %s)' % fo - ) - except ValueError: - raise error.SubstrateUnderrunError( - 'Bad character Real syntax' - ) - else: - raise error.SubstrateUnderrunError( - 'Unknown encoding (tag %s)' % fo - ) - return self._createComponent(asn1Spec, tagSet, value), tail - -class SequenceDecoder(AbstractConstructedDecoder): - protoComponent = univ.Sequence() - def _getComponentTagMap(self, r, idx): - try: - return r.getComponentTagMapNearPosition(idx) - except error.PyAsn1Error: - return - - def _getComponentPositionByType(self, r, t, idx): - return r.getComponentPositionNearType(t, idx) - - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - r = self._createComponent(asn1Spec, tagSet) - idx = 0 - if substrateFun: - return substrateFun(r, substrate, length) - while head: - asn1Spec = self._getComponentTagMap(r, idx) - component, head = decodeFun(head, asn1Spec) - idx = self._getComponentPositionByType( - r, component.getEffectiveTagSet(), idx - ) - r.setComponentByPosition(idx, component, asn1Spec is None) - idx = idx + 1 - r.setDefaultComponents() - r.verifySizeSpec() - return r, tail - - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - r = self._createComponent(asn1Spec, tagSet) - if substrateFun: - return substrateFun(r, substrate, length) - idx = 0 - while substrate: - asn1Spec = self._getComponentTagMap(r, idx) - component, substrate = decodeFun(substrate, asn1Spec, allowEoo=True) - if eoo.endOfOctets.isSameTypeWith(component) and \ - component == eoo.endOfOctets: - break - idx = self._getComponentPositionByType( - r, component.getEffectiveTagSet(), idx - ) - r.setComponentByPosition(idx, component, asn1Spec is None) - idx = idx + 1 - else: - raise error.SubstrateUnderrunError( - 'No EOO seen before substrate ends' - ) - r.setDefaultComponents() - r.verifySizeSpec() - return r, substrate - -class SequenceOfDecoder(AbstractConstructedDecoder): - protoComponent = univ.SequenceOf() - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - r = self._createComponent(asn1Spec, tagSet) - if substrateFun: - return substrateFun(r, substrate, length) - asn1Spec = r.getComponentType() - idx = 0 - while head: - component, head = decodeFun(head, asn1Spec) - r.setComponentByPosition(idx, component, asn1Spec is None) - idx = idx + 1 - r.verifySizeSpec() - return r, tail - - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - r = self._createComponent(asn1Spec, tagSet) - if substrateFun: - return substrateFun(r, substrate, length) - asn1Spec = r.getComponentType() - idx = 0 - while substrate: - component, substrate = decodeFun(substrate, asn1Spec, allowEoo=True) - if eoo.endOfOctets.isSameTypeWith(component) and \ - component == eoo.endOfOctets: - break - r.setComponentByPosition(idx, component, asn1Spec is None) - idx = idx + 1 - else: - raise error.SubstrateUnderrunError( - 'No EOO seen before substrate ends' - ) - r.verifySizeSpec() - return r, substrate - -class SetDecoder(SequenceDecoder): - protoComponent = univ.Set() - def _getComponentTagMap(self, r, idx): - return r.getComponentTagMap() - - def _getComponentPositionByType(self, r, t, idx): - nextIdx = r.getComponentPositionByType(t) - if nextIdx is None: - return idx - else: - return nextIdx - -class SetOfDecoder(SequenceOfDecoder): - protoComponent = univ.SetOf() - -class ChoiceDecoder(AbstractConstructedDecoder): - protoComponent = univ.Choice() - tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed) - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - r = self._createComponent(asn1Spec, tagSet) - if substrateFun: - return substrateFun(r, substrate, length) - if r.getTagSet() == tagSet: # explicitly tagged Choice - component, head = decodeFun( - head, r.getComponentTagMap() - ) - else: - component, head = decodeFun( - head, r.getComponentTagMap(), tagSet, length, state - ) - if isinstance(component, univ.Choice): - effectiveTagSet = component.getEffectiveTagSet() - else: - effectiveTagSet = component.getTagSet() - r.setComponentByType(effectiveTagSet, component, 0, asn1Spec is None) - return r, tail - - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - r = self._createComponent(asn1Spec, tagSet) - if substrateFun: - return substrateFun(r, substrate, length) - if r.getTagSet() == tagSet: # explicitly tagged Choice - component, substrate = decodeFun(substrate, r.getComponentTagMap()) - # eat up EOO marker - eooMarker, substrate = decodeFun(substrate, allowEoo=True) - if not eoo.endOfOctets.isSameTypeWith(eooMarker) or \ - eooMarker != eoo.endOfOctets: - raise error.PyAsn1Error('No EOO seen before substrate ends') - else: - component, substrate= decodeFun( - substrate, r.getComponentTagMap(), tagSet, length, state - ) - if isinstance(component, univ.Choice): - effectiveTagSet = component.getEffectiveTagSet() - else: - effectiveTagSet = component.getTagSet() - r.setComponentByType(effectiveTagSet, component, 0, asn1Spec is None) - return r, substrate - -class AnyDecoder(AbstractSimpleDecoder): - protoComponent = univ.Any() - tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed) - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - if asn1Spec is None or \ - asn1Spec is not None and tagSet != asn1Spec.getTagSet(): - # untagged Any container, recover inner header substrate - length = length + len(fullSubstrate) - len(substrate) - substrate = fullSubstrate - if substrateFun: - return substrateFun(self._createComponent(asn1Spec, tagSet), - substrate, length) - head, tail = substrate[:length], substrate[length:] - return self._createComponent(asn1Spec, tagSet, value=head), tail - - def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, - length, state, decodeFun, substrateFun): - if asn1Spec is not None and tagSet == asn1Spec.getTagSet(): - # tagged Any type -- consume header substrate - header = '' - else: - # untagged Any, recover header substrate - header = fullSubstrate[:-len(substrate)] - - r = self._createComponent(asn1Spec, tagSet, header) - - # Any components do not inherit initial tag - asn1Spec = self.protoComponent - - if substrateFun: - return substrateFun(r, substrate, length) - while substrate: - component, substrate = decodeFun(substrate, asn1Spec, allowEoo=True) - if eoo.endOfOctets.isSameTypeWith(component) and \ - component == eoo.endOfOctets: - break - r = r + component - else: - raise error.SubstrateUnderrunError( - 'No EOO seen before substrate ends' - ) - return r, substrate - -# character string types -class UTF8StringDecoder(OctetStringDecoder): - protoComponent = char.UTF8String() -class NumericStringDecoder(OctetStringDecoder): - protoComponent = char.NumericString() -class PrintableStringDecoder(OctetStringDecoder): - protoComponent = char.PrintableString() -class TeletexStringDecoder(OctetStringDecoder): - protoComponent = char.TeletexString() -class VideotexStringDecoder(OctetStringDecoder): - protoComponent = char.VideotexString() -class IA5StringDecoder(OctetStringDecoder): - protoComponent = char.IA5String() -class GraphicStringDecoder(OctetStringDecoder): - protoComponent = char.GraphicString() -class VisibleStringDecoder(OctetStringDecoder): - protoComponent = char.VisibleString() -class GeneralStringDecoder(OctetStringDecoder): - protoComponent = char.GeneralString() -class UniversalStringDecoder(OctetStringDecoder): - protoComponent = char.UniversalString() -class BMPStringDecoder(OctetStringDecoder): - protoComponent = char.BMPString() - -# "useful" types -class ObjectDescriptorDecoder(OctetStringDecoder): - protoComponent = useful.ObjectDescriptor() -class GeneralizedTimeDecoder(OctetStringDecoder): - protoComponent = useful.GeneralizedTime() -class UTCTimeDecoder(OctetStringDecoder): - protoComponent = useful.UTCTime() - -tagMap = { - univ.Integer.tagSet: IntegerDecoder(), - univ.Boolean.tagSet: BooleanDecoder(), - univ.BitString.tagSet: BitStringDecoder(), - univ.OctetString.tagSet: OctetStringDecoder(), - univ.Null.tagSet: NullDecoder(), - univ.ObjectIdentifier.tagSet: ObjectIdentifierDecoder(), - univ.Enumerated.tagSet: IntegerDecoder(), - univ.Real.tagSet: RealDecoder(), - univ.Sequence.tagSet: SequenceDecoder(), # conflicts with SequenceOf - univ.Set.tagSet: SetDecoder(), # conflicts with SetOf - univ.Choice.tagSet: ChoiceDecoder(), # conflicts with Any - # character string types - char.UTF8String.tagSet: UTF8StringDecoder(), - char.NumericString.tagSet: NumericStringDecoder(), - char.PrintableString.tagSet: PrintableStringDecoder(), - char.TeletexString.tagSet: TeletexStringDecoder(), - char.VideotexString.tagSet: VideotexStringDecoder(), - char.IA5String.tagSet: IA5StringDecoder(), - char.GraphicString.tagSet: GraphicStringDecoder(), - char.VisibleString.tagSet: VisibleStringDecoder(), - char.GeneralString.tagSet: GeneralStringDecoder(), - char.UniversalString.tagSet: UniversalStringDecoder(), - char.BMPString.tagSet: BMPStringDecoder(), - # useful types - useful.ObjectDescriptor.tagSet: ObjectDescriptorDecoder(), - useful.GeneralizedTime.tagSet: GeneralizedTimeDecoder(), - useful.UTCTime.tagSet: UTCTimeDecoder() -} - -# Type-to-codec map for ambiguous ASN.1 types -typeMap = { - univ.Set.typeId: SetDecoder(), - univ.SetOf.typeId: SetOfDecoder(), - univ.Sequence.typeId: SequenceDecoder(), - univ.SequenceOf.typeId: SequenceOfDecoder(), - univ.Choice.typeId: ChoiceDecoder(), - univ.Any.typeId: AnyDecoder() -} - -( stDecodeTag, stDecodeLength, stGetValueDecoder, stGetValueDecoderByAsn1Spec, - stGetValueDecoderByTag, stTryAsExplicitTag, stDecodeValue, - stDumpRawValue, stErrorCondition, stStop ) = [x for x in range(10)] - -class Decoder: - defaultErrorState = stErrorCondition -# defaultErrorState = stDumpRawValue - defaultRawDecoder = AnyDecoder() - supportIndefLength = True - def __init__(self, tagMap, typeMap={}): - self.__tagMap = tagMap - self.__typeMap = typeMap - # Tag & TagSet objects caches - self.__tagCache = {} - self.__tagSetCache = {} - - def __call__(self, substrate, asn1Spec=None, tagSet=None, - length=None, state=stDecodeTag, recursiveFlag=1, - substrateFun=None, allowEoo=False): - if debug.logger & debug.flagDecoder: - debug.logger('decoder called at scope %s with state %d, working with up to %d octets of substrate: %s' % (debug.scope, state, len(substrate), debug.hexdump(substrate))) - fullSubstrate = substrate - while state != stStop: - if state == stDecodeTag: - if not substrate: - raise error.SubstrateUnderrunError( - 'Short octet stream on tag decoding' - ) - if not isOctetsType(substrate) and \ - not isinstance(substrate, univ.OctetString): - raise error.PyAsn1Error('Bad octet stream type') - # Decode tag - firstOctet = substrate[0] - substrate = substrate[1:] - if firstOctet in self.__tagCache: - lastTag = self.__tagCache[firstOctet] - else: - t = oct2int(firstOctet) - # Look for end-of-octets sentinel - if t == 0: - if substrate and oct2int(substrate[0]) == 0: - if allowEoo and self.supportIndefLength: - debug.logger and debug.logger & debug.flagDecoder and debug.logger('end-of-octets sentinel found') - value, substrate = eoo.endOfOctets, substrate[1:] - state = stStop - continue - else: - raise error.PyAsn1Error('Unexpected end-of-contents sentinel') - else: - raise error.PyAsn1Error('Zero tag encountered') - tagClass = t&0xC0 - tagFormat = t&0x20 - tagId = t&0x1F - if tagId == 0x1F: - tagId = 0 - while 1: - if not substrate: - raise error.SubstrateUnderrunError( - 'Short octet stream on long tag decoding' - ) - t = oct2int(substrate[0]) - tagId = tagId << 7 | (t&0x7F) - substrate = substrate[1:] - if not t&0x80: - break - lastTag = tag.Tag( - tagClass=tagClass, tagFormat=tagFormat, tagId=tagId - ) - if tagId < 31: - # cache short tags - self.__tagCache[firstOctet] = lastTag - if tagSet is None: - if firstOctet in self.__tagSetCache: - tagSet = self.__tagSetCache[firstOctet] - else: - # base tag not recovered - tagSet = tag.TagSet((), lastTag) - if firstOctet in self.__tagCache: - self.__tagSetCache[firstOctet] = tagSet - else: - tagSet = lastTag + tagSet - state = stDecodeLength - debug.logger and debug.logger & debug.flagDecoder and debug.logger('tag decoded into %s, decoding length' % tagSet) - if state == stDecodeLength: - # Decode length - if not substrate: - raise error.SubstrateUnderrunError( - 'Short octet stream on length decoding' - ) - firstOctet = oct2int(substrate[0]) - if firstOctet == 128: - size = 1 - length = -1 - elif firstOctet < 128: - length, size = firstOctet, 1 - else: - size = firstOctet & 0x7F - # encoded in size bytes - length = 0 - lengthString = substrate[1:size+1] - # missing check on maximum size, which shouldn't be a - # problem, we can handle more than is possible - if len(lengthString) != size: - raise error.SubstrateUnderrunError( - '%s<%s at %s' % - (size, len(lengthString), tagSet) - ) - for char in lengthString: - length = (length << 8) | oct2int(char) - size = size + 1 - substrate = substrate[size:] - if length != -1 and len(substrate) < length: - raise error.SubstrateUnderrunError( - '%d-octet short' % (length - len(substrate)) - ) - if length == -1 and not self.supportIndefLength: - error.PyAsn1Error('Indefinite length encoding not supported by this codec') - state = stGetValueDecoder - debug.logger and debug.logger & debug.flagDecoder and debug.logger('value length decoded into %d, payload substrate is: %s' % (length, debug.hexdump(length == -1 and substrate or substrate[:length]))) - if state == stGetValueDecoder: - if asn1Spec is None: - state = stGetValueDecoderByTag - else: - state = stGetValueDecoderByAsn1Spec - # - # There're two ways of creating subtypes in ASN.1 what influences - # decoder operation. These methods are: - # 1) Either base types used in or no IMPLICIT tagging has been - # applied on subtyping. - # 2) Subtype syntax drops base type information (by means of - # IMPLICIT tagging. - # The first case allows for complete tag recovery from substrate - # while the second one requires original ASN.1 type spec for - # decoding. - # - # In either case a set of tags (tagSet) is coming from substrate - # in an incremental, tag-by-tag fashion (this is the case of - # EXPLICIT tag which is most basic). Outermost tag comes first - # from the wire. - # - if state == stGetValueDecoderByTag: - if tagSet in self.__tagMap: - concreteDecoder = self.__tagMap[tagSet] - else: - concreteDecoder = None - if concreteDecoder: - state = stDecodeValue - else: - _k = tagSet[:1] - if _k in self.__tagMap: - concreteDecoder = self.__tagMap[_k] - else: - concreteDecoder = None - if concreteDecoder: - state = stDecodeValue - else: - state = stTryAsExplicitTag - if debug.logger and debug.logger & debug.flagDecoder: - debug.logger('codec %s chosen by a built-in type, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "", state == stDecodeValue and 'value' or 'as explicit tag')) - debug.scope.push(concreteDecoder is None and '?' or concreteDecoder.protoComponent.__class__.__name__) - if state == stGetValueDecoderByAsn1Spec: - if isinstance(asn1Spec, (dict, tagmap.TagMap)): - if tagSet in asn1Spec: - __chosenSpec = asn1Spec[tagSet] - else: - __chosenSpec = None - if debug.logger and debug.logger & debug.flagDecoder: - debug.logger('candidate ASN.1 spec is a map of:') - for t, v in asn1Spec.getPosMap().items(): - debug.logger(' %s -> %s' % (t, v.__class__.__name__)) - if asn1Spec.getNegMap(): - debug.logger('but neither of: ') - for t, v in asn1Spec.getNegMap().items(): - debug.logger(' %s -> %s' % (t, v.__class__.__name__)) - debug.logger('new candidate ASN.1 spec is %s, chosen by %s' % (__chosenSpec is None and '' or __chosenSpec.prettyPrintType(), tagSet)) - else: - __chosenSpec = asn1Spec - debug.logger and debug.logger & debug.flagDecoder and debug.logger('candidate ASN.1 spec is %s' % asn1Spec.__class__.__name__) - if __chosenSpec is not None and ( - tagSet == __chosenSpec.getTagSet() or \ - tagSet in __chosenSpec.getTagMap() - ): - # use base type for codec lookup to recover untagged types - baseTagSet = __chosenSpec.baseTagSet - if __chosenSpec.typeId is not None and \ - __chosenSpec.typeId in self.__typeMap: - # ambiguous type - concreteDecoder = self.__typeMap[__chosenSpec.typeId] - debug.logger and debug.logger & debug.flagDecoder and debug.logger('value decoder chosen for an ambiguous type by type ID %s' % (__chosenSpec.typeId,)) - elif baseTagSet in self.__tagMap: - # base type or tagged subtype - concreteDecoder = self.__tagMap[baseTagSet] - debug.logger and debug.logger & debug.flagDecoder and debug.logger('value decoder chosen by base %s' % (baseTagSet,)) - else: - concreteDecoder = None - if concreteDecoder: - asn1Spec = __chosenSpec - state = stDecodeValue - else: - state = stTryAsExplicitTag - else: - concreteDecoder = None - state = stTryAsExplicitTag - if debug.logger and debug.logger & debug.flagDecoder: - debug.logger('codec %s chosen by ASN.1 spec, decoding %s' % (state == stDecodeValue and concreteDecoder.__class__.__name__ or "", state == stDecodeValue and 'value' or 'as explicit tag')) - debug.scope.push(__chosenSpec is None and '?' or __chosenSpec.__class__.__name__) - if state == stTryAsExplicitTag: - if tagSet and \ - tagSet[0][1] == tag.tagFormatConstructed and \ - tagSet[0][0] != tag.tagClassUniversal: - # Assume explicit tagging - concreteDecoder = explicitTagDecoder - state = stDecodeValue - else: - concreteDecoder = None - state = self.defaultErrorState - debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s chosen, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "", state == stDecodeValue and 'value' or 'as failure')) - if state == stDumpRawValue: - concreteDecoder = self.defaultRawDecoder - debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s chosen, decoding value' % concreteDecoder.__class__.__name__) - state = stDecodeValue - if state == stDecodeValue: - if recursiveFlag == 0 and not substrateFun: # legacy - substrateFun = lambda a,b,c: (a,b[:c]) - if length == -1: # indef length - value, substrate = concreteDecoder.indefLenValueDecoder( - fullSubstrate, substrate, asn1Spec, tagSet, length, - stGetValueDecoder, self, substrateFun - ) - else: - value, substrate = concreteDecoder.valueDecoder( - fullSubstrate, substrate, asn1Spec, tagSet, length, - stGetValueDecoder, self, substrateFun - ) - state = stStop - debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s yields type %s, value:\n%s\n...remaining substrate is: %s' % (concreteDecoder.__class__.__name__, value.__class__.__name__, value.prettyPrint(), substrate and debug.hexdump(substrate) or '')) - if state == stErrorCondition: - raise error.PyAsn1Error( - '%s not in asn1Spec: %s' % (tagSet, asn1Spec) - ) - if debug.logger and debug.logger & debug.flagDecoder: - debug.scope.pop() - debug.logger('decoder left scope %s, call completed' % debug.scope) - return value, substrate - -decode = Decoder(tagMap, typeMap) - -# XXX -# non-recursive decoding; return position rather than substrate diff --git a/lib/sambatools/pyasn1/codec/ber/encoder.py b/lib/sambatools/pyasn1/codec/ber/encoder.py deleted file mode 100644 index f9fe4f20..00000000 --- a/lib/sambatools/pyasn1/codec/ber/encoder.py +++ /dev/null @@ -1,434 +0,0 @@ -# BER encoder -from pyasn1 import debug, error -from pyasn1.codec.ber import eoo -from pyasn1.compat.octets import int2oct, oct2int, ints2octs, null, str2octs -from pyasn1.type import base, tag, univ, char, useful - - -class Error(Exception): pass - -class AbstractItemEncoder: - supportIndefLenMode = 1 - def encodeTag(self, t, isConstructed): - tagClass, tagFormat, tagId = t.asTuple() # this is a hotspot - v = tagClass | tagFormat - if isConstructed: - v = v|tag.tagFormatConstructed - if tagId < 31: - return int2oct(v|tagId) - else: - s = int2oct(tagId&0x7f) - tagId = tagId >> 7 - while tagId: - s = int2oct(0x80|(tagId&0x7f)) + s - tagId = tagId >> 7 - return int2oct(v|0x1F) + s - - def encodeLength(self, length, defMode): - if not defMode and self.supportIndefLenMode: - return int2oct(0x80) - if length < 0x80: - return int2oct(length) - else: - substrate = null - while length: - substrate = int2oct(length&0xff) + substrate - length = length >> 8 - substrateLen = len(substrate) - if substrateLen > 126: - raise Error('Length octets overflow (%d)' % substrateLen) - return int2oct(0x80 | substrateLen) + substrate - - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - raise Error('Not implemented') - - def _encodeEndOfOctets(self, encodeFun, defMode): - if defMode or not self.supportIndefLenMode: - return null - else: - return encodeFun(eoo.endOfOctets, defMode) - - def encode(self, encodeFun, value, defMode, maxChunkSize): - substrate, isConstructed = self.encodeValue( - encodeFun, value, defMode, maxChunkSize - ) - tagSet = value.getTagSet() - if tagSet: - if not isConstructed: # primitive form implies definite mode - defMode = 1 - return self.encodeTag( - tagSet[-1], isConstructed - ) + self.encodeLength( - len(substrate), defMode - ) + substrate + self._encodeEndOfOctets(encodeFun, defMode) - else: - return substrate # untagged value - -class EndOfOctetsEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - return null, 0 - -class ExplicitlyTaggedItemEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - if isinstance(value, base.AbstractConstructedAsn1Item): - value = value.clone(tagSet=value.getTagSet()[:-1], - cloneValueFlag=1) - else: - value = value.clone(tagSet=value.getTagSet()[:-1]) - return encodeFun(value, defMode, maxChunkSize), 1 - -explicitlyTaggedItemEncoder = ExplicitlyTaggedItemEncoder() - -class BooleanEncoder(AbstractItemEncoder): - supportIndefLenMode = 0 - _true = ints2octs((1,)) - _false = ints2octs((0,)) - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - return value and self._true or self._false, 0 - -class IntegerEncoder(AbstractItemEncoder): - supportIndefLenMode = 0 - supportCompactZero = False - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - if value == 0: # shortcut for zero value - if self.supportCompactZero: - # this seems to be a correct way for encoding zeros - return null, 0 - else: - # this seems to be a widespread way for encoding zeros - return ints2octs((0,)), 0 - octets = [] - value = int(value) # to save on ops on asn1 type - while 1: - octets.insert(0, value & 0xff) - if value == 0 or value == -1: - break - value = value >> 8 - if value == 0 and octets[0] & 0x80: - octets.insert(0, 0) - while len(octets) > 1 and \ - (octets[0] == 0 and octets[1] & 0x80 == 0 or \ - octets[0] == 0xff and octets[1] & 0x80 != 0): - del octets[0] - return ints2octs(octets), 0 - -class BitStringEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - if not maxChunkSize or len(value) <= maxChunkSize*8: - out_len = (len(value) + 7) // 8 - out_list = out_len * [0] - j = 7 - i = -1 - for val in value: - j += 1 - if j == 8: - i += 1 - j = 0 - out_list[i] = out_list[i] | val << (7-j) - return int2oct(7-j) + ints2octs(out_list), 0 - else: - pos = 0; substrate = null - while 1: - # count in octets - v = value.clone(value[pos*8:pos*8+maxChunkSize*8]) - if not v: - break - substrate = substrate + encodeFun(v, defMode, maxChunkSize) - pos = pos + maxChunkSize - return substrate, 1 - -class OctetStringEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - if not maxChunkSize or len(value) <= maxChunkSize: - return value.asOctets(), 0 - else: - pos = 0; substrate = null - while 1: - v = value.clone(value[pos:pos+maxChunkSize]) - if not v: - break - substrate = substrate + encodeFun(v, defMode, maxChunkSize) - pos = pos + maxChunkSize - return substrate, 1 - -class NullEncoder(AbstractItemEncoder): - supportIndefLenMode = 0 - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - return null, 0 - -class ObjectIdentifierEncoder(AbstractItemEncoder): - supportIndefLenMode = 0 - precomputedValues = { - (1, 3, 6, 1, 2): (43, 6, 1, 2), - (1, 3, 6, 1, 4): (43, 6, 1, 4) - } - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - oid = value.asTuple() - if oid[:5] in self.precomputedValues: - octets = self.precomputedValues[oid[:5]] - oid = oid[5:] - else: - if len(oid) < 2: - raise error.PyAsn1Error('Short OID %s' % (value,)) - - octets = () - - # Build the first twos - if oid[0] == 0 and 0 <= oid[1] <= 39: - oid = (oid[1],) + oid[2:] - elif oid[0] == 1 and 0 <= oid[1] <= 39: - oid = (oid[1] + 40,) + oid[2:] - elif oid[0] == 2: - oid = (oid[1] + 80,) + oid[2:] - else: - raise error.PyAsn1Error( - 'Impossible initial arcs %s at %s' % (oid[:2], value) - ) - - # Cycle through subIds - for subId in oid: - if subId > -1 and subId < 128: - # Optimize for the common case - octets = octets + (subId & 0x7f,) - elif subId < 0: - raise error.PyAsn1Error( - 'Negative OID arc %s at %s' % (subId, value) - ) - else: - # Pack large Sub-Object IDs - res = (subId & 0x7f,) - subId = subId >> 7 - while subId > 0: - res = (0x80 | (subId & 0x7f),) + res - subId = subId >> 7 - # Add packed Sub-Object ID to resulted Object ID - octets += res - - return ints2octs(octets), 0 - -class RealEncoder(AbstractItemEncoder): - supportIndefLenMode = 0 - binEncBase = 2 # set to None to choose encoding base automatically - def _dropFloatingPoint(self, m, encbase, e): - ms, es = 1, 1 - if m < 0: - ms = -1 # mantissa sign - if e < 0: - es = -1 # exponenta sign - m *= ms - if encbase == 8: - m = m*2**(abs(e) % 3 * es) - e = abs(e) // 3 * es - elif encbase == 16: - m = m*2**(abs(e) % 4 * es) - e = abs(e) // 4 * es - - while 1: - if int(m) != m: - m *= encbase - e -= 1 - continue - break - return ms, int(m), encbase, e - - def _chooseEncBase(self, value): - m, b, e = value - base = [2, 8, 16] - if value.binEncBase in base: - return self._dropFloatingPoint(m, value.binEncBase, e) - elif self.binEncBase in base: - return self._dropFloatingPoint(m, self.binEncBase, e) - # auto choosing base 2/8/16 - mantissa = [m, m, m] - exponenta = [e, e, e] - encbase = 2 - e = float('inf') - for i in range(3): - sign, mantissa[i], base[i], exponenta[i] = \ - self._dropFloatingPoint(mantissa[i], base[i], exponenta[i]) - if abs(exponenta[i]) < abs(e) or \ - (abs(exponenta[i]) == abs(e) and mantissa[i] < m): - e = exponenta[i] - m = int(mantissa[i]) - encbase = base[i] - return sign, m, encbase, e - - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - if value.isPlusInfinity(): - return int2oct(0x40), 0 - if value.isMinusInfinity(): - return int2oct(0x41), 0 - m, b, e = value - if not m: - return null, 0 - if b == 10: - return str2octs('\x03%dE%s%d' % (m, e == 0 and '+' or '', e)), 0 - elif b == 2: - fo = 0x80 # binary encoding - ms, m, encbase, e = self._chooseEncBase(value) - if ms < 0: # mantissa sign - fo = fo | 0x40 # sign bit - # exponenta & mantissa normalization - if encbase == 2: - while m & 0x1 == 0: - m >>= 1 - e += 1 - elif encbase == 8: - while m & 0x7 == 0: - m >>= 3 - e += 1 - fo |= 0x10 - else: # encbase = 16 - while m & 0xf == 0: - m >>= 4 - e += 1 - fo |= 0x20 - sf = 0 # scale factor - while m & 0x1 == 0: - m >>= 1 - sf += 1 - if sf > 3: - raise error.PyAsn1Error('Scale factor overflow') # bug if raised - fo |= sf << 2 - eo = null - if e == 0 or e == -1: - eo = int2oct(e&0xff) - else: - while e not in (0, -1): - eo = int2oct(e&0xff) + eo - e >>= 8 - if e == 0 and eo and oct2int(eo[0]) & 0x80: - eo = int2oct(0) + eo - if e == -1 and eo and not (oct2int(eo[0]) & 0x80): - eo = int2oct(0xff) + eo - n = len(eo) - if n > 0xff: - raise error.PyAsn1Error('Real exponent overflow') - if n == 1: - pass - elif n == 2: - fo |= 1 - elif n == 3: - fo |= 2 - else: - fo |= 3 - eo = int2oct(n&0xff) + eo - po = null - while m: - po = int2oct(m&0xff) + po - m >>= 8 - substrate = int2oct(fo) + eo + po - return substrate, 0 - else: - raise error.PyAsn1Error('Prohibited Real base %s' % b) - -class SequenceEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - value.setDefaultComponents() - value.verifySizeSpec() - substrate = null; idx = len(value) - while idx > 0: - idx = idx - 1 - if value[idx] is None: # Optional component - continue - component = value.getDefaultComponentByPosition(idx) - if component is not None and component == value[idx]: - continue - substrate = encodeFun( - value[idx], defMode, maxChunkSize - ) + substrate - return substrate, 1 - -class SequenceOfEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - value.verifySizeSpec() - substrate = null; idx = len(value) - while idx > 0: - idx = idx - 1 - substrate = encodeFun( - value[idx], defMode, maxChunkSize - ) + substrate - return substrate, 1 - -class ChoiceEncoder(AbstractItemEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - return encodeFun(value.getComponent(), defMode, maxChunkSize), 1 - -class AnyEncoder(OctetStringEncoder): - def encodeValue(self, encodeFun, value, defMode, maxChunkSize): - return value.asOctets(), defMode == 0 - -tagMap = { - eoo.endOfOctets.tagSet: EndOfOctetsEncoder(), - univ.Boolean.tagSet: BooleanEncoder(), - univ.Integer.tagSet: IntegerEncoder(), - univ.BitString.tagSet: BitStringEncoder(), - univ.OctetString.tagSet: OctetStringEncoder(), - univ.Null.tagSet: NullEncoder(), - univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(), - univ.Enumerated.tagSet: IntegerEncoder(), - univ.Real.tagSet: RealEncoder(), - # Sequence & Set have same tags as SequenceOf & SetOf - univ.SequenceOf.tagSet: SequenceOfEncoder(), - univ.SetOf.tagSet: SequenceOfEncoder(), - univ.Choice.tagSet: ChoiceEncoder(), - # character string types - char.UTF8String.tagSet: OctetStringEncoder(), - char.NumericString.tagSet: OctetStringEncoder(), - char.PrintableString.tagSet: OctetStringEncoder(), - char.TeletexString.tagSet: OctetStringEncoder(), - char.VideotexString.tagSet: OctetStringEncoder(), - char.IA5String.tagSet: OctetStringEncoder(), - char.GraphicString.tagSet: OctetStringEncoder(), - char.VisibleString.tagSet: OctetStringEncoder(), - char.GeneralString.tagSet: OctetStringEncoder(), - char.UniversalString.tagSet: OctetStringEncoder(), - char.BMPString.tagSet: OctetStringEncoder(), - # useful types - useful.ObjectDescriptor.tagSet: OctetStringEncoder(), - useful.GeneralizedTime.tagSet: OctetStringEncoder(), - useful.UTCTime.tagSet: OctetStringEncoder() - } - -# Type-to-codec map for ambiguous ASN.1 types -typeMap = { - univ.Set.typeId: SequenceEncoder(), - univ.SetOf.typeId: SequenceOfEncoder(), - univ.Sequence.typeId: SequenceEncoder(), - univ.SequenceOf.typeId: SequenceOfEncoder(), - univ.Choice.typeId: ChoiceEncoder(), - univ.Any.typeId: AnyEncoder() - } - -class Encoder: - supportIndefLength = True - def __init__(self, tagMap, typeMap={}): - self.__tagMap = tagMap - self.__typeMap = typeMap - - def __call__(self, value, defMode=True, maxChunkSize=0): - if not defMode and not self.supportIndefLength: - raise error.PyAsn1Error('Indefinite length encoding not supported by this codec') - debug.logger & debug.flagEncoder and debug.logger('encoder called in %sdef mode, chunk size %s for type %s, value:\n%s' % (not defMode and 'in' or '', maxChunkSize, value.prettyPrintType(), value.prettyPrint())) - tagSet = value.getTagSet() - if len(tagSet) > 1: - concreteEncoder = explicitlyTaggedItemEncoder - else: - if value.typeId is not None and value.typeId in self.__typeMap: - concreteEncoder = self.__typeMap[value.typeId] - elif tagSet in self.__tagMap: - concreteEncoder = self.__tagMap[tagSet] - else: - tagSet = value.baseTagSet - if tagSet in self.__tagMap: - concreteEncoder = self.__tagMap[tagSet] - else: - raise Error('No encoder for %s' % (value,)) - debug.logger & debug.flagEncoder and debug.logger('using value codec %s chosen by %s' % (concreteEncoder.__class__.__name__, tagSet)) - substrate = concreteEncoder.encode( - self, value, defMode, maxChunkSize - ) - debug.logger & debug.flagEncoder and debug.logger('built %s octets of substrate: %s\nencoder completed' % (len(substrate), debug.hexdump(substrate))) - return substrate - -encode = Encoder(tagMap, typeMap) diff --git a/lib/sambatools/pyasn1/codec/ber/eoo.py b/lib/sambatools/pyasn1/codec/ber/eoo.py deleted file mode 100644 index 379be199..00000000 --- a/lib/sambatools/pyasn1/codec/ber/eoo.py +++ /dev/null @@ -1,8 +0,0 @@ -from pyasn1.type import base, tag - -class EndOfOctets(base.AbstractSimpleAsn1Item): - defaultValue = 0 - tagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x00) - ) -endOfOctets = EndOfOctets() diff --git a/lib/sambatools/pyasn1/codec/cer/decoder.py b/lib/sambatools/pyasn1/codec/cer/decoder.py deleted file mode 100644 index 9376a4dc..00000000 --- a/lib/sambatools/pyasn1/codec/cer/decoder.py +++ /dev/null @@ -1,36 +0,0 @@ -# CER decoder -from pyasn1 import error -from pyasn1.codec.ber import decoder -from pyasn1.compat.octets import oct2int -from pyasn1.type import univ - - -class BooleanDecoder(decoder.AbstractSimpleDecoder): - protoComponent = univ.Boolean(0) - def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length, - state, decodeFun, substrateFun): - head, tail = substrate[:length], substrate[length:] - if not head or length != 1: - raise error.PyAsn1Error('Not single-octet Boolean payload') - byte = oct2int(head[0]) - # CER/DER specifies encoding of TRUE as 0xFF and FALSE as 0x0, while - # BER allows any non-zero value as TRUE; cf. sections 8.2.2. and 11.1 - # in http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf - if byte == 0xff: - value = 1 - elif byte == 0x00: - value = 0 - else: - raise error.PyAsn1Error('Unexpected Boolean payload: %s' % byte) - return self._createComponent(asn1Spec, tagSet, value), tail - -tagMap = decoder.tagMap.copy() -tagMap.update({ - univ.Boolean.tagSet: BooleanDecoder() - }) - -typeMap = decoder.typeMap - -class Decoder(decoder.Decoder): pass - -decode = Decoder(tagMap, decoder.typeMap) diff --git a/lib/sambatools/pyasn1/codec/cer/encoder.py b/lib/sambatools/pyasn1/codec/cer/encoder.py deleted file mode 100644 index 1966a460..00000000 --- a/lib/sambatools/pyasn1/codec/cer/encoder.py +++ /dev/null @@ -1,131 +0,0 @@ -# CER encoder -from pyasn1 import error -from pyasn1.codec.ber import encoder -from pyasn1.compat.octets import int2oct, str2octs, null -from pyasn1.type import univ -from pyasn1.type import useful - - -class BooleanEncoder(encoder.IntegerEncoder): - def encodeValue(self, encodeFun, client, defMode, maxChunkSize): - if client == 0: - substrate = int2oct(0) - else: - substrate = int2oct(255) - return substrate, 0 - -class BitStringEncoder(encoder.BitStringEncoder): - def encodeValue(self, encodeFun, client, defMode, maxChunkSize): - return encoder.BitStringEncoder.encodeValue( - self, encodeFun, client, defMode, 1000 - ) - -class OctetStringEncoder(encoder.OctetStringEncoder): - def encodeValue(self, encodeFun, client, defMode, maxChunkSize): - return encoder.OctetStringEncoder.encodeValue( - self, encodeFun, client, defMode, 1000 - ) - -class RealEncoder(encoder.RealEncoder): - def _chooseEncBase(self, value): - m, b, e = value - return self._dropFloatingPoint(m, b, e) - -# specialized GeneralStringEncoder here - -class GeneralizedTimeEncoder(OctetStringEncoder): - zchar = str2octs('Z') - pluschar = str2octs('+') - minuschar = str2octs('-') - zero = str2octs('0') - def encodeValue(self, encodeFun, client, defMode, maxChunkSize): - octets = client.asOctets() -# This breaks too many existing data items -# if '.' not in octets: -# raise error.PyAsn1Error('Format must include fraction of second: %r' % octets) - if len(octets) < 15: - raise error.PyAsn1Error('Bad UTC time length: %r' % octets) - if self.pluschar in octets or self.minuschar in octets: - raise error.PyAsn1Error('Must be UTC time: %r' % octets) - if octets[-1] != self.zchar[0]: - raise error.PyAsn1Error('Missing timezone specifier: %r' % octets) - return encoder.OctetStringEncoder.encodeValue( - self, encodeFun, client, defMode, 1000 - ) - -class UTCTimeEncoder(encoder.OctetStringEncoder): - zchar = str2octs('Z') - pluschar = str2octs('+') - minuschar = str2octs('-') - def encodeValue(self, encodeFun, client, defMode, maxChunkSize): - octets = client.asOctets() - if self.pluschar in octets or self.minuschar in octets: - raise error.PyAsn1Error('Must be UTC time: %r' % octets) - if octets and octets[-1] != self.zchar[0]: - client = client.clone(octets + self.zchar) - if len(client) != 13: - raise error.PyAsn1Error('Bad UTC time length: %r' % client) - return encoder.OctetStringEncoder.encodeValue( - self, encodeFun, client, defMode, 1000 - ) - -class SetOfEncoder(encoder.SequenceOfEncoder): - def encodeValue(self, encodeFun, client, defMode, maxChunkSize): - if isinstance(client, univ.SequenceAndSetBase): - client.setDefaultComponents() - client.verifySizeSpec() - substrate = null; idx = len(client) - # This is certainly a hack but how else do I distinguish SetOf - # from Set if they have the same tags&constraints? - if isinstance(client, univ.SequenceAndSetBase): - # Set - comps = [] - while idx > 0: - idx = idx - 1 - if client[idx] is None: # Optional component - continue - if client.getDefaultComponentByPosition(idx) == client[idx]: - continue - comps.append(client[idx]) - comps.sort(key=lambda x: isinstance(x, univ.Choice) and \ - x.getMinTagSet() or x.getTagSet()) - for c in comps: - substrate += encodeFun(c, defMode, maxChunkSize) - else: - # SetOf - compSubs = [] - while idx > 0: - idx = idx - 1 - compSubs.append( - encodeFun(client[idx], defMode, maxChunkSize) - ) - compSubs.sort() # perhaps padding's not needed - substrate = null - for compSub in compSubs: - substrate += compSub - return substrate, 1 - -tagMap = encoder.tagMap.copy() -tagMap.update({ - univ.Boolean.tagSet: BooleanEncoder(), - univ.BitString.tagSet: BitStringEncoder(), - univ.OctetString.tagSet: OctetStringEncoder(), - univ.Real.tagSet: RealEncoder(), - useful.GeneralizedTime.tagSet: GeneralizedTimeEncoder(), - useful.UTCTime.tagSet: UTCTimeEncoder(), - univ.SetOf().tagSet: SetOfEncoder() # conflcts with Set -}) - -typeMap = encoder.typeMap.copy() -typeMap.update({ - univ.Set.typeId: SetOfEncoder(), - univ.SetOf.typeId: SetOfEncoder() -}) - -class Encoder(encoder.Encoder): - def __call__(self, client, defMode=False, maxChunkSize=0): - return encoder.Encoder.__call__(self, client, defMode, maxChunkSize) - -encode = Encoder(tagMap, typeMap) - -# EncoderFactory queries class instance and builds a map of tags -> encoders diff --git a/lib/sambatools/pyasn1/codec/der/decoder.py b/lib/sambatools/pyasn1/codec/der/decoder.py deleted file mode 100644 index ea58d6d7..00000000 --- a/lib/sambatools/pyasn1/codec/der/decoder.py +++ /dev/null @@ -1,9 +0,0 @@ -# DER decoder -from pyasn1.codec.cer import decoder - -tagMap = decoder.tagMap -typeMap = decoder.typeMap -class Decoder(decoder.Decoder): - supportIndefLength = False - -decode = Decoder(tagMap, typeMap) diff --git a/lib/sambatools/pyasn1/codec/der/encoder.py b/lib/sambatools/pyasn1/codec/der/encoder.py deleted file mode 100644 index aa4d429d..00000000 --- a/lib/sambatools/pyasn1/codec/der/encoder.py +++ /dev/null @@ -1,33 +0,0 @@ -# DER encoder -from pyasn1 import error -from pyasn1.codec.cer import encoder -from pyasn1.type import univ - - -class SetOfEncoder(encoder.SetOfEncoder): - def _cmpSetComponents(self, c1, c2): - tagSet1 = isinstance(c1, univ.Choice) and \ - c1.getEffectiveTagSet() or c1.getTagSet() - tagSet2 = isinstance(c2, univ.Choice) and \ - c2.getEffectiveTagSet() or c2.getTagSet() - return cmp(tagSet1, tagSet2) - -tagMap = encoder.tagMap.copy() -tagMap.update({ - # Overload CER encoders with BER ones (a bit hackerish XXX) - univ.BitString.tagSet: encoder.encoder.BitStringEncoder(), - univ.OctetString.tagSet: encoder.encoder.OctetStringEncoder(), - # Set & SetOf have same tags - univ.SetOf().tagSet: SetOfEncoder() -}) - -typeMap = encoder.typeMap - -class Encoder(encoder.Encoder): - supportIndefLength = False - def __call__(self, client, defMode=True, maxChunkSize=0): - if not defMode: - raise error.PyAsn1Error('DER forbids indefinite length mode') - return encoder.Encoder.__call__(self, client, defMode, maxChunkSize) - -encode = Encoder(tagMap, typeMap) diff --git a/lib/sambatools/pyasn1/compat/binary.py b/lib/sambatools/pyasn1/compat/binary.py deleted file mode 100644 index b38932af..00000000 --- a/lib/sambatools/pyasn1/compat/binary.py +++ /dev/null @@ -1,10 +0,0 @@ -from sys import version_info - -if version_info[0:2] < (2, 6): - def bin(x): - if x <= 1: - return '0b'+str(x) - else: - return bin(x>>1) + str(x&1) -else: - bin = bin diff --git a/lib/sambatools/pyasn1/compat/octets.py b/lib/sambatools/pyasn1/compat/octets.py deleted file mode 100644 index e8127370..00000000 --- a/lib/sambatools/pyasn1/compat/octets.py +++ /dev/null @@ -1,22 +0,0 @@ -from sys import version_info - -if version_info[0] <= 2: - int2oct = chr - ints2octs = lambda s: ''.join([ int2oct(x) for x in s ]) - null = '' - oct2int = ord - octs2ints = lambda s: [ oct2int(x) for x in s ] - str2octs = lambda x: x - octs2str = lambda x: x - isOctetsType = lambda s: isinstance(s, str) - isStringType = lambda s: isinstance(s, (str, unicode)) -else: - ints2octs = bytes - int2oct = lambda x: ints2octs((x,)) - null = ints2octs() - oct2int = lambda x: x - octs2ints = lambda s: [ x for x in s ] - str2octs = lambda x: x.encode() - octs2str = lambda x: x.decode() - isOctetsType = lambda s: isinstance(s, bytes) - isStringType = lambda s: isinstance(s, str) diff --git a/lib/sambatools/pyasn1/debug.py b/lib/sambatools/pyasn1/debug.py deleted file mode 100644 index 873605d4..00000000 --- a/lib/sambatools/pyasn1/debug.py +++ /dev/null @@ -1,110 +0,0 @@ -import logging - -from pyasn1 import __version__ -from pyasn1 import error -from pyasn1.compat.octets import octs2ints - -flagNone = 0x0000 -flagEncoder = 0x0001 -flagDecoder = 0x0002 -flagAll = 0xffff - -flagMap = { - 'encoder': flagEncoder, - 'decoder': flagDecoder, - 'all': flagAll - } - -class Printer: - def __init__(self, logger=None, handler=None, formatter=None): - if logger is None: - logger = logging.getLogger('pyasn1') - logger.setLevel(logging.DEBUG) - if handler is None: - handler = logging.StreamHandler() - if formatter is None: - formatter = logging.Formatter('%(asctime)s %(name)s: %(message)s') - handler.setFormatter(formatter) - handler.setLevel(logging.DEBUG) - logger.addHandler(handler) - self.__logger = logger - - def __call__(self, msg): self.__logger.debug(msg) - def __str__(self): return '' - -if hasattr(logging, 'NullHandler'): - NullHandler = logging.NullHandler -else: - # Python 2.6 and older - class NullHandler(logging.Handler): - def emit(self, record): - pass - -class Debug: - defaultPrinter = None - def __init__(self, *flags, **options): - self._flags = flagNone - if options.get('printer') is not None: - self._printer = options.get('printer') - elif self.defaultPrinter is not None: - self._printer = self.defaultPrinter - if 'loggerName' in options: - # route our logs to parent logger - self._printer = Printer( - logger=logging.getLogger(options['loggerName']), - handler=NullHandler() - ) - else: - self._printer = Printer() - self('running pyasn1 version %s' % __version__) - for f in flags: - inverse = f and f[0] in ('!', '~') - if inverse: - f = f[1:] - try: - if inverse: - self._flags &= ~flagMap[f] - else: - self._flags |= flagMap[f] - except KeyError: - raise error.PyAsn1Error('bad debug flag %s' % f) - - self('debug category \'%s\' %s' % (f, inverse and 'disabled' or 'enabled')) - - def __str__(self): - return 'logger %s, flags %x' % (self._printer, self._flags) - - def __call__(self, msg): - self._printer(msg) - - def __and__(self, flag): - return self._flags & flag - - def __rand__(self, flag): - return flag & self._flags - -logger = 0 - -def setLogger(l): - global logger - logger = l - -def hexdump(octets): - return ' '.join( - [ '%s%.2X' % (n%16 == 0 and ('\n%.5d: ' % n) or '', x) - for n,x in zip(range(len(octets)), octs2ints(octets)) ] - ) - -class Scope: - def __init__(self): - self._list = [] - - def __str__(self): return '.'.join(self._list) - - def push(self, token): - self._list.append(token) - - def pop(self): - return self._list.pop() - -scope = Scope() diff --git a/lib/sambatools/pyasn1/error.py b/lib/sambatools/pyasn1/error.py deleted file mode 100644 index 716406ff..00000000 --- a/lib/sambatools/pyasn1/error.py +++ /dev/null @@ -1,3 +0,0 @@ -class PyAsn1Error(Exception): pass -class ValueConstraintError(PyAsn1Error): pass -class SubstrateUnderrunError(PyAsn1Error): pass diff --git a/lib/sambatools/pyasn1/type/base.py b/lib/sambatools/pyasn1/type/base.py deleted file mode 100644 index e93e7b6a..00000000 --- a/lib/sambatools/pyasn1/type/base.py +++ /dev/null @@ -1,280 +0,0 @@ -# Base classes for ASN.1 types -import sys - -from pyasn1 import error -from pyasn1.type import constraint, tagmap, tag - - -class Asn1Item: pass - -class Asn1ItemBase(Asn1Item): - # Set of tags for this ASN.1 type - tagSet = tag.TagSet() - - # A list of constraint.Constraint instances for checking values - subtypeSpec = constraint.ConstraintsIntersection() - - # Used for ambiguous ASN.1 types identification - typeId = None - - def __init__(self, tagSet=None, subtypeSpec=None): - if tagSet is None: - self._tagSet = self.tagSet - else: - self._tagSet = tagSet - if subtypeSpec is None: - self._subtypeSpec = self.subtypeSpec - else: - self._subtypeSpec = subtypeSpec - - def _verifySubtypeSpec(self, value, idx=None): - try: - self._subtypeSpec(value, idx) - except error.PyAsn1Error: - c, i, t = sys.exc_info() - raise c('%s at %s' % (i, self.__class__.__name__)) - - def getSubtypeSpec(self): return self._subtypeSpec - - def getTagSet(self): return self._tagSet - def getEffectiveTagSet(self): return self._tagSet # used by untagged types - def getTagMap(self): return tagmap.TagMap({self._tagSet: self}) - - def isSameTypeWith(self, other, matchTags=True, matchConstraints=True): - return self is other or \ - (not matchTags or \ - self._tagSet == other.getTagSet()) and \ - (not matchConstraints or \ - self._subtypeSpec==other.getSubtypeSpec()) - - def isSuperTypeOf(self, other, matchTags=True, matchConstraints=True): - """Returns true if argument is a ASN1 subtype of ourselves""" - return (not matchTags or \ - self._tagSet.isSuperTagSetOf(other.getTagSet())) and \ - (not matchConstraints or \ - (self._subtypeSpec.isSuperTypeOf(other.getSubtypeSpec()))) - -class NoValue: - def __getattr__(self, attr): - raise error.PyAsn1Error('No value for %s()' % attr) - def __getitem__(self, i): - raise error.PyAsn1Error('No value') - def __repr__(self): return '%s()' % self.__class__.__name__ - -noValue = NoValue() - -# Base class for "simple" ASN.1 objects. These are immutable. -class AbstractSimpleAsn1Item(Asn1ItemBase): - defaultValue = noValue - def __init__(self, value=None, tagSet=None, subtypeSpec=None): - Asn1ItemBase.__init__(self, tagSet, subtypeSpec) - if value is None or value is noValue: - value = self.defaultValue - if value is None or value is noValue: - self.__hashedValue = value = noValue - else: - value = self.prettyIn(value) - self._verifySubtypeSpec(value) - self.__hashedValue = hash(value) - self._value = value - self._len = None - - def __repr__(self): - r = [] - if self._value is not self.defaultValue: - r.append(self.prettyOut(self._value)) - if self._tagSet is not self.tagSet: - r.append('tagSet=%r' % (self._tagSet,)) - if self._subtypeSpec is not self.subtypeSpec: - r.append('subtypeSpec=%r' % (self._subtypeSpec,)) - return '%s(%s)' % (self.__class__.__name__, ', '.join(r)) - - def __str__(self): return str(self._value) - def __eq__(self, other): - return self is other and True or self._value == other - def __ne__(self, other): return self._value != other - def __lt__(self, other): return self._value < other - def __le__(self, other): return self._value <= other - def __gt__(self, other): return self._value > other - def __ge__(self, other): return self._value >= other - if sys.version_info[0] <= 2: - def __nonzero__(self): return bool(self._value) - else: - def __bool__(self): return bool(self._value) - def __hash__(self): - return self.__hashedValue is noValue and hash(noValue) or self.__hashedValue - - def hasValue(self): - return not isinstance(self._value, NoValue) - - def clone(self, value=None, tagSet=None, subtypeSpec=None): - if value is None and tagSet is None and subtypeSpec is None: - return self - if value is None: - value = self._value - if tagSet is None: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - return self.__class__(value, tagSet, subtypeSpec) - - def subtype(self, value=None, implicitTag=None, explicitTag=None, - subtypeSpec=None): - if value is None: - value = self._value - if implicitTag is not None: - tagSet = self._tagSet.tagImplicitly(implicitTag) - elif explicitTag is not None: - tagSet = self._tagSet.tagExplicitly(explicitTag) - else: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - else: - subtypeSpec = subtypeSpec + self._subtypeSpec - return self.__class__(value, tagSet, subtypeSpec) - - def prettyIn(self, value): return value - def prettyOut(self, value): return str(value) - - def prettyPrint(self, scope=0): - if self.hasValue(): - return self.prettyOut(self._value) - else: - return '' - - # XXX Compatibility stub - def prettyPrinter(self, scope=0): return self.prettyPrint(scope) - - def prettyPrintType(self, scope=0): - return '%s -> %s' % (self.getTagSet(), self.__class__.__name__) - -# -# Constructed types: -# * There are five of them: Sequence, SequenceOf/SetOf, Set and Choice -# * ASN1 types and values are represened by Python class instances -# * Value initialization is made for defaulted components only -# * Primary method of component addressing is by-position. Data model for base -# type is Python sequence. Additional type-specific addressing methods -# may be implemented for particular types. -# * SequenceOf and SetOf types do not implement any additional methods -# * Sequence, Set and Choice types also implement by-identifier addressing -# * Sequence, Set and Choice types also implement by-asn1-type (tag) addressing -# * Sequence and Set types may include optional and defaulted -# components -# * Constructed types hold a reference to component types used for value -# verification and ordering. -# * Component type is a scalar type for SequenceOf/SetOf types and a list -# of types for Sequence/Set/Choice. -# - -class AbstractConstructedAsn1Item(Asn1ItemBase): - componentType = None - sizeSpec = constraint.ConstraintsIntersection() - def __init__(self, componentType=None, tagSet=None, - subtypeSpec=None, sizeSpec=None): - Asn1ItemBase.__init__(self, tagSet, subtypeSpec) - if componentType is None: - self._componentType = self.componentType - else: - self._componentType = componentType - if sizeSpec is None: - self._sizeSpec = self.sizeSpec - else: - self._sizeSpec = sizeSpec - self._componentValues = [] - self._componentValuesSet = 0 - - def __repr__(self): - r = [] - if self._componentType is not self.componentType: - r.append('componentType=%r' % (self._componentType,)) - if self._tagSet is not self.tagSet: - r.append('tagSet=%r' % (self._tagSet,)) - if self._subtypeSpec is not self.subtypeSpec: - r.append('subtypeSpec=%r' % (self._subtypeSpec,)) - r = '%s(%s)' % (self.__class__.__name__, ', '.join(r)) - if self._componentValues: - r += '.setComponents(%s)' % ', '.join([repr(x) for x in self._componentValues]) - return r - - def __eq__(self, other): - return self is other and True or self._componentValues == other - def __ne__(self, other): return self._componentValues != other - def __lt__(self, other): return self._componentValues < other - def __le__(self, other): return self._componentValues <= other - def __gt__(self, other): return self._componentValues > other - def __ge__(self, other): return self._componentValues >= other - if sys.version_info[0] <= 2: - def __nonzero__(self): return bool(self._componentValues) - else: - def __bool__(self): return bool(self._componentValues) - - def getComponentTagMap(self): - raise error.PyAsn1Error('Method not implemented') - - def _cloneComponentValues(self, myClone, cloneValueFlag): pass - - def clone(self, tagSet=None, subtypeSpec=None, sizeSpec=None, - cloneValueFlag=None): - if tagSet is None: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - if sizeSpec is None: - sizeSpec = self._sizeSpec - r = self.__class__(self._componentType, tagSet, subtypeSpec, sizeSpec) - if cloneValueFlag: - self._cloneComponentValues(r, cloneValueFlag) - return r - - def subtype(self, implicitTag=None, explicitTag=None, subtypeSpec=None, - sizeSpec=None, cloneValueFlag=None): - if implicitTag is not None: - tagSet = self._tagSet.tagImplicitly(implicitTag) - elif explicitTag is not None: - tagSet = self._tagSet.tagExplicitly(explicitTag) - else: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - else: - subtypeSpec = subtypeSpec + self._subtypeSpec - if sizeSpec is None: - sizeSpec = self._sizeSpec - else: - sizeSpec = sizeSpec + self._sizeSpec - r = self.__class__(self._componentType, tagSet, subtypeSpec, sizeSpec) - if cloneValueFlag: - self._cloneComponentValues(r, cloneValueFlag) - return r - - def _verifyComponent(self, idx, value): pass - - def verifySizeSpec(self): self._sizeSpec(self) - - def getComponentByPosition(self, idx): - raise error.PyAsn1Error('Method not implemented') - def setComponentByPosition(self, idx, value, verifyConstraints=True): - raise error.PyAsn1Error('Method not implemented') - - def setComponents(self, *args, **kwargs): - for idx in range(len(args)): - self[idx] = args[idx] - for k in kwargs: - self[k] = kwargs[k] - return self - - def getComponentType(self): return self._componentType - - def setDefaultComponents(self): pass - - def __getitem__(self, idx): return self.getComponentByPosition(idx) - def __setitem__(self, idx, value): self.setComponentByPosition(idx, value) - - def __len__(self): return len(self._componentValues) - - def clear(self): - self._componentValues = [] - self._componentValuesSet = 0 - diff --git a/lib/sambatools/pyasn1/type/char.py b/lib/sambatools/pyasn1/type/char.py deleted file mode 100644 index af49ab3e..00000000 --- a/lib/sambatools/pyasn1/type/char.py +++ /dev/null @@ -1,64 +0,0 @@ -# ASN.1 "character string" types -from pyasn1.type import univ, tag - -class NumericString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 18) - ) - -class PrintableString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 19) - ) - -class TeletexString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 20) - ) - -class T61String(TeletexString): pass - -class VideotexString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 21) - ) - -class IA5String(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 22) - ) - -class GraphicString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 25) - ) - -class VisibleString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 26) - ) - -class ISO646String(VisibleString): pass - -class GeneralString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 27) - ) - -class UniversalString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 28) - ) - encoding = "utf-32-be" - -class BMPString(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 30) - ) - encoding = "utf-16-be" - -class UTF8String(univ.OctetString): - tagSet = univ.OctetString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12) - ) - encoding = "utf-8" diff --git a/lib/sambatools/pyasn1/type/constraint.py b/lib/sambatools/pyasn1/type/constraint.py deleted file mode 100644 index b0b1c79f..00000000 --- a/lib/sambatools/pyasn1/type/constraint.py +++ /dev/null @@ -1,202 +0,0 @@ -# -# ASN.1 subtype constraints classes. -# -# Constraints are relatively rare, but every ASN1 object -# is doing checks all the time for whether they have any -# constraints and whether they are applicable to the object. -# -# What we're going to do is define objects/functions that -# can be called unconditionally if they are present, and that -# are simply not present if there are no constraints. -# -# Original concept and code by Mike C. Fletcher. -# -import sys - -from pyasn1.type import error - - -class AbstractConstraint: - """Abstract base-class for constraint objects - - Constraints should be stored in a simple sequence in the - namespace of their client Asn1Item sub-classes. - """ - def __init__(self, *values): - self._valueMap = {} - self._setValues(values) - self.__hashedValues = None - def __call__(self, value, idx=None): - try: - self._testValue(value, idx) - except error.ValueConstraintError: - raise error.ValueConstraintError( - '%s failed at: \"%s\"' % (self, sys.exc_info()[1]) - ) - def __repr__(self): - return '%s(%s)' % ( - self.__class__.__name__, - ', '.join([repr(x) for x in self._values]) - ) - def __eq__(self, other): - return self is other and True or self._values == other - def __ne__(self, other): return self._values != other - def __lt__(self, other): return self._values < other - def __le__(self, other): return self._values <= other - def __gt__(self, other): return self._values > other - def __ge__(self, other): return self._values >= other - if sys.version_info[0] <= 2: - def __nonzero__(self): return bool(self._values) - else: - def __bool__(self): return bool(self._values) - - def __hash__(self): - if self.__hashedValues is None: - self.__hashedValues = hash((self.__class__.__name__, self._values)) - return self.__hashedValues - - def _setValues(self, values): self._values = values - def _testValue(self, value, idx): - raise error.ValueConstraintError(value) - - # Constraints derivation logic - def getValueMap(self): return self._valueMap - def isSuperTypeOf(self, otherConstraint): - return self in otherConstraint.getValueMap() or \ - otherConstraint is self or otherConstraint == self - def isSubTypeOf(self, otherConstraint): - return otherConstraint in self._valueMap or \ - otherConstraint is self or otherConstraint == self - -class SingleValueConstraint(AbstractConstraint): - """Value must be part of defined values constraint""" - def _testValue(self, value, idx): - # XXX index vals for performance? - if value not in self._values: - raise error.ValueConstraintError(value) - -class ContainedSubtypeConstraint(AbstractConstraint): - """Value must satisfy all of defined set of constraints""" - def _testValue(self, value, idx): - for c in self._values: - c(value, idx) - -class ValueRangeConstraint(AbstractConstraint): - """Value must be within start and stop values (inclusive)""" - def _testValue(self, value, idx): - if value < self.start or value > self.stop: - raise error.ValueConstraintError(value) - - def _setValues(self, values): - if len(values) != 2: - raise error.PyAsn1Error( - '%s: bad constraint values' % (self.__class__.__name__,) - ) - self.start, self.stop = values - if self.start > self.stop: - raise error.PyAsn1Error( - '%s: screwed constraint values (start > stop): %s > %s' % ( - self.__class__.__name__, - self.start, self.stop - ) - ) - AbstractConstraint._setValues(self, values) - -class ValueSizeConstraint(ValueRangeConstraint): - """len(value) must be within start and stop values (inclusive)""" - def _testValue(self, value, idx): - l = len(value) - if l < self.start or l > self.stop: - raise error.ValueConstraintError(value) - -class PermittedAlphabetConstraint(SingleValueConstraint): - def _setValues(self, values): - self._values = () - for v in values: - self._values = self._values + tuple(v) - - def _testValue(self, value, idx): - for v in value: - if v not in self._values: - raise error.ValueConstraintError(value) - -# This is a bit kludgy, meaning two op modes within a single constraing -class InnerTypeConstraint(AbstractConstraint): - """Value must satisfy type and presense constraints""" - def _testValue(self, value, idx): - if self.__singleTypeConstraint: - self.__singleTypeConstraint(value) - elif self.__multipleTypeConstraint: - if idx not in self.__multipleTypeConstraint: - raise error.ValueConstraintError(value) - constraint, status = self.__multipleTypeConstraint[idx] - if status == 'ABSENT': # XXX presense is not checked! - raise error.ValueConstraintError(value) - constraint(value) - - def _setValues(self, values): - self.__multipleTypeConstraint = {} - self.__singleTypeConstraint = None - for v in values: - if isinstance(v, tuple): - self.__multipleTypeConstraint[v[0]] = v[1], v[2] - else: - self.__singleTypeConstraint = v - AbstractConstraint._setValues(self, values) - -# Boolean ops on constraints - -class ConstraintsExclusion(AbstractConstraint): - """Value must not fit the single constraint""" - def _testValue(self, value, idx): - try: - self._values[0](value, idx) - except error.ValueConstraintError: - return - else: - raise error.ValueConstraintError(value) - - def _setValues(self, values): - if len(values) != 1: - raise error.PyAsn1Error('Single constraint expected') - AbstractConstraint._setValues(self, values) - -class AbstractConstraintSet(AbstractConstraint): - """Value must not satisfy the single constraint""" - def __getitem__(self, idx): return self._values[idx] - - def __add__(self, value): return self.__class__(self, value) - def __radd__(self, value): return self.__class__(self, value) - - def __len__(self): return len(self._values) - - # Constraints inclusion in sets - - def _setValues(self, values): - self._values = values - for v in values: - self._valueMap[v] = 1 - self._valueMap.update(v.getValueMap()) - -class ConstraintsIntersection(AbstractConstraintSet): - """Value must satisfy all constraints""" - def _testValue(self, value, idx): - for v in self._values: - v(value, idx) - -class ConstraintsUnion(AbstractConstraintSet): - """Value must satisfy at least one constraint""" - def _testValue(self, value, idx): - for v in self._values: - try: - v(value, idx) - except error.ValueConstraintError: - pass - else: - return - raise error.ValueConstraintError( - 'all of %s failed for \"%s\"' % (self._values, value) - ) - -# XXX -# add tests for type check diff --git a/lib/sambatools/pyasn1/type/error.py b/lib/sambatools/pyasn1/type/error.py deleted file mode 100644 index 3e684844..00000000 --- a/lib/sambatools/pyasn1/type/error.py +++ /dev/null @@ -1,3 +0,0 @@ -from pyasn1.error import PyAsn1Error - -class ValueConstraintError(PyAsn1Error): pass diff --git a/lib/sambatools/pyasn1/type/namedtype.py b/lib/sambatools/pyasn1/type/namedtype.py deleted file mode 100644 index bac806c3..00000000 --- a/lib/sambatools/pyasn1/type/namedtype.py +++ /dev/null @@ -1,151 +0,0 @@ -# NamedType specification for constructed types -import sys - -from pyasn1 import error -from pyasn1.type import tagmap - - -class NamedType: - isOptional = 0 - isDefaulted = 0 - def __init__(self, name, t): - self.__name = name; self.__type = t - def __repr__(self): return '%s(%r, %r)' % ( - self.__class__.__name__, self.__name, self.__type - ) - def __eq__(self, other): return tuple(self) == tuple(other) - def __ne__(self, other): return tuple(self) != tuple(other) - def __lt__(self, other): return tuple(self) < tuple(other) - def __le__(self, other): return tuple(self) <= tuple(other) - def __gt__(self, other): return tuple(self) > tuple(other) - def __ge__(self, other): return tuple(self) >= tuple(other) - def __hash__(self): return hash(tuple(self)) - - def getType(self): return self.__type - def getName(self): return self.__name - def __getitem__(self, idx): - if idx == 0: return self.__name - if idx == 1: return self.__type - raise IndexError() - -class OptionalNamedType(NamedType): - isOptional = 1 -class DefaultedNamedType(NamedType): - isDefaulted = 1 - -class NamedTypes: - def __init__(self, *namedTypes): - self.__namedTypes = namedTypes - self.__namedTypesLen = len(self.__namedTypes) - self.__minTagSet = None - self.__tagToPosIdx = {}; self.__nameToPosIdx = {} - self.__tagMap = { False: None, True: None } - self.__ambigiousTypes = {} - - def __repr__(self): - return '%s(%s)' % ( - self.__class__.__name__, - ', '.join([ repr(x) for x in self.__namedTypes ]) - ) - def __eq__(self, other): return tuple(self) == tuple(other) - def __ne__(self, other): return tuple(self) != tuple(other) - def __lt__(self, other): return tuple(self) < tuple(other) - def __le__(self, other): return tuple(self) <= tuple(other) - def __gt__(self, other): return tuple(self) > tuple(other) - def __ge__(self, other): return tuple(self) >= tuple(other) - def __hash__(self): return hash(tuple(self)) - - def __getitem__(self, idx): return self.__namedTypes[idx] - - if sys.version_info[0] <= 2: - def __nonzero__(self): return bool(self.__namedTypesLen) - else: - def __bool__(self): return bool(self.__namedTypesLen) - def __len__(self): return self.__namedTypesLen - - def clone(self): return self.__class__(*self.__namedTypes) - - def getTypeByPosition(self, idx): - if idx < 0 or idx >= self.__namedTypesLen: - raise error.PyAsn1Error('Type position out of range') - else: - return self.__namedTypes[idx].getType() - - def getPositionByType(self, tagSet): - if not self.__tagToPosIdx: - idx = self.__namedTypesLen - while idx > 0: - idx = idx - 1 - tagMap = self.__namedTypes[idx].getType().getTagMap() - for t in tagMap.getPosMap(): - if t in self.__tagToPosIdx: - raise error.PyAsn1Error('Duplicate type %s' % (t,)) - self.__tagToPosIdx[t] = idx - try: - return self.__tagToPosIdx[tagSet] - except KeyError: - raise error.PyAsn1Error('Type %s not found' % (tagSet,)) - - def getNameByPosition(self, idx): - try: - return self.__namedTypes[idx].getName() - except IndexError: - raise error.PyAsn1Error('Type position out of range') - def getPositionByName(self, name): - if not self.__nameToPosIdx: - idx = self.__namedTypesLen - while idx > 0: - idx = idx - 1 - n = self.__namedTypes[idx].getName() - if n in self.__nameToPosIdx: - raise error.PyAsn1Error('Duplicate name %s' % (n,)) - self.__nameToPosIdx[n] = idx - try: - return self.__nameToPosIdx[name] - except KeyError: - raise error.PyAsn1Error('Name %s not found' % (name,)) - - def __buildAmbigiousTagMap(self): - ambigiousTypes = () - idx = self.__namedTypesLen - while idx > 0: - idx = idx - 1 - t = self.__namedTypes[idx] - if t.isOptional or t.isDefaulted: - ambigiousTypes = (t, ) + ambigiousTypes - else: - ambigiousTypes = (t, ) - self.__ambigiousTypes[idx] = NamedTypes(*ambigiousTypes) - - def getTagMapNearPosition(self, idx): - if not self.__ambigiousTypes: self.__buildAmbigiousTagMap() - try: - return self.__ambigiousTypes[idx].getTagMap() - except KeyError: - raise error.PyAsn1Error('Type position out of range') - - def getPositionNearType(self, tagSet, idx): - if not self.__ambigiousTypes: self.__buildAmbigiousTagMap() - try: - return idx+self.__ambigiousTypes[idx].getPositionByType(tagSet) - except KeyError: - raise error.PyAsn1Error('Type position out of range') - - def genMinTagSet(self): - if self.__minTagSet is None: - for t in self.__namedTypes: - __type = t.getType() - tagSet = getattr(__type,'getMinTagSet',__type.getTagSet)() - if self.__minTagSet is None or tagSet < self.__minTagSet: - self.__minTagSet = tagSet - return self.__minTagSet - - def getTagMap(self, uniq=False): - if self.__tagMap[uniq] is None: - tagMap = tagmap.TagMap() - for nt in self.__namedTypes: - tagMap = tagMap.clone( - nt.getType(), nt.getType().getTagMap(), uniq - ) - self.__tagMap[uniq] = tagMap - return self.__tagMap[uniq] diff --git a/lib/sambatools/pyasn1/type/namedval.py b/lib/sambatools/pyasn1/type/namedval.py deleted file mode 100644 index 676cb934..00000000 --- a/lib/sambatools/pyasn1/type/namedval.py +++ /dev/null @@ -1,58 +0,0 @@ -# ASN.1 named integers -from pyasn1 import error - -__all__ = [ 'NamedValues' ] - -class NamedValues: - def __init__(self, *namedValues): - self.nameToValIdx = {}; self.valToNameIdx = {} - self.namedValues = () - automaticVal = 1 - for namedValue in namedValues: - if isinstance(namedValue, tuple): - name, val = namedValue - else: - name = namedValue - val = automaticVal - if name in self.nameToValIdx: - raise error.PyAsn1Error('Duplicate name %s' % (name,)) - self.nameToValIdx[name] = val - if val in self.valToNameIdx: - raise error.PyAsn1Error('Duplicate value %s=%s' % (name, val)) - self.valToNameIdx[val] = name - self.namedValues = self.namedValues + ((name, val),) - automaticVal = automaticVal + 1 - - def __repr__(self): - return '%s(%s)' % (self.__class__.__name__, ', '.join([repr(x) for x in self.namedValues])) - - def __str__(self): return str(self.namedValues) - - def __eq__(self, other): return tuple(self) == tuple(other) - def __ne__(self, other): return tuple(self) != tuple(other) - def __lt__(self, other): return tuple(self) < tuple(other) - def __le__(self, other): return tuple(self) <= tuple(other) - def __gt__(self, other): return tuple(self) > tuple(other) - def __ge__(self, other): return tuple(self) >= tuple(other) - def __hash__(self): return hash(tuple(self)) - - def getName(self, value): - if value in self.valToNameIdx: - return self.valToNameIdx[value] - - def getValue(self, name): - if name in self.nameToValIdx: - return self.nameToValIdx[name] - - def __getitem__(self, i): return self.namedValues[i] - def __len__(self): return len(self.namedValues) - - def __add__(self, namedValues): - return self.__class__(*self.namedValues + namedValues) - def __radd__(self, namedValues): - return self.__class__(*namedValues + tuple(self)) - - def clone(self, *namedValues): - return self.__class__(*tuple(self) + namedValues) - -# XXX clone/subtype? diff --git a/lib/sambatools/pyasn1/type/tag.py b/lib/sambatools/pyasn1/type/tag.py deleted file mode 100644 index 96b70b04..00000000 --- a/lib/sambatools/pyasn1/type/tag.py +++ /dev/null @@ -1,129 +0,0 @@ -# ASN.1 types tags -from operator import getitem - -from pyasn1 import error - -tagClassUniversal = 0x00 -tagClassApplication = 0x40 -tagClassContext = 0x80 -tagClassPrivate = 0xC0 - -tagFormatSimple = 0x00 -tagFormatConstructed = 0x20 - -tagCategoryImplicit = 0x01 -tagCategoryExplicit = 0x02 -tagCategoryUntagged = 0x04 - -class Tag: - def __init__(self, tagClass, tagFormat, tagId): - if tagId < 0: - raise error.PyAsn1Error( - 'Negative tag ID (%s) not allowed' % (tagId,) - ) - self.__tag = (tagClass, tagFormat, tagId) - self.uniq = (tagClass, tagId) - self.__hashedUniqTag = hash(self.uniq) - - def __str__(self): - return '[%s:%s:%s]' % self.__tag - - def __repr__(self): - return '%s(tagClass=%s, tagFormat=%s, tagId=%s)' % ( - (self.__class__.__name__,) + self.__tag - ) - # These is really a hotspot -- expose public "uniq" attribute to save on - # function calls - def __eq__(self, other): return self.uniq == other.uniq - def __ne__(self, other): return self.uniq != other.uniq - def __lt__(self, other): return self.uniq < other.uniq - def __le__(self, other): return self.uniq <= other.uniq - def __gt__(self, other): return self.uniq > other.uniq - def __ge__(self, other): return self.uniq >= other.uniq - def __hash__(self): return self.__hashedUniqTag - def __getitem__(self, idx): return self.__tag[idx] - def __and__(self, otherTag): - (tagClass, tagFormat, tagId) = otherTag - return self.__class__( - self.__tag&tagClass, self.__tag&tagFormat, self.__tag&tagId - ) - def __or__(self, otherTag): - (tagClass, tagFormat, tagId) = otherTag - return self.__class__( - self.__tag[0]|tagClass, - self.__tag[1]|tagFormat, - self.__tag[2]|tagId - ) - def asTuple(self): return self.__tag # __getitem__() is slow - -class TagSet: - def __init__(self, baseTag=(), *superTags): - self.__baseTag = baseTag - self.__superTags = superTags - self.__hashedSuperTags = hash(superTags) - _uniq = () - for t in superTags: - _uniq = _uniq + t.uniq - self.uniq = _uniq - self.__lenOfSuperTags = len(superTags) - - def __str__(self): - return self.__superTags and '+'.join([str(x) for x in self.__superTags]) or '[untagged]' - - def __repr__(self): - return '%s(%s)' % ( - self.__class__.__name__, - '(), ' + ', '.join([repr(x) for x in self.__superTags]) - ) - - def __add__(self, superTag): - return self.__class__( - self.__baseTag, *self.__superTags + (superTag,) - ) - def __radd__(self, superTag): - return self.__class__( - self.__baseTag, *(superTag,) + self.__superTags - ) - - def tagExplicitly(self, superTag): - tagClass, tagFormat, tagId = superTag - if tagClass == tagClassUniversal: - raise error.PyAsn1Error( - 'Can\'t tag with UNIVERSAL-class tag' - ) - if tagFormat != tagFormatConstructed: - superTag = Tag(tagClass, tagFormatConstructed, tagId) - return self + superTag - - def tagImplicitly(self, superTag): - tagClass, tagFormat, tagId = superTag - if self.__superTags: - superTag = Tag(tagClass, self.__superTags[-1][1], tagId) - return self[:-1] + superTag - - def getBaseTag(self): return self.__baseTag - def __getitem__(self, idx): - if isinstance(idx, slice): - return self.__class__( - self.__baseTag, *getitem(self.__superTags, idx) - ) - return self.__superTags[idx] - def __eq__(self, other): return self.uniq == other.uniq - def __ne__(self, other): return self.uniq != other.uniq - def __lt__(self, other): return self.uniq < other.uniq - def __le__(self, other): return self.uniq <= other.uniq - def __gt__(self, other): return self.uniq > other.uniq - def __ge__(self, other): return self.uniq >= other.uniq - def __hash__(self): return self.__hashedSuperTags - def __len__(self): return self.__lenOfSuperTags - def isSuperTagSetOf(self, tagSet): - if len(tagSet) < self.__lenOfSuperTags: - return - idx = self.__lenOfSuperTags - 1 - while idx >= 0: - if self.__superTags[idx] != tagSet[idx]: - return - idx = idx - 1 - return 1 - -def initTagSet(tag): return TagSet(tag, tag) diff --git a/lib/sambatools/pyasn1/type/tagmap.py b/lib/sambatools/pyasn1/type/tagmap.py deleted file mode 100644 index feb91ae3..00000000 --- a/lib/sambatools/pyasn1/type/tagmap.py +++ /dev/null @@ -1,66 +0,0 @@ -from pyasn1 import error - -class TagMap: - def __init__(self, posMap={}, negMap={}, defType=None): - self.__posMap = posMap.copy() - self.__negMap = negMap.copy() - self.__defType = defType - - def __contains__(self, tagSet): - return tagSet in self.__posMap or \ - self.__defType is not None and tagSet not in self.__negMap - - def __getitem__(self, tagSet): - if tagSet in self.__posMap: - return self.__posMap[tagSet] - elif tagSet in self.__negMap: - raise error.PyAsn1Error('Key in negative map') - elif self.__defType is not None: - return self.__defType - else: - raise KeyError() - - def __repr__(self): - s = self.__class__.__name__ + '(' - if self.__posMap: - s = s + 'posMap=%r, ' % (self.__posMap,) - if self.__negMap: - s = s + 'negMap=%r, ' % (self.__negMap,) - if self.__defType is not None: - s = s + 'defType=%r' % (self.__defType,) - return s + ')' - - def __str__(self): - s = self.__class__.__name__ + ':\n' - if self.__posMap: - s = s + 'posMap:\n%s, ' % ',\n '.join([ x.prettyPrintType() for x in self.__posMap.values()]) - if self.__negMap: - s = s + 'negMap:\n%s, ' % ',\n '.join([ x.prettyPrintType() for x in self.__negMap.values()]) - if self.__defType is not None: - s = s + 'defType:\n%s, ' % self.__defType.prettyPrintType() - return s - - def clone(self, parentType, tagMap, uniq=False): - if self.__defType is not None and tagMap.getDef() is not None: - raise error.PyAsn1Error('Duplicate default value at %s' % (self,)) - if tagMap.getDef() is not None: - defType = tagMap.getDef() - else: - defType = self.__defType - - posMap = self.__posMap.copy() - for k in tagMap.getPosMap(): - if uniq and k in posMap: - raise error.PyAsn1Error('Duplicate positive key %s' % (k,)) - posMap[k] = parentType - - negMap = self.__negMap.copy() - negMap.update(tagMap.getNegMap()) - - return self.__class__( - posMap, negMap, defType, - ) - - def getPosMap(self): return self.__posMap.copy() - def getNegMap(self): return self.__negMap.copy() - def getDef(self): return self.__defType diff --git a/lib/sambatools/pyasn1/type/univ.py b/lib/sambatools/pyasn1/type/univ.py deleted file mode 100644 index eda7719e..00000000 --- a/lib/sambatools/pyasn1/type/univ.py +++ /dev/null @@ -1,1160 +0,0 @@ -# ASN.1 "universal" data types -import math -import operator -import sys - -from pyasn1 import error -from pyasn1.codec.ber import eoo -from pyasn1.compat import octets -from pyasn1.type import base, tag, constraint, namedtype, namedval, tagmap - - -# "Simple" ASN.1 types (yet incomplete) - -class Integer(base.AbstractSimpleAsn1Item): - tagSet = baseTagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x02) - ) - namedValues = namedval.NamedValues() - def __init__(self, value=None, tagSet=None, subtypeSpec=None, - namedValues=None): - if namedValues is None: - self.__namedValues = self.namedValues - else: - self.__namedValues = namedValues - base.AbstractSimpleAsn1Item.__init__( - self, value, tagSet, subtypeSpec - ) - - def __repr__(self): - if self.__namedValues is not self.namedValues: - return '%s, %r)' % (base.AbstractSimpleAsn1Item.__repr__(self)[:-1], self.__namedValues) - else: - return base.AbstractSimpleAsn1Item.__repr__(self) - - def __and__(self, value): return self.clone(self._value & value) - def __rand__(self, value): return self.clone(value & self._value) - def __or__(self, value): return self.clone(self._value | value) - def __ror__(self, value): return self.clone(value | self._value) - def __xor__(self, value): return self.clone(self._value ^ value) - def __rxor__(self, value): return self.clone(value ^ self._value) - def __lshift__(self, value): return self.clone(self._value << value) - def __rshift__(self, value): return self.clone(self._value >> value) - - def __add__(self, value): return self.clone(self._value + value) - def __radd__(self, value): return self.clone(value + self._value) - def __sub__(self, value): return self.clone(self._value - value) - def __rsub__(self, value): return self.clone(value - self._value) - def __mul__(self, value): return self.clone(self._value * value) - def __rmul__(self, value): return self.clone(value * self._value) - def __mod__(self, value): return self.clone(self._value % value) - def __rmod__(self, value): return self.clone(value % self._value) - def __pow__(self, value, modulo=None): return self.clone(pow(self._value, value, modulo)) - def __rpow__(self, value): return self.clone(pow(value, self._value)) - - if sys.version_info[0] <= 2: - def __div__(self, value): return self.clone(self._value // value) - def __rdiv__(self, value): return self.clone(value // self._value) - else: - def __truediv__(self, value): return self.clone(self._value / value) - def __rtruediv__(self, value): return self.clone(value / self._value) - def __divmod__(self, value): return self.clone(self._value // value) - def __rdivmod__(self, value): return self.clone(value // self._value) - - __hash__ = base.AbstractSimpleAsn1Item.__hash__ - - def __int__(self): return int(self._value) - if sys.version_info[0] <= 2: - def __long__(self): return long(self._value) - def __float__(self): return float(self._value) - def __abs__(self): return self.clone(abs(self._value)) - def __index__(self): return int(self._value) - def __pos__(self): return self.clone(+self._value) - def __neg__(self): return self.clone(-self._value) - def __invert__(self): return self.clone(~self._value) - def __round__(self, n=0): - r = round(self._value, n) - if n: - return self.clone(r) - else: - return r - def __floor__(self): return math.floor(self._value) - def __ceil__(self): return math.ceil(self._value) - if sys.version_info[0:2] > (2, 5): - def __trunc__(self): return self.clone(math.trunc(self._value)) - - def __lt__(self, value): return self._value < value - def __le__(self, value): return self._value <= value - def __eq__(self, value): return self._value == value - def __ne__(self, value): return self._value != value - def __gt__(self, value): return self._value > value - def __ge__(self, value): return self._value >= value - - def prettyIn(self, value): - if not isinstance(value, str): - try: - return int(value) - except: - raise error.PyAsn1Error( - 'Can\'t coerce %r into integer: %s' % (value, sys.exc_info()[1]) - ) - r = self.__namedValues.getValue(value) - if r is not None: - return r - try: - return int(value) - except: - raise error.PyAsn1Error( - 'Can\'t coerce %r into integer: %s' % (value, sys.exc_info()[1]) - ) - - def prettyOut(self, value): - r = self.__namedValues.getName(value) - return r is None and str(value) or repr(r) - - def getNamedValues(self): return self.__namedValues - - def clone(self, value=None, tagSet=None, subtypeSpec=None, - namedValues=None): - if value is None and tagSet is None and subtypeSpec is None \ - and namedValues is None: - return self - if value is None: - value = self._value - if tagSet is None: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - if namedValues is None: - namedValues = self.__namedValues - return self.__class__(value, tagSet, subtypeSpec, namedValues) - - def subtype(self, value=None, implicitTag=None, explicitTag=None, - subtypeSpec=None, namedValues=None): - if value is None: - value = self._value - if implicitTag is not None: - tagSet = self._tagSet.tagImplicitly(implicitTag) - elif explicitTag is not None: - tagSet = self._tagSet.tagExplicitly(explicitTag) - else: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - else: - subtypeSpec = subtypeSpec + self._subtypeSpec - if namedValues is None: - namedValues = self.__namedValues - else: - namedValues = namedValues + self.__namedValues - return self.__class__(value, tagSet, subtypeSpec, namedValues) - -class Boolean(Integer): - tagSet = baseTagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x01), - ) - subtypeSpec = Integer.subtypeSpec+constraint.SingleValueConstraint(0,1) - namedValues = Integer.namedValues.clone(('False', 0), ('True', 1)) - -class BitString(base.AbstractSimpleAsn1Item): - tagSet = baseTagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x03) - ) - namedValues = namedval.NamedValues() - def __init__(self, value=None, tagSet=None, subtypeSpec=None, - namedValues=None): - if namedValues is None: - self.__namedValues = self.namedValues - else: - self.__namedValues = namedValues - base.AbstractSimpleAsn1Item.__init__( - self, value, tagSet, subtypeSpec - ) - - def clone(self, value=None, tagSet=None, subtypeSpec=None, - namedValues=None): - if value is None and tagSet is None and subtypeSpec is None \ - and namedValues is None: - return self - if value is None: - value = self._value - if tagSet is None: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - if namedValues is None: - namedValues = self.__namedValues - return self.__class__(value, tagSet, subtypeSpec, namedValues) - - def subtype(self, value=None, implicitTag=None, explicitTag=None, - subtypeSpec=None, namedValues=None): - if value is None: - value = self._value - if implicitTag is not None: - tagSet = self._tagSet.tagImplicitly(implicitTag) - elif explicitTag is not None: - tagSet = self._tagSet.tagExplicitly(explicitTag) - else: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - else: - subtypeSpec = subtypeSpec + self._subtypeSpec - if namedValues is None: - namedValues = self.__namedValues - else: - namedValues = namedValues + self.__namedValues - return self.__class__(value, tagSet, subtypeSpec, namedValues) - - def __str__(self): return str(tuple(self)) - - # Immutable sequence object protocol - - def __len__(self): - if self._len is None: - self._len = len(self._value) - return self._len - def __getitem__(self, i): - if isinstance(i, slice): - return self.clone(operator.getitem(self._value, i)) - else: - return self._value[i] - - def __add__(self, value): return self.clone(self._value + value) - def __radd__(self, value): return self.clone(value + self._value) - def __mul__(self, value): return self.clone(self._value * value) - def __rmul__(self, value): return self * value - - def prettyIn(self, value): - r = [] - if not value: - return () - elif isinstance(value, str): - if value[0] == '\'': - if value[-2:] == '\'B': - for v in value[1:-2]: - if v == '0': - r.append(0) - elif v == '1': - r.append(1) - else: - raise error.PyAsn1Error( - 'Non-binary BIT STRING initializer %s' % (v,) - ) - return tuple(r) - elif value[-2:] == '\'H': - for v in value[1:-2]: - i = 4 - v = int(v, 16) - while i: - i = i - 1 - r.append((v>>i)&0x01) - return tuple(r) - else: - raise error.PyAsn1Error( - 'Bad BIT STRING value notation %s' % (value,) - ) - else: - for i in value.split(','): - j = self.__namedValues.getValue(i) - if j is None: - raise error.PyAsn1Error( - 'Unknown bit identifier \'%s\'' % (i,) - ) - if j >= len(r): - r.extend([0]*(j-len(r)+1)) - r[j] = 1 - return tuple(r) - elif isinstance(value, (tuple, list)): - r = tuple(value) - for b in r: - if b and b != 1: - raise error.PyAsn1Error( - 'Non-binary BitString initializer \'%s\'' % (r,) - ) - return r - elif isinstance(value, BitString): - return tuple(value) - else: - raise error.PyAsn1Error( - 'Bad BitString initializer type \'%s\'' % (value,) - ) - - def prettyOut(self, value): - return '\"\'%s\'B\"' % ''.join([str(x) for x in value]) - -try: - all -except NameError: # Python 2.4 - def all(iterable): - for element in iterable: - if not element: - return False - return True - -class OctetString(base.AbstractSimpleAsn1Item): - tagSet = baseTagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x04) - ) - defaultBinValue = defaultHexValue = base.noValue - encoding = 'us-ascii' - def __init__(self, value=None, tagSet=None, subtypeSpec=None, - encoding=None, binValue=None, hexValue=None): - if encoding is None: - self._encoding = self.encoding - else: - self._encoding = encoding - if binValue is not None: - value = self.fromBinaryString(binValue) - if hexValue is not None: - value = self.fromHexString(hexValue) - if value is None or value is base.noValue: - value = self.defaultHexValue - if value is None or value is base.noValue: - value = self.defaultBinValue - self.__asNumbersCache = None - base.AbstractSimpleAsn1Item.__init__(self, value, tagSet, subtypeSpec) - - def clone(self, value=None, tagSet=None, subtypeSpec=None, - encoding=None, binValue=None, hexValue=None): - if value is None and tagSet is None and subtypeSpec is None and \ - encoding is None and binValue is None and hexValue is None: - return self - if value is None and binValue is None and hexValue is None: - value = self._value - if tagSet is None: - tagSet = self._tagSet - if subtypeSpec is None: - subtypeSpec = self._subtypeSpec - if encoding is None: - encoding = self._encoding - return self.__class__( - value, tagSet, subtypeSpec, encoding, binValue, hexValue - ) - - if sys.version_info[0] <= 2: - def prettyIn(self, value): - if isinstance(value, str): - return value - elif isinstance(value, unicode): - try: - return value.encode(self._encoding) - except (LookupError, UnicodeEncodeError): - raise error.PyAsn1Error( - 'Can\'t encode string \'%s\' with \'%s\' codec' % (value, self._encoding) - ) - elif isinstance(value, (tuple, list)): - try: - return ''.join([ chr(x) for x in value ]) - except ValueError: - raise error.PyAsn1Error( - 'Bad OctetString initializer \'%s\'' % (value,) - ) - else: - return str(value) - else: - def prettyIn(self, value): - if isinstance(value, bytes): - return value - elif isinstance(value, str): - try: - return value.encode(self._encoding) - except UnicodeEncodeError: - raise error.PyAsn1Error( - 'Can\'t encode string \'%s\' with \'%s\' codec' % (value, self._encoding) - ) - elif isinstance(value, OctetString): - return value.asOctets() - elif isinstance(value, (tuple, list, map)): - try: - return bytes(value) - except ValueError: - raise error.PyAsn1Error( - 'Bad OctetString initializer \'%s\'' % (value,) - ) - else: - try: - return str(value).encode(self._encoding) - except UnicodeEncodeError: - raise error.PyAsn1Error( - 'Can\'t encode string \'%s\' with \'%s\' codec' % (value, self._encoding) - ) - - - def fromBinaryString(self, value): - bitNo = 8; byte = 0; r = () - for v in value: - if bitNo: - bitNo = bitNo - 1 - else: - bitNo = 7 - r = r + (byte,) - byte = 0 - if v == '0': - v = 0 - elif v == '1': - v = 1 - else: - raise error.PyAsn1Error( - 'Non-binary OCTET STRING initializer %s' % (v,) - ) - byte = byte | (v << bitNo) - return octets.ints2octs(r + (byte,)) - - def fromHexString(self, value): - r = p = () - for v in value: - if p: - r = r + (int(p+v, 16),) - p = () - else: - p = v - if p: - r = r + (int(p+'0', 16),) - return octets.ints2octs(r) - - def prettyOut(self, value): - if sys.version_info[0] <= 2: - numbers = tuple(( ord(x) for x in value )) - else: - numbers = tuple(value) - if all(x >= 32 and x <= 126 for x in numbers): - return str(value) - else: - return '0x' + ''.join(( '%.2x' % x for x in numbers )) - - def __repr__(self): - r = [] - doHex = False - if self._value is not self.defaultValue: - for x in self.asNumbers(): - if x < 32 or x > 126: - doHex = True - break - if not doHex: - r.append('%r' % (self._value,)) - if self._tagSet is not self.tagSet: - r.append('tagSet=%r' % (self._tagSet,)) - if self._subtypeSpec is not self.subtypeSpec: - r.append('subtypeSpec=%r' % (self._subtypeSpec,)) - if self.encoding is not self._encoding: - r.append('encoding=%r' % (self._encoding,)) - if doHex: - r.append('hexValue=%r' % ''.join([ '%.2x' % x for x in self.asNumbers() ])) - return '%s(%s)' % (self.__class__.__name__, ', '.join(r)) - - if sys.version_info[0] <= 2: - def __str__(self): return str(self._value) - def __unicode__(self): - return self._value.decode(self._encoding, 'ignore') - def asOctets(self): return self._value - def asNumbers(self): - if self.__asNumbersCache is None: - self.__asNumbersCache = tuple([ ord(x) for x in self._value ]) - return self.__asNumbersCache - else: - def __str__(self): return self._value.decode(self._encoding, 'ignore') - def __bytes__(self): return self._value - def asOctets(self): return self._value - def asNumbers(self): - if self.__asNumbersCache is None: - self.__asNumbersCache = tuple(self._value) - return self.__asNumbersCache - - # Immutable sequence object protocol - - def __len__(self): - if self._len is None: - self._len = len(self._value) - return self._len - def __getitem__(self, i): - if isinstance(i, slice): - return self.clone(operator.getitem(self._value, i)) - else: - return self._value[i] - - def __add__(self, value): return self.clone(self._value + self.prettyIn(value)) - def __radd__(self, value): return self.clone(self.prettyIn(value) + self._value) - def __mul__(self, value): return self.clone(self._value * value) - def __rmul__(self, value): return self * value - def __int__(self): return int(self._value) - def __float__(self): return float(self._value) - -class Null(OctetString): - defaultValue = ''.encode() # This is tightly constrained - tagSet = baseTagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x05) - ) - subtypeSpec = OctetString.subtypeSpec+constraint.SingleValueConstraint(''.encode()) - -if sys.version_info[0] <= 2: - intTypes = (int, long) -else: - intTypes = (int,) - -numericTypes = intTypes + (float,) - -class ObjectIdentifier(base.AbstractSimpleAsn1Item): - tagSet = baseTagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x06) - ) - def __add__(self, other): return self.clone(self._value + other) - def __radd__(self, other): return self.clone(other + self._value) - - def asTuple(self): return self._value - - # Sequence object protocol - - def __len__(self): - if self._len is None: - self._len = len(self._value) - return self._len - def __getitem__(self, i): - if isinstance(i, slice): - return self.clone( - operator.getitem(self._value, i) - ) - else: - return self._value[i] - - def __str__(self): return self.prettyPrint() - def __repr__(self): - return '%s(%r)' % (self.__class__.__name__, self.prettyPrint()) - - def index(self, suboid): return self._value.index(suboid) - - def isPrefixOf(self, value): - """Returns true if argument OID resides deeper in the OID tree""" - l = len(self) - if l <= len(value): - if self._value[:l] == value[:l]: - return 1 - return 0 - - def prettyIn(self, value): - """Dotted -> tuple of numerics OID converter""" - if isinstance(value, tuple): - pass - elif isinstance(value, ObjectIdentifier): - return tuple(value) - elif octets.isStringType(value): - r = [] - for element in [ x for x in value.split('.') if x != '' ]: - try: - r.append(int(element, 0)) - except ValueError: - raise error.PyAsn1Error( - 'Malformed Object ID %s at %s: %s' % - (str(value), self.__class__.__name__, sys.exc_info()[1]) - ) - value = tuple(r) - else: - try: - value = tuple(value) - except TypeError: - raise error.PyAsn1Error( - 'Malformed Object ID %s at %s: %s' % - (str(value), self.__class__.__name__,sys.exc_info()[1]) - ) - - for x in value: - if not isinstance(x, intTypes) or x < 0: - raise error.PyAsn1Error( - 'Invalid sub-ID in %s at %s' % (value, self.__class__.__name__) - ) - - return value - - def prettyOut(self, value): return '.'.join([ str(x) for x in value ]) - -class Real(base.AbstractSimpleAsn1Item): - binEncBase = None # binEncBase = 16 is recommended for large numbers - try: - _plusInf = float('inf') - _minusInf = float('-inf') - _inf = (_plusInf, _minusInf) - except ValueError: - # Infinity support is platform and Python dependent - _plusInf = _minusInf = None - _inf = () - - tagSet = baseTagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x09) - ) - - def __normalizeBase10(self, value): - m, b, e = value - while m and m % 10 == 0: - m = m / 10 - e = e + 1 - return m, b, e - - def prettyIn(self, value): - if isinstance(value, tuple) and len(value) == 3: - if not isinstance(value[0], numericTypes) or \ - not isinstance(value[1], intTypes) or \ - not isinstance(value[2], intTypes): - raise error.PyAsn1Error('Lame Real value syntax: %s' % (value,)) - if isinstance(value[0], float) and \ - self._inf and value[0] in self._inf: - return value[0] - if value[1] not in (2, 10): - raise error.PyAsn1Error( - 'Prohibited base for Real value: %s' % (value[1],) - ) - if value[1] == 10: - value = self.__normalizeBase10(value) - return value - elif isinstance(value, intTypes): - return self.__normalizeBase10((value, 10, 0)) - elif isinstance(value, (str, float)): - if isinstance(value, str): - try: - value = float(value) - except ValueError: - raise error.PyAsn1Error( - 'Bad real value syntax: %s' % (value,) - ) - if self._inf and value in self._inf: - return value - else: - e = 0 - while int(value) != value: - value = value * 10 - e = e - 1 - return self.__normalizeBase10((int(value), 10, e)) - elif isinstance(value, Real): - return tuple(value) - raise error.PyAsn1Error( - 'Bad real value syntax: %s' % (value,) - ) - - def prettyOut(self, value): - if value in self._inf: - return '\'%s\'' % value - else: - return str(value) - - def prettyPrint(self, scope=0): - if self.isInfinity(): - return self.prettyOut(self._value) - else: - return str(float(self)) - - def isPlusInfinity(self): return self._value == self._plusInf - def isMinusInfinity(self): return self._value == self._minusInf - def isInfinity(self): return self._value in self._inf - - def __str__(self): return str(float(self)) - - def __add__(self, value): return self.clone(float(self) + value) - def __radd__(self, value): return self + value - def __mul__(self, value): return self.clone(float(self) * value) - def __rmul__(self, value): return self * value - def __sub__(self, value): return self.clone(float(self) - value) - def __rsub__(self, value): return self.clone(value - float(self)) - def __mod__(self, value): return self.clone(float(self) % value) - def __rmod__(self, value): return self.clone(value % float(self)) - def __pow__(self, value, modulo=None): return self.clone(pow(float(self), value, modulo)) - def __rpow__(self, value): return self.clone(pow(value, float(self))) - - if sys.version_info[0] <= 2: - def __div__(self, value): return self.clone(float(self) / value) - def __rdiv__(self, value): return self.clone(value / float(self)) - else: - def __truediv__(self, value): return self.clone(float(self) / value) - def __rtruediv__(self, value): return self.clone(value / float(self)) - def __divmod__(self, value): return self.clone(float(self) // value) - def __rdivmod__(self, value): return self.clone(value // float(self)) - - def __int__(self): return int(float(self)) - if sys.version_info[0] <= 2: - def __long__(self): return long(float(self)) - def __float__(self): - if self._value in self._inf: - return self._value - else: - return float( - self._value[0] * pow(self._value[1], self._value[2]) - ) - def __abs__(self): return self.clone(abs(float(self))) - def __pos__(self): return self.clone(+float(self)) - def __neg__(self): return self.clone(-float(self)) - def __round__(self, n=0): - r = round(float(self), n) - if n: - return self.clone(r) - else: - return r - def __floor__(self): return self.clone(math.floor(float(self))) - def __ceil__(self): return self.clone(math.ceil(float(self))) - if sys.version_info[0:2] > (2, 5): - def __trunc__(self): return self.clone(math.trunc(float(self))) - - def __lt__(self, value): return float(self) < value - def __le__(self, value): return float(self) <= value - def __eq__(self, value): return float(self) == value - def __ne__(self, value): return float(self) != value - def __gt__(self, value): return float(self) > value - def __ge__(self, value): return float(self) >= value - - if sys.version_info[0] <= 2: - def __nonzero__(self): return bool(float(self)) - else: - def __bool__(self): return bool(float(self)) - __hash__ = base.AbstractSimpleAsn1Item.__hash__ - - def __getitem__(self, idx): - if self._value in self._inf: - raise error.PyAsn1Error('Invalid infinite value operation') - else: - return self._value[idx] - -class Enumerated(Integer): - tagSet = baseTagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x0A) - ) - -# "Structured" ASN.1 types - -class SetOf(base.AbstractConstructedAsn1Item): - componentType = None - tagSet = baseTagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) - ) - typeId = 1 - strictConstraints = False - - def _cloneComponentValues(self, myClone, cloneValueFlag): - idx = 0; l = len(self._componentValues) - while idx < l: - c = self._componentValues[idx] - if c is not None: - if isinstance(c, base.AbstractConstructedAsn1Item): - myClone.setComponentByPosition( - idx, c.clone(cloneValueFlag=cloneValueFlag) - ) - else: - myClone.setComponentByPosition(idx, c.clone()) - idx = idx + 1 - - def _verifyComponent(self, idx, value): - t = self._componentType - if t is None: - return - if not t.isSameTypeWith(value,matchConstraints=self.strictConstraints): - raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, t)) - if self.strictConstraints and \ - not t.isSuperTypeOf(value, matchTags=False): - raise error.PyAsn1Error('Component value is constraints-incompatible: %r vs %r' % (value, t)) - - def getComponentByPosition(self, idx): return self._componentValues[idx] - def setComponentByPosition(self, idx, value=None, verifyConstraints=True): - l = len(self._componentValues) - if idx >= l: - self._componentValues = self._componentValues + (idx-l+1)*[None] - if value is None: - if self._componentValues[idx] is None: - if self._componentType is None: - raise error.PyAsn1Error('Component type not defined') - self._componentValues[idx] = self._componentType.clone() - self._componentValuesSet = self._componentValuesSet + 1 - return self - elif not isinstance(value, base.Asn1Item): - if self._componentType is None: - raise error.PyAsn1Error('Component type not defined') - if isinstance(self._componentType, base.AbstractSimpleAsn1Item): - value = self._componentType.clone(value=value) - else: - raise error.PyAsn1Error('Instance value required') - if verifyConstraints: - if self._componentType is not None: - self._verifyComponent(idx, value) - self._verifySubtypeSpec(value, idx) - if self._componentValues[idx] is None: - self._componentValuesSet = self._componentValuesSet + 1 - self._componentValues[idx] = value - return self - - def getComponentTagMap(self): - if self._componentType is not None: - return self._componentType.getTagMap() - - def prettyPrint(self, scope=0): - scope = scope + 1 - r = self.__class__.__name__ + ':\n' - for idx in range(len(self._componentValues)): - r = r + ' '*scope - if self._componentValues[idx] is None: - r = r + '' - else: - r = r + self._componentValues[idx].prettyPrint(scope) - return r - - def prettyPrintType(self, scope=0): - scope = scope + 1 - r = '%s -> %s {\n' % (self.getTagSet(), self.__class__.__name__) - if self._componentType is not None: - r = r + ' '*scope - r = r + self._componentType.prettyPrintType(scope) - return r + '\n' + ' '*(scope-1) + '}' - -class SequenceOf(SetOf): - tagSet = baseTagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10) - ) - typeId = 2 - -class SequenceAndSetBase(base.AbstractConstructedAsn1Item): - componentType = namedtype.NamedTypes() - strictConstraints = False - def __init__(self, componentType=None, tagSet=None, - subtypeSpec=None, sizeSpec=None): - if componentType is None: - componentType = self.componentType - base.AbstractConstructedAsn1Item.__init__( - self, componentType.clone(), tagSet, subtypeSpec, sizeSpec - ) - self._componentTypeLen = len(self._componentType) - - def __getitem__(self, idx): - if isinstance(idx, str): - return self.getComponentByName(idx) - else: - return base.AbstractConstructedAsn1Item.__getitem__(self, idx) - - def __setitem__(self, idx, value): - if isinstance(idx, str): - self.setComponentByName(idx, value) - else: - base.AbstractConstructedAsn1Item.__setitem__(self, idx, value) - - def _cloneComponentValues(self, myClone, cloneValueFlag): - idx = 0; l = len(self._componentValues) - while idx < l: - c = self._componentValues[idx] - if c is not None: - if isinstance(c, base.AbstractConstructedAsn1Item): - myClone.setComponentByPosition( - idx, c.clone(cloneValueFlag=cloneValueFlag) - ) - else: - myClone.setComponentByPosition(idx, c.clone()) - idx = idx + 1 - - def _verifyComponent(self, idx, value): - if idx >= self._componentTypeLen: - raise error.PyAsn1Error( - 'Component type error out of range' - ) - t = self._componentType[idx].getType() - if not t.isSameTypeWith(value,matchConstraints=self.strictConstraints): - raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, t)) - if self.strictConstraints and \ - not t.isSuperTypeOf(value, matchTags=False): - raise error.PyAsn1Error('Component value is constraints-incompatible: %r vs %r' % (value, t)) - - def getComponentByName(self, name): - return self.getComponentByPosition( - self._componentType.getPositionByName(name) - ) - def setComponentByName(self, name, value=None, verifyConstraints=True): - return self.setComponentByPosition( - self._componentType.getPositionByName(name),value,verifyConstraints - ) - - def getComponentByPosition(self, idx): - try: - return self._componentValues[idx] - except IndexError: - if idx < self._componentTypeLen: - return - raise - def setComponentByPosition(self, idx, value=None, - verifyConstraints=True, - exactTypes=False, - matchTags=True, - matchConstraints=True): - l = len(self._componentValues) - if idx >= l: - self._componentValues = self._componentValues + (idx-l+1)*[None] - if value is None: - if self._componentValues[idx] is None: - self._componentValues[idx] = self._componentType.getTypeByPosition(idx).clone() - self._componentValuesSet = self._componentValuesSet + 1 - return self - elif not isinstance(value, base.Asn1Item): - t = self._componentType.getTypeByPosition(idx) - if isinstance(t, base.AbstractSimpleAsn1Item): - value = t.clone(value=value) - else: - raise error.PyAsn1Error('Instance value required') - if verifyConstraints: - if self._componentTypeLen: - self._verifyComponent(idx, value) - self._verifySubtypeSpec(value, idx) - if self._componentValues[idx] is None: - self._componentValuesSet = self._componentValuesSet + 1 - self._componentValues[idx] = value - return self - - def getNameByPosition(self, idx): - if self._componentTypeLen: - return self._componentType.getNameByPosition(idx) - - def getDefaultComponentByPosition(self, idx): - if self._componentTypeLen and self._componentType[idx].isDefaulted: - return self._componentType[idx].getType() - - def getComponentType(self): - if self._componentTypeLen: - return self._componentType - - def setDefaultComponents(self): - if self._componentTypeLen == self._componentValuesSet: - return - idx = self._componentTypeLen - while idx: - idx = idx - 1 - if self._componentType[idx].isDefaulted: - if self.getComponentByPosition(idx) is None: - self.setComponentByPosition(idx) - elif not self._componentType[idx].isOptional: - if self.getComponentByPosition(idx) is None: - raise error.PyAsn1Error( - 'Uninitialized component #%s at %r' % (idx, self) - ) - - def prettyPrint(self, scope=0): - scope = scope + 1 - r = self.__class__.__name__ + ':\n' - for idx in range(len(self._componentValues)): - if self._componentValues[idx] is not None: - r = r + ' '*scope - componentType = self.getComponentType() - if componentType is None: - r = r + '' - else: - r = r + componentType.getNameByPosition(idx) - r = '%s=%s\n' % ( - r, self._componentValues[idx].prettyPrint(scope) - ) - return r - - def prettyPrintType(self, scope=0): - scope = scope + 1 - r = '%s -> %s {\n' % (self.getTagSet(), self.__class__.__name__) - for idx in range(len(self.componentType)): - r = r + ' '*scope - r = r + '"%s"' % self.componentType.getNameByPosition(idx) - r = '%s = %s\n' % ( - r, self._componentType.getTypeByPosition(idx).prettyPrintType(scope) - ) - return r + '\n' + ' '*(scope-1) + '}' - -class Sequence(SequenceAndSetBase): - tagSet = baseTagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10) - ) - typeId = 3 - - def getComponentTagMapNearPosition(self, idx): - if self._componentType: - return self._componentType.getTagMapNearPosition(idx) - - def getComponentPositionNearType(self, tagSet, idx): - if self._componentType: - return self._componentType.getPositionNearType(tagSet, idx) - else: - return idx - -class Set(SequenceAndSetBase): - tagSet = baseTagSet = tag.initTagSet( - tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) - ) - typeId = 4 - - def getComponent(self, innerFlag=0): return self - - def getComponentByType(self, tagSet, innerFlag=0): - c = self.getComponentByPosition( - self._componentType.getPositionByType(tagSet) - ) - if innerFlag and isinstance(c, Set): - # get inner component by inner tagSet - return c.getComponent(1) - else: - # get outer component by inner tagSet - return c - - def setComponentByType(self, tagSet, value=None, innerFlag=0, - verifyConstraints=True): - idx = self._componentType.getPositionByType(tagSet) - t = self._componentType.getTypeByPosition(idx) - if innerFlag: # set inner component by inner tagSet - if t.getTagSet(): - return self.setComponentByPosition( - idx, value, verifyConstraints - ) - else: - t = self.setComponentByPosition(idx).getComponentByPosition(idx) - return t.setComponentByType( - tagSet, value, innerFlag, verifyConstraints - ) - else: # set outer component by inner tagSet - return self.setComponentByPosition( - idx, value, verifyConstraints - ) - - def getComponentTagMap(self): - if self._componentType: - return self._componentType.getTagMap(True) - - def getComponentPositionByType(self, tagSet): - if self._componentType: - return self._componentType.getPositionByType(tagSet) - -class Choice(Set): - tagSet = baseTagSet = tag.TagSet() # untagged - sizeSpec = constraint.ConstraintsIntersection( - constraint.ValueSizeConstraint(1, 1) - ) - typeId = 5 - _currentIdx = None - - def __eq__(self, other): - if self._componentValues: - return self._componentValues[self._currentIdx] == other - return NotImplemented - def __ne__(self, other): - if self._componentValues: - return self._componentValues[self._currentIdx] != other - return NotImplemented - def __lt__(self, other): - if self._componentValues: - return self._componentValues[self._currentIdx] < other - return NotImplemented - def __le__(self, other): - if self._componentValues: - return self._componentValues[self._currentIdx] <= other - return NotImplemented - def __gt__(self, other): - if self._componentValues: - return self._componentValues[self._currentIdx] > other - return NotImplemented - def __ge__(self, other): - if self._componentValues: - return self._componentValues[self._currentIdx] >= other - return NotImplemented - if sys.version_info[0] <= 2: - def __nonzero__(self): return bool(self._componentValues) - else: - def __bool__(self): return bool(self._componentValues) - - def __len__(self): return self._currentIdx is not None and 1 or 0 - - def verifySizeSpec(self): - if self._currentIdx is None: - raise error.PyAsn1Error('Component not chosen') - else: - self._sizeSpec(' ') - - def _cloneComponentValues(self, myClone, cloneValueFlag): - try: - c = self.getComponent() - except error.PyAsn1Error: - pass - else: - if isinstance(c, Choice): - tagSet = c.getEffectiveTagSet() - else: - tagSet = c.getTagSet() - if isinstance(c, base.AbstractConstructedAsn1Item): - myClone.setComponentByType( - tagSet, c.clone(cloneValueFlag=cloneValueFlag) - ) - else: - myClone.setComponentByType(tagSet, c.clone()) - - def setComponentByPosition(self, idx, value=None, verifyConstraints=True): - l = len(self._componentValues) - if idx >= l: - self._componentValues = self._componentValues + (idx-l+1)*[None] - if self._currentIdx is not None: - self._componentValues[self._currentIdx] = None - if value is None: - if self._componentValues[idx] is None: - self._componentValues[idx] = self._componentType.getTypeByPosition(idx).clone() - self._componentValuesSet = 1 - self._currentIdx = idx - return self - elif not isinstance(value, base.Asn1Item): - value = self._componentType.getTypeByPosition(idx).clone( - value=value - ) - if verifyConstraints: - if self._componentTypeLen: - self._verifyComponent(idx, value) - self._verifySubtypeSpec(value, idx) - self._componentValues[idx] = value - self._currentIdx = idx - self._componentValuesSet = 1 - return self - - def getMinTagSet(self): - if self._tagSet: - return self._tagSet - else: - return self._componentType.genMinTagSet() - - def getEffectiveTagSet(self): - if self._tagSet: - return self._tagSet - else: - c = self.getComponent() - if isinstance(c, Choice): - return c.getEffectiveTagSet() - else: - return c.getTagSet() - - def getTagMap(self): - if self._tagSet: - return Set.getTagMap(self) - else: - return Set.getComponentTagMap(self) - - def getComponent(self, innerFlag=0): - if self._currentIdx is None: - raise error.PyAsn1Error('Component not chosen') - else: - c = self._componentValues[self._currentIdx] - if innerFlag and isinstance(c, Choice): - return c.getComponent(innerFlag) - else: - return c - - def getName(self, innerFlag=0): - if self._currentIdx is None: - raise error.PyAsn1Error('Component not chosen') - else: - if innerFlag: - c = self._componentValues[self._currentIdx] - if isinstance(c, Choice): - return c.getName(innerFlag) - return self._componentType.getNameByPosition(self._currentIdx) - - def setDefaultComponents(self): pass - -class Any(OctetString): - tagSet = baseTagSet = tag.TagSet() # untagged - typeId = 6 - - def getTagMap(self): - return tagmap.TagMap( - { self.getTagSet(): self }, - { eoo.endOfOctets.getTagSet(): eoo.endOfOctets }, - self - ) - -# XXX -# coercion rules? diff --git a/lib/sambatools/pyasn1/type/useful.py b/lib/sambatools/pyasn1/type/useful.py deleted file mode 100644 index 17665348..00000000 --- a/lib/sambatools/pyasn1/type/useful.py +++ /dev/null @@ -1,17 +0,0 @@ -# ASN.1 "useful" types -from pyasn1.type import char, tag - -class ObjectDescriptor(char.GraphicString): - tagSet = char.GraphicString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 7) - ) - -class GeneralizedTime(char.VisibleString): - tagSet = char.VisibleString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 24) - ) - -class UTCTime(char.VisibleString): - tagSet = char.VisibleString.tagSet.tagImplicitly( - tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 23) - ) diff --git a/lib/sambatools/nmb/NetBIOS.py b/lib/sambatools/python2/nmb/NetBIOS.py similarity index 100% rename from lib/sambatools/nmb/NetBIOS.py rename to lib/sambatools/python2/nmb/NetBIOS.py diff --git a/lib/sambatools/nmb/NetBIOSProtocol.py b/lib/sambatools/python2/nmb/NetBIOSProtocol.py similarity index 100% rename from lib/sambatools/nmb/NetBIOSProtocol.py rename to lib/sambatools/python2/nmb/NetBIOSProtocol.py diff --git a/lib/sambatools/nmb/__init__.py b/lib/sambatools/python2/nmb/__init__.py similarity index 100% rename from lib/sambatools/nmb/__init__.py rename to lib/sambatools/python2/nmb/__init__.py diff --git a/lib/sambatools/nmb/base.py b/lib/sambatools/python2/nmb/base.py similarity index 90% rename from lib/sambatools/nmb/base.py rename to lib/sambatools/python2/nmb/base.py index 0bbef825..6de08678 100644 --- a/lib/sambatools/nmb/base.py +++ b/lib/sambatools/python2/nmb/base.py @@ -154,21 +154,25 @@ class NBNS: opcode = (code >> 11) & 0x0F flags = (code >> 4) & 0x7F rcode = code & 0x0F - numnames = struct.unpack('B', data[self.HEADER_STRUCT_SIZE + 44])[0] - if numnames > 0: - ret = [ ] - offset = self.HEADER_STRUCT_SIZE + 45 + try: + numnames = struct.unpack('B', data[self.HEADER_STRUCT_SIZE + 44])[0] - for i in range(0, numnames): - mynme = data[offset:offset + 15] - mynme = mynme.strip() - ret.append(( mynme, ord(data[offset+15]) )) - offset += 18 + if numnames > 0: + ret = [ ] + offset = self.HEADER_STRUCT_SIZE + 45 - return trn_id, ret - else: - return trn_id, None + for i in range(0, numnames): + mynme = data[offset:offset + 15] + mynme = mynme.strip() + ret.append(( mynme, ord(data[offset+15]) )) + offset += 18 + + return trn_id, ret + except IndexError: + pass + + return trn_id, None # # Contributed by Jason Anderson diff --git a/lib/sambatools/nmb/nmb_constants.py b/lib/sambatools/python2/nmb/nmb_constants.py similarity index 100% rename from lib/sambatools/nmb/nmb_constants.py rename to lib/sambatools/python2/nmb/nmb_constants.py diff --git a/lib/sambatools/nmb/nmb_structs.py b/lib/sambatools/python2/nmb/nmb_structs.py similarity index 100% rename from lib/sambatools/nmb/nmb_structs.py rename to lib/sambatools/python2/nmb/nmb_structs.py diff --git a/lib/sambatools/nmb/utils.py b/lib/sambatools/python2/nmb/utils.py similarity index 100% rename from lib/sambatools/nmb/utils.py rename to lib/sambatools/python2/nmb/utils.py diff --git a/lib/sambatools/smb/SMBConnection.py b/lib/sambatools/python2/smb/SMBConnection.py similarity index 96% rename from lib/sambatools/smb/SMBConnection.py rename to lib/sambatools/python2/smb/SMBConnection.py index 603c48df..036c6fae 100644 --- a/lib/sambatools/smb/SMBConnection.py +++ b/lib/sambatools/python2/smb/SMBConnection.py @@ -21,6 +21,7 @@ class SMBConnection(SMB): Create a new SMBConnection instance. *username* and *password* are the user credentials required to authenticate the underlying SMB connection with the remote server. + *password* can be a string or a callable returning a string. File operations can only be proceeded after the connection has been authenticated successfully. Note that you need to call *connect* method to actually establish the SMB connection to the remote server and perform authentication. @@ -71,6 +72,15 @@ class SMBConnection(SMB): raise NotConnectedError('Server disconnected') total_sent = total_sent + sent + # + # Support for "with" context + # + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + # # Misc Properties # @@ -389,10 +399,12 @@ class SMBConnection(SMB): return results[0] - def deleteFiles(self, service_name, path_file_pattern, timeout = 30): + def deleteFiles(self, service_name, path_file_pattern, delete_matching_folders = False, timeout = 30): """ Delete one or more regular files. It supports the use of wildcards in file names, allowing for deletion of multiple files in a single request. + If delete_matching_folders is True, immediate sub-folders that match the path_file_pattern will be deleted recursively. + :param string/unicode service_name: Contains the name of the shared folder. :param string/unicode path_file_pattern: The pathname of the file(s) to be deleted, relative to the service_name. Wildcards may be used in th filename component of the path. @@ -411,23 +423,27 @@ class SMBConnection(SMB): self.is_busy = True try: - self._deleteFiles(service_name, path_file_pattern, cb, eb, timeout = timeout) + self._deleteFiles(service_name, path_file_pattern, delete_matching_folders, cb, eb, timeout = timeout) while self.is_busy: self._pollForNetBIOSPacket(timeout) finally: self.is_busy = False - def resetFileAttributes(self, service_name, path_file_pattern, timeout = 30): + def resetFileAttributes(self, service_name, path_file_pattern, file_attributes = ATTR_NORMAL, timeout = 30): """ Reset file attributes of one or more regular files or folders. It supports the use of wildcards in file names, allowing for unlocking of multiple files/folders in a single request. This function is very helpful when deleting files/folders that are read-only. - Note: this function is currently only implemented for SMB2! Technically, it sets the FILE_ATTRIBUTE_NORMAL flag, therefore clearing all other flags. (See https://msdn.microsoft.com/en-us/library/cc232110.aspx for further information) + By default, it sets the ATTR_NORMAL flag, therefore clearing all other flags. + (See https://msdn.microsoft.com/en-us/library/cc232110.aspx for further information) + + Note: this function is currently only implemented for SMB2! :param string/unicode service_name: Contains the name of the shared folder. :param string/unicode path_file_pattern: The pathname of the file(s) to be deleted, relative to the service_name. Wildcards may be used in the filename component of the path. If your path/filename contains non-English characters, you must pass in an unicode string. + :param int file_attributes: The desired file attributes to set. Defaults to `ATTR_NORMAL`. :return: None """ if not self.sock: @@ -442,7 +458,7 @@ class SMBConnection(SMB): self.is_busy = True try: - self._resetFileAttributes(service_name, path_file_pattern, cb, eb, timeout = timeout) + self._resetFileAttributes(service_name, path_file_pattern, cb, eb, file_attributes, timeout = timeout) while self.is_busy: self._pollForNetBIOSPacket(timeout) finally: @@ -592,17 +608,8 @@ class SMBConnection(SMB): raise ex type_, flags, length = struct.unpack('>BBH', data) - if type_ == 0x0: - # This is a Direct TCP packet - # The length is specified in the header from byte 8. (0-indexed) - # we read a structure assuming NBT, so to get the real length - # combine the length and flag fields together - length = length + (flags << 16) - else: - # This is a NetBIOS over TCP (NBT) packet - # The length is specified in the header from byte 16. (0-indexed) - if flags & 0x01: - length = length | 0x10000 + if flags & 0x01: + length = length | 0x10000 read_len = length while read_len > 0: diff --git a/lib/sambatools/smb/SMBHandler.py b/lib/sambatools/python2/smb/SMBHandler.py similarity index 88% rename from lib/sambatools/smb/SMBHandler.py rename to lib/sambatools/python2/smb/SMBHandler.py index 137e943a..4fcc74f6 100644 --- a/lib/sambatools/smb/SMBHandler.py +++ b/lib/sambatools/python2/smb/SMBHandler.py @@ -44,12 +44,15 @@ class SMBHandler(urllib2.BaseHandler): passwd = passwd or '' myname = MACHINE_NAME or self.generateClientMachineName() - n = NetBIOS() - names = n.queryIPForName(host) - if names: - server_name = names[0] - else: - raise urllib2.URLError('SMB error: Hostname does not reply back with its machine name') + server_name,host = host.split(',') if ',' in host else [None,host] + + if server_name is None: + n = NetBIOS() + names = n.queryIPForName(host) + if names: + server_name = names[0] + else: + raise urllib2.URLError('SMB error: Hostname does not reply back with its machine name') path, attrs = splitattr(req.get_selector()) if path.startswith('/'): diff --git a/lib/sambatools/smb/SMBProtocol.py b/lib/sambatools/python2/smb/SMBProtocol.py similarity index 100% rename from lib/sambatools/smb/SMBProtocol.py rename to lib/sambatools/python2/smb/SMBProtocol.py diff --git a/lib/sambatools/smb/__init__.py b/lib/sambatools/python2/smb/__init__.py similarity index 100% rename from lib/sambatools/smb/__init__.py rename to lib/sambatools/python2/smb/__init__.py diff --git a/lib/sambatools/smb/base.py b/lib/sambatools/python2/smb/base.py similarity index 88% rename from lib/sambatools/smb/base.py rename to lib/sambatools/python2/smb/base.py index 5dd9c826..29d414fe 100644 --- a/lib/sambatools/smb/base.py +++ b/lib/sambatools/python2/smb/base.py @@ -60,12 +60,12 @@ class SMB(NMBSession): def __init__(self, username, password, my_name, remote_name, domain = '', use_ntlm_v2 = True, sign_options = SIGN_WHEN_REQUIRED, is_direct_tcp = False): NMBSession.__init__(self, my_name, remote_name, is_direct_tcp = is_direct_tcp) self.username = _convert_to_unicode(username) - self.password = _convert_to_unicode(password) + self._password = password self.domain = _convert_to_unicode(domain) self.sign_options = sign_options self.is_direct_tcp = is_direct_tcp self.use_ntlm_v2 = use_ntlm_v2 #: Similar to LMAuthenticationPolicy and NTAuthenticationPolicy as described in [MS-CIFS] 3.2.1.1 - self.smb_message = SMBMessage(self) + self.smb_message = SMBMessage() self.is_using_smb2 = False #: Are we communicating using SMB2 protocol? self.smb_message will be a SMB2Message instance if this flag is True self.async_requests = { } #: AsyncID mapped to _PendingRequest instance self.pending_requests = { } #: MID mapped to _PendingRequest instance @@ -98,13 +98,6 @@ class SMB(NMBSession): self.max_write_size = 0 #: Similar to MaxWriteSize as described in [MS-SMB2] 2.2.4 self.max_transact_size = 0 #: Similar to MaxTransactSize as described in [MS-SMB2] 2.2.4 self.session_id = 0 #: Similar to SessionID as described in [MS-SMB2] 2.2.4. This will be set in _updateState_SMB2 method - self.smb2_dialect = 0 - - - # SMB 2.1 attributes - self.cap_leasing = False - self.cap_multi_credit = False - self.credits = 0 # how many credits we're allowed to spend per request self._setupSMB1Methods() @@ -113,13 +106,17 @@ class SMB(NMBSession): (self.use_ntlm_v2 and 'v2') or 'v1', (SUPPORT_EXTENDED_SECURITY and 'with') or 'without') + @property + def password(self): + password = self._password() if callable(self._password) else self._password + return _convert_to_unicode(password) # # NMBSession Methods # def onNMBSessionOK(self): - self._sendSMBMessage(SMBMessage(self, ComNegotiateRequest())) + self._sendSMBMessage(SMBMessage(ComNegotiateRequest())) def onNMBSessionFailed(self): pass @@ -133,31 +130,13 @@ class SMB(NMBSession): self.is_using_smb2 = True self.mid = 0 # Must reset messageID counter, or else remote SMB2 server will disconnect self._setupSMB2Methods() - self.smb_message = self._klassSMBMessage(self) + self.smb_message = self._klassSMBMessage() i = self.smb_message.decode(data) - self.log.info('SMB2 dialect is 0x%04x', self.smb2_dialect) next_message_offset = 0 if self.is_using_smb2: next_message_offset = self.smb_message.next_command_offset - # update how many credits we're allowed to spend on requests - self.credits = self.smb_message.credit_response - - # SMB2 CANCEL commands do not consume message IDs - if self.smb_message.command != SMB2_COM_CANCEL: - self.log.debug('Received SMB2 packet from server - "%s" (command:0x%02X). Credit charge recv: %s', - SMB_COMMAND_NAMES.get(self.smb_message.command, ''), self.smb_message.command, self.smb_message.credit_charge) - if self.smb_message.credit_charge > 0: - # Let's update the sequenceWindow based on the CreditsCharged - # In the SMB 2.0.2 dialect, this field MUST NOT be used and MUST be reserved. - # The sender MUST set this to 0, and the receiver MUST ignore it. - # In all other dialects, this field indicates the number of credits that this request consumes. - self.log.debug("Updating MID to add credit charge from server...") - self.log.debug("*** Before: " + str(self.mid)) - self.mid = self.mid + (self.smb_message.credit_charge - 1) - self.log.debug("*** After: " + str(self.mid)) - if i > 0: if not self.is_using_smb2: self.log.debug('Received SMB message "%s" (command:0x%2X flags:0x%02X flags2:0x%04X TID:%d UID:%d)', @@ -169,7 +148,7 @@ class SMB(NMBSession): self.smb_message.command, self.smb_message.flags) if self._updateState(self.smb_message): # We need to create a new instance instead of calling reset() because the instance could be captured in the message history. - self.smb_message = self._klassSMBMessage(self) + self.smb_message = self._klassSMBMessage() if next_message_offset > 0: data = data[next_message_offset:] @@ -270,23 +249,10 @@ class SMB(NMBSession): if message.isReply: if message.command == SMB2_COM_NEGOTIATE: if message.status == 0: - - if self.smb_message.payload.dialect_revision == SMB2_DIALECT_2ALL: - # Dialects from SMB 2.1 must be negotiated in a second negotiate phase - # We send a SMB2 Negotiate Request to accomplish this - self._sendSMBMessage(SMB2Message(self, SMB2NegotiateRequest())) - else: - if self.smb_message.payload.dialect_revision == SMB2_DIALECT_21: - # We negotiated SMB 2.1. - # we must now send credit requests (MUST!) - #self.send_credits_request = True - pass - - self.has_negotiated = True - self.log.info('SMB2 dialect negotiation successful') - self.dialect = self.smb_message.payload.dialect_revision - self._updateServerInfo(message.payload) - self._handleNegotiateResponse(message) + self.has_negotiated = True + self.log.info('SMB2 dialect negotiation successful') + self._updateServerInfo(message.payload) + self._handleNegotiateResponse(message) else: raise ProtocolError('Unknown status value (0x%08X) in SMB2_COM_NEGOTIATE' % message.status, message.raw_data, message) @@ -386,17 +352,11 @@ class SMB(NMBSession): self.max_write_size = payload.max_write_size self.use_plaintext_authentication = False # SMB2 never allows plaintext authentication - if (self.capabilities & SMB2_GLOBAL_CAP_LEASING) == SMB2_GLOBAL_CAP_LEASING: - self.cap_leasing = True - - if (self.capabilities & SMB2_GLOBAL_CAP_LARGE_MTU) == SMB2_GLOBAL_CAP_LARGE_MTU: - self.cap_multi_credit = True - def _handleNegotiateResponse_SMB2(self, message): ntlm_data = ntlm.generateNegotiateMessage() blob = securityblob.generateNegotiateSecurityBlob(ntlm_data) - self._sendSMBMessage(SMB2Message(self, SMB2SessionSetupRequest(blob))) + self._sendSMBMessage(SMB2Message(SMB2SessionSetupRequest(blob))) def _handleSessionChallenge_SMB2(self, message, ntlm_token): @@ -416,20 +376,20 @@ class SMB(NMBSession): self.log.info('Performing NTLMv1 authentication (on SMB2) with server challenge "%s"', binascii.hexlify(server_challenge)) nt_challenge_response, lm_challenge_response, session_key = ntlm.generateChallengeResponseV1(self.password, server_challenge, True) - ntlm_data = ntlm.generateAuthenticateMessage(server_flags, - nt_challenge_response, - lm_challenge_response, - session_key, - self.username, - self.domain, - self.my_name) + ntlm_data, session_signing_key = ntlm.generateAuthenticateMessage(server_flags, + nt_challenge_response, + lm_challenge_response, + session_key, + self.username, + self.domain, + self.my_name) if self.log.isEnabledFor(logging.DEBUG): self.log.debug('NT challenge response is "%s" (%d bytes)', binascii.hexlify(nt_challenge_response), len(nt_challenge_response)) self.log.debug('LM challenge response is "%s" (%d bytes)', binascii.hexlify(lm_challenge_response), len(lm_challenge_response)) blob = securityblob.generateAuthSecurityBlob(ntlm_data) - self._sendSMBMessage(SMB2Message(self, SMB2SessionSetupRequest(blob))) + self._sendSMBMessage(SMB2Message(SMB2SessionSetupRequest(blob))) if self.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED: self.log.info('Server requires all SMB messages to be signed') @@ -442,7 +402,10 @@ class SMB(NMBSession): if self.is_signing_active: self.log.info("SMB signing activated. All SMB messages will be signed.") - self.signing_session_key = (session_key + '\0'*16)[:16] + self.signing_session_key = session_signing_key + if self.log.isEnabledFor(logging.DEBUG): + self.log.info("SMB signing key is %s", binascii.hexlify(self.signing_session_key)) + if self.capabilities & CAP_EXTENDED_SECURITY: self.signing_challenge_response = None else: @@ -460,7 +423,7 @@ class SMB(NMBSession): messages_history = [ ] def connectSrvSvc(tid): - m = SMB2Message(self, SMB2CreateRequest('srvsvc', + m = SMB2Message(SMB2CreateRequest('srvsvc', file_attributes = 0, access_mask = FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_READ_EA | FILE_WRITE_EA | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, @@ -492,7 +455,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 2c 1c b7 6c 12 98 40 45 03 00 00 00 00 00 00 00 01 00 00 00 """.replace(' ', '').replace('\n', '')) - m = SMB2Message(self, SMB2WriteRequest(create_message.payload.fid, data_bytes, 0)) + m = SMB2Message(SMB2WriteRequest(create_message.payload.fid, data_bytes, 0)) m.tid = kwargs['tid'] self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, rpcBindCB, errback, tid = kwargs['tid'], fid = create_message.payload.fid) @@ -503,7 +466,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 def rpcBindCB(trans_message, **kwargs): messages_history.append(trans_message) if trans_message.status == 0: - m = SMB2Message(self, SMB2ReadRequest(kwargs['fid'], read_len = 1024, read_offset = 0)) + m = SMB2Message(SMB2ReadRequest(kwargs['fid'], read_len = 1024, read_offset = 0)) m.tid = kwargs['tid'] self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, rpcReadCB, errback, tid = kwargs['tid'], fid = kwargs['fid']) @@ -536,7 +499,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 01 00 00 00 01 00 00 00 04 00 02 00 00 00 00 00 00 00 00 00 ff ff ff ff 08 00 02 00 00 00 00 00 """.replace(' ', '').replace('\n', '')) - m = SMB2Message(self, SMB2IoctlRequest(kwargs['fid'], 0x0011C017, flags = 0x01, max_out_size = 8196, in_data = data_bytes)) + m = SMB2Message(SMB2IoctlRequest(kwargs['fid'], 0x0011C017, flags = 0x01, max_out_size = 8196, in_data = data_bytes)) m.tid = kwargs['tid'] self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, listShareResultsCB, errback, tid = kwargs['tid'], fid = kwargs['fid']) @@ -590,7 +553,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 def sendReadRequest(tid, fid, data_bytes): read_count = min(4280, self.max_read_size) - m = SMB2Message(self, SMB2ReadRequest(fid, 0, read_count)) + m = SMB2Message(SMB2ReadRequest(fid, 0, read_count)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, readCB, errback, @@ -610,7 +573,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 errback(OperationFailure('Failed to list shares: Unable to retrieve shared device list', messages_history)) def closeFid(tid, fid, results = None, error = None): - m = SMB2Message(self, SMB2CloseRequest(fid)) + m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, results = results, error = error) @@ -631,7 +594,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 else: errback(OperationFailure('Failed to list shares: Unable to connect to IPC$', messages_history)) - m = SMB2Message(self, SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), path ))) + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), path ))) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = path) messages_history.append(m) @@ -660,7 +623,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 51 46 69 64 00 00 00 00 """.replace(' ', '').replace('\n', '')) - m = SMB2Message(self, SMB2CreateRequest(path, + m = SMB2Message(SMB2CreateRequest(path, file_attributes = 0, access_mask = FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | SYNCHRONIZE, share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, @@ -678,19 +641,16 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 messages_history.append(create_message) if create_message.status == 0: sendQuery(kwargs['tid'], create_message.payload.fid, '') + elif create_message.status == 0xC0000034L: # [MS-ERREF]: STATUS_OBJECT_NAME_INVALID + errback(OperationFailure('Failed to list %s on %s: Path not found' % ( path, service_name ), messages_history)) else: errback(OperationFailure('Failed to list %s on %s: Unable to open directory' % ( path, service_name ), messages_history)) def sendQuery(tid, fid, data_buf): - if self.smb2_dialect != SMB2_DIALECT_2 and self.cap_multi_credit: - output_buf_len = 64 * 1024 * (self.credits - 1) - else: - output_buf_len = self.max_transact_size - - m = SMB2Message(self, SMB2QueryDirectoryRequest(fid, pattern, + m = SMB2Message(SMB2QueryDirectoryRequest(fid, pattern, info_class = 0x25, # FileIdBothDirectoryInformation flags = 0, - output_buf_len = output_buf_len)) + output_buf_len = self.max_transact_size)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, queryCB, errback, tid = tid, fid = fid, data_buf = data_buf) @@ -701,6 +661,9 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 if query_message.status == 0: data_buf = decodeQueryStruct(kwargs['data_buf'] + query_message.payload.data) sendQuery(kwargs['tid'], kwargs['fid'], data_buf) + elif query_message.status == 0xC000000FL: # [MS-ERREF]: STATUS_NO_SUCH_FILE + # If there are no matching files, we just treat as success instead of failing + closeFid(kwargs['tid'], kwargs['fid'], results = results) elif query_message.status == 0x80000006L: # STATUS_NO_MORE_FILES closeFid(kwargs['tid'], kwargs['fid'], results = results) else: @@ -746,7 +709,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 return '' def closeFid(tid, fid, results = None, error = None): - m = SMB2Message(self, SMB2CloseRequest(fid)) + m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, results = results, error = error) @@ -756,7 +719,11 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 if kwargs['results'] is not None: callback(kwargs['results']) elif kwargs['error'] is not None: - errback(OperationFailure('Failed to list %s on %s: Query failed with errorcode 0x%08x' % ( path, service_name, kwargs['error'] ), messages_history)) + if kwargs['error'] == 0xC000000F: # [MS-ERREF]: STATUS_NO_SUCH_FILE + # Remote server returns STATUS_NO_SUCH_FILE error so we assume that the search returns no matching files + callback([ ]) + else: + errback(OperationFailure('Failed to list %s on %s: Query failed with errorcode 0x%08x' % ( path, service_name, kwargs['error'] ), messages_history)) if not self.connected_trees.has_key(service_name): def connectCB(connect_message, **kwargs): @@ -767,7 +734,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 else: errback(OperationFailure('Failed to list %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) - m = SMB2Message(self, SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) messages_history.append(m) @@ -795,7 +762,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 51 46 69 64 00 00 00 00 """.replace(' ', '').replace('\n', '')) - m = SMB2Message(self, SMB2CreateRequest(path, + m = SMB2Message(SMB2CreateRequest(path, file_attributes = 0, access_mask = FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | SYNCHRONIZE, share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, @@ -822,7 +789,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 errback(OperationFailure('Failed to get attributes for %s on %s: Unable to open remote file object' % ( path, service_name ), messages_history)) def closeFid(tid, fid, info = None, error = None): - m = SMB2Message(self, SMB2CloseRequest(fid)) + m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, info = info, error = error) @@ -843,7 +810,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 else: errback(OperationFailure('Failed to get attributes for %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) - m = SMB2Message(self, SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) messages_history.append(m) @@ -864,7 +831,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 results = [ ] def sendCreate(tid): - m = SMB2Message(self, SMB2CreateRequest(path, + m = SMB2Message(SMB2CreateRequest(path, file_attributes = 0, access_mask = FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | READ_CONTROL | SYNCHRONIZE, share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, @@ -880,18 +847,13 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 def createCB(create_message, **kwargs): messages_history.append(create_message) if create_message.status == 0: - if self.smb2_dialect != SMB2_DIALECT_2 and self.cap_multi_credit: - output_buf_len = 64 * 1024 * (self.credits - 1) - else: - output_buf_len = self.max_transact_size - - m = SMB2Message(self, SMB2QueryInfoRequest(create_message.payload.fid, + m = SMB2Message(SMB2QueryInfoRequest(create_message.payload.fid, flags = 0, additional_info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, info_type = SMB2_INFO_SECURITY, file_info_class = 0, # [MS-SMB2] 2.2.37, 3.2.4.12 input_buf = '', - output_buf_len = output_buf_len)) + output_buf_len = self.max_transact_size)) m.tid = kwargs['tid'] self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, queryCB, errback, tid = kwargs['tid'], fid = create_message.payload.fid) @@ -908,7 +870,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 closeFid(kwargs['tid'], kwargs['fid'], error = query_message.status) def closeFid(tid, fid, result = None, error = None): - m = SMB2Message(self, SMB2CloseRequest(fid)) + m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, result = result, error = error) @@ -929,7 +891,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 else: errback(OperationFailure('Failed to get the security descriptor of %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) - m = SMB2Message(self, SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) messages_history.append(m) @@ -961,7 +923,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 51 46 69 64 00 00 00 00 """.replace(' ', '').replace('\n', '')) - m = SMB2Message(self, SMB2CreateRequest(path, + m = SMB2Message(SMB2CreateRequest(path, file_attributes = 0, access_mask = FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | READ_CONTROL | SYNCHRONIZE, share_access = FILE_SHARE_READ | FILE_SHARE_WRITE, @@ -978,7 +940,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 def createCB(create_message, **kwargs): messages_history.append(create_message) if create_message.status == 0: - m = SMB2Message(self, SMB2QueryInfoRequest(create_message.payload.fid, + m = SMB2Message(SMB2QueryInfoRequest(create_message.payload.fid, flags = 0, additional_info = 0, info_type = SMB2_INFO_FILE, @@ -1014,12 +976,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 def sendRead(tid, fid, offset, remaining_len, read_len, file_attributes): read_count = min(self.max_read_size, remaining_len) - - if self.smb2_dialect != SMB2_DIALECT_2 and self.cap_multi_credit: - max_read_count = 64 * 1024 * (self.credits -1) - read_count = min(read_count, max_read_count) - - m = SMB2Message(self, SMB2ReadRequest(fid, offset, read_count)) + m = SMB2Message(SMB2ReadRequest(fid, offset, read_count)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, readCB, errback, @@ -1045,7 +1002,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 closeFid(kwargs['tid'], kwargs['fid'], error = read_message.status) def closeFid(tid, fid, ret = None, error = None): - m = SMB2Message(self, SMB2CloseRequest(fid)) + m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, ret = ret, error = error) @@ -1066,7 +1023,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 else: errback(OperationFailure('Failed to retrieve %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) - m = SMB2Message(self, SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) messages_history.append(m) @@ -1099,7 +1056,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 51 46 69 64 00 00 00 00 """.replace(' ', '').replace('\n', '')) - m = SMB2Message(self, SMB2CreateRequest(path, + m = SMB2Message(SMB2CreateRequest(path, file_attributes = ATTR_ARCHIVE, access_mask = FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_EA | READ_CONTROL | SYNCHRONIZE, share_access = 0, @@ -1122,14 +1079,11 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 errback(OperationFailure('Failed to store %s on %s: Unable to open file' % ( path, service_name ), messages_history)) def sendWrite(tid, fid, offset): - if self.smb2_dialect != SMB2_DIALECT_2 and self.cap_multi_credit: - write_count = 64 * 1024 * (self.credits -1) - else: - write_count = self.max_write_size + write_count = self.max_write_size data = file_obj.read(write_count) data_len = len(data) if data_len > 0: - m = SMB2Message(self, SMB2WriteRequest(fid, data, offset)) + m = SMB2Message(SMB2WriteRequest(fid, data, offset)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, writeCB, errback, tid = tid, fid = fid, offset = offset+data_len) @@ -1146,7 +1100,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 errback(OperationFailure('Failed to store %s on %s: Write failed' % ( path, service_name ), messages_history)) def closeFid(tid, fid, error = None, offset = None): - m = SMB2Message(self, SMB2CloseRequest(fid)) + m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, closeCB, errback, fid = fid, offset = offset, error = error) @@ -1167,7 +1121,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 else: errback(OperationFailure('Failed to store %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) - m = SMB2Message(self, SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, connectCB, errback, path = service_name) messages_history.append(m) @@ -1175,16 +1129,99 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 sendCreate(self.connected_trees[service_name]) - def _deleteFiles_SMB2(self, service_name, path_file_pattern, callback, errback, timeout = 30): + def _deleteFiles_SMB2(self, service_name, path_file_pattern, delete_matching_folders, callback, errback, timeout = 30): if not self.has_authenticated: raise NotReadyError('SMB connection not authenticated') expiry_time = time.time() + timeout + pattern = None path = path_file_pattern.replace('/', '\\') if path.startswith('\\'): path = path[1:] if path.endswith('\\'): path = path[:-1] + else: + path_components = path.split('\\') + if path_components[-1].find('*') > -1 or path_components[-1].find('?') > -1: + path = '\\'.join(path_components[:-1]) + pattern = path_components[-1] + messages_history, files_queue = [ ], [ ] + + if pattern is None: + path_components = path.split('\\') + if len(path_components) > 1: + files_queue.append(( '\\'.join(path_components[:-1]), path_components[-1] )) + else: + files_queue.append(( '', path )) + + def deleteCB(path): + if files_queue: + p, filename = files_queue.pop(0) + if filename: + if p: + filename = p + '\\' + filename + self._deleteFiles_SMB2__del(service_name, self.connected_trees[service_name], filename, deleteCB, errback, timeout) + else: + self._deleteDirectory_SMB2(service_name, p, deleteCB, errback, timeout) + else: + callback(path_file_pattern) + + def listCB(files_list): + files_queue.extend(files_list) + deleteCB(None) + + if not self.connected_trees.has_key(service_name): + def connectCB(connect_message, **kwargs): + messages_history.append(connect_message) + if connect_message.status == 0: + self.connected_trees[service_name] = connect_message.tid + if files_queue: + deleteCB(None) + else: + self._deleteFiles_SMB2__list(service_name, path, pattern, delete_matching_folders, listCB, errback, timeout) + else: + errback(OperationFailure('Failed to delete %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) + messages_history.append(m) + else: + if files_queue: + deleteCB(None) + else: + self._deleteFiles_SMB2__list(service_name, path, pattern, delete_matching_folders, listCB, errback, timeout) + + def _deleteFiles_SMB2__list(self, service_name, path, pattern, delete_matching_folders, callback, errback, timeout = 30): + folder_queue = [ ] + files_list = [ ] + current_path = [ path ] + search = SMB_FILE_ATTRIBUTE_READONLY | SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_DIRECTORY | SMB_FILE_ATTRIBUTE_ARCHIVE | SMB_FILE_ATTRIBUTE_INCL_NORMAL + + def listCB(results): + files = [ ] + for f in filter(lambda x: x.filename not in [ '.', '..' ], results): + if f.isDirectory: + if delete_matching_folders: + folder_queue.append(current_path[0]+'\\'+f.filename) + else: + files.append(( current_path[0], f.filename )) + if current_path[0]!=path and delete_matching_folders: + files.append(( current_path[0], None )) + + if files: + files_list[0:0] = files + + if folder_queue: + p = folder_queue.pop() + current_path[0] = p + self._listPath_SMB2(service_name, current_path[0], listCB, errback, search = search, pattern = '*', timeout = 30) + else: + callback(files_list) + + self._listPath_SMB2(service_name, path, listCB, errback, search = search, pattern = pattern, timeout = timeout) + + def _deleteFiles_SMB2__del(self, service_name, tid, path, callback, errback, timeout = 30): messages_history = [ ] def sendCreate(tid): @@ -1196,7 +1233,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 51 46 69 64 00 00 00 00 """.replace(' ', '').replace('\n', '')) - m = SMB2Message(self, SMB2CreateRequest(path, + m = SMB2Message(SMB2CreateRequest(path, file_attributes = 0, access_mask = DELETE | FILE_READ_ATTRIBUTES, share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, @@ -1215,11 +1252,15 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 messages_history.append(open_message) if open_message.status == 0: sendDelete(open_message.tid, open_message.payload.fid) + elif open_message.status == 0xC0000034L: # [MS-ERREF]: STATUS_OBJECT_NAME_NOT_FOUND + callback(path) + elif open_message.status == 0xC00000BAL: # [MS-ERREF]: STATUS_FILE_IS_A_DIRECTORY + errback(OperationFailure('Failed to delete %s on %s: Cannot delete a folder. Please use deleteDirectory() method or append "/*" to your path if you wish to delete all files in the folder.' % ( path, service_name ), messages_history)) else: errback(OperationFailure('Failed to delete %s on %s: Unable to open file' % ( path, service_name ), messages_history)) def sendDelete(tid, fid): - m = SMB2Message(self, SMB2SetInfoRequest(fid, + m = SMB2Message(SMB2SetInfoRequest(fid, additional_info = 0, info_type = SMB2_INFO_FILE, file_info_class = 0x0d, # SMB2_FILE_DISPOSITION_INFO @@ -1238,7 +1279,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 closeFid(kwargs['tid'], kwargs['fid'], status = delete_message.status) def closeFid(tid, fid, status = None): - m = SMB2Message(self, SMB2CloseRequest(fid)) + m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, closeCB, errback, status = status) @@ -1246,27 +1287,13 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 def closeCB(close_message, **kwargs): if kwargs['status'] == 0: - callback(path_file_pattern) + callback(path) else: errback(OperationFailure('Failed to delete %s on %s: Delete failed' % ( path, service_name ), messages_history)) - if not self.connected_trees.has_key(service_name): - def connectCB(connect_message, **kwargs): - messages_history.append(connect_message) - if connect_message.status == 0: - self.connected_trees[service_name] = connect_message.tid - sendCreate(connect_message.tid) - else: - errback(OperationFailure('Failed to delete %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + sendCreate(tid) - m = SMB2Message(self, SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) - self._sendSMBMessage(m) - self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) - messages_history.append(m) - else: - sendCreate(self.connected_trees[service_name]) - - def _resetFileAttributes_SMB2(self, service_name, path_file_pattern, callback, errback, timeout = 30): + def _resetFileAttributes_SMB2(self, service_name, path_file_pattern, callback, errback, file_attributes = ATTR_NORMAL, timeout = 30): if not self.has_authenticated: raise NotReadyError('SMB connection not authenticated') @@ -1288,7 +1315,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 51 46 69 64 00 00 00 00 """.replace(' ', '').replace('\n', '')) - m = SMB2Message(self, SMB2CreateRequest(path, + m = SMB2Message(SMB2CreateRequest(path, file_attributes = 0, access_mask = FILE_WRITE_ATTRIBUTES, share_access = FILE_SHARE_READ | FILE_SHARE_WRITE, @@ -1310,11 +1337,11 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 errback(OperationFailure('Failed to reset attributes of %s on %s: Unable to open file' % ( path, service_name ), messages_history)) def sendReset(tid, fid): - m = SMB2Message(self, SMB2SetInfoRequest(fid, + m = SMB2Message(SMB2SetInfoRequest(fid, additional_info = 0, info_type = SMB2_INFO_FILE, file_info_class = 4, # FileBasicInformation - data = struct.pack('qqqqii',0,0,0,0,0x80,0))) # FILE_ATTRIBUTE_NORMAL + data = struct.pack('qqqqii',0,0,0,0,file_attributes,0))) # [MS-SMB2]: 2.2.39, [MS-FSCC]: 2.4, [MS-FSCC]: 2.4.7, [MS-FSCC]: 2.6 m.tid = tid self._sendSMBMessage(m) @@ -1329,7 +1356,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 closeFid(kwargs['tid'], kwargs['fid'], status = reset_message.status) def closeFid(tid, fid, status = None): - m = SMB2Message(self, SMB2CloseRequest(fid)) + m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, closeCB, errback, status = status) @@ -1350,7 +1377,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 else: errback(OperationFailure('Failed to reset attributes of %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) - m = SMB2Message(self, SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) messages_history.append(m) @@ -1378,7 +1405,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 51 46 69 64 00 00 00 00 """.replace(' ', '').replace('\n', '')) - m = SMB2Message(self, SMB2CreateRequest(path, + m = SMB2Message(SMB2CreateRequest(path, file_attributes = 0, access_mask = FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_EA | FILE_WRITE_EA | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | READ_CONTROL | DELETE | SYNCHRONIZE, share_access = 0, @@ -1400,7 +1427,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 errback(OperationFailure('Failed to create directory %s on %s: Create failed' % ( path, service_name ), messages_history)) def closeFid(tid, fid): - m = SMB2Message(self, SMB2CloseRequest(fid)) + m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, closeCB, errback) @@ -1418,7 +1445,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 else: errback(OperationFailure('Failed to create directory %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) - m = SMB2Message(self, SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) messages_history.append(m) @@ -1446,7 +1473,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 51 46 69 64 00 00 00 00 """.replace(' ', '').replace('\n', '')) - m = SMB2Message(self, SMB2CreateRequest(path, + m = SMB2Message(SMB2CreateRequest(path, file_attributes = 0, access_mask = DELETE | FILE_READ_ATTRIBUTES, share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, @@ -1468,7 +1495,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 errback(OperationFailure('Failed to delete %s on %s: Unable to open directory' % ( path, service_name ), messages_history)) def sendDelete(tid, fid): - m = SMB2Message(self, SMB2SetInfoRequest(fid, + m = SMB2Message(SMB2SetInfoRequest(fid, additional_info = 0, info_type = SMB2_INFO_FILE, file_info_class = 0x0d, # SMB2_FILE_DISPOSITION_INFO @@ -1486,7 +1513,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 closeFid(kwargs['tid'], kwargs['fid'], status = delete_message.status) def closeFid(tid, fid, status = None): - m = SMB2Message(self, SMB2CloseRequest(fid)) + m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, status = status) @@ -1507,7 +1534,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 else: errback(OperationFailure('Failed to delete %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) - m = SMB2Message(self, SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) messages_history.append(m) @@ -1542,7 +1569,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 51 46 69 64 00 00 00 00 """.replace(' ', '').replace('\n', '')) - m = SMB2Message(self, SMB2CreateRequest(old_path, + m = SMB2Message(SMB2CreateRequest(old_path, file_attributes = 0, access_mask = DELETE | FILE_READ_ATTRIBUTES | SYNCHRONIZE, share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, @@ -1565,7 +1592,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 def sendRename(tid, fid): data = '\x00'*16 + struct.pack(' 0: - m = SMBMessage(self, ComWriteAndxRequest(fid = fid, offset = offset, data_bytes = data_bytes)) + m = SMBMessage(ComWriteAndxRequest(fid = fid, offset = offset, data_bytes = data_bytes)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, writeCB, errback, fid = fid, offset = offset+data_len) @@ -2528,7 +2559,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 errback(OperationFailure('Failed to store %s on %s: Write failed' % ( path, service_name ), messages_history)) def closeFid(tid, fid): - m = SMBMessage(self, ComCloseRequest(fid)) + m = SMBMessage(ComCloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) messages_history.append(m) @@ -2542,22 +2573,111 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 else: errback(OperationFailure('Failed to store %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) - m = SMBMessage(self, ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) + m = SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, connectCB, errback, path = service_name) messages_history.append(m) else: sendOpen(self.connected_trees[service_name]) - def _deleteFiles_SMB1(self, service_name, path_file_pattern, callback, errback, timeout = 30): + def _deleteFiles_SMB1(self, service_name, path_file_pattern, delete_matching_folders, callback, errback, timeout = 30): if not self.has_authenticated: raise NotReadyError('SMB connection not authenticated') + expiry_time = time.time() + timeout + pattern = None path = path_file_pattern.replace('/', '\\') + if path.startswith('\\'): + path = path[1:] + if path.endswith('\\'): + path = path[:-1] + else: + path_components = path.split('\\') + if path_components[-1].find('*') > -1 or path_components[-1].find('?') > -1: + path = '\\'.join(path_components[:-1]) + pattern = path_components[-1] + messages_history, files_queue = [ ], [ ] + + if pattern is None: + path_components = path.split('\\') + if len(path_components) > 1: + files_queue.append(( '\\'.join(path_components[:-1]), path_components[-1] )) + else: + files_queue.append(( '', path )) + + def deleteCB(path): + if files_queue: + p, filename = files_queue.pop(0) + if filename: + if p: + filename = p + '\\' + filename + self._deleteFiles_SMB1__del(service_name, self.connected_trees[service_name], filename, deleteCB, errback, timeout) + else: + self._deleteDirectory_SMB1(service_name, p, deleteCB, errback, timeout = 30) + else: + callback(path_file_pattern) + + def listCB(files_list): + files_queue.extend(files_list) + deleteCB(None) + + if not self.connected_trees.has_key(service_name): + def connectCB(connect_message, **kwargs): + messages_history.append(connect_message) + if not connect_message.status.hasError: + self.connected_trees[service_name] = connect_message.tid + if files_queue: + deleteCB(None) + else: + self._deleteFiles_SMB1__list(service_name, path, pattern, delete_matching_folders, listCB, errback, timeout) + else: + errback(OperationFailure('Failed to delete %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + + m = SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) + messages_history.append(m) + else: + if files_queue: + deleteCB(None) + else: + self._deleteFiles_SMB1__list(service_name, path, pattern, delete_matching_folders, listCB, errback, timeout) + + def _deleteFiles_SMB1__list(self, service_name, path, pattern, delete_matching_folders, callback, errback, timeout = 30): + folder_queue = [ ] + files_list = [ ] + current_path = [ path ] + search = SMB_FILE_ATTRIBUTE_READONLY | SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_DIRECTORY | SMB_FILE_ATTRIBUTE_ARCHIVE | SMB_FILE_ATTRIBUTE_INCL_NORMAL + + def listCB(results): + files = [ ] + for f in filter(lambda x: x.filename not in [ '.', '..' ], results): + if f.isDirectory: + if delete_matching_folders: + folder_queue.append(current_path[0]+'\\'+f.filename) + else: + files.append(( current_path[0], f.filename )) + if current_path[0]!=path and delete_matching_folders: + files.append(( current_path[0], None )) + + if files: + files_list[0:0] = files + + if folder_queue: + p = folder_queue.pop() + current_path[0] = p + self._listPath_SMB1(service_name, current_path[0], listCB, errback, search = search, pattern = '*', timeout = 30) + else: + callback(files_list) + + self._listPath_SMB1(service_name, path, listCB, errback, search = search, pattern = pattern, timeout = timeout) + + + def _deleteFiles_SMB1__del(self, service_name, tid, path, callback, errback, timeout = 30): messages_history = [ ] def sendDelete(tid): - m = SMBMessage(self, ComDeleteRequest(filename_pattern = path, + m = SMBMessage(ComDeleteRequest(filename_pattern = path, search_attributes = SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM)) m.tid = tid self._sendSMBMessage(m) @@ -2567,27 +2687,20 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 def deleteCB(delete_message, **kwargs): messages_history.append(delete_message) if not delete_message.status.hasError: + callback(path) + elif delete_message.status.internal_value == 0xC000000FL: # [MS-ERREF]: STATUS_NO_SUCH_FILE + # If there are no matching files, we just treat as success instead of failing callback(path_file_pattern) + elif delete_message.status.internal_value == 0xC00000BAL: # [MS-ERREF]: STATUS_FILE_IS_A_DIRECTORY + errback(OperationFailure('Failed to delete %s on %s: Cannot delete a folder. Please use deleteDirectory() method or append "/*" to your path if you wish to delete all files in the folder.' % ( path, service_name ), messages_history)) + elif delete_message.status.internal_value == 0xC0000034L: # [MS-ERREF]: STATUS_OBJECT_NAME_INVALID + errback(OperationFailure('Failed to delete %s on %s: Path not found' % ( path, service_name ), messages_history)) else: - errback(OperationFailure('Failed to store %s on %s: Delete failed' % ( path, service_name ), messages_history)) + errback(OperationFailure('Failed to delete %s on %s: Delete failed' % ( path, service_name ), messages_history)) - if not self.connected_trees.has_key(service_name): - def connectCB(connect_message, **kwargs): - messages_history.append(connect_message) - if not connect_message.status.hasError: - self.connected_trees[service_name] = connect_message.tid - sendDelete(connect_message.tid) - else: - errback(OperationFailure('Failed to delete %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + sendDelete(tid) - m = SMBMessage(self, ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) - self._sendSMBMessage(m) - self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, connectCB, errback, path = service_name) - messages_history.append(m) - else: - sendDelete(self.connected_trees[service_name]) - - def _resetFileAttributes_SMB1(self, service_name, path_file_pattern, callback, errback, timeout = 30): + def _resetFileAttributes_SMB1(self, service_name, path_file_pattern, callback, errback, file_attributes=ATTR_NORMAL, timeout = 30): raise NotReadyError('resetFileAttributes is not yet implemented for SMB1') def _createDirectory_SMB1(self, service_name, path, callback, errback, timeout = 30): @@ -2598,7 +2711,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 messages_history = [ ] def sendCreate(tid): - m = SMBMessage(self, ComCreateDirectoryRequest(path)) + m = SMBMessage(ComCreateDirectoryRequest(path)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, createCB, errback) @@ -2620,7 +2733,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 else: errback(OperationFailure('Failed to create directory %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) - m = SMBMessage(self, ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) + m = SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, connectCB, errback, path = service_name) messages_history.append(m) @@ -2635,7 +2748,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 messages_history = [ ] def sendDelete(tid): - m = SMBMessage(self, ComDeleteDirectoryRequest(path)) + m = SMBMessage(ComDeleteDirectoryRequest(path)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, deleteCB, errback) @@ -2655,9 +2768,9 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 self.connected_trees[service_name] = connect_message.tid sendDelete(connect_message.tid) else: - errback(OperationFailure('Failed to delete %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + errback(OperationFailure('Failed to delete directory %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) - m = SMBMessage(self, ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) + m = SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, connectCB, errback, path = service_name) messages_history.append(m) @@ -2673,7 +2786,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 messages_history = [ ] def sendRename(tid): - m = SMBMessage(self, ComRenameRequest(old_path = old_path, + m = SMBMessage(ComRenameRequest(old_path = old_path, new_path = new_path, search_attributes = SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM)) m.tid = tid @@ -2697,7 +2810,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 else: errback(OperationFailure('Failed to rename %s on %s: Unable to connect to shared device' % ( old_path, service_name ), messages_history)) - m = SMBMessage(self, ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) + m = SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, connectCB, errback, path = service_name) messages_history.append(m) @@ -2716,7 +2829,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 results = [ ] def sendOpen(tid): - m = SMBMessage(self, ComOpenAndxRequest(filename = path, + m = SMBMessage(ComOpenAndxRequest(filename = path, access_mode = 0x0040, # Sharing mode: Deny nothing to others open_mode = 0x0001, # Failed if file does not exist search_attributes = 0, @@ -2741,7 +2854,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 fid, # FID 0x01, # IsFctl 0) # IsFlags - m = SMBMessage(self, ComNTTransactRequest(function = 0x0002, # NT_TRANSACT_IOCTL. [MS-CIFS]: 2.2.7.2.1 + m = SMBMessage(ComNTTransactRequest(function = 0x0002, # NT_TRANSACT_IOCTL. [MS-CIFS]: 2.2.7.2.1 max_params_count = 0, max_data_count = 0xFFFF, max_setup_count = 0, @@ -2766,7 +2879,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 errback(OperationFailure('Failed to list snapshots %s on %s: Unable to list snapshots on path' % ( path, service_name ), messages_history)) def closeFid(tid, fid): - m = SMBMessage(self, ComCloseRequest(fid)) + m = SMBMessage(ComCloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) messages_history.append(m) @@ -2780,7 +2893,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 else: errback(OperationFailure('Failed to list snapshots %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) - m = SMBMessage(self, ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) + m = SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) messages_history.append(m) @@ -2800,7 +2913,7 @@ c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 else: errback(OperationFailure('Echo failed', messages_history)) - m = SMBMessage(self, ComEchoRequest(echo_data = data)) + m = SMBMessage(ComEchoRequest(echo_data = data)) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, echoCB, errback) messages_history.append(m) diff --git a/lib/sambatools/smb/ntlm.py b/lib/sambatools/python2/smb/ntlm.py similarity index 92% rename from lib/sambatools/smb/ntlm.py rename to lib/sambatools/python2/smb/ntlm.py index ae6fc9e7..e9acc36a 100644 --- a/lib/sambatools/smb/ntlm.py +++ b/lib/sambatools/python2/smb/ntlm.py @@ -1,5 +1,6 @@ -import types, hmac, binascii, struct, random +import types, hmac, binascii, struct, random, string +from .utils.rc4 import RC4_encrypt from utils.pyDes import des try: @@ -58,14 +59,14 @@ NTLM_Negotiate56 = 0x80000000 NTLM_FLAGS = NTLM_NegotiateUnicode | \ NTLM_RequestTarget | \ + NTLM_NegotiateSign | \ NTLM_NegotiateNTLM | \ NTLM_NegotiateAlwaysSign | \ NTLM_NegotiateExtendedSecurity | \ NTLM_NegotiateTargetInfo | \ NTLM_NegotiateVersion | \ NTLM_Negotiate128 | \ - NTLM_NegotiateKeyExchange | \ - NTLM_Negotiate56 + NTLM_NegotiateKeyExchange def generateNegotiateMessage(): """ @@ -81,7 +82,7 @@ def generateNegotiateMessage(): return s -def generateAuthenticateMessage(challenge_flags, nt_response, lm_response, session_key, user, domain = 'WORKGROUP', workstation = 'LOCALHOST'): +def generateAuthenticateMessage(challenge_flags, nt_response, lm_response, request_session_key, user, domain = 'WORKGROUP', workstation = 'LOCALHOST'): """ References: =========== @@ -90,6 +91,13 @@ def generateAuthenticateMessage(challenge_flags, nt_response, lm_response, sessi FORMAT = '<8sIHHIHHIHHIHHIHHIHHII' FORMAT_SIZE = struct.calcsize(FORMAT) + # [MS-NLMP]: 3.1.5.1.2 + # http://grutz.jingojango.net/exploits/davenport-ntlm.html + session_key = session_signing_key = request_session_key + if challenge_flags & NTLM_NegotiateKeyExchange: + session_signing_key = "".join([ random.choice(string.digits+string.ascii_letters) for _ in range(16) ]).encode('ascii') + session_key = RC4_encrypt(request_session_key, session_signing_key) + lm_response_length = len(lm_response) lm_response_offset = FORMAT_SIZE nt_response_length = len(nt_response) @@ -125,7 +133,7 @@ def generateAuthenticateMessage(challenge_flags, nt_response, lm_response, sessi session_key_length, session_key_length, session_key_offset, auth_flags) - return s + lm_response + nt_response + padding + domain_unicode + user_unicode + workstation_unicode + session_key + return s + lm_response + nt_response + padding + domain_unicode + user_unicode + workstation_unicode + session_key, session_signing_key def decodeChallengeMessage(ntlm_data): diff --git a/lib/sambatools/smb/security_descriptors.py b/lib/sambatools/python2/smb/security_descriptors.py similarity index 100% rename from lib/sambatools/smb/security_descriptors.py rename to lib/sambatools/python2/smb/security_descriptors.py diff --git a/lib/sambatools/smb/securityblob.py b/lib/sambatools/python2/smb/securityblob.py similarity index 100% rename from lib/sambatools/smb/securityblob.py rename to lib/sambatools/python2/smb/securityblob.py diff --git a/lib/sambatools/smb/smb2_constants.py b/lib/sambatools/python2/smb/smb2_constants.py similarity index 83% rename from lib/sambatools/smb/smb2_constants.py rename to lib/sambatools/python2/smb/smb2_constants.py index 024ed2c4..71ef74be 100644 --- a/lib/sambatools/smb/smb2_constants.py +++ b/lib/sambatools/python2/smb/smb2_constants.py @@ -50,12 +50,9 @@ SMB2_COMMAND_NAMES = { } # Values for dialect_revision field in SMB2NegotiateResponse class -SMB2_DIALECT_2 = 0x0202 # 2.0.2 - First SMB2 version -SMB2_DIALECT_21 = 0x0210 # 2.1 - Windows 7 -SMB2_DIALET_30 = 0x0300 # 3.0 - Windows 8 -SMB2_DIALECT_302 = 0x0302 # 3.0.2 - Windows 8.1 -SMB2_DIALECT_311 = 0x0311 # 3.1.1 - Windows 10 -SMB2_DIALECT_2ALL = 0x02FF # Wildcard (for negotiation only) +SMB2_DIALECT_2 = 0x0202 +SMB2_DIALECT_21 = 0x0210 +SMB2_DIALECT_2ALL = 0x02FF # Bit mask for SecurityMode field in SMB2NegotiateResponse class SMB2_NEGOTIATE_SIGNING_ENABLED = 0x0001 @@ -69,17 +66,6 @@ SMB2_SHARE_TYPE_PRINTER = 0x03 # Bitmask for Capabilities in SMB2TreeConnectResponse class SMB2_SHARE_CAP_DFS = 0x0008 - -# SMB 2.1 / 3 Capabilities flags -SMB2_GLOBAL_CAP_DFS = 0x01 -SMB2_GLOBAL_CAP_LEASING = 0x02 -SMB2_GLOBAL_CAP_LARGE_MTU = 0x04 -SMB2_GLOBAL_CAP_MULTI_CHANNEL = 0x08 -SMB2_GLOBAL_CAP_PERSISTENT_HANDLES = 0x10 -SMB2_GLOBAL_CAP_DIRECTORY_LEASING = 0x20 -SMB2_GLOBAL_CAP_ENCRYPTION = 0x40 - - # Values for OpLockLevel field in SMB2CreateRequest class SMB2_OPLOCK_LEVEL_NONE = 0x00 SMB2_OPLOCK_LEVEL_II = 0x01 diff --git a/lib/sambatools/smb/smb2_structs.py b/lib/sambatools/python2/smb/smb2_structs.py similarity index 80% rename from lib/sambatools/smb/smb2_structs.py rename to lib/sambatools/python2/smb/smb2_structs.py index 2e13b491..5699eed2 100644 --- a/lib/sambatools/smb/smb2_structs.py +++ b/lib/sambatools/python2/smb/smb2_structs.py @@ -1,5 +1,5 @@ -import os, sys, struct, types, logging, binascii, time, uuid +import os, sys, struct, types, logging, binascii, time from StringIO import StringIO from smb_structs import ProtocolError from smb_constants import * @@ -23,15 +23,8 @@ class SMB2Message: log = logging.getLogger('SMB.SMB2Message') protocol = 2 - - def __init__(self, conn = None, payload = None): - """ - Initialise a new SMB2 Message. - conn - reference to the connection, the SMB class - payload - the message payload, if any - """ + def __init__(self, payload = None): self.reset() - self.conn = conn if payload: self.payload = payload self.payload.initMessage(self) @@ -67,10 +60,6 @@ class SMB2Message: self.pid = 0 self.tid = 0 - # credit related - self.credit_charge = 0 - self.credit_request = 1 - # Not used in this class. Maintained for compatibility with SMBMessage class self.flags2 = 0 self.uid = 0 @@ -80,66 +69,18 @@ class SMB2Message: def encode(self): """ Encode this SMB2 message into a series of bytes suitable to be embedded with a NetBIOS session message. - AssertionError will be raised if this SMB message has not been initialized with an SMB instance AssertionError will be raised if this SMB message has not been initialized with a Payload instance - The header format is: - - Protocol ID - - Structure Size - - Credit Charge - - Status / Channel Sequence - - Command - - Credit Request / Credit Response - - Flags - - Next Compound - - MessageId - - Reserved - - TreeId - - Session ID - - Signature - @return: a string containing the encoded SMB2 message """ assert self.payload - assert self.conn self.pid = os.getpid() self.payload.prepare(self) - # If Connection.Dialect is not "2.0.2" and if Connection.SupportsMultiCredit is TRUE, the - # CreditCharge field in the SMB2 header MUST be set to ( 1 + (OutputBufferLength - 1) / 65536 ) - # This only applies to SMB2ReadRequest, SMB2WriteRequest, SMB2IoctlRequest and SMB2QueryDirectory - # See: MS-SMB2 3.2.4.1.5: For all other requests, the client MUST set CreditCharge to 1, even if the - # payload size of a request or the anticipated response is greater than 65536. - if self.conn.smb2_dialect != SMB2_DIALECT_2: - if self.conn.cap_multi_credit: - # self.credit_charge will be set by some commands if necessary (Read/Write/Ioctl/QueryDirectory) - # If not set, but dialect is SMB 2.1 or above, we must set it to 1 - if self.credit_charge is 0: - self.credit_charge = 1 - else: - # If >= SMB 2.1, but server does not support multi credit operations we must set to 1 - self.credit_charge = 1 - - if self.mid > 3: - self.credit_request = 127 - headers_data = struct.pack(self.HEADER_STRUCT_FORMAT, - '\xFESMB', # Protocol ID - self.HEADER_SIZE, # Structure Size - self.credit_charge, # Credit Charge - self.status, # Status / Channel Sequence - self.command, # Command - self.credit_request, # Credit Request / Credit Response - self.flags, # Flags - ) + \ - struct.pack(self.SYNC_HEADER_STRUCT_FORMAT, - self.next_command_offset, # Next Compound - self.mid, # Message ID - self.pid, # Process ID - self.tid, # Tree ID - self.session_id, # Session ID - self.signature) # Signature + '\xFESMB', self.HEADER_SIZE, 0, self.status, self.command, 0, self.flags) + \ + struct.pack(self.SYNC_HEADER_STRUCT_FORMAT, self.next_command_offset, self.mid, self.pid, self.tid, self.session_id, self.signature) return headers_data + self.data def decode(self, buf): @@ -165,8 +106,7 @@ class SMB2Message: self.reset() protocol, struct_size, self.credit_charge, self.status, \ - self.command, self.credit_response, \ - self.flags = struct.unpack(self.HEADER_STRUCT_FORMAT, buf[:self.HEADER_STRUCT_SIZE]) + self.command, self.credit_re, self.flags = struct.unpack(self.HEADER_STRUCT_FORMAT, buf[:self.HEADER_STRUCT_SIZE]) if protocol != '\xFESMB': raise ProtocolError('Invalid 4-byte SMB2 protocol field', buf) @@ -249,53 +189,6 @@ class Structure: raise NotImplementedError -class SMB2NegotiateRequest(Structure): - """ - 2.2.3 SMB2 NEGOTIATE Request - The SMB2 NEGOTIATE Request packet is used by the client to notify the server what dialects of the SMB 2 Protocol - the client understands. This request is composed of an SMB2 header, as specified in section 2.2.1, - followed by this request structure: - - SMB2 Negotiate Request Packet structure: - StructureSize (2 bytes) - DialectCount (2 bytes) - SecurityMode (2 bytes) - Reserved (2 bytes) - Capabilities (4 bytes) - ClientGuid (16 bytes) - ClientStartTime (8 bytes): - ClientStartTime (8 bytes): - Dialects (variable): An array of one or more 16-bit integers - - References: - =========== - - [MS-SMB2]: 2.2.3 - - """ - - - STRUCTURE_FORMAT = " 0 # SMB2_SESSION_FLAG_IS_NULL + return (self.session_flags & 0x0002) > 0 # SMB2_SESSION_FLAG_IS_NULL def decode(self, message): assert message.command == SMB2_COM_SESSION_SETUP @@ -478,6 +370,7 @@ class SMB2CreateRequest(Structure): def prepare(self, message): buf = self.filename.encode('UTF-16LE') + filename_len = len(buf) if self.create_context_data: n = SMB2Message.HEADER_SIZE + self.STRUCTURE_SIZE + len(buf) if n % 8 != 0: @@ -505,7 +398,7 @@ class SMB2CreateRequest(Structure): self.create_disp, self.create_options, SMB2Message.HEADER_SIZE + self.STRUCTURE_SIZE, # NameOffset - len(self.filename)*2, # NameLength in bytes + filename_len, # Length of encoded filename in bytes create_context_offset, # CreateContextOffset len(self.create_context_data) # CreateContextLength ) + buf @@ -581,13 +474,6 @@ class SMB2WriteRequest(Structure): 0, # WriteChannelInfoLength self.flags) + self.data - # MS-SMB2 3.2.4.7 - # If a client requests writing to a file, Connection.Dialect is not "2.0.2", and if - # Connection.SupportsMultiCredit is TRUE, the CreditCharge field in the SMB2 header MUST be set - # to ( 1 + (Length - 1) / 65536 ) - if message.conn.smb2_dialect != SMB2_DIALECT_2 and message.conn.cap_multi_credit: - message.credit_charge = int(1 + (len(self.data) -1) / 65536) - class SMB2WriteResponse(Structure): """ @@ -646,13 +532,6 @@ class SMB2ReadRequest(Structure): 0 # ReadChannelInfoLength ) + '\0' - # MS-SMB2 3.2.4.6 - # If a client requests reading from a file, Connection.Dialect is not "2.0.2", and if - # Connection.SupportsMultiCredit is TRUE, the CreditCharge field in the SMB2 header MUST be set - # to ( 1 + (Length - 1) / 65536 ) - if message.conn.smb2_dialect != SMB2_DIALECT_2 and message.conn.cap_multi_credit: - message.credit_charge = int(1 + (self.read_len -1) / 65536) - class SMB2ReadResponse(Structure): """ @@ -709,11 +588,6 @@ class SMB2IoctlRequest(Structure): 0 # Reserved ) + self.in_data - # If Connection.SupportsMultiCredit is TRUE, the CreditCharge field in the SMB2 header - # SHOULD be set to (max(InputCount, MaxOutputResponse) - 1) / 65536 + 1 - if message.conn.smb2_dialect != SMB2_DIALECT_2 and message.conn.cap_multi_credit: - message.credit_charge = int((max(len(self.in_data), self.max_out_size) - 1) / 65536 + 1) - class SMB2IoctlResponse(Structure): """ @@ -822,12 +696,6 @@ class SMB2QueryDirectoryRequest(Structure): len(self.filename)*2, self.output_buf_len) + self.filename.encode('UTF-16LE') - # MS-SMB2 3.2.4.17 - # If Connection.Dialect is not "2.0.2" and if Connection.SupportsMultiCredit is TRUE, the - # CreditCharge field in the SMB2 header MUST be set to ( 1 + (OutputBufferLength - 1) / 65536 ) - if message.conn.smb2_dialect != SMB2_DIALECT_2 and message.conn.cap_multi_credit: - message.credit_charge = int(1 + (self.output_buf_len -1) / 65536) - class SMB2QueryDirectoryResponse(Structure): """ @@ -890,12 +758,6 @@ class SMB2QueryInfoRequest(Structure): self.fid # FileId ) + self.input_buf - # MS-SMB2 3.2.4.17 - # If Connection.Dialect is not "2.0.2" and if Connection.SupportsMultiCredit is TRUE, the - # CreditCharge field in the SMB2 header MUST be set to ( 1 + (OutputBufferLength - 1) / 65536 ) - if message.conn.smb2_dialect != SMB2_DIALECT_2 and message.conn.cap_multi_credit: - message.credit_charge = int(1 + ((self.output_buf_len + len(self.input_buf)) -1) / 65536) - class SMB2QueryInfoResponse(Structure): """ @@ -954,12 +816,6 @@ class SMB2SetInfoRequest(Structure): self.fid # FileId ) + self.data - # MS-SMB2 3.2.4.17 - # If Connection.Dialect is not "2.0.2" and if Connection.SupportsMultiCredit is TRUE, the - # CreditCharge field in the SMB2 header MUST be set to ( 1 + (OutputBufferLength - 1) / 65536 ) - if message.conn.smb2_dialect != SMB2_DIALECT_2 and message.conn.cap_multi_credit: - message.credit_charge = int(1 + (len(self.data) -1) / 65536) - class SMB2SetInfoResponse(Structure): """ References: diff --git a/lib/sambatools/smb/smb_constants.py b/lib/sambatools/python2/smb/smb_constants.py similarity index 100% rename from lib/sambatools/smb/smb_constants.py rename to lib/sambatools/python2/smb/smb_constants.py diff --git a/lib/sambatools/smb/smb_structs.py b/lib/sambatools/python2/smb/smb_structs.py similarity index 98% rename from lib/sambatools/smb/smb_structs.py rename to lib/sambatools/python2/smb/smb_structs.py index aa81ac9c..65ecac0f 100644 --- a/lib/sambatools/smb/smb_structs.py +++ b/lib/sambatools/python2/smb/smb_structs.py @@ -10,20 +10,17 @@ SUPPORT_EXTENDED_SECURITY = True # Set to True if you want to enable SMB2 protocol. SUPPORT_SMB2 = True -# Set to True if you want to enable SMB2.1 and above protocol. -SUPPORT_SMB2x = True - # Supported dialects -NT_LAN_MANAGER_DIALECT = 0 # 'NT LM 0.12' is always the first element in the dialect list and must always be included (MS-SMB 2.2.4.5.1) +DIALECTS = [ ] +for i, ( name, dialect ) in enumerate([ ( 'NT_LAN_MANAGER_DIALECT', 'NT LM 0.12' ), ]): + DIALECTS.append(dialect) + globals()[name] = i + +DIALECTS2 = [ ] +for i, ( name, dialect ) in enumerate([ ( 'SMB2_DIALECT', 'SMB 2.002' ) ]): + DIALECTS2.append(dialect) + globals()[name] = i + len(DIALECTS) -# Return the list of support SMB dialects based on the SUPPORT_x constants -def init_dialects_list(): - dialects = [ 'NT LM 0.12' ] - if SUPPORT_SMB2: - dialects.append('SMB 2.002') - if SUPPORT_SMB2x: - dialects.append('SMB 2.???') - return dialects class UnsupportedFeature(Exception): """ @@ -111,9 +108,8 @@ class SMBMessage: log = logging.getLogger('SMB.SMBMessage') protocol = 1 - def __init__(self, conn, payload = None): + def __init__(self, payload = None): self.reset() - self.conn = conn if payload: self.payload = payload self.payload.initMessage(self) @@ -294,7 +290,10 @@ class ComNegotiateRequest(Payload): def prepare(self, message): assert message.payload == self message.parameters_data = '' - message.data = ''.join(map(lambda s: '\x02'+s+'\x00', init_dialects_list())) + if SUPPORT_SMB2: + message.data = ''.join(map(lambda s: '\x02'+s+'\x00', DIALECTS + DIALECTS2)) + else: + message.data = ''.join(map(lambda s: '\x02'+s+'\x00', DIALECTS)) class ComNegotiateResponse(Payload): diff --git a/lib/sambatools/smb/utils/README.txt b/lib/sambatools/python2/smb/utils/README.txt similarity index 100% rename from lib/sambatools/smb/utils/README.txt rename to lib/sambatools/python2/smb/utils/README.txt diff --git a/lib/sambatools/smb/utils/U32.py b/lib/sambatools/python2/smb/utils/U32.py similarity index 100% rename from lib/sambatools/smb/utils/U32.py rename to lib/sambatools/python2/smb/utils/U32.py diff --git a/lib/sambatools/smb/utils/__init__.py b/lib/sambatools/python2/smb/utils/__init__.py similarity index 100% rename from lib/sambatools/smb/utils/__init__.py rename to lib/sambatools/python2/smb/utils/__init__.py diff --git a/lib/sambatools/smb/utils/md4.py b/lib/sambatools/python2/smb/utils/md4.py similarity index 100% rename from lib/sambatools/smb/utils/md4.py rename to lib/sambatools/python2/smb/utils/md4.py diff --git a/lib/sambatools/smb/utils/pyDes.py b/lib/sambatools/python2/smb/utils/pyDes.py similarity index 100% rename from lib/sambatools/smb/utils/pyDes.py rename to lib/sambatools/python2/smb/utils/pyDes.py diff --git a/lib/sambatools/python2/smb/utils/rc4.py b/lib/sambatools/python2/smb/utils/rc4.py new file mode 100644 index 00000000..490a2f00 --- /dev/null +++ b/lib/sambatools/python2/smb/utils/rc4.py @@ -0,0 +1,22 @@ + +def RC4_encrypt(key, data): + S = list(range(256)) + j = 0 + + key_len = len(key) + for i in list(range(256)): + j = (j + S[i] + ord(key[i % key_len])) % 256 + S[i], S[j] = S[j], S[i] + + j = 0 + y = 0 + out = [] + + for char in data: + j = (j + 1) % 256 + y = (y + S[j]) % 256 + S[j], S[y] = S[y], S[j] + + out.append(chr(ord(char) ^ S[(S[j] + S[y]) % 256])) + + return ''.join(out) diff --git a/lib/sambatools/smb/utils/sha256.py b/lib/sambatools/python2/smb/utils/sha256.py similarity index 99% rename from lib/sambatools/smb/utils/sha256.py rename to lib/sambatools/python2/smb/utils/sha256.py index a13d6bf3..6efc8de9 100644 --- a/lib/sambatools/smb/utils/sha256.py +++ b/lib/sambatools/python2/smb/utils/sha256.py @@ -1,4 +1,3 @@ -#!/usr/bin/python __author__ = 'Thomas Dixon' __license__ = 'MIT' diff --git a/lib/sambatools/python3/nmb/NetBIOS.py b/lib/sambatools/python3/nmb/NetBIOS.py new file mode 100644 index 00000000..3a39bae2 --- /dev/null +++ b/lib/sambatools/python3/nmb/NetBIOS.py @@ -0,0 +1,144 @@ + +import os, logging, random, socket, time, select +from .base import NBNS, NotConnectedError +from .nmb_constants import TYPE_CLIENT, TYPE_SERVER, TYPE_WORKSTATION + +class NetBIOS(NBNS): + + log = logging.getLogger('NMB.NetBIOS') + + def __init__(self, broadcast = True, listen_port = 0): + """ + Instantiate a NetBIOS instance, and creates a IPv4 UDP socket to listen/send NBNS packets. + + :param boolean broadcast: A boolean flag to indicate if we should setup the listening UDP port in broadcast mode + :param integer listen_port: Specifies the UDP port number to bind to for listening. If zero, OS will automatically select a free port number. + """ + self.broadcast = broadcast + self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + if self.broadcast: + self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + if listen_port: + self.sock.bind(( '', listen_port )) + + def close(self): + """ + Close the underlying and free resources. + + The NetBIOS instance should not be used to perform any operations after this method returns. + + :return: None + """ + self.sock.close() + self.sock = None + + def write(self, data, ip, port): + assert self.sock, 'Socket is already closed' + self.sock.sendto(data, ( ip, port )) + + def queryName(self, name, ip = '', port = 137, timeout = 30): + """ + Send a query on the network and hopes that if machine matching the *name* will reply with its IP address. + + :param string ip: If the NBNSProtocol instance was instianted with broadcast=True, then this parameter can be an empty string. We will leave it to the OS to determine an appropriate broadcast address. + If the NBNSProtocol instance was instianted with broadcast=False, then you should provide a target IP to send the query. + :param integer port: The NetBIOS-NS port (IANA standard defines this port to be 137). You should not touch this parameter unless you know what you are doing. + :param integer/float timeout: Number of seconds to wait for a reply, after which the method will return None + :return: A list of IP addresses in dotted notation (aaa.bbb.ccc.ddd). On timeout, returns None. + """ + assert self.sock, 'Socket is already closed' + + trn_id = random.randint(1, 0xFFFF) + data = self.prepareNameQuery(trn_id, name) + if self.broadcast and not ip: + ip = '' + elif not ip: + self.log.warning('queryName: ip parameter is empty. OS might not transmit this query to the network') + + self.write(data, ip, port) + + return self._pollForNetBIOSPacket(trn_id, timeout) + + def queryIPForName(self, ip, port = 137, timeout = 30): + """ + Send a query to the machine with *ip* and hopes that the machine will reply back with its name. + + The implementation of this function is contributed by Jason Anderson. + + :param string ip: If the NBNSProtocol instance was instianted with broadcast=True, then this parameter can be an empty string. We will leave it to the OS to determine an appropriate broadcast address. + If the NBNSProtocol instance was instianted with broadcast=False, then you should provide a target IP to send the query. + :param integer port: The NetBIOS-NS port (IANA standard defines this port to be 137). You should not touch this parameter unless you know what you are doing. + :param integer/float timeout: Number of seconds to wait for a reply, after which the method will return None + :return: A list of string containing the names of the machine at *ip*. On timeout, returns None. + """ + assert self.sock, 'Socket is already closed' + + trn_id = random.randint(1, 0xFFFF) + data = self.prepareNetNameQuery(trn_id, False) + self.write(data, ip, port) + ret = self._pollForQueryPacket(trn_id, timeout) + if ret: + return list(map(lambda s: s[0], filter(lambda s: s[1] == TYPE_SERVER, ret))) + else: + return None + + # + # Protected Methods + # + + def _pollForNetBIOSPacket(self, wait_trn_id, timeout): + end_time = time.time() - timeout + while True: + try: + _timeout = time.time()-end_time + if _timeout <= 0: + return None + + ready, _, _ = select.select([ self.sock.fileno() ], [ ], [ ], _timeout) + if not ready: + return None + + data, _ = self.sock.recvfrom(0xFFFF) + if len(data) == 0: + raise NotConnectedError + + trn_id, ret = self.decodePacket(data) + + if trn_id == wait_trn_id: + return ret + except select.error as ex: + if type(ex) is tuple: + if ex[0] != errno.EINTR and ex[0] != errno.EAGAIN: + raise ex + else: + raise ex + + # + # Contributed by Jason Anderson + # + def _pollForQueryPacket(self, wait_trn_id, timeout): + end_time = time.time() - timeout + while True: + try: + _timeout = time.time()-end_time + if _timeout <= 0: + return None + + ready, _, _ = select.select([ self.sock.fileno() ], [ ], [ ], _timeout) + if not ready: + return None + + data, _ = self.sock.recvfrom(0xFFFF) + if len(data) == 0: + raise NotConnectedError + + trn_id, ret = self.decodeIPQueryPacket(data) + + if trn_id == wait_trn_id: + return ret + except select.error as ex: + if type(ex) is tuple: + if ex[0] != errno.EINTR and ex[0] != errno.EAGAIN: + raise ex + else: + raise ex diff --git a/lib/sambatools/python3/nmb/NetBIOSProtocol.py b/lib/sambatools/python3/nmb/NetBIOSProtocol.py new file mode 100644 index 00000000..9e4bf866 --- /dev/null +++ b/lib/sambatools/python3/nmb/NetBIOSProtocol.py @@ -0,0 +1,134 @@ + +import os, logging, random, socket, time +from twisted.internet import reactor, defer +from twisted.internet.protocol import DatagramProtocol +from .base import NBNS + +class NetBIOSTimeout(Exception): + """Raised in NBNSProtocol via Deferred.errback method when queryName method has timeout waiting for reply""" + pass + +class NBNSProtocol(DatagramProtocol, NBNS): + + log = logging.getLogger('NMB.NBNSProtocol') + + def __init__(self, broadcast = True, listen_port = 0): + """ + Instantiate a NBNSProtocol instance. + + This automatically calls reactor.listenUDP method to start listening for incoming packets, so you **must not** call the listenUDP method again. + + :param boolean broadcast: A boolean flag to indicate if we should setup the listening UDP port in broadcast mode + :param integer listen_port: Specifies the UDP port number to bind to for listening. If zero, OS will automatically select a free port number. + """ + self.broadcast = broadcast + self.pending_trns = { } # TRN ID -> ( expiry_time, name, Deferred instance ) + self.transport = reactor.listenUDP(listen_port, self) + if self.broadcast: + self.transport.getHandle().setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + reactor.callLater(1, self.cleanupPendingTrns) + + def datagramReceived(self, data, from_info): + host, port = from_info + trn_id, ret = self.decodePacket(data) + + # pending transaction exists for trn_id - handle it and remove from queue + if trn_id in self.pending_trns: + _, ip, d = self.pending_trns.pop(trn_id) + if ip is NAME_QUERY: + # decode as query packet + trn_id, ret = self.decodeIPQueryPacket(data) + d.callback(ret) + + def write(self, data, ip, port): + # We don't use the transport.write method directly as it keeps raising DeprecationWarning for ip='' + self.transport.getHandle().sendto(data, ( ip, port )) + + def queryName(self, name, ip = '', port = 137, timeout = 30): + """ + Send a query on the network and hopes that if machine matching the *name* will reply with its IP address. + + :param string ip: If the NBNSProtocol instance was instianted with broadcast=True, then this parameter can be an empty string. We will leave it to the OS to determine an appropriate broadcast address. + If the NBNSProtocol instance was instianted with broadcast=False, then you should provide a target IP to send the query. + :param integer port: The NetBIOS-NS port (IANA standard defines this port to be 137). You should not touch this parameter unless you know what you are doing. + :param integer/float timeout: Number of seconds to wait for a reply, after which the returned Deferred instance will be called with a NetBIOSTimeout exception. + :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a list of IP addresses in dotted notation (aaa.bbb.ccc.ddd). + On timeout, the errback function will be called with a Failure instance wrapping around a NetBIOSTimeout exception + """ + trn_id = random.randint(1, 0xFFFF) + while True: + if trn_id not in self.pending_trns: + break + else: + trn_id = (trn_id + 1) & 0xFFFF + + data = self.prepareNameQuery(trn_id, name) + if self.broadcast and not ip: + ip = '' + elif not ip: + self.log.warning('queryName: ip parameter is empty. OS might not transmit this query to the network') + + self.write(data, ip, port) + + d = defer.Deferred() + self.pending_trns[trn_id] = ( time.time()+timeout, name, d ) + return d + + def queryIPForName(self, ip, port = 137, timeout = 30): + """ + Send a query to the machine with *ip* and hopes that the machine will reply back with its name. + + The implementation of this function is contributed by Jason Anderson. + + :param string ip: If the NBNSProtocol instance was instianted with broadcast=True, then this parameter can be an empty string. We will leave it to the OS to determine an appropriate broadcast address. + If the NBNSProtocol instance was instianted with broadcast=False, then you should provide a target IP to send the query. + :param integer port: The NetBIOS-NS port (IANA standard defines this port to be 137). You should not touch this parameter unless you know what you are doing. + :param integer/float timeout: Number of seconds to wait for a reply, after which the method will return None + :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a list of names of the machine at *ip*. + On timeout, the errback function will be called with a Failure instance wrapping around a NetBIOSTimeout exception + """ + trn_id = random.randint(1, 0xFFFF) + while True: + if trn_id not in self.pending_trns: + break + else: + trn_id = (trn_id + 1) & 0xFFFF + + data = self.prepareNetNameQuery(trn_id) + self.write(data, ip, port) + + d = defer.Deferred() + d2 = defer.Deferred() + d2.addErrback(d.errback) + + def stripCode(ret): + if ret is not None: # got valid response. Somehow the callback is also called when there is an error. + d.callback(map(lambda s: s[0], filter(lambda s: s[1] == TYPE_SERVER, ret))) + + d2.addCallback(stripCode) + self.pending_trns[trn_id] = ( time.time()+timeout, NAME_QUERY, d2 ) + return d + + def stopProtocol(self): + DatagramProtocol.stopProtocol(self) + + def cleanupPendingTrns(self): + now = time.time() + + # reply should have been received in the past + # info is tuple of ( expiry_time, name, d ) + expired = filter(lambda trn_id, info: info[0] < now, self.pending_trns.iteritems()) + + # remove expired items from dict + call errback + def expire_item(item): + trn_id, (expiry_time, name, d) = item + + del self.pending_trns[trn_id] + try: + d.errback(NetBIOSTimeout(name)) + except: pass + + map(expire_item, expired) + + if self.transport: + reactor.callLater(1, self.cleanupPendingTrns) diff --git a/lib/sambatools/python3/nmb/__init__.py b/lib/sambatools/python3/nmb/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lib/sambatools/python3/nmb/base.py b/lib/sambatools/python3/nmb/base.py new file mode 100644 index 00000000..f3e76517 --- /dev/null +++ b/lib/sambatools/python3/nmb/base.py @@ -0,0 +1,187 @@ + +import struct, logging, random +from .nmb_constants import * +from .nmb_structs import * +from .utils import encode_name + +class NMBSession: + + log = logging.getLogger('NMB.NMBSession') + + def __init__(self, my_name, remote_name, host_type = TYPE_SERVER, is_direct_tcp = False): + self.my_name = my_name.upper() + self.remote_name = remote_name.upper() + self.host_type = host_type + self.data_buf = b'' + + if is_direct_tcp: + self.data_nmb = DirectTCPSessionMessage() + self.sendNMBPacket = self._sendNMBPacket_DirectTCP + else: + self.data_nmb = NMBSessionMessage() + self.sendNMBPacket = self._sendNMBPacket_NetBIOS + + # + # Overridden Methods + # + + def write(self, data): + raise NotImplementedError + + def onNMBSessionMessage(self, flags, data): + pass + + def onNMBSessionOK(self): + pass + + def onNMBSessionFailed(self): + pass + + # + # Public Methods + # + + def feedData(self, data): + self.data_buf = self.data_buf + data + + offset = 0 + while True: + length = self.data_nmb.decode(self.data_buf, offset) + if length == 0: + break + elif length > 0: + offset += length + self._processNMBSessionPacket(self.data_nmb) + else: + raise NMBError + + if offset > 0: + self.data_buf = self.data_buf[offset:] + + def sendNMBMessage(self, data): + self.sendNMBPacket(SESSION_MESSAGE, data) + + def requestNMBSession(self): + my_name_encoded = encode_name(self.my_name, TYPE_WORKSTATION) + remote_name_encoded = encode_name(self.remote_name, self.host_type) + self.sendNMBPacket(SESSION_REQUEST, remote_name_encoded + my_name_encoded) + + # + # Protected Methods + # + + def _processNMBSessionPacket(self, packet): + if packet.type == SESSION_MESSAGE: + self.onNMBSessionMessage(packet.flags, packet.data) + elif packet.type == POSITIVE_SESSION_RESPONSE: + self.onNMBSessionOK() + elif packet.type == NEGATIVE_SESSION_RESPONSE: + self.onNMBSessionFailed() + elif packet.type == SESSION_KEEPALIVE: + # Discard keepalive packets - [RFC1002]: 5.2.2.1 + pass + else: + self.log.warning('Unrecognized NMB session type: 0x%02x', packet.type) + + def _sendNMBPacket_NetBIOS(self, packet_type, data): + length = len(data) + assert length <= 0x01FFFF + flags = 0 + if length > 0xFFFF: + flags |= 0x01 + length &= 0xFFFF + self.write(struct.pack('>BBH', packet_type, flags, length) + data) + + def _sendNMBPacket_DirectTCP(self, packet_type, data): + length = len(data) + assert length <= 0x00FFFFFF + self.write(struct.pack('>I', length) + data) + + +class NBNS: + + log = logging.getLogger('NMB.NBNS') + + HEADER_STRUCT_FORMAT = '>HHHHHH' + HEADER_STRUCT_SIZE = struct.calcsize(HEADER_STRUCT_FORMAT) + + def write(self, data, ip, port): + raise NotImplementedError + + def decodePacket(self, data): + if len(data) < self.HEADER_STRUCT_SIZE: + raise Exception + + trn_id, code, question_count, answer_count, authority_count, additional_count = \ + struct.unpack(self.HEADER_STRUCT_FORMAT, data[:self.HEADER_STRUCT_SIZE]) + + is_response = bool((code >> 15) & 0x01) + opcode = (code >> 11) & 0x0F + flags = (code >> 4) & 0x7F + rcode = code & 0x0F + + if opcode == 0x0000 and is_response: + name_len = data[self.HEADER_STRUCT_SIZE] + # Constant 2 for the padding bytes before/after the Name and constant 8 for the Type, + # Class and TTL fields in the Answer section after the Name: + offset = self.HEADER_STRUCT_SIZE + 2 + name_len + 8 + record_count = (struct.unpack('>H', data[offset:offset+2])[0]) // 6 + + offset += 4 # Constant 4 for the Data Length and Flags field + ret = [] + for i in range(0, record_count): + ret.append('%d.%d.%d.%d' % struct.unpack('4B', (data[offset:offset + 4]))) + offset += 6 + return trn_id, ret + else: + return trn_id, None + + def prepareNameQuery(self, trn_id, name, is_broadcast = True): + header = struct.pack(self.HEADER_STRUCT_FORMAT, + trn_id, (is_broadcast and 0x0110) or 0x0100, 1, 0, 0, 0) + payload = encode_name(name, 0x20) + b'\x00\x20\x00\x01' + + return header + payload + + # + # Contributed by Jason Anderson + # + def decodeIPQueryPacket(self, data): + if len(data) < self.HEADER_STRUCT_SIZE: + raise Exception + + trn_id, code, question_count, answer_count, authority_count, additional_count = struct.unpack(self.HEADER_STRUCT_FORMAT, data[:self.HEADER_STRUCT_SIZE]) + + is_response = bool((code >> 15) & 0x01) + opcode = (code >> 11) & 0x0F + flags = (code >> 4) & 0x7F + rcode = code & 0x0F + + try: + numnames = data[self.HEADER_STRUCT_SIZE + 44] + + if numnames > 0: + ret = [ ] + offset = self.HEADER_STRUCT_SIZE + 45 + + for i in range(0, numnames): + mynme = data[offset:offset + 15] + mynme = mynme.strip() + ret.append(( str(mynme, 'ascii'), data[offset+15] )) + offset += 18 + + return trn_id, ret + except IndexError: + pass + + return trn_id, None + + # + # Contributed by Jason Anderson + # + def prepareNetNameQuery(self, trn_id, is_broadcast = True): + header = struct.pack(self.HEADER_STRUCT_FORMAT, + trn_id, (is_broadcast and 0x0010) or 0x0000, 1, 0, 0, 0) + payload = encode_name('*', 0) + b'\x00\x21\x00\x01' + + return header + payload diff --git a/lib/sambatools/python3/nmb/nmb_constants.py b/lib/sambatools/python3/nmb/nmb_constants.py new file mode 100644 index 00000000..fcf6007a --- /dev/null +++ b/lib/sambatools/python3/nmb/nmb_constants.py @@ -0,0 +1,38 @@ + +# Default port for NetBIOS name service +NETBIOS_NS_PORT = 137 + +# Default port for NetBIOS session service +NETBIOS_SESSION_PORT = 139 + +# Owner Node Type Constants +NODE_B = 0x00 +NODE_P = 0x01 +NODE_M = 0x10 +NODE_RESERVED = 0x11 + +# Name Type Constants +TYPE_UNKNOWN = 0x01 +TYPE_WORKSTATION = 0x00 +TYPE_CLIENT = 0x03 +TYPE_SERVER = 0x20 +TYPE_DOMAIN_MASTER = 0x1B +TYPE_MASTER_BROWSER = 0x1D +TYPE_BROWSER = 0x1E + +TYPE_NAMES = { TYPE_UNKNOWN: 'Unknown', + TYPE_WORKSTATION: 'Workstation', + TYPE_CLIENT: 'Client', + TYPE_SERVER: 'Server', + TYPE_MASTER_BROWSER: 'Master Browser', + TYPE_BROWSER: 'Browser Server', + TYPE_DOMAIN_MASTER: 'Domain Master' + } + +# Values for Session Packet Type field in Session Packets +SESSION_MESSAGE = 0x00 +SESSION_REQUEST = 0x81 +POSITIVE_SESSION_RESPONSE = 0x82 +NEGATIVE_SESSION_RESPONSE = 0x83 +REGTARGET_SESSION_RESPONSE = 0x84 +SESSION_KEEPALIVE = 0x85 diff --git a/lib/sambatools/python3/nmb/nmb_structs.py b/lib/sambatools/python3/nmb/nmb_structs.py new file mode 100644 index 00000000..d1eb165e --- /dev/null +++ b/lib/sambatools/python3/nmb/nmb_structs.py @@ -0,0 +1,66 @@ + +import struct + +class NMBError(Exception): pass + +class NotConnectedError(NMBError): + """ + Raisd when the underlying NMB connection has been disconnected or not connected yet + """ + pass + +class NMBSessionMessage: + + HEADER_STRUCT_FORMAT = '>BBH' + HEADER_STRUCT_SIZE = struct.calcsize(HEADER_STRUCT_FORMAT) + + def __init__(self): + self.reset() + + def reset(self): + self.type = 0 + self.flags = 0 + self.data = '' + + def decode(self, data, offset): + data_len = len(data) + + if data_len < offset + self.HEADER_STRUCT_SIZE: + # Not enough data for decoding + return 0 + + self.reset() + self.type, self.flags, length = struct.unpack(self.HEADER_STRUCT_FORMAT, data[offset:offset+self.HEADER_STRUCT_SIZE]) + + if self.flags & 0x01: + length |= 0x010000 + + if data_len < offset + self.HEADER_STRUCT_SIZE + length: + return 0 + + self.data = data[offset+self.HEADER_STRUCT_SIZE:offset+self.HEADER_STRUCT_SIZE+length] + return self.HEADER_STRUCT_SIZE + length + +class DirectTCPSessionMessage(NMBSessionMessage): + + HEADER_STRUCT_FORMAT = '>I' + HEADER_STRUCT_SIZE = struct.calcsize(HEADER_STRUCT_FORMAT) + + def decode(self, data, offset): + data_len = len(data) + + if data_len < offset + self.HEADER_STRUCT_SIZE: + # Not enough data for decoding + return 0 + + self.reset() + length = struct.unpack(self.HEADER_STRUCT_FORMAT, data[offset:offset+self.HEADER_STRUCT_SIZE])[0] + + if length >> 24 != 0: + raise NMBError("Invalid protocol header for Direct TCP session message") + + if data_len < offset + self.HEADER_STRUCT_SIZE + length: + return 0 + + self.data = data[offset+self.HEADER_STRUCT_SIZE:offset+self.HEADER_STRUCT_SIZE+length] + return self.HEADER_STRUCT_SIZE + length diff --git a/lib/sambatools/python3/nmb/utils.py b/lib/sambatools/python3/nmb/utils.py new file mode 100644 index 00000000..c1c4ced1 --- /dev/null +++ b/lib/sambatools/python3/nmb/utils.py @@ -0,0 +1,50 @@ + +import string, re + + +def encode_name(name, type, scope = None): + """ + Perform first and second level encoding of name as specified in RFC 1001 (Section 4) + """ + if name == '*': + name = name + '\0' * 15 + elif len(name) > 15: + name = name[:15] + chr(type) + else: + name = name.ljust(15) + chr(type) + + def _do_first_level_encoding(m): + s = ord(m.group(0)) + return string.ascii_uppercase[s >> 4] + string.ascii_uppercase[s & 0x0f] + + encoded_name = chr(len(name) * 2) + re.sub('.', _do_first_level_encoding, name) + if scope: + encoded_scope = '' + for s in string.split(scope, '.'): + encoded_scope = encoded_scope + chr(len(s)) + s + return bytes(encoded_name + encoded_scope + '\0', 'ascii') + else: + return bytes(encoded_name + '\0', 'ascii') + + +def decode_name(name): + name_length = ord(name[0]) + assert name_length == 32 + + def _do_first_level_decoding(m): + s = m.group(0) + return chr(((ord(s[0]) - ord('A')) << 4) | (ord(s[1]) - ord('A'))) + + decoded_name = re.sub('..', _do_first_level_decoding, name[1:33]) + if name[33] == '\0': + return 34, decoded_name, '' + else: + decoded_domain = '' + offset = 34 + while 1: + domain_length = ord(name[offset]) + if domain_length == 0: + break + decoded_domain = '.' + name[offset:offset + domain_length] + offset = offset + domain_length + return offset + 1, decoded_name, decoded_domain diff --git a/lib/sambatools/python3/smb/SMBConnection.py b/lib/sambatools/python3/smb/SMBConnection.py new file mode 100644 index 00000000..dbfab3bd --- /dev/null +++ b/lib/sambatools/python3/smb/SMBConnection.py @@ -0,0 +1,637 @@ + +import os, logging, select, socket, types, struct, errno +from .smb_constants import * +from .smb_structs import * +from .base import SMB, NotConnectedError, NotReadyError, SMBTimeout + + +class SMBConnection(SMB): + + log = logging.getLogger('SMB.SMBConnection') + + #: SMB messages will never be signed regardless of remote server's configurations; access errors will occur if the remote server requires signing. + SIGN_NEVER = 0 + #: SMB messages will be signed when remote server supports signing but not requires signing. + SIGN_WHEN_SUPPORTED = 1 + #: SMB messages will only be signed when remote server requires signing. + SIGN_WHEN_REQUIRED = 2 + + def __init__(self, username, password, my_name, remote_name, domain = '', use_ntlm_v2 = True, sign_options = SIGN_WHEN_REQUIRED, is_direct_tcp = False): + """ + Create a new SMBConnection instance. + + *username* and *password* are the user credentials required to authenticate the underlying SMB connection with the remote server. + *password* can be a string or a callable returning a string. + File operations can only be proceeded after the connection has been authenticated successfully. + + Note that you need to call *connect* method to actually establish the SMB connection to the remote server and perform authentication. + + The default TCP port for most SMB/CIFS servers using NetBIOS over TCP/IP is 139. + Some newer server installations might also support Direct hosting of SMB over TCP/IP; for these servers, the default TCP port is 445. + + :param string my_name: The local NetBIOS machine name that will identify where this connection is originating from. + You can freely choose a name as long as it contains a maximum of 15 alphanumeric characters and does not contain spaces and any of ``\/:*?";|+`` + :param string remote_name: The NetBIOS machine name of the remote server. + On windows, you can find out the machine name by right-clicking on the "My Computer" and selecting "Properties". + This parameter must be the same as what has been configured on the remote server, or else the connection will be rejected. + :param string domain: The network domain. On windows, it is known as the workgroup. Usually, it is safe to leave this parameter as an empty string. + :param boolean use_ntlm_v2: Indicates whether pysmb should be NTLMv1 or NTLMv2 authentication algorithm for authentication. + The choice of NTLMv1 and NTLMv2 is configured on the remote server, and there is no mechanism to auto-detect which algorithm has been configured. + Hence, we can only "guess" or try both algorithms. + On Sambda, Windows Vista and Windows 7, NTLMv2 is enabled by default. On Windows XP, we can use NTLMv1 before NTLMv2. + :param int sign_options: Determines whether SMB messages will be signed. Default is *SIGN_WHEN_REQUIRED*. + If *SIGN_WHEN_REQUIRED* (value=2), SMB messages will only be signed when remote server requires signing. + If *SIGN_WHEN_SUPPORTED* (value=1), SMB messages will be signed when remote server supports signing but not requires signing. + If *SIGN_NEVER* (value=0), SMB messages will never be signed regardless of remote server's configurations; access errors will occur if the remote server requires signing. + :param boolean is_direct_tcp: Controls whether the NetBIOS over TCP/IP (is_direct_tcp=False) or the newer Direct hosting of SMB over TCP/IP (is_direct_tcp=True) will be used for the communication. + The default parameter is False which will use NetBIOS over TCP/IP for wider compatibility (TCP port: 139). + """ + SMB.__init__(self, username, password, my_name, remote_name, domain, use_ntlm_v2, sign_options, is_direct_tcp) + self.sock = None + self.auth_result = None + self.is_busy = False + self.is_direct_tcp = is_direct_tcp + + # + # SMB (and its superclass) Methods + # + + def onAuthOK(self): + self.auth_result = True + + def onAuthFailed(self): + self.auth_result = False + + def write(self, data): + assert self.sock + data_len = len(data) + total_sent = 0 + while total_sent < data_len: + sent = self.sock.send(data[total_sent:]) + if sent == 0: + raise NotConnectedError('Server disconnected') + total_sent = total_sent + sent + + # + # Support for "with" context + # + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + # + # Misc Properties + # + + @property + def isUsingSMB2(self): + """A convenient property to return True if the underlying SMB connection is using SMB2 protocol.""" + return self.is_using_smb2 + + + # + # Public Methods + # + + def connect(self, ip, port = 139, sock_family = socket.AF_INET, timeout = 60): + """ + Establish the SMB connection to the remote SMB/CIFS server. + + You must call this method before attempting any of the file operations with the remote server. + This method will block until the SMB connection has attempted at least one authentication. + + :return: A boolean value indicating the result of the authentication atttempt: True if authentication is successful; False, if otherwise. + """ + if self.sock: + self.sock.close() + + self.auth_result = None + self.sock = socket.socket(sock_family) + self.sock.settimeout(timeout) + self.sock.connect(( ip, port )) + + self.is_busy = True + try: + if not self.is_direct_tcp: + self.requestNMBSession() + else: + self.onNMBSessionOK() + while self.auth_result is None: + self._pollForNetBIOSPacket(timeout) + finally: + self.is_busy = False + + return self.auth_result + + def close(self): + """ + Terminate the SMB connection (if it has been started) and release any sources held by the underlying socket. + """ + if self.sock: + self.sock.close() + self.sock = None + + def listShares(self, timeout = 30): + """ + Retrieve a list of shared resources on remote server. + + :return: A list of :doc:`smb.base.SharedDevice` instances describing the shared resource + """ + if not self.sock: + raise NotConnectedError('Not connected to server') + + results = [ ] + + def cb(entries): + self.is_busy = False + results.extend(entries) + + def eb(failure): + self.is_busy = False + raise failure + + self.is_busy = True + try: + self._listShares(cb, eb, timeout) + while self.is_busy: + self._pollForNetBIOSPacket(timeout) + finally: + self.is_busy = False + + return results + + def listPath(self, service_name, path, + search = SMB_FILE_ATTRIBUTE_READONLY | SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_DIRECTORY | SMB_FILE_ATTRIBUTE_ARCHIVE | SMB_FILE_ATTRIBUTE_INCL_NORMAL, + pattern = '*', timeout = 30): + """ + Retrieve a directory listing of files/folders at *path* + + For simplicity, pysmb defines a "normal" file as a file entry that is not read-only, not hidden, not system, not archive and not a directory. + It ignores other attributes like compression, indexed, sparse, temporary and encryption. + + Note that the default search parameter will query for all read-only (SMB_FILE_ATTRIBUTE_READONLY), hidden (SMB_FILE_ATTRIBUTE_HIDDEN), + system (SMB_FILE_ATTRIBUTE_SYSTEM), archive (SMB_FILE_ATTRIBUTE_ARCHIVE), normal (SMB_FILE_ATTRIBUTE_INCL_NORMAL) files + and directories (SMB_FILE_ATTRIBUTE_DIRECTORY). + If you do not need to include "normal" files in the result, define your own search parameter without the SMB_FILE_ATTRIBUTE_INCL_NORMAL constant. + SMB_FILE_ATTRIBUTE_NORMAL should be used by itself and not be used with other bit constants. + + :param string/unicode service_name: the name of the shared folder for the *path* + :param string/unicode path: path relative to the *service_name* where we are interested to learn about its files/sub-folders. + :param integer search: integer value made up from a bitwise-OR of *SMB_FILE_ATTRIBUTE_xxx* bits (see smb_constants.py). + :param string/unicode pattern: the filter to apply to the results before returning to the client. + :return: A list of :doc:`smb.base.SharedFile` instances. + """ + if not self.sock: + raise NotConnectedError('Not connected to server') + + results = [ ] + + def cb(entries): + self.is_busy = False + results.extend(entries) + + def eb(failure): + self.is_busy = False + raise failure + + self.is_busy = True + try: + self._listPath(service_name, path, cb, eb, search = search, pattern = pattern, timeout = timeout) + while self.is_busy: + self._pollForNetBIOSPacket(timeout) + finally: + self.is_busy = False + + return results + + def listSnapshots(self, service_name, path, timeout = 30): + """ + Retrieve a list of available snapshots (shadow copies) for *path*. + + Note that snapshot features are only supported on Windows Vista Business, Enterprise and Ultimate, and on all Windows 7 editions. + + :param string/unicode service_name: the name of the shared folder for the *path* + :param string/unicode path: path relative to the *service_name* where we are interested in the list of available snapshots + :return: A list of python *datetime.DateTime* instances in GMT/UTC time zone + """ + if not self.sock: + raise NotConnectedError('Not connected to server') + + results = [ ] + + def cb(entries): + self.is_busy = False + results.extend(entries) + + def eb(failure): + self.is_busy = False + raise failure + + self.is_busy = True + try: + self._listSnapshots(service_name, path, cb, eb, timeout = timeout) + while self.is_busy: + self._pollForNetBIOSPacket(timeout) + finally: + self.is_busy = False + + return results + + def getAttributes(self, service_name, path, timeout = 30): + """ + Retrieve information about the file at *path* on the *service_name*. + + :param string/unicode service_name: the name of the shared folder for the *path* + :param string/unicode path: Path of the file on the remote server. If the file cannot be opened for reading, an :doc:`OperationFailure` will be raised. + :return: A :doc:`smb.base.SharedFile` instance containing the attributes of the file. + """ + if not self.sock: + raise NotConnectedError('Not connected to server') + + results = [ ] + + def cb(info): + self.is_busy = False + results.append(info) + + def eb(failure): + self.is_busy = False + raise failure + + self.is_busy = True + try: + self._getAttributes(service_name, path, cb, eb, timeout) + while self.is_busy: + self._pollForNetBIOSPacket(timeout) + finally: + self.is_busy = False + + return results[0] + + def getSecurity(self, service_name, path, timeout = 30): + """ + Retrieve the security descriptor of the file at *path* on the *service_name*. + + :param string/unicode service_name: the name of the shared folder for the *path* + :param string/unicode path: Path of the file on the remote server. If the file cannot be opened for reading, an :doc:`OperationFailure` will be raised. + :return: A :class:`smb.security_descriptors.SecurityDescriptor` instance containing the security information of the file. + """ + if not self.sock: + raise NotConnectedError('Not connected to server') + + results = [ ] + + def cb(info): + self.is_busy = False + results.append(info) + + def eb(failure): + self.is_busy = False + raise failure + + self.is_busy = True + try: + self._getSecurity(service_name, path, cb, eb, timeout) + while self.is_busy: + self._pollForNetBIOSPacket(timeout) + finally: + self.is_busy = False + + return results[0] + + def retrieveFile(self, service_name, path, file_obj, timeout = 30): + """ + Retrieve the contents of the file at *path* on the *service_name* and write these contents to the provided *file_obj*. + + Use *retrieveFileFromOffset()* method if you wish to specify the offset to read from the remote *path* and/or the number of bytes to write to the *file_obj*. + + :param string/unicode service_name: the name of the shared folder for the *path* + :param string/unicode path: Path of the file on the remote server. If the file cannot be opened for reading, an :doc:`OperationFailure` will be raised. + :param file_obj: A file-like object that has a *write* method. Data will be written continuously to *file_obj* until EOF is received from the remote service. In Python3, this file-like object must have a *write* method which accepts a bytes parameter. + :return: A 2-element tuple of ( file attributes of the file on server, number of bytes written to *file_obj* ). + The file attributes is an integer value made up from a bitwise-OR of *SMB_FILE_ATTRIBUTE_xxx* bits (see smb_constants.py) + """ + return self.retrieveFileFromOffset(service_name, path, file_obj, 0, -1, timeout) + + def retrieveFileFromOffset(self, service_name, path, file_obj, offset = 0, max_length = -1, timeout = 30): + """ + Retrieve the contents of the file at *path* on the *service_name* and write these contents to the provided *file_obj*. + + :param string/unicode service_name: the name of the shared folder for the *path* + :param string/unicode path: Path of the file on the remote server. If the file cannot be opened for reading, an :doc:`OperationFailure` will be raised. + :param file_obj: A file-like object that has a *write* method. Data will be written continuously to *file_obj* up to *max_length* number of bytes. In Python3, this file-like object must have a *write* method which accepts a bytes parameter. + :param integer/long offset: the offset in the remote *path* where the first byte will be read and written to *file_obj*. Must be either zero or a positive integer/long value. + :param integer/long max_length: maximum number of bytes to read from the remote *path* and write to the *file_obj*. Specify a negative value to read from *offset* to the EOF. + If zero, the method returns immediately after the file is opened successfully for reading. + :return: A 2-element tuple of ( file attributes of the file on server, number of bytes written to *file_obj* ). + The file attributes is an integer value made up from a bitwise-OR of *SMB_FILE_ATTRIBUTE_xxx* bits (see smb_constants.py) + """ + if not self.sock: + raise NotConnectedError('Not connected to server') + + results = [ ] + + def cb(r): + self.is_busy = False + results.append(r[1:]) + + def eb(failure): + self.is_busy = False + raise failure + + self.is_busy = True + try: + self._retrieveFileFromOffset(service_name, path, file_obj, cb, eb, offset, max_length, timeout = timeout) + while self.is_busy: + self._pollForNetBIOSPacket(timeout) + finally: + self.is_busy = False + + return results[0] + + def storeFile(self, service_name, path, file_obj, timeout = 30): + """ + Store the contents of the *file_obj* at *path* on the *service_name*. + If the file already exists on the remote server, it will be truncated and overwritten. + + :param string/unicode service_name: the name of the shared folder for the *path* + :param string/unicode path: Path of the file on the remote server. If the file at *path* does not exist, it will be created. Otherwise, it will be overwritten. + If the *path* refers to a folder or the file cannot be opened for writing, an :doc:`OperationFailure` will be raised. + :param file_obj: A file-like object that has a *read* method. Data will read continuously from *file_obj* until EOF. In Python3, this file-like object must have a *read* method which returns a bytes parameter. + :return: Number of bytes uploaded + """ + return self.storeFileFromOffset(service_name, path, file_obj, 0, True, timeout) + + def storeFileFromOffset(self, service_name, path, file_obj, offset = 0, truncate = False, timeout = 30): + """ + Store the contents of the *file_obj* at *path* on the *service_name*. + + :param string/unicode service_name: the name of the shared folder for the *path* + :param string/unicode path: Path of the file on the remote server. If the file at *path* does not exist, it will be created. + If the *path* refers to a folder or the file cannot be opened for writing, an :doc:`OperationFailure` will be raised. + :param file_obj: A file-like object that has a *read* method. Data will read continuously from *file_obj* until EOF. + :param offset: Long integer value which specifies the offset in the remote server to start writing. First byte of the file is 0. + :param truncate: Boolean value. If True and the file exists on the remote server, it will be truncated first before writing. Default is False. + :return: the file position where the next byte will be written. + """ + if not self.sock: + raise NotConnectedError('Not connected to server') + + results = [ ] + + def cb(r): + self.is_busy = False + results.append(r[1]) + + def eb(failure): + self.is_busy = False + raise failure + + self.is_busy = True + try: + self._storeFileFromOffset(service_name, path, file_obj, cb, eb, offset, truncate = truncate, timeout = timeout) + while self.is_busy: + self._pollForNetBIOSPacket(timeout) + finally: + self.is_busy = False + + return results[0] + + def deleteFiles(self, service_name, path_file_pattern, delete_matching_folders = False, timeout = 30): + """ + Delete one or more regular files. It supports the use of wildcards in file names, allowing for deletion of multiple files in a single request. + + If delete_matching_folders is True, immediate sub-folders that match the path_file_pattern will be deleted recursively. + + :param string/unicode service_name: Contains the name of the shared folder. + :param string/unicode path_file_pattern: The pathname of the file(s) to be deleted, relative to the service_name. + Wildcards may be used in th filename component of the path. + If your path/filename contains non-English characters, you must pass in an unicode string. + :return: None + """ + if not self.sock: + raise NotConnectedError('Not connected to server') + + def cb(r): + self.is_busy = False + + def eb(failure): + self.is_busy = False + raise failure + + self.is_busy = True + try: + self._deleteFiles(service_name, path_file_pattern, delete_matching_folders, cb, eb, timeout = timeout) + while self.is_busy: + self._pollForNetBIOSPacket(timeout) + finally: + self.is_busy = False + + def resetFileAttributes(self, service_name, path_file_pattern, file_attributes = ATTR_NORMAL, timeout = 30): + """ + Reset file attributes of one or more regular files or folders. + It supports the use of wildcards in file names, allowing for unlocking of multiple files/folders in a single request. + This function is very helpful when deleting files/folders that are read-only. + By default, it sets the ATTR_NORMAL flag, therefore clearing all other flags. + (See https://msdn.microsoft.com/en-us/library/cc232110.aspx for further information) + + Note: this function is currently only implemented for SMB2! + + :param string/unicode service_name: Contains the name of the shared folder. + :param string/unicode path_file_pattern: The pathname of the file(s) to be deleted, relative to the service_name. + Wildcards may be used in the filename component of the path. + If your path/filename contains non-English characters, you must pass in an unicode string. + :param int file_attributes: The desired file attributes to set. Defaults to `ATTR_NORMAL`. + :return: None + """ + if not self.sock: + raise NotConnectedError('Not connected to server') + + def cb(r): + self.is_busy = False + + def eb(failure): + self.is_busy = False + raise failure + + self.is_busy = True + try: + self._resetFileAttributes(service_name, path_file_pattern, cb, eb, file_attributes, timeout) + while self.is_busy: + self._pollForNetBIOSPacket(timeout) + finally: + self.is_busy = False + + def createDirectory(self, service_name, path, timeout = 30): + """ + Creates a new directory *path* on the *service_name*. + + :param string/unicode service_name: Contains the name of the shared folder. + :param string/unicode path: The path of the new folder (relative to) the shared folder. + If the path contains non-English characters, an unicode string must be used to pass in the path. + :return: None + """ + if not self.sock: + raise NotConnectedError('Not connected to server') + + def cb(r): + self.is_busy = False + + def eb(failure): + self.is_busy = False + raise failure + + self.is_busy = True + try: + self._createDirectory(service_name, path, cb, eb, timeout = timeout) + while self.is_busy: + self._pollForNetBIOSPacket(timeout) + finally: + self.is_busy = False + + def deleteDirectory(self, service_name, path, timeout = 30): + """ + Delete the empty folder at *path* on *service_name* + + :param string/unicode service_name: Contains the name of the shared folder. + :param string/unicode path: The path of the to-be-deleted folder (relative to) the shared folder. + If the path contains non-English characters, an unicode string must be used to pass in the path. + :return: None + """ + if not self.sock: + raise NotConnectedError('Not connected to server') + + def cb(r): + self.is_busy = False + + def eb(failure): + self.is_busy = False + raise failure + + self.is_busy = True + try: + self._deleteDirectory(service_name, path, cb, eb, timeout = timeout) + while self.is_busy: + self._pollForNetBIOSPacket(timeout) + finally: + self.is_busy = False + + def rename(self, service_name, old_path, new_path, timeout = 30): + """ + Rename a file or folder at *old_path* to *new_path* shared at *service_name*. Note that this method cannot be used to rename file/folder across different shared folders + + *old_path* and *new_path* are string/unicode referring to the old and new path of the renamed resources (relative to) the shared folder. + If the path contains non-English characters, an unicode string must be used to pass in the path. + + :param string/unicode service_name: Contains the name of the shared folder. + :return: None + """ + if not self.sock: + raise NotConnectedError('Not connected to server') + + def cb(r): + self.is_busy = False + + def eb(failure): + self.is_busy = False + raise failure + + self.is_busy = True + try: + self._rename(service_name, old_path, new_path, cb, eb) + while self.is_busy: + self._pollForNetBIOSPacket(timeout) + finally: + self.is_busy = False + + def echo(self, data, timeout = 10): + """ + Send an echo command containing *data* to the remote SMB/CIFS server. The remote SMB/CIFS will reply with the same *data*. + + :param bytes data: Data to send to the remote server. Must be a bytes object. + :return: The *data* parameter + """ + if not self.sock: + raise NotConnectedError('Not connected to server') + + results = [ ] + + def cb(r): + self.is_busy = False + results.append(r) + + def eb(failure): + self.is_busy = False + raise failure + + self.is_busy = True + try: + self._echo(data, cb, eb) + while self.is_busy: + self._pollForNetBIOSPacket(timeout) + finally: + self.is_busy = False + + return results[0] + + # + # Protected Methods + # + + def _pollForNetBIOSPacket(self, timeout): + expiry_time = time.time() + timeout + read_len = 4 + data = b'' + + while read_len > 0: + try: + if expiry_time < time.time(): + raise SMBTimeout + + ready, _, _ = select.select([ self.sock.fileno() ], [ ], [ ], timeout) + if not ready: + raise SMBTimeout + + d = self.sock.recv(read_len) + if len(d) == 0: + raise NotConnectedError + + data = data + d + read_len -= len(d) + except select.error as ex: + if isinstance(ex, tuple): + if ex[0] != errno.EINTR and ex[0] != errno.EAGAIN: + raise ex + else: + raise ex + + type, flags, length = struct.unpack('>BBH', data) + if flags & 0x01: + length = length | 0x10000 + + read_len = length + while read_len > 0: + try: + if expiry_time < time.time(): + raise SMBTimeout + + ready, _, _ = select.select([ self.sock.fileno() ], [ ], [ ], timeout) + if not ready: + raise SMBTimeout + + d = self.sock.recv(read_len) + if len(d) == 0: + raise NotConnectedError + + data = data + d + read_len -= len(d) + except select.error as ex: + if isinstance(ex, tuple): + if ex[0] != errno.EINTR and ex[0] != errno.EAGAIN: + raise ex + else: + raise ex + + self.feedData(data) diff --git a/lib/sambatools/python3/smb/SMBHandler.py b/lib/sambatools/python3/smb/SMBHandler.py new file mode 100644 index 00000000..0241a01a --- /dev/null +++ b/lib/sambatools/python3/smb/SMBHandler.py @@ -0,0 +1,96 @@ +import os, sys, socket, urllib.request, urllib.error, urllib.parse, mimetypes, email, tempfile +from urllib.parse import (unwrap, unquote, splittype, splithost, quote, + splitport, splittag, splitattr, splituser, splitpasswd, splitvalue) +from urllib.response import addinfourl +from urllib.request import ftpwrapper +from nmb.NetBIOS import NetBIOS +from smb.SMBConnection import SMBConnection + +from io import BytesIO + +USE_NTLM = True +MACHINE_NAME = None + +class SMBHandler(urllib.request.BaseHandler): + + def smb_open(self, req): + global USE_NTLM, MACHINE_NAME + + if not req.host: + raise urllib.error.URLError('SMB error: no host given') + host, port = splitport(req.host) + if port is None: + port = 139 + else: + port = int(port) + + # username/password handling + + user, host = splituser(host) + + if user: + user, passwd = splitpasswd(user) + else: + passwd = None + + host = unquote(host) + user = user or '' + + domain = '' + if ';' in user: + domain, user = user.split(';', 1) + + passwd = passwd or '' + myname = MACHINE_NAME or self.generateClientMachineName() + + server_name,host = host.split(',') if ',' in host else [None,host] + + if server_name is None: + n = NetBIOS() + + names = n.queryIPForName(host) + if names: + server_name = names[0] + else: + raise urllib.error.URLError('SMB error: Hostname does not reply back with its machine name') + + path, attrs = splitattr(req.selector) + if path.startswith('/'): + path = path[1:] + dirs = path.split('/') + dirs = list(map(unquote, dirs)) + service, path = dirs[0], '/'.join(dirs[1:]) + + try: + conn = SMBConnection(user, passwd, myname, server_name, domain=domain, use_ntlm_v2 = USE_NTLM) + conn.connect(host, port) + + headers = email.message.Message() + if req.data: + filelen = conn.storeFile(service, path, req.data) + + headers.add_header('Content-length', '0') + fp = BytesIO(b"") + else: + fp = self.createTempFile() + file_attrs, retrlen = conn.retrieveFile(service, path, fp) + fp.seek(0) + + mtype = mimetypes.guess_type(req.get_full_url())[0] + if mtype: + headers.add_header('Content-type', mtype) + if retrlen is not None and retrlen >= 0: + headers.add_header('Content-length', '%d' % retrlen) + + return addinfourl(fp, headers, req.get_full_url()) + except Exception as ex: + raise urllib.error.URLError('smb error: %s' % ex).with_traceback(sys.exc_info()[2]) + + def createTempFile(self): + return tempfile.TemporaryFile() + + def generateClientMachineName(self): + hostname = socket.gethostname() + if hostname: + return hostname.split('.')[0] + return 'SMB%d' % os.getpid() diff --git a/lib/sambatools/python3/smb/SMBProtocol.py b/lib/sambatools/python3/smb/SMBProtocol.py new file mode 100644 index 00000000..b76aa57d --- /dev/null +++ b/lib/sambatools/python3/smb/SMBProtocol.py @@ -0,0 +1,412 @@ + +import os, logging, time +from twisted.internet import reactor, defer +from twisted.internet.protocol import ClientFactory, Protocol +from .smb_constants import * +from .smb_structs import * +from .base import SMB, NotConnectedError, NotReadyError, SMBTimeout + + +__all__ = [ 'SMBProtocolFactory', 'NotConnectedError', 'NotReadyError' ] + + +class SMBProtocol(Protocol, SMB): + + log = logging.getLogger('SMB.SMBProtocol') + + # + # Protocol Methods + # + + def connectionMade(self): + self.factory.instance = self + if not self.is_direct_tcp: + self.requestNMBSession() + else: + self.onNMBSessionOK() + + + def connectionLost(self, reason): + if self.factory.instance == self: + self.instance = None + + def dataReceived(self, data): + self.feedData(data) + + # + # SMB (and its superclass) Methods + # + + def write(self, data): + self.transport.write(data) + + def onAuthOK(self): + if self.factory.instance == self: + self.factory.onAuthOK() + reactor.callLater(1, self._cleanupPendingRequests) + + def onAuthFailed(self): + if self.factory.instance == self: + self.factory.onAuthFailed() + + def onNMBSessionFailed(self): + self.log.error('Cannot establish NetBIOS session. You might have provided a wrong remote_name') + + # + # Protected Methods + # + + def _cleanupPendingRequests(self): + if self.factory.instance == self: + now = time.time() + to_remove = [] + for mid, r in self.pending_requests.items(): + if r.expiry_time < now: + try: + r.errback(SMBTimeout()) + except Exception: pass + to_remove.append(mid) + + for mid in to_remove: + del self.pending_requests[mid] + + reactor.callLater(1, self._cleanupPendingRequests) + + +class SMBProtocolFactory(ClientFactory): + + protocol = SMBProtocol + log = logging.getLogger('SMB.SMBFactory') + + #: SMB messages will never be signed regardless of remote server's configurations; access errors will occur if the remote server requires signing. + SIGN_NEVER = 0 + #: SMB messages will be signed when remote server supports signing but not requires signing. + SIGN_WHEN_SUPPORTED = 1 + #: SMB messages will only be signed when remote server requires signing. + SIGN_WHEN_REQUIRED = 2 + + def __init__(self, username, password, my_name, remote_name, domain = '', use_ntlm_v2 = True, sign_options = SIGN_WHEN_REQUIRED, is_direct_tcp = False): + """ + Create a new SMBProtocolFactory instance. You will pass this instance to *reactor.connectTCP()* which will then instantiate the TCP connection to the remote SMB/CIFS server. + Note that the default TCP port for most SMB/CIFS servers using NetBIOS over TCP/IP is 139. + Some newer server installations might also support Direct hosting of SMB over TCP/IP; for these servers, the default TCP port is 445. + + *username* and *password* are the user credentials required to authenticate the underlying SMB connection with the remote server. + File operations can only be proceeded after the connection has been authenticated successfully. + + :param string my_name: The local NetBIOS machine name that will identify where this connection is originating from. + You can freely choose a name as long as it contains a maximum of 15 alphanumeric characters and does not contain spaces and any of ``\/:*?";|+`` + :param string remote_name: The NetBIOS machine name of the remote server. + On windows, you can find out the machine name by right-clicking on the "My Computer" and selecting "Properties". + This parameter must be the same as what has been configured on the remote server, or else the connection will be rejected. + :param string domain: The network domain. On windows, it is known as the workgroup. Usually, it is safe to leave this parameter as an empty string. + :param boolean use_ntlm_v2: Indicates whether pysmb should be NTLMv1 or NTLMv2 authentication algorithm for authentication. + The choice of NTLMv1 and NTLMv2 is configured on the remote server, and there is no mechanism to auto-detect which algorithm has been configured. + Hence, we can only "guess" or try both algorithms. + On Sambda, Windows Vista and Windows 7, NTLMv2 is enabled by default. On Windows XP, we can use NTLMv1 before NTLMv2. + :param int sign_options: Determines whether SMB messages will be signed. Default is *SIGN_WHEN_REQUIRED*. + If *SIGN_WHEN_REQUIRED* (value=2), SMB messages will only be signed when remote server requires signing. + If *SIGN_WHEN_SUPPORTED* (value=1), SMB messages will be signed when remote server supports signing but not requires signing. + If *SIGN_NEVER* (value=0), SMB messages will never be signed regardless of remote server's configurations; access errors will occur if the remote server requires signing. + :param boolean is_direct_tcp: Controls whether the NetBIOS over TCP/IP (is_direct_tcp=False) or the newer Direct hosting of SMB over TCP/IP (is_direct_tcp=True) will be used for the communication. + The default parameter is False which will use NetBIOS over TCP/IP for wider compatibility (TCP port: 139). + """ + self.username = username + self.password = password + self.my_name = my_name + self.remote_name = remote_name + self.domain = domain + self.use_ntlm_v2 = use_ntlm_v2 + self.sign_options = sign_options + self.is_direct_tcp = is_direct_tcp + self.instance = None #: The single SMBProtocol instance for each SMBProtocolFactory instance. Usually, you should not need to touch this attribute directly. + + # + # Public Property + # + + @property + def isReady(self): + """A convenient property to return True if the underlying SMB connection has connected to remote server, has successfully authenticated itself and is ready for file operations.""" + return bool(self.instance and self.instance.has_authenticated) + + @property + def isUsingSMB2(self): + """A convenient property to return True if the underlying SMB connection is using SMB2 protocol.""" + return self.instance and self.instance.is_using_smb2 + + # + # Public Methods for Callbacks + # + + def onAuthOK(self): + """ + Override this method in your *SMBProtocolFactory* subclass to add in post-authentication handling. + This method will be called when the server has replied that the SMB connection has been successfully authenticated. + File operations can proceed when this method has been called. + """ + pass + + def onAuthFailed(self): + """ + Override this method in your *SMBProtocolFactory* subclass to add in post-authentication handling. + This method will be called when the server has replied that the SMB connection has been successfully authenticated. + + If you want to retry authenticating from this method, + 1. Disconnect the underlying SMB connection (call ``self.instance.transport.loseConnection()``) + 2. Create a new SMBProtocolFactory subclass instance with different user credientials or different NTLM algorithm flag. + 3. Call ``reactor.connectTCP`` with the new instance to re-establish the SMB connection + """ + pass + + # + # Public Methods + # + + def listShares(self, timeout = 30): + """ + Retrieve a list of shared resources on remote server. + + :param integer/float timeout: Number of seconds that pysmb will wait before raising *SMBTimeout* via the returned *Deferred* instance's *errback* method. + :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a list of :doc:`smb.base.SharedDevice` instances. + """ + if not self.instance: + raise NotConnectedError('Not connected to server') + + d = defer.Deferred() + self.instance._listShares(d.callback, d.errback, timeout) + return d + + def listPath(self, service_name, path, + search = SMB_FILE_ATTRIBUTE_READONLY | SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_DIRECTORY | SMB_FILE_ATTRIBUTE_ARCHIVE | SMB_FILE_ATTRIBUTE_INCL_NORMAL, + pattern = '*', timeout = 30): + """ + Retrieve a directory listing of files/folders at *path* + + For simplicity, pysmb defines a "normal" file as a file entry that is not read-only, not hidden, not system, not archive and not a directory. + It ignores other attributes like compression, indexed, sparse, temporary and encryption. + + Note that the default search parameter will query for all read-only (SMB_FILE_ATTRIBUTE_READONLY), hidden (SMB_FILE_ATTRIBUTE_HIDDEN), + system (SMB_FILE_ATTRIBUTE_SYSTEM), archive (SMB_FILE_ATTRIBUTE_ARCHIVE), normal (SMB_FILE_ATTRIBUTE_INCL_NORMAL) files + and directories (SMB_FILE_ATTRIBUTE_DIRECTORY). + If you do not need to include "normal" files in the result, define your own search parameter without the SMB_FILE_ATTRIBUTE_INCL_NORMAL constant. + SMB_FILE_ATTRIBUTE_NORMAL should be used by itself and not be used with other bit constants. + + :param string/unicode service_name: the name of the shared folder for the *path* + :param string/unicode path: path relative to the *service_name* where we are interested to learn about its files/sub-folders. + :param integer search: integer value made up from a bitwise-OR of *SMB_FILE_ATTRIBUTE_xxx* bits (see smb_constants.py). + :param string/unicode pattern: the filter to apply to the results before returning to the client. + :param integer/float timeout: Number of seconds that pysmb will wait before raising *SMBTimeout* via the returned *Deferred* instance's *errback* method. + :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a list of :doc:`smb.base.SharedFile` instances. + """ + if not self.instance: + raise NotConnectedError('Not connected to server') + + d = defer.Deferred() + self.instance._listPath(service_name, path, d.callback, d.errback, search = search, pattern = pattern, timeout = timeout) + return d + + def listSnapshots(self, service_name, path, timeout = 30): + """ + Retrieve a list of available snapshots (a.k.a. shadow copies) for *path*. + + Note that snapshot features are only supported on Windows Vista Business, Enterprise and Ultimate, and on all Windows 7 editions. + + :param string/unicode service_name: the name of the shared folder for the *path* + :param string/unicode path: path relative to the *service_name* where we are interested in the list of available snapshots + :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a list of python *datetime.DateTime* + instances in GMT/UTC time zone + """ + if not self.instance: + raise NotConnectedError('Not connected to server') + + d = defer.Deferred() + self.instance._listSnapshots(service_name, path, d.callback, d.errback, timeout = timeout) + return d + + def getAttributes(self, service_name, path, timeout = 30): + """ + Retrieve information about the file at *path* on the *service_name*. + + :param string/unicode service_name: the name of the shared folder for the *path* + :param string/unicode path: Path of the file on the remote server. If the file cannot be opened for reading, an :doc:`OperationFailure` will be raised. + :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a :doc:`smb.base.SharedFile` instance containing the attributes of the file. + """ + if not self.instance: + raise NotConnectedError('Not connected to server') + + d = defer.Deferred() + self.instance._getAttributes(service_name, path, d.callback, d.errback, timeout = timeout) + return d + + def retrieveFile(self, service_name, path, file_obj, timeout = 30): + """ + Retrieve the contents of the file at *path* on the *service_name* and write these contents to the provided *file_obj*. + + Use *retrieveFileFromOffset()* method if you need to specify the offset to read from the remote *path* and/or the maximum number of bytes to write to the *file_obj*. + + The meaning of the *timeout* parameter will be different from other file operation methods. As the downloaded file usually exceeeds the maximum size + of each SMB/CIFS data message, it will be packetized into a series of request messages (each message will request about about 60kBytes). + The *timeout* parameter is an integer/float value that specifies the timeout interval for these individual SMB/CIFS message to be transmitted and downloaded from the remote SMB/CIFS server. + + :param string/unicode service_name: the name of the shared folder for the *path* + :param string/unicode path: Path of the file on the remote server. If the file cannot be opened for reading, an :doc:`OperationFailure` will be called in the returned *Deferred* errback. + :param file_obj: A file-like object that has a *write* method. Data will be written continuously to *file_obj* until EOF is received from the remote service. In Python3, this file-like object must have a *write* method which accepts a bytes parameter. + :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a 3-element tuple of ( *file_obj*, file attributes of the file on server, number of bytes written to *file_obj* ). + The file attributes is an integer value made up from a bitwise-OR of *SMB_FILE_ATTRIBUTE_xxx* bits (see smb_constants.py) + """ + return self.retrieveFileFromOffset(service_name, path, file_obj, 0, -1, timeout) + + def retrieveFileFromOffset(self, service_name, path, file_obj, offset = 0, max_length = -1, timeout = 30): + """ + Retrieve the contents of the file at *path* on the *service_name* and write these contents to the provided *file_obj*. + + The meaning of the *timeout* parameter will be different from other file operation methods. As the downloaded file usually exceeeds the maximum size + of each SMB/CIFS data message, it will be packetized into a series of request messages (each message will request about about 60kBytes). + The *timeout* parameter is an integer/float value that specifies the timeout interval for these individual SMB/CIFS message to be transmitted and downloaded from the remote SMB/CIFS server. + + :param string/unicode service_name: the name of the shared folder for the *path* + :param string/unicode path: Path of the file on the remote server. If the file cannot be opened for reading, an :doc:`OperationFailure` will be called in the returned *Deferred* errback. + :param file_obj: A file-like object that has a *write* method. Data will be written continuously to *file_obj* until EOF is received from the remote service. In Python3, this file-like object must have a *write* method which accepts a bytes parameter. + :param integer/long offset: the offset in the remote *path* where the first byte will be read and written to *file_obj*. Must be either zero or a positive integer/long value. + :param integer/long max_length: maximum number of bytes to read from the remote *path* and write to the *file_obj*. Specify a negative value to read from *offset* to the EOF. + If zero, the *Deferred* callback is invoked immediately after the file is opened successfully for reading. + :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a 3-element tuple of ( *file_obj*, file attributes of the file on server, number of bytes written to *file_obj* ). + The file attributes is an integer value made up from a bitwise-OR of *SMB_FILE_ATTRIBUTE_xxx* bits (see smb_constants.py) + """ + if not self.instance: + raise NotConnectedError('Not connected to server') + + d = defer.Deferred() + self.instance._retrieveFileFromOffset(service_name, path, file_obj, d.callback, d.errback, offset, max_length, timeout = timeout) + return d + + def storeFile(self, service_name, path, file_obj, timeout = 30): + """ + Store the contents of the *file_obj* at *path* on the *service_name*. + + The meaning of the *timeout* parameter will be different from other file operation methods. As the uploaded file usually exceeeds the maximum size + of each SMB/CIFS data message, it will be packetized into a series of messages (usually about 60kBytes). + The *timeout* parameter is an integer/float value that specifies the timeout interval for these individual SMB/CIFS message to be transmitted and acknowledged + by the remote SMB/CIFS server. + + :param string/unicode service_name: the name of the shared folder for the *path* + :param string/unicode path: Path of the file on the remote server. If the file at *path* does not exist, it will be created. Otherwise, it will be overwritten. + If the *path* refers to a folder or the file cannot be opened for writing, an :doc:`OperationFailure` will be called in the returned *Deferred* errback. + :param file_obj: A file-like object that has a *read* method. Data will read continuously from *file_obj* until EOF. In Python3, this file-like object must have a *read* method which returns a bytes parameter. + :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a 2-element tuple of ( *file_obj*, number of bytes uploaded ). + """ + if not self.instance: + raise NotConnectedError('Not connected to server') + + d = defer.Deferred() + self.instance._storeFile(service_name, path, file_obj, d.callback, d.errback, timeout = timeout) + return d + + def deleteFiles(self, service_name, path_file_pattern, delete_matching_folders = False, timeout = 30): + """ + Delete one or more regular files. It supports the use of wildcards in file names, allowing for deletion of multiple files in a single request. + + If delete_matching_folders is True, immediate sub-folders that match the path_file_pattern will be deleted recursively. + + :param string/unicode service_name: Contains the name of the shared folder. + :param string/unicode path_file_pattern: The pathname of the file(s) to be deleted, relative to the service_name. + Wildcards may be used in th filename component of the path. + If your path/filename contains non-English characters, you must pass in an unicode string. + :param integer/float timeout: Number of seconds that pysmb will wait before raising *SMBTimeout* via the returned *Deferred* instance's *errback* method. + :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with the *path_file_pattern* parameter. + """ + if not self.instance: + raise NotConnectedError('Not connected to server') + + d = defer.Deferred() + self.instance._deleteFiles(service_name, path_file_pattern, delete_matching_folders, d.callback, d.errback, timeout = timeout) + return d + + def createDirectory(self, service_name, path): + """ + Creates a new directory *path* on the *service_name*. + + :param string/unicode service_name: Contains the name of the shared folder. + :param string/unicode path: The path of the new folder (relative to) the shared folder. + If the path contains non-English characters, an unicode string must be used to pass in the path. + :param integer/float timeout: Number of seconds that pysmb will wait before raising *SMBTimeout* via the returned *Deferred* instance's *errback* method. + :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with the *path* parameter. + """ + if not self.instance: + raise NotConnectedError('Not connected to server') + + d = defer.Deferred() + self.instance._createDirectory(service_name, path, d.callback, d.errback) + return d + + def deleteDirectory(self, service_name, path): + """ + Delete the empty folder at *path* on *service_name* + + :param string/unicode service_name: Contains the name of the shared folder. + :param string/unicode path: The path of the to-be-deleted folder (relative to) the shared folder. + If the path contains non-English characters, an unicode string must be used to pass in the path. + :param integer/float timeout: Number of seconds that pysmb will wait before raising *SMBTimeout* via the returned *Deferred* instance's *errback* method. + :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with the *path* parameter. + """ + if not self.instance: + raise NotConnectedError('Not connected to server') + + d = defer.Deferred() + self.instance._deleteDirectory(service_name, path, d.callback, d.errback) + return d + + def rename(self, service_name, old_path, new_path): + """ + Rename a file or folder at *old_path* to *new_path* shared at *service_name*. Note that this method cannot be used to rename file/folder across different shared folders + + *old_path* and *new_path* are string/unicode referring to the old and new path of the renamed resources (relative to) the shared folder. + If the path contains non-English characters, an unicode string must be used to pass in the path. + + :param string/unicode service_name: Contains the name of the shared folder. + :param integer/float timeout: Number of seconds that pysmb will wait before raising *SMBTimeout* via the returned *Deferred* instance's *errback* method. + :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with a 2-element tuple of ( *old_path*, *new_path* ). + """ + if not self.instance: + raise NotConnectedError('Not connected to server') + + d = defer.Deferred() + self.instance._rename(service_name, old_path, new_path, d.callback, d.errback) + return d + + def echo(self, data, timeout = 10): + """ + Send an echo command containing *data* to the remote SMB/CIFS server. The remote SMB/CIFS will reply with the same *data*. + + :param bytes data: Data to send to the remote server. Must be a bytes object. + :param integer/float timeout: Number of seconds that pysmb will wait before raising *SMBTimeout* via the returned *Deferred* instance's *errback* method. + :return: A *twisted.internet.defer.Deferred* instance. The callback function will be called with the *data* parameter. + """ + if not self.instance: + raise NotConnectedError('Not connected to server') + + d = defer.Deferred() + self.instance._echo(data, d.callback, d.errback, timeout) + return d + + def closeConnection(self): + """ + Disconnect from the remote SMB/CIFS server. The TCP connection will be closed at the earliest opportunity after this method returns. + + :return: None + """ + if not self.instance: + raise NotConnectedError('Not connected to server') + + self.instance.transport.loseConnection() + + # + # ClientFactory methods + # (Do not touch these unless you know what you are doing) + # + + def buildProtocol(self, addr): + p = self.protocol(self.username, self.password, self.my_name, self.remote_name, self.domain, self.use_ntlm_v2, self.sign_options, self.is_direct_tcp) + p.factory = self + return p diff --git a/lib/sambatools/python3/smb/__init__.py b/lib/sambatools/python3/smb/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/lib/sambatools/python3/smb/__init__.py @@ -0,0 +1 @@ + diff --git a/lib/sambatools/python3/smb/base.py b/lib/sambatools/python3/smb/base.py new file mode 100644 index 00000000..f88632f2 --- /dev/null +++ b/lib/sambatools/python3/smb/base.py @@ -0,0 +1,3040 @@ + +import logging, binascii, time, hmac +from datetime import datetime +from .smb_constants import * +from .smb2_constants import * +from .smb_structs import * +from .smb2_structs import * +from .security_descriptors import SecurityDescriptor +from nmb.base import NMBSession +from .utils import convertFILETIMEtoEpoch +from . import ntlm, securityblob + +try: + import hashlib + sha256 = hashlib.sha256 +except ImportError: + from .utils import sha256 + + +class NotReadyError(Exception): + """Raised when SMB connection is not ready (i.e. not authenticated or authentication failed)""" + pass + +class NotConnectedError(Exception): + """Raised when underlying SMB connection has been disconnected or not connected yet""" + pass + +class SMBTimeout(Exception): + """Raised when a timeout has occurred while waiting for a response or for a SMB/CIFS operation to complete.""" + pass + + +class SMB(NMBSession): + """ + This class represents a "connection" to the remote SMB/CIFS server. + It is not meant to be used directly in an application as it does not have any network transport implementations. + + For application use, please refer to + - L{SMBProtocol.SMBProtocolFactory} if you are using Twisted framework + + In [MS-CIFS], this class will contain attributes of Client, Client.Connection and Client.Session abstract data models. + + References: + =========== + - [MS-CIFS]: 3.2.1 + """ + + log = logging.getLogger('SMB.SMB') + + SIGN_NEVER = 0 + SIGN_WHEN_SUPPORTED = 1 + SIGN_WHEN_REQUIRED = 2 + + def __init__(self, username, password, my_name, remote_name, domain = '', use_ntlm_v2 = True, sign_options = SIGN_WHEN_REQUIRED, is_direct_tcp = False): + NMBSession.__init__(self, my_name, remote_name, is_direct_tcp = is_direct_tcp) + self.username = username + self._password = password + self.domain = domain + self.sign_options = sign_options + self.is_direct_tcp = is_direct_tcp + self.use_ntlm_v2 = use_ntlm_v2 #: Similar to LMAuthenticationPolicy and NTAuthenticationPolicy as described in [MS-CIFS] 3.2.1.1 + self.smb_message = SMBMessage() + self.is_using_smb2 = False #: Are we communicating using SMB2 protocol? self.smb_message will be a SMB2Message instance if this flag is True + self.async_requests = { } #: AsyncID mapped to _PendingRequest instance + self.pending_requests = { } #: MID mapped to _PendingRequest instance + self.connected_trees = { } #: Share name mapped to TID + self.next_rpc_call_id = 1 #: Next RPC callID value. Not used directly in SMB message. Usually encapsulated in sub-commands under SMB_COM_TRANSACTION or SMB_COM_TRANSACTION2 messages + + self.has_negotiated = False + self.has_authenticated = False + self.is_signing_active = False #: True if the remote server accepts message signing. All outgoing messages will be signed. Simiar to IsSigningActive as described in [MS-CIFS] 3.2.1.2 + self.signing_session_key = None #: Session key for signing packets, if signing is active. Similar to SigningSessionKey as described in [MS-CIFS] 3.2.1.2 + self.signing_challenge_response = None #: Contains the challenge response for signing, if signing is active. Similar to SigningChallengeResponse as described in [MS-CIFS] 3.2.1.2 + self.mid = 0 + self.uid = 0 + self.next_signing_id = 2 #: Similar to ClientNextSendSequenceNumber as described in [MS-CIFS] 3.2.1.2 + + # SMB1 and SMB2 attributes + # Note that the interpretations of the values may differ between SMB1 and SMB2 protocols + self.capabilities = 0 + self.security_mode = 0 #: Initialized from the SecurityMode field of the SMB_COM_NEGOTIATE message + + # SMB1 attributes + # Most of the following attributes will be initialized upon receipt of SMB_COM_NEGOTIATE message from server (via self._updateServerInfo_SMB1 method) + self.use_plaintext_authentication = False #: Similar to PlaintextAuthenticationPolicy in in [MS-CIFS] 3.2.1.1 + self.max_raw_size = 0 + self.max_buffer_size = 0 #: Similar to MaxBufferSize as described in [MS-CIFS] 3.2.1.1 + self.max_mpx_count = 0 #: Similar to MaxMpxCount as described in [MS-CIFS] 3.2.1.1 + + # SMB2 attributes + self.max_read_size = 0 #: Similar to MaxReadSize as described in [MS-SMB2] 2.2.4 + self.max_write_size = 0 #: Similar to MaxWriteSize as described in [MS-SMB2] 2.2.4 + self.max_transact_size = 0 #: Similar to MaxTransactSize as described in [MS-SMB2] 2.2.4 + self.session_id = 0 #: Similar to SessionID as described in [MS-SMB2] 2.2.4. This will be set in _updateState_SMB2 method + + self._setupSMB1Methods() + + self.log.info('Authentication with remote machine "%s" for user "%s" will be using NTLM %s authentication (%s extended security)', + self.remote_name, self.username, + (self.use_ntlm_v2 and 'v2') or 'v1', + (SUPPORT_EXTENDED_SECURITY and 'with') or 'without') + + @property + def password(self): + if callable(self._password): + return self._password() + return self._password + + # + # NMBSession Methods + # + + def onNMBSessionOK(self): + self._sendSMBMessage(SMBMessage(ComNegotiateRequest())) + + def onNMBSessionFailed(self): + pass + + def onNMBSessionMessage(self, flags, data): + while True: + try: + i = self.smb_message.decode(data) + except SMB2ProtocolHeaderError: + self.log.info('Now switching over to SMB2 protocol communication') + self.is_using_smb2 = True + self.mid = 0 # Must reset messageID counter, or else remote SMB2 server will disconnect + self._setupSMB2Methods() + self.smb_message = self._klassSMBMessage() + i = self.smb_message.decode(data) + + next_message_offset = 0 + if self.is_using_smb2: + next_message_offset = self.smb_message.next_command_offset + + if i > 0: + if not self.is_using_smb2: + self.log.debug('Received SMB message "%s" (command:0x%2X flags:0x%02X flags2:0x%04X TID:%d UID:%d)', + SMB_COMMAND_NAMES.get(self.smb_message.command, ''), + self.smb_message.command, self.smb_message.flags, self.smb_message.flags2, self.smb_message.tid, self.smb_message.uid) + else: + self.log.debug('Received SMB2 message "%s" (command:0x%04X flags:0x%04x)', + SMB2_COMMAND_NAMES.get(self.smb_message.command, ''), + self.smb_message.command, self.smb_message.flags) + if self._updateState(self.smb_message): + # We need to create a new instance instead of calling reset() because the instance could be captured in the message history. + self.smb_message = self._klassSMBMessage() + + if next_message_offset > 0: + data = data[next_message_offset:] + else: + break + + # + # Public Methods for Overriding in Subclasses + # + + def onAuthOK(self): + pass + + def onAuthFailed(self): + pass + + # + # Protected Methods + # + + def _setupSMB1Methods(self): + self._klassSMBMessage = SMBMessage + self._updateState = self._updateState_SMB1 + self._updateServerInfo = self._updateServerInfo_SMB1 + self._handleNegotiateResponse = self._handleNegotiateResponse_SMB1 + self._sendSMBMessage = self._sendSMBMessage_SMB1 + self._handleSessionChallenge = self._handleSessionChallenge_SMB1 + self._listShares = self._listShares_SMB1 + self._listPath = self._listPath_SMB1 + self._listSnapshots = self._listSnapshots_SMB1 + self._getSecurity = self._getSecurity_SMB1 + self._getAttributes = self._getAttributes_SMB1 + self._retrieveFile = self._retrieveFile_SMB1 + self._retrieveFileFromOffset = self._retrieveFileFromOffset_SMB1 + self._storeFile = self._storeFile_SMB1 + self._storeFileFromOffset = self._storeFileFromOffset_SMB1 + self._deleteFiles = self._deleteFiles_SMB1 + self._resetFileAttributes = self._resetFileAttributes_SMB1 + self._createDirectory = self._createDirectory_SMB1 + self._deleteDirectory = self._deleteDirectory_SMB1 + self._rename = self._rename_SMB1 + self._echo = self._echo_SMB1 + + def _setupSMB2Methods(self): + self._klassSMBMessage = SMB2Message + self._updateState = self._updateState_SMB2 + self._updateServerInfo = self._updateServerInfo_SMB2 + self._handleNegotiateResponse = self._handleNegotiateResponse_SMB2 + self._sendSMBMessage = self._sendSMBMessage_SMB2 + self._handleSessionChallenge = self._handleSessionChallenge_SMB2 + self._listShares = self._listShares_SMB2 + self._listPath = self._listPath_SMB2 + self._listSnapshots = self._listSnapshots_SMB2 + self._getSecurity = self._getSecurity_SMB2 + self._getAttributes = self._getAttributes_SMB2 + self._retrieveFile = self._retrieveFile_SMB2 + self._retrieveFileFromOffset = self._retrieveFileFromOffset_SMB2 + self._storeFile = self._storeFile_SMB2 + self._storeFileFromOffset = self._storeFileFromOffset_SMB2 + self._deleteFiles = self._deleteFiles_SMB2 + self._resetFileAttributes = self._resetFileAttributes_SMB2 + self._createDirectory = self._createDirectory_SMB2 + self._deleteDirectory = self._deleteDirectory_SMB2 + self._rename = self._rename_SMB2 + self._echo = self._echo_SMB2 + + def _getNextRPCCallID(self): + self.next_rpc_call_id += 1 + return self.next_rpc_call_id + + # + # SMB2 Methods Family + # + + def _sendSMBMessage_SMB2(self, smb_message): + if smb_message.mid == 0: + smb_message.mid = self._getNextMID_SMB2() + + if smb_message.command != SMB2_COM_NEGOTIATE: + smb_message.session_id = self.session_id + + if self.is_signing_active: + smb_message.flags |= SMB2_FLAGS_SIGNED + raw_data = smb_message.encode() + smb_message.signature = hmac.new(self.signing_session_key, raw_data, sha256).digest()[:16] + + smb_message.raw_data = smb_message.encode() + self.log.debug('MID is %d. Signature is %s. Total raw message is %d bytes', smb_message.mid, binascii.hexlify(smb_message.signature), len(smb_message.raw_data)) + else: + smb_message.raw_data = smb_message.encode() + self.sendNMBMessage(smb_message.raw_data) + + def _getNextMID_SMB2(self): + self.mid += 1 + return self.mid + + def _updateState_SMB2(self, message): + if message.isReply: + if message.command == SMB2_COM_NEGOTIATE: + if message.status == 0: + self.has_negotiated = True + self.log.info('SMB2 dialect negotiation successful') + self._updateServerInfo(message.payload) + self._handleNegotiateResponse(message) + else: + raise ProtocolError('Unknown status value (0x%08X) in SMB2_COM_NEGOTIATE' % message.status, + message.raw_data, message) + elif message.command == SMB2_COM_SESSION_SETUP: + if message.status == 0: + self.session_id = message.session_id + try: + result = securityblob.decodeAuthResponseSecurityBlob(message.payload.security_blob) + if result == securityblob.RESULT_ACCEPT_COMPLETED: + self.has_authenticated = True + self.log.info('Authentication (on SMB2) successful!') + + # [MS-SMB2]: 3.2.5.3.1 + # If the security subsystem indicates that the session was established by an anonymous user, + # Session.SigningRequired MUST be set to FALSE. + # If the SMB2_SESSION_FLAG_IS_GUEST bit is set in the SessionFlags field of the + # SMB2 SESSION_SETUP Response and if Session.SigningRequired is TRUE, this indicates a SESSION_SETUP + # failure and the connection MUST be terminated. If the SMB2_SESSION_FLAG_IS_GUEST bit is set in the SessionFlags + # field of the SMB2 SESSION_SETUP Response and if RequireMessageSigning is FALSE, Session.SigningRequired + # MUST be set to FALSE. + if message.payload.isGuestSession or message.payload.isAnonymousSession: + self.is_signing_active = False + self.log.info('Signing disabled because session is guest/anonymous') + + self.onAuthOK() + else: + raise ProtocolError('SMB2_COM_SESSION_SETUP status is 0 but security blob negResult value is %d' % result, message.raw_data, message) + except securityblob.BadSecurityBlobError as ex: + raise ProtocolError(str(ex), message.raw_data, message) + elif message.status == 0xc0000016: # STATUS_MORE_PROCESSING_REQUIRED + self.session_id = message.session_id + try: + result, ntlm_token = securityblob.decodeChallengeSecurityBlob(message.payload.security_blob) + if result == securityblob.RESULT_ACCEPT_INCOMPLETE: + self._handleSessionChallenge(message, ntlm_token) + except ( securityblob.BadSecurityBlobError, securityblob.UnsupportedSecurityProvider ) as ex: + raise ProtocolError(str(ex), message.raw_data, message) + elif (message.status == 0xc000006d # STATUS_LOGON_FAILURE + or message.status == 0xc0000064 # STATUS_NO_SUCH_USER + or message.status == 0xc000006a):# STATUS_WRONG_PASSWORD + self.has_authenticated = False + self.log.info('Authentication (on SMB2) failed. Please check username and password.') + self.onAuthFailed() + elif (message.status == 0xc0000193 # STATUS_ACCOUNT_EXPIRED + or message.status == 0xC0000071): # STATUS_PASSWORD_EXPIRED + self.has_authenticated = False + self.log.info('Authentication (on SMB2) failed. Account or password has expired.') + self.onAuthFailed() + elif message.status == 0xc0000234: # STATUS_ACCOUNT_LOCKED_OUT + self.has_authenticated = False + self.log.info('Authentication (on SMB2) failed. Account has been locked due to too many invalid logon attempts.') + self.onAuthFailed() + elif message.status == 0xc0000072: # STATUS_ACCOUNT_DISABLED + self.has_authenticated = False + self.log.info('Authentication (on SMB2) failed. Account has been disabled.') + self.onAuthFailed() + elif (message.status == 0xc000006f # STATUS_INVALID_LOGON_HOURS + or message.status == 0xc000015b # STATUS_LOGON_TYPE_NOT_GRANTED + or message.status == 0xc0000070): # STATUS_INVALID_WORKSTATION + self.has_authenticated = False + self.log.info('Authentication (on SMB2) failed. Not allowed.') + self.onAuthFailed() + elif message.status == 0xc000018c: # STATUS_TRUSTED_DOMAIN_FAILURE + self.has_authenticated = False + self.log.info('Authentication (on SMB2) failed. Domain not trusted.') + self.onAuthFailed() + elif message.status == 0xc000018d: # STATUS_TRUSTED_RELATIONSHIP_FAILURE + self.has_authenticated = False + self.log.info('Authentication (on SMB2) failed. Workstation not trusted.') + self.onAuthFailed() + else: + raise ProtocolError('Unknown status value (0x%08X) in SMB_COM_SESSION_SETUP_ANDX (with extended security)' % message.status, + message.raw_data, message) + + if message.isAsync: + if message.status == 0x00000103: # STATUS_PENDING + req = self.pending_requests.pop(message.mid, None) + if req: + self.async_requests[message.async_id] = req + else: # All other status including SUCCESS + req = self.async_requests.pop(message.async_id, None) + if req: + req.callback(message, **req.kwargs) + return True + else: + req = self.pending_requests.pop(message.mid, None) + if req: + req.callback(message, **req.kwargs) + return True + + + def _updateServerInfo_SMB2(self, payload): + self.capabilities = payload.capabilities + self.security_mode = payload.security_mode + self.max_transact_size = payload.max_transact_size + self.max_read_size = payload.max_read_size + self.max_write_size = payload.max_write_size + self.use_plaintext_authentication = False # SMB2 never allows plaintext authentication + + + def _handleNegotiateResponse_SMB2(self, message): + ntlm_data = ntlm.generateNegotiateMessage() + blob = securityblob.generateNegotiateSecurityBlob(ntlm_data) + self._sendSMBMessage(SMB2Message(SMB2SessionSetupRequest(blob))) + + + def _handleSessionChallenge_SMB2(self, message, ntlm_token): + server_challenge, server_flags, server_info = ntlm.decodeChallengeMessage(ntlm_token) + + self.log.info('Performing NTLMv2 authentication (on SMB2) with server challenge "%s"', binascii.hexlify(server_challenge)) + + if self.use_ntlm_v2: + self.log.info('Performing NTLMv2 authentication (on SMB2) with server challenge "%s"', binascii.hexlify(server_challenge)) + nt_challenge_response, lm_challenge_response, session_key = ntlm.generateChallengeResponseV2(self.password, + self.username, + server_challenge, + server_info, + self.domain) + + else: + self.log.info('Performing NTLMv1 authentication (on SMB2) with server challenge "%s"', binascii.hexlify(server_challenge)) + nt_challenge_response, lm_challenge_response, session_key = ntlm.generateChallengeResponseV1(self.password, server_challenge, True) + + ntlm_data, session_signing_key = ntlm.generateAuthenticateMessage(server_flags, + nt_challenge_response, + lm_challenge_response, + session_key, + self.username, + self.domain, + self.my_name) + + if self.log.isEnabledFor(logging.DEBUG): + self.log.debug('NT challenge response is "%s" (%d bytes)', binascii.hexlify(nt_challenge_response), len(nt_challenge_response)) + self.log.debug('LM challenge response is "%s" (%d bytes)', binascii.hexlify(lm_challenge_response), len(lm_challenge_response)) + + blob = securityblob.generateAuthSecurityBlob(ntlm_data) + self._sendSMBMessage(SMB2Message(SMB2SessionSetupRequest(blob))) + + if self.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED: + self.log.info('Server requires all SMB messages to be signed') + self.is_signing_active = (self.sign_options != SMB.SIGN_NEVER) + elif self.security_mode & SMB2_NEGOTIATE_SIGNING_ENABLED: + self.log.info('Server supports SMB signing') + self.is_signing_active = (self.sign_options == SMB.SIGN_WHEN_SUPPORTED) + else: + self.is_signing_active = False + + if self.is_signing_active: + self.log.info("SMB signing activated. All SMB messages will be signed.") + self.signing_session_key = session_signing_key + if self.log.isEnabledFor(logging.DEBUG): + self.log.info("SMB signing key is %s", binascii.hexlify(self.signing_session_key)) + + if self.capabilities & CAP_EXTENDED_SECURITY: + self.signing_challenge_response = None + else: + self.signing_challenge_response = blob + else: + self.log.info("SMB signing deactivated. SMB messages will NOT be signed.") + + + def _listShares_SMB2(self, callback, errback, timeout = 30): + if not self.has_authenticated: + raise NotReadyError('SMB connection not authenticated') + + expiry_time = time.time() + timeout + path = 'IPC$' + messages_history = [ ] + + def connectSrvSvc(tid): + m = SMB2Message(SMB2CreateRequest('srvsvc', + file_attributes = 0, + access_mask = FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_READ_EA | FILE_WRITE_EA | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, + share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + oplock = SMB2_OPLOCK_LEVEL_NONE, + impersonation = SEC_IMPERSONATE, + create_options = FILE_NON_DIRECTORY_FILE | FILE_OPEN_NO_RECALL, + create_disp = FILE_OPEN)) + + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectSrvSvcCB, errback, tid = tid) + messages_history.append(m) + + def connectSrvSvcCB(create_message, **kwargs): + messages_history.append(create_message) + if create_message.status == 0: + call_id = self._getNextRPCCallID() + # The data_bytes are binding call to Server Service RPC using DCE v1.1 RPC over SMB. See [MS-SRVS] and [C706] + # If you wish to understand the meanings of the byte stream, I would suggest you use a recent version of WireShark to packet capture the stream + data_bytes = \ + binascii.unhexlify(b"""05 00 0b 03 10 00 00 00 74 00 00 00""".replace(b' ', b'')) + \ + struct.pack(' data_length: + return data_bytes[offset:] + + next_offset, _, \ + create_time, last_access_time, last_write_time, last_attr_change_time, \ + file_size, alloc_size, file_attributes, filename_length, ea_size, \ + short_name_length, _, short_name, _, file_id = struct.unpack(info_format, data_bytes[offset:offset+info_size]) + + offset2 = offset + info_size + if offset2 + filename_length > data_length: + return data_bytes[offset:] + + filename = data_bytes[offset2:offset2+filename_length].decode('UTF-16LE') + short_name = short_name[:short_name_length].decode('UTF-16LE') + + accept_result = False + if (file_attributes & 0xff) in ( 0x00, ATTR_NORMAL ): # Only the first 8-bits are compared. We ignore other bits like temp, compressed, encryption, sparse, indexed, etc + accept_result = (search == SMB_FILE_ATTRIBUTE_NORMAL) or (search & SMB_FILE_ATTRIBUTE_INCL_NORMAL) + else: + accept_result = (file_attributes & search) > 0 + if accept_result: + results.append(SharedFile(convertFILETIMEtoEpoch(create_time), convertFILETIMEtoEpoch(last_access_time), + convertFILETIMEtoEpoch(last_write_time), convertFILETIMEtoEpoch(last_attr_change_time), + file_size, alloc_size, file_attributes, short_name, filename, file_id)) + + if next_offset: + offset += next_offset + else: + break + return b'' + + def closeFid(tid, fid, results = None, error = None): + m = SMB2Message(SMB2CloseRequest(fid)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, results = results, error = error) + messages_history.append(m) + + def closeCB(close_message, **kwargs): + if kwargs['results'] is not None: + callback(kwargs['results']) + elif kwargs['error'] is not None: + if kwargs['error'] == 0xC000000F: # [MS-ERREF]: STATUS_NO_SUCH_FILE + # Remote server returns STATUS_NO_SUCH_FILE error so we assume that the search returns no matching files + callback([ ]) + else: + errback(OperationFailure('Failed to list %s on %s: Query failed with errorcode 0x%08x' % ( path, service_name, kwargs['error'] ), messages_history)) + + if service_name not in self.connected_trees: + def connectCB(connect_message, **kwargs): + messages_history.append(connect_message) + if connect_message.status == 0: + self.connected_trees[service_name] = connect_message.tid + sendCreate(connect_message.tid) + else: + errback(OperationFailure('Failed to list %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) + messages_history.append(m) + else: + sendCreate(self.connected_trees[service_name]) + + def _getAttributes_SMB2(self, service_name, path, callback, errback, timeout = 30): + if not self.has_authenticated: + raise NotReadyError('SMB connection not authenticated') + + expiry_time = time.time() + timeout + path = path.replace('/', '\\') + if path.startswith('\\'): + path = path[1:] + if path.endswith('\\'): + path = path[:-1] + messages_history = [ ] + + def sendCreate(tid): + create_context_data = binascii.unhexlify(""" +28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00 +44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 18 00 00 00 10 00 04 00 +00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00 +00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 +51 46 69 64 00 00 00 00 +""".replace(' ', '').replace('\n', '')) + m = SMB2Message(SMB2CreateRequest(path, + file_attributes = 0, + access_mask = FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | SYNCHRONIZE, + share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + oplock = SMB2_OPLOCK_LEVEL_NONE, + impersonation = SEC_IMPERSONATE, + create_options = 0, + create_disp = FILE_OPEN, + create_context_data = create_context_data)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, createCB, errback, tid = tid) + messages_history.append(m) + + def createCB(create_message, **kwargs): + messages_history.append(create_message) + if create_message.status == 0: + p = create_message.payload + filename = self._extractLastPathComponent(path) + info = SharedFile(p.create_time, p.lastaccess_time, p.lastwrite_time, p.change_time, + p.file_size, p.allocation_size, p.file_attributes, + filename, filename) + closeFid(kwargs['tid'], p.fid, info = info) + else: + errback(OperationFailure('Failed to get attributes for %s on %s: Unable to open remote file object' % ( path, service_name ), messages_history)) + + def closeFid(tid, fid, info = None, error = None): + m = SMB2Message(SMB2CloseRequest(fid)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, info = info, error = error) + messages_history.append(m) + + def closeCB(close_message, **kwargs): + if kwargs['info'] is not None: + callback(kwargs['info']) + elif kwargs['error'] is not None: + errback(OperationFailure('Failed to get attributes for %s on %s: Query failed with errorcode 0x%08x' % ( path, service_name, kwargs['error'] ), messages_history)) + + if service_name not in self.connected_trees: + def connectCB(connect_message, **kwargs): + messages_history.append(connect_message) + if connect_message.status == 0: + self.connected_trees[service_name] = connect_message.tid + sendCreate(connect_message.tid) + else: + errback(OperationFailure('Failed to get attributes for %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) + messages_history.append(m) + else: + sendCreate(self.connected_trees[service_name]) + + def _getSecurity_SMB2(self, service_name, path, callback, errback, timeout = 30): + if not self.has_authenticated: + raise NotReadyError('SMB connection not authenticated') + + expiry_time = time.time() + timeout + path = path.replace('/', '\\') + if path.startswith('\\'): + path = path[1:] + if path.endswith('\\'): + path = path[:-1] + messages_history = [ ] + results = [ ] + + def sendCreate(tid): + m = SMB2Message(SMB2CreateRequest(path, + file_attributes = 0, + access_mask = FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | READ_CONTROL | SYNCHRONIZE, + share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + oplock = SMB2_OPLOCK_LEVEL_NONE, + impersonation = SEC_IMPERSONATE, + create_options = 0, + create_disp = FILE_OPEN)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, createCB, errback, tid = tid) + messages_history.append(m) + + def createCB(create_message, **kwargs): + messages_history.append(create_message) + if create_message.status == 0: + m = SMB2Message(SMB2QueryInfoRequest(create_message.payload.fid, + flags = 0, + additional_info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + info_type = SMB2_INFO_SECURITY, + file_info_class = 0, # [MS-SMB2] 2.2.37, 3.2.4.12 + input_buf = '', + output_buf_len = self.max_transact_size)) + m.tid = kwargs['tid'] + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, queryCB, errback, tid = kwargs['tid'], fid = create_message.payload.fid) + messages_history.append(m) + else: + errback(OperationFailure('Failed to get the security descriptor of %s on %s: Unable to open file or directory' % ( path, service_name ), messages_history)) + + def queryCB(query_message, **kwargs): + messages_history.append(query_message) + if query_message.status == 0: + security = SecurityDescriptor.from_bytes(query_message.payload.data) + closeFid(kwargs['tid'], kwargs['fid'], result = security) + else: + closeFid(kwargs['tid'], kwargs['fid'], error = query_message.status) + + def closeFid(tid, fid, result = None, error = None): + m = SMB2Message(SMB2CloseRequest(fid)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, result = result, error = error) + messages_history.append(m) + + def closeCB(close_message, **kwargs): + if kwargs['result'] is not None: + callback(kwargs['result']) + elif kwargs['error'] is not None: + errback(OperationFailure('Failed to get the security descriptor of %s on %s: Query failed with errorcode 0x%08x' % ( path, service_name, kwargs['error'] ), messages_history)) + + if service_name not in self.connected_trees: + def connectCB(connect_message, **kwargs): + messages_history.append(connect_message) + if connect_message.status == 0: + self.connected_trees[service_name] = connect_message.tid + sendCreate(connect_message.tid) + else: + errback(OperationFailure('Failed to get the security descriptor of %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) + messages_history.append(m) + else: + sendCreate(self.connected_trees[service_name]) + + def _retrieveFile_SMB2(self, service_name, path, file_obj, callback, errback, timeout = 30): + return self._retrieveFileFromOffset(service_name, path, file_obj, callback, errback, 0, -1, timeout) + + def _retrieveFileFromOffset_SMB2(self, service_name, path, file_obj, callback, errback, starting_offset, max_length, timeout = 30): + if not self.has_authenticated: + raise NotReadyError('SMB connection not authenticated') + + expiry_time = time.time() + timeout + path = path.replace('/', '\\') + if path.startswith('\\'): + path = path[1:] + if path.endswith('\\'): + path = path[:-1] + messages_history = [ ] + results = [ ] + + def sendCreate(tid): + create_context_data = binascii.unhexlify(b""" +28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00 +44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 18 00 00 00 10 00 04 00 +00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00 +00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 +51 46 69 64 00 00 00 00 +""".replace(b' ', b'').replace(b'\n', b'')) + m = SMB2Message(SMB2CreateRequest(path, + file_attributes = 0, + access_mask = FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | READ_CONTROL | SYNCHRONIZE, + share_access = FILE_SHARE_READ | FILE_SHARE_WRITE, + oplock = SMB2_OPLOCK_LEVEL_NONE, + impersonation = SEC_IMPERSONATE, + create_options = FILE_SEQUENTIAL_ONLY | FILE_NON_DIRECTORY_FILE, + create_disp = FILE_OPEN, + create_context_data = create_context_data)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, createCB, errback, tid = tid) + messages_history.append(m) + + def createCB(create_message, **kwargs): + messages_history.append(create_message) + if create_message.status == 0: + m = SMB2Message(SMB2QueryInfoRequest(create_message.payload.fid, + flags = 0, + additional_info = 0, + info_type = SMB2_INFO_FILE, + file_info_class = 0x16, # FileStreamInformation [MS-FSCC] 2.4 + input_buf = b'', + output_buf_len = 4096)) + m.tid = kwargs['tid'] + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, infoCB, errback, + tid = kwargs['tid'], + fid = create_message.payload.fid, + file_attributes = create_message.payload.file_attributes) + messages_history.append(m) + else: + errback(OperationFailure('Failed to retrieve %s on %s: Unable to open file' % ( path, service_name ), messages_history)) + + def infoCB(info_message, **kwargs): + messages_history.append(info_message) + if info_message.status == 0: + file_len = struct.unpack(' file_len: + closeFid(info_message.tid, kwargs['fid']) + callback(( file_obj, kwargs['file_attributes'], 0 )) # Note that this is a tuple of 3-elements + else: + remaining_len = max_length + if remaining_len < 0: + remaining_len = file_len + if starting_offset + remaining_len > file_len: + remaining_len = file_len - starting_offset + sendRead(kwargs['tid'], kwargs['fid'], starting_offset, remaining_len, 0, kwargs['file_attributes']) + else: + errback(OperationFailure('Failed to retrieve %s on %s: Unable to retrieve information on file' % ( path, service_name ), messages_history)) + + def sendRead(tid, fid, offset, remaining_len, read_len, file_attributes): + read_count = min(self.max_read_size, remaining_len) + m = SMB2Message(SMB2ReadRequest(fid, offset, read_count)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, readCB, errback, + tid = tid, fid = fid, offset = offset, + remaining_len = remaining_len, + read_len = read_len, + file_attributes = file_attributes) + + def readCB(read_message, **kwargs): + # To avoid crazy memory usage when retrieving large files, we do not save every read_message in messages_history. + if read_message.status == 0: + data_len = read_message.payload.data_length + file_obj.write(read_message.payload.data) + + remaining_len = kwargs['remaining_len'] - data_len + + if remaining_len > 0: + sendRead(kwargs['tid'], kwargs['fid'], kwargs['offset'] + data_len, remaining_len, kwargs['read_len'] + data_len, kwargs['file_attributes']) + else: + closeFid(kwargs['tid'], kwargs['fid'], ret = ( file_obj, kwargs['file_attributes'], kwargs['read_len'] + data_len )) + else: + messages_history.append(read_message) + closeFid(kwargs['tid'], kwargs['fid'], error = read_message.status) + + def closeFid(tid, fid, ret = None, error = None): + m = SMB2Message(SMB2CloseRequest(fid)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, ret = ret, error = error) + messages_history.append(m) + + def closeCB(close_message, **kwargs): + if kwargs['ret'] is not None: + callback(kwargs['ret']) + elif kwargs['error'] is not None: + errback(OperationFailure('Failed to retrieve %s on %s: Read failed' % ( path, service_name ), messages_history)) + + if service_name not in self.connected_trees: + def connectCB(connect_message, **kwargs): + messages_history.append(connect_message) + if connect_message.status == 0: + self.connected_trees[service_name] = connect_message.tid + sendCreate(connect_message.tid) + else: + errback(OperationFailure('Failed to retrieve %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) + messages_history.append(m) + else: + sendCreate(self.connected_trees[service_name]) + + def _storeFile_SMB2(self, service_name, path, file_obj, callback, errback, timeout = 30): + self._storeFileFromOffset_SMB2(service_name, path, file_obj, callback, errback, 0, True, timeout) + + def _storeFileFromOffset_SMB2(self, service_name, path, file_obj, callback, errback, starting_offset, truncate = False, timeout = 30): + if not self.has_authenticated: + raise NotReadyError('SMB connection not authenticated') + + expiry_time = time.time() + timeout + path = path.replace('/', '\\') + if path.startswith('\\'): + path = path[1:] + if path.endswith('\\'): + path = path[:-1] + messages_history = [ ] + + def sendCreate(tid): + create_context_data = binascii.unhexlify(b""" +28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00 +44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 20 00 00 00 10 00 04 00 +00 00 18 00 08 00 00 00 41 6c 53 69 00 00 00 00 +85 62 00 00 00 00 00 00 18 00 00 00 10 00 04 00 +00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00 +00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 +51 46 69 64 00 00 00 00 +""".replace(b' ', b'').replace(b'\n', b'')) + m = SMB2Message(SMB2CreateRequest(path, + file_attributes = ATTR_ARCHIVE, + access_mask = FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_EA | READ_CONTROL | SYNCHRONIZE, + share_access = 0, + oplock = SMB2_OPLOCK_LEVEL_NONE, + impersonation = SEC_IMPERSONATE, + create_options = FILE_SEQUENTIAL_ONLY | FILE_NON_DIRECTORY_FILE, + create_disp = FILE_OVERWRITE_IF if truncate else FILE_OPEN_IF, + create_context_data = create_context_data)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, createCB, errback, tid = tid) + messages_history.append(m) + + def createCB(create_message, **kwargs): + create_message.tid = kwargs['tid'] + messages_history.append(create_message) + if create_message.status == 0: + sendWrite(create_message.tid, create_message.payload.fid, starting_offset) + else: + errback(OperationFailure('Failed to store %s on %s: Unable to open file' % ( path, service_name ), messages_history)) + + def sendWrite(tid, fid, offset): + write_count = self.max_write_size + data = file_obj.read(write_count) + data_len = len(data) + if data_len > 0: + m = SMB2Message(SMB2WriteRequest(fid, data, offset)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, writeCB, errback, tid = tid, fid = fid, offset = offset+data_len) + else: + closeFid(tid, fid, offset = offset) + + def writeCB(write_message, **kwargs): + # To avoid crazy memory usage when saving large files, we do not save every write_message in messages_history. + if write_message.status == 0: + sendWrite(kwargs['tid'], kwargs['fid'], kwargs['offset']) + else: + messages_history.append(write_message) + closeFid(kwargs['tid'], kwargs['fid']) + errback(OperationFailure('Failed to store %s on %s: Write failed' % ( path, service_name ), messages_history)) + + def closeFid(tid, fid, error = None, offset = None): + m = SMB2Message(SMB2CloseRequest(fid)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, closeCB, errback, fid = fid, offset = offset, error = error) + messages_history.append(m) + + def closeCB(close_message, **kwargs): + if kwargs['offset'] is not None: + callback(( file_obj, kwargs['offset'] )) # Note that this is a tuple of 2-elements + elif kwargs['error'] is not None: + errback(OperationFailure('Failed to store %s on %s: Write failed' % ( path, service_name ), messages_history)) + + if service_name not in self.connected_trees: + def connectCB(connect_message, **kwargs): + messages_history.append(connect_message) + if connect_message.status == 0: + self.connected_trees[service_name] = connect_message.tid + sendCreate(connect_message.tid) + else: + errback(OperationFailure('Failed to store %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, connectCB, errback, path = service_name) + messages_history.append(m) + else: + sendCreate(self.connected_trees[service_name]) + + + def _deleteFiles_SMB2(self, service_name, path_file_pattern, delete_matching_folders, callback, errback, timeout = 30): + if not self.has_authenticated: + raise NotReadyError('SMB connection not authenticated') + + expiry_time = time.time() + timeout + pattern = None + path = path_file_pattern.replace('/', '\\') + if path.startswith('\\'): + path = path[1:] + if path.endswith('\\'): + path = path[:-1] + else: + path_components = path.split('\\') + if path_components[-1].find('*') > -1 or path_components[-1].find('?') > -1: + path = '\\'.join(path_components[:-1]) + pattern = path_components[-1] + messages_history, files_queue = [ ], [ ] + + if pattern is None: + path_components = path.split('\\') + if len(path_components) > 1: + files_queue.append(( '\\'.join(path_components[:-1]), path_components[-1] )) + else: + files_queue.append(( '', path )) + + def deleteCB(path): + if files_queue: + p, filename = files_queue.pop(0) + if filename: + if p: + filename = p + '\\' + filename + self._deleteFiles_SMB2__del(service_name, self.connected_trees[service_name], filename, deleteCB, errback, timeout) + else: + self._deleteDirectory_SMB2(service_name, p, deleteCB, errback, timeout) + else: + callback(path_file_pattern) + + def listCB(files_list): + files_queue.extend(files_list) + deleteCB(None) + + if service_name not in self.connected_trees: + def connectCB(connect_message, **kwargs): + messages_history.append(connect_message) + if connect_message.status == 0: + self.connected_trees[service_name] = connect_message.tid + if files_queue: + deleteCB(None) + else: + self._deleteFiles_SMB2__list(service_name, path, pattern, delete_matching_folders, listCB, errback, timeout) + else: + errback(OperationFailure('Failed to delete %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) + messages_history.append(m) + else: + if files_queue: + deleteCB(None) + else: + self._deleteFiles_SMB2__list(service_name, path, pattern, delete_matching_folders, listCB, errback, timeout) + + def _deleteFiles_SMB2__list(self, service_name, path, pattern, delete_matching_folders, callback, errback, timeout = 30): + folder_queue = [ ] + files_list = [ ] + current_path = [ path ] + search = SMB_FILE_ATTRIBUTE_READONLY | SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_DIRECTORY | SMB_FILE_ATTRIBUTE_ARCHIVE | SMB_FILE_ATTRIBUTE_INCL_NORMAL + + def listCB(results): + files = [ ] + for f in filter(lambda x: x.filename not in [ '.', '..' ], results): + if f.isDirectory: + if delete_matching_folders: + folder_queue.append(current_path[0]+'\\'+f.filename) + else: + files.append(( current_path[0], f.filename )) + if current_path[0]!=path and delete_matching_folders: + files.append(( current_path[0], None )) + + if files: + files_list[0:0] = files + + if folder_queue: + p = folder_queue.pop() + current_path[0] = p + self._listPath_SMB2(service_name, current_path[0], listCB, errback, search = search, pattern = '*', timeout = 30) + else: + callback(files_list) + + self._listPath_SMB2(service_name, path, listCB, errback, search = search, pattern = pattern, timeout = timeout) + + def _deleteFiles_SMB2__del(self, service_name, tid, path, callback, errback, timeout = 30): + messages_history = [ ] + + def sendCreate(tid): + create_context_data = binascii.unhexlify(b""" + 28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00 + 44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 18 00 00 00 10 00 04 00 + 00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00 + 00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 + 51 46 69 64 00 00 00 00 + """.replace(b' ', b'').replace(b'\n', b'')) + m = SMB2Message(SMB2CreateRequest(path, + file_attributes = 0, + access_mask = DELETE | FILE_READ_ATTRIBUTES, + share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + oplock = SMB2_OPLOCK_LEVEL_NONE, + impersonation = SEC_IMPERSONATE, + create_options = FILE_NON_DIRECTORY_FILE, + create_disp = FILE_OPEN, + create_context_data = create_context_data)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, createCB, errback, tid = tid) + messages_history.append(m) + + def createCB(open_message, **kwargs): + open_message.tid = kwargs['tid'] + messages_history.append(open_message) + if open_message.status == 0: + sendDelete(open_message.tid, open_message.payload.fid) + elif open_message.status == 0xc0000034: # STATUS_OBJECT_NAME_NOT_FOUND + callback(path) + elif open_message.status == 0xC00000BA: # [MS-ERREF]: STATUS_FILE_IS_A_DIRECTORY + errback(OperationFailure('Failed to delete %s on %s: Cannot delete a folder. Please use deleteDirectory() method or append "/*" to your path if you wish to delete all files in the folder.' % ( path, service_name ), messages_history)) + else: + errback(OperationFailure('Failed to delete %s on %s: Unable to open file' % ( path, service_name ), messages_history)) + + def sendDelete(tid, fid): + m = SMB2Message(SMB2SetInfoRequest(fid, + additional_info = 0, + info_type = SMB2_INFO_FILE, + file_info_class = 0x0d, # SMB2_FILE_DISPOSITION_INFO + data = b'\x01')) + # [MS-SMB2]: 2.2.39, [MS-FSCC]: 2.4.11 + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, deleteCB, errback, tid = tid, fid = fid) + messages_history.append(m) + + def deleteCB(delete_message, **kwargs): + messages_history.append(delete_message) + if delete_message.status == 0: + closeFid(kwargs['tid'], kwargs['fid'], status = 0) + else: + closeFid(kwargs['tid'], kwargs['fid'], status = delete_message.status) + + def closeFid(tid, fid, status = None): + m = SMB2Message(SMB2CloseRequest(fid)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, closeCB, errback, status = status) + messages_history.append(m) + + def closeCB(close_message, **kwargs): + if kwargs['status'] == 0: + callback(path) + else: + errback(OperationFailure('Failed to delete %s on %s: Delete failed' % ( path, service_name ), messages_history)) + + sendCreate(tid) + + def _resetFileAttributes_SMB2(self, service_name, path_file_pattern, callback, errback, file_attributes = ATTR_NORMAL, timeout = 30): + if not self.has_authenticated: + raise NotReadyError('SMB connection not authenticated') + + expiry_time = time.time() + timeout + path = path_file_pattern.replace('/', '\\') + if path.startswith('\\'): + path = path[1:] + if path.endswith('\\'): + path = path[:-1] + messages_history = [ ] + + def sendCreate(tid): + create_context_data = binascii.unhexlify(b""" +28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00 +44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 18 00 00 00 10 00 04 00 +00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00 +00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 +51 46 69 64 00 00 00 00 +""".replace(b' ', b'').replace(b'\n', b'')) + + m = SMB2Message(SMB2CreateRequest(path, + file_attributes = 0, + access_mask = FILE_WRITE_ATTRIBUTES, + share_access = FILE_SHARE_READ | FILE_SHARE_WRITE, + oplock = SMB2_OPLOCK_LEVEL_NONE, + impersonation = SEC_IMPERSONATE, + create_options = 0, + create_disp = FILE_OPEN, + create_context_data = create_context_data)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, createCB, errback, tid = tid) + messages_history.append(m) + + def createCB(open_message, **kwargs): + messages_history.append(open_message) + if open_message.status == 0: + sendReset(kwargs['tid'], open_message.payload.fid) + else: + errback(OperationFailure('Failed to reset attributes of %s on %s: Unable to open file' % ( path, service_name ), messages_history)) + + def sendReset(tid, fid): + m = SMB2Message(SMB2SetInfoRequest(fid, + additional_info = 0, + info_type = SMB2_INFO_FILE, + file_info_class = 4, # FileBasicInformation + data = struct.pack('qqqqii', 0, 0, 0, 0, file_attributes, 0))) + # [MS-SMB2]: 2.2.39, [MS-FSCC]: 2.4, [MS-FSCC]: 2.4.7, [MS-FSCC]: 2.6 + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, resetCB, errback, tid = tid, fid = fid) + messages_history.append(m) + + def resetCB(reset_message, **kwargs): + messages_history.append(reset_message) + if reset_message.status == 0: + closeFid(kwargs['tid'], kwargs['fid'], status = 0) + else: + closeFid(kwargs['tid'], kwargs['fid'], status = reset_message.status) + + def closeFid(tid, fid, status = None): + m = SMB2Message(SMB2CloseRequest(fid)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, closeCB, errback, status = status) + messages_history.append(m) + + def closeCB(close_message, **kwargs): + if kwargs['status'] == 0: + callback(path_file_pattern) + else: + errback(OperationFailure('Failed to reset attributes of %s on %s: Reset failed' % ( path, service_name ), messages_history)) + + if service_name not in self.connected_trees: + def connectCB(connect_message, **kwargs): + messages_history.append(connect_message) + if connect_message.status == 0: + self.connected_trees[service_name] = connect_message.tid + sendCreate(connect_message.tid) + else: + errback(OperationFailure('Failed to reset attributes of %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) + messages_history.append(m) + else: + sendCreate(self.connected_trees[service_name]) + + def _createDirectory_SMB2(self, service_name, path, callback, errback, timeout = 30): + if not self.has_authenticated: + raise NotReadyError('SMB connection not authenticated') + + expiry_time = time.time() + timeout + path = path.replace('/', '\\') + if path.startswith('\\'): + path = path[1:] + if path.endswith('\\'): + path = path[:-1] + messages_history = [ ] + + def sendCreate(tid): + create_context_data = binascii.unhexlify(b""" +28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00 +44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 18 00 00 00 10 00 04 00 +00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00 +00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 +51 46 69 64 00 00 00 00 +""".replace(b' ', b'').replace(b'\n', b'')) + m = SMB2Message(SMB2CreateRequest(path, + file_attributes = 0, + access_mask = FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_EA | FILE_WRITE_EA | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | READ_CONTROL | DELETE | SYNCHRONIZE, + share_access = 0, + oplock = SMB2_OPLOCK_LEVEL_NONE, + impersonation = SEC_IMPERSONATE, + create_options = FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, + create_disp = FILE_CREATE, + create_context_data = create_context_data)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, createCB, errback, tid = tid) + messages_history.append(m) + + def createCB(create_message, **kwargs): + messages_history.append(create_message) + if create_message.status == 0: + closeFid(kwargs['tid'], create_message.payload.fid) + else: + errback(OperationFailure('Failed to create directory %s on %s: Create failed' % ( path, service_name ), messages_history)) + + def closeFid(tid, fid): + m = SMB2Message(SMB2CloseRequest(fid)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, closeCB, errback) + messages_history.append(m) + + def closeCB(close_message, **kwargs): + callback(path) + + if service_name not in self.connected_trees: + def connectCB(connect_message, **kwargs): + messages_history.append(connect_message) + if connect_message.status == 0: + self.connected_trees[service_name] = connect_message.tid + sendCreate(connect_message.tid) + else: + errback(OperationFailure('Failed to create directory %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) + messages_history.append(m) + else: + sendCreate(self.connected_trees[service_name]) + + def _deleteDirectory_SMB2(self, service_name, path, callback, errback, timeout = 30): + if not self.has_authenticated: + raise NotReadyError('SMB connection not authenticated') + + expiry_time = time.time() + timeout + path = path.replace('/', '\\') + if path.startswith('\\'): + path = path[1:] + if path.endswith('\\'): + path = path[:-1] + messages_history = [ ] + + def sendCreate(tid): + create_context_data = binascii.unhexlify(b""" +28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00 +44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 18 00 00 00 10 00 04 00 +00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00 +00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 +51 46 69 64 00 00 00 00 +""".replace(b' ', b'').replace(b'\n', b'')) + m = SMB2Message(SMB2CreateRequest(path, + file_attributes = 0, + access_mask = DELETE | FILE_READ_ATTRIBUTES, + share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + oplock = SMB2_OPLOCK_LEVEL_NONE, + impersonation = SEC_IMPERSONATE, + create_options = FILE_DIRECTORY_FILE, + create_disp = FILE_OPEN, + create_context_data = create_context_data)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, createCB, errback, tid = tid) + messages_history.append(m) + + def createCB(open_message, **kwargs): + messages_history.append(open_message) + if open_message.status == 0: + sendDelete(kwargs['tid'], open_message.payload.fid) + else: + errback(OperationFailure('Failed to delete %s on %s: Unable to open directory' % ( path, service_name ), messages_history)) + + def sendDelete(tid, fid): + m = SMB2Message(SMB2SetInfoRequest(fid, + additional_info = 0, + info_type = SMB2_INFO_FILE, + file_info_class = 0x0d, # SMB2_FILE_DISPOSITION_INFO + data = b'\x01')) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, deleteCB, errback, tid = tid, fid = fid) + messages_history.append(m) + + def deleteCB(delete_message, **kwargs): + messages_history.append(delete_message) + if delete_message.status == 0: + closeFid(kwargs['tid'], kwargs['fid'], status = 0) + else: + closeFid(kwargs['tid'], kwargs['fid'], status = delete_message.status) + + def closeFid(tid, fid, status = None): + m = SMB2Message(SMB2CloseRequest(fid)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, status = status) + messages_history.append(m) + + def closeCB(close_message, **kwargs): + if kwargs['status'] == 0: + callback(path) + else: + errback(OperationFailure('Failed to delete %s on %s: Delete failed' % ( path, service_name ), messages_history)) + + if service_name not in self.connected_trees: + def connectCB(connect_message, **kwargs): + messages_history.append(connect_message) + if connect_message.status == 0: + self.connected_trees[service_name] = connect_message.tid + sendCreate(connect_message.tid) + else: + errback(OperationFailure('Failed to delete %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + + m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ))) + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) + messages_history.append(m) + else: + sendCreate(self.connected_trees[service_name]) + + def _rename_SMB2(self, service_name, old_path, new_path, callback, errback, timeout = 30): + if not self.has_authenticated: + raise NotReadyError('SMB connection not authenticated') + + expiry_time = time.time() + timeout + messages_history = [ ] + + new_path = new_path.replace('/', '\\') + if new_path.startswith('\\'): + new_path = new_path[1:] + if new_path.endswith('\\'): + new_path = new_path[:-1] + + old_path = old_path.replace('/', '\\') + if old_path.startswith('\\'): + old_path = old_path[1:] + if old_path.endswith('\\'): + old_path = old_path[:-1] + + def sendCreate(tid): + create_context_data = binascii.unhexlify(b""" +28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00 +44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 18 00 00 00 10 00 04 00 +00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00 +00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 +51 46 69 64 00 00 00 00 +""".replace(b' ', b'').replace(b'\n', b'')) + m = SMB2Message(SMB2CreateRequest(old_path, + file_attributes = 0, + access_mask = DELETE | FILE_READ_ATTRIBUTES | SYNCHRONIZE, + share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + oplock = SMB2_OPLOCK_LEVEL_NONE, + impersonation = SEC_IMPERSONATE, + create_options = FILE_SYNCHRONOUS_IO_NONALERT, + create_disp = FILE_OPEN, + create_context_data = create_context_data)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, createCB, errback, tid = tid) + messages_history.append(m) + + def createCB(create_message, **kwargs): + messages_history.append(create_message) + if create_message.status == 0: + sendRename(kwargs['tid'], create_message.payload.fid) + else: + errback(OperationFailure('Failed to rename %s on %s: Unable to open file/directory' % ( old_path, service_name ), messages_history)) + + def sendRename(tid, fid): + data = b'\x00'*16 + struct.pack('= 0xFFFF: # MID cannot be 0xFFFF. [MS-CIFS]: 2.2.1.6.2 + # We don't use MID of 0 as MID can be reused for SMB_COM_TRANSACTION2_SECONDARY messages + # where if mid=0, _sendSMBMessage will re-assign new MID values again + self.mid = 1 + return self.mid + + def _updateState_SMB1(self, message): + if message.isReply: + if message.command == SMB_COM_NEGOTIATE: + if not message.status.hasError: + self.has_negotiated = True + self.log.info('SMB dialect negotiation successful (ExtendedSecurity:%s)', message.hasExtendedSecurity) + self._updateServerInfo(message.payload) + self._handleNegotiateResponse(message) + else: + raise ProtocolError('Unknown status value (0x%08X) in SMB_COM_NEGOTIATE' % message.status.internal_value, + message.raw_data, message) + elif message.command == SMB_COM_SESSION_SETUP_ANDX: + if message.hasExtendedSecurity: + if not message.status.hasError: + try: + result = securityblob.decodeAuthResponseSecurityBlob(message.payload.security_blob) + if result == securityblob.RESULT_ACCEPT_COMPLETED: + self.log.debug('SMB uid is now %d', message.uid) + self.uid = message.uid + self.has_authenticated = True + self.log.info('Authentication (with extended security) successful!') + self.onAuthOK() + else: + raise ProtocolError('SMB_COM_SESSION_SETUP_ANDX status is 0 but security blob negResult value is %d' % result, message.raw_data, message) + except securityblob.BadSecurityBlobError as ex: + raise ProtocolError(str(ex), message.raw_data, message) + elif message.status.internal_value == 0xc0000016: # STATUS_MORE_PROCESSING_REQUIRED + try: + result, ntlm_token = securityblob.decodeChallengeSecurityBlob(message.payload.security_blob) + if result == securityblob.RESULT_ACCEPT_INCOMPLETE: + self._handleSessionChallenge(message, ntlm_token) + except ( securityblob.BadSecurityBlobError, securityblob.UnsupportedSecurityProvider ) as ex: + raise ProtocolError(str(ex), message.raw_data, message) + elif (message.status.internal_value == 0xc000006d # STATUS_LOGON_FAILURE + or message.status.internal_value == 0xc0000064 # STATUS_NO_SUCH_USER + or message.status.internal_value == 0xc000006a): # STATUS_WRONG_PASSWORD + self.has_authenticated = False + self.log.info('Authentication (with extended security) failed. Please check username and password.') + self.onAuthFailed() + elif (message.status.internal_value == 0xc0000193 # STATUS_ACCOUNT_EXPIRED + or message.status.internal_value == 0xC0000071): # STATUS_PASSWORD_EXPIRED + self.has_authenticated = False + self.log.info('Authentication (with extended security) failed. Account or password has expired.') + self.onAuthFailed() + elif message.status.internal_value == 0xc0000234: # STATUS_ACCOUNT_LOCKED_OUT + self.has_authenticated = False + self.log.info('Authentication (with extended security) failed. Account has been locked due to too many invalid logon attempts.') + self.onAuthFailed() + elif message.status.internal_value == 0xc0000072: # STATUS_ACCOUNT_DISABLED + self.has_authenticated = False + self.log.info('Authentication (with extended security) failed. Account has been disabled.') + self.onAuthFailed() + elif (message.status.internal_value == 0xc000006f # STATUS_INVALID_LOGON_HOURS + or message.status.internal_value == 0xc000015b # STATUS_LOGON_TYPE_NOT_GRANTED + or message.status.internal_value == 0xc0000070): # STATUS_INVALID_WORKSTATION + self.has_authenticated = False + self.log.info('Authentication (with extended security) failed. Not allowed.') + self.onAuthFailed() + elif message.status.internal_value == 0xc000018c: # STATUS_TRUSTED_DOMAIN_FAILURE + self.has_authenticated = False + self.log.info('Authentication (with extended security) failed. Domain not trusted.') + self.onAuthFailed() + elif message.status.internal_value == 0xc000018d: # STATUS_TRUSTED_RELATIONSHIP_FAILURE + self.has_authenticated = False + self.log.info('Authentication (with extended security) failed. Workstation not trusted.') + self.onAuthFailed() + else: + raise ProtocolError('Unknown status value (0x%08X) in SMB_COM_SESSION_SETUP_ANDX (with extended security)' % message.status.internal_value, + message.raw_data, message) + else: + if message.status.internal_value == 0: + self.log.debug('SMB uid is now %d', message.uid) + self.uid = message.uid + self.has_authenticated = True + self.log.info('Authentication (without extended security) successful!') + self.onAuthOK() + else: + self.has_authenticated = False + self.log.info('Authentication (without extended security) failed. Please check username and password') + self.onAuthFailed() + elif message.command == SMB_COM_TREE_CONNECT_ANDX: + try: + req = self.pending_requests[message.mid] + except KeyError: + pass + else: + if not message.status.hasError: + self.connected_trees[req.kwargs['path']] = message.tid + + req = self.pending_requests.pop(message.mid, None) + if req: + req.callback(message, **req.kwargs) + return True + + + def _updateServerInfo_SMB1(self, payload): + self.capabilities = payload.capabilities + self.security_mode = payload.security_mode + self.max_raw_size = payload.max_raw_size + self.max_buffer_size = payload.max_buffer_size + self.max_mpx_count = payload.max_mpx_count + self.use_plaintext_authentication = not bool(payload.security_mode & NEGOTIATE_ENCRYPT_PASSWORDS) + + if self.use_plaintext_authentication: + self.log.warning('Remote server only supports plaintext authentication. Your password can be stolen easily over the network.') + + + def _handleSessionChallenge_SMB1(self, message, ntlm_token): + assert message.hasExtendedSecurity + + if message.uid and not self.uid: + self.uid = message.uid + + server_challenge, server_flags, server_info = ntlm.decodeChallengeMessage(ntlm_token) + if self.use_ntlm_v2: + self.log.info('Performing NTLMv2 authentication (with extended security) with server challenge "%s"', binascii.hexlify(server_challenge)) + nt_challenge_response, lm_challenge_response, session_key = ntlm.generateChallengeResponseV2(self.password, + self.username, + server_challenge, + server_info, + self.domain) + + else: + self.log.info('Performing NTLMv1 authentication (with extended security) with server challenge "%s"', binascii.hexlify(server_challenge)) + nt_challenge_response, lm_challenge_response, session_key = ntlm.generateChallengeResponseV1(self.password, server_challenge, True) + + ntlm_data, signing_session_key = ntlm.generateAuthenticateMessage(server_flags, + nt_challenge_response, + lm_challenge_response, + session_key, + self.username, + self.domain, + self.my_name) + + if self.log.isEnabledFor(logging.DEBUG): + self.log.debug('NT challenge response is "%s" (%d bytes)', binascii.hexlify(nt_challenge_response), len(nt_challenge_response)) + self.log.debug('LM challenge response is "%s" (%d bytes)', binascii.hexlify(lm_challenge_response), len(lm_challenge_response)) + + blob = securityblob.generateAuthSecurityBlob(ntlm_data) + self._sendSMBMessage(SMBMessage(ComSessionSetupAndxRequest__WithSecurityExtension(0, blob))) + + if self.security_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRE: + self.log.info('Server requires all SMB messages to be signed') + self.is_signing_active = (self.sign_options != SMB.SIGN_NEVER) + elif self.security_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLE: + self.log.info('Server supports SMB signing') + self.is_signing_active = (self.sign_options == SMB.SIGN_WHEN_SUPPORTED) + else: + self.is_signing_active = False + + if self.is_signing_active: + self.log.info("SMB signing activated. All SMB messages will be signed.") + self.signing_session_key = signing_session_key + if self.capabilities & CAP_EXTENDED_SECURITY: + self.signing_challenge_response = None + else: + self.signing_challenge_response = blob + else: + self.log.info("SMB signing deactivated. SMB messages will NOT be signed.") + + + def _handleNegotiateResponse_SMB1(self, message): + if message.uid and not self.uid: + self.uid = message.uid + + if message.hasExtendedSecurity or message.payload.supportsExtendedSecurity: + ntlm_data = ntlm.generateNegotiateMessage() + blob = securityblob.generateNegotiateSecurityBlob(ntlm_data) + self._sendSMBMessage(SMBMessage(ComSessionSetupAndxRequest__WithSecurityExtension(message.payload.session_key, blob))) + else: + nt_password, _, _ = ntlm.generateChallengeResponseV1(self.password, message.payload.challenge, False) + self.log.info('Performing NTLMv1 authentication (without extended security) with challenge "%s" and hashed password of "%s"', + binascii.hexlify(message.payload.challenge), + binascii.hexlify(nt_password)) + self._sendSMBMessage(SMBMessage(ComSessionSetupAndxRequest__NoSecurityExtension(message.payload.session_key, + self.username, + nt_password, + True, + self.domain))) + + def _listShares_SMB1(self, callback, errback, timeout = 30): + if not self.has_authenticated: + raise NotReadyError('SMB connection not authenticated') + + expiry_time = time.time() + timeout + path = 'IPC$' + messages_history = [ ] + + def connectSrvSvc(tid): + m = SMBMessage(ComNTCreateAndxRequest('\\srvsvc', + flags = NT_CREATE_REQUEST_EXTENDED_RESPONSE, + access_mask = READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | FILE_WRITE_EA | FILE_READ_EA | FILE_APPEND_DATA | FILE_WRITE_DATA | FILE_READ_DATA, + share_access = FILE_SHARE_READ | FILE_SHARE_WRITE, + create_disp = FILE_OPEN, + create_options = FILE_OPEN_NO_RECALL | FILE_NON_DIRECTORY_FILE, + impersonation = SEC_IMPERSONATE, + security_flags = 0)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectSrvSvcCB, errback) + messages_history.append(m) + + def connectSrvSvcCB(create_message, **kwargs): + messages_history.append(create_message) + if not create_message.status.hasError: + call_id = self._getNextRPCCallID() + # See [MS-CIFS]: 2.2.5.6.1 for more information on TRANS_TRANSACT_NMPIPE (0x0026) parameters + setup_bytes = struct.pack(' data_length: + return data_bytes[offset:] + + next_offset, _, \ + create_time, last_access_time, last_write_time, last_attr_change_time, \ + file_size, alloc_size, file_attributes, filename_length, ea_size, \ + short_name_length, _, short_name = struct.unpack(info_format, data_bytes[offset:offset+info_size]) + + offset2 = offset + info_size + if offset2 + filename_length > data_length: + return data_bytes[offset:] + + filename = data_bytes[offset2:offset2+filename_length].decode('UTF-16LE') + short_name = short_name.decode('UTF-16LE') + + accept_result = False + if (file_attributes & 0xff) in ( 0x00, ATTR_NORMAL ): # Only the first 8-bits are compared. We ignore other bits like temp, compressed, encryption, sparse, indexed, etc + accept_result = (search == SMB_FILE_ATTRIBUTE_NORMAL) or (search & SMB_FILE_ATTRIBUTE_INCL_NORMAL) + else: + accept_result = (file_attributes & search) > 0 + if accept_result: + results.append(SharedFile(convertFILETIMEtoEpoch(create_time), convertFILETIMEtoEpoch(last_access_time), + convertFILETIMEtoEpoch(last_write_time), convertFILETIMEtoEpoch(last_attr_change_time), + file_size, alloc_size, file_attributes, short_name, filename)) + + if next_offset: + offset += next_offset + else: + break + return b'' + + def findFirstCB(find_message, **kwargs): + messages_history.append(find_message) + if not find_message.status.hasError: + if 'total_count' not in kwargs: + # TRANS2_FIND_FIRST2 response. [MS-CIFS]: 2.2.6.2.2 + sid, search_count, end_of_search, _, last_name_offset = struct.unpack(' 0: + if data_len > remaining_len: + file_obj.write(read_message.payload.data[:remaining_len]) + read_len += remaining_len + remaining_len = 0 + else: + file_obj.write(read_message.payload.data) + remaining_len -= data_len + read_len += data_len + else: + file_obj.write(read_message.payload.data) + read_len += data_len + + if (max_length > 0 and remaining_len <= 0) or data_len < (self.max_raw_size - 2): + closeFid(read_message.tid, kwargs['fid']) + callback(( file_obj, kwargs['file_attributes'], read_len )) # Note that this is a tuple of 3-elements + else: + sendRead(read_message.tid, kwargs['fid'], kwargs['offset']+data_len, kwargs['file_attributes'], read_len, remaining_len) + else: + messages_history.append(read_message) + closeFid(read_message.tid, kwargs['fid']) + errback(OperationFailure('Failed to retrieve %s on %s: Read failed' % ( path, service_name ), messages_history)) + + def closeFid(tid, fid): + m = SMBMessage(ComCloseRequest(fid)) + m.tid = tid + self._sendSMBMessage(m) + messages_history.append(m) + + if service_name not in self.connected_trees: + def connectCB(connect_message, **kwargs): + messages_history.append(connect_message) + if not connect_message.status.hasError: + self.connected_trees[service_name] = connect_message.tid + sendOpen(connect_message.tid) + else: + errback(OperationFailure('Failed to retrieve %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + + m = SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, connectCB, errback, path = service_name) + messages_history.append(m) + else: + sendOpen(self.connected_trees[service_name]) + + def _storeFile_SMB1(self, service_name, path, file_obj, callback, errback, timeout = 30): + self._storeFileFromOffset_SMB1(service_name, path, file_obj, callback, errback, 0, True, timeout) + + def _storeFileFromOffset_SMB1(self, service_name, path, file_obj, callback, errback, starting_offset, truncate = False, timeout = 30): + if not self.has_authenticated: + raise NotReadyError('SMB connection not authenticated') + + path = path.replace('/', '\\') + messages_history = [ ] + + def sendOpen(tid): + m = SMBMessage(ComOpenAndxRequest(filename = path, + access_mode = 0x0041, # Sharing mode: Deny nothing to others + Open for writing + open_mode = 0x0012 if truncate else 0x0011, # Create file if file does not exist. Overwrite or append depending on truncate parameter. + search_attributes = SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM, + timeout = timeout * 1000)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, openCB, errback) + messages_history.append(m) + + def openCB(open_message, **kwargs): + messages_history.append(open_message) + if not open_message.status.hasError: + sendWrite(open_message.tid, open_message.payload.fid, starting_offset) + else: + errback(OperationFailure('Failed to store %s on %s: Unable to open file' % ( path, service_name ), messages_history)) + + def sendWrite(tid, fid, offset): + # [MS-SMB] 2.2.4.5.2.2: The total SMB message size (inclusive of SMB header) must be not exceed the max_buffer_size. + write_count = min(self.max_buffer_size-64, 0xFFFF-64) # SMB header is 32-bytes. We factor in another 32-bytes for the message parameter block + data_bytes = file_obj.read(write_count) + data_len = len(data_bytes) + if data_len > 0: + m = SMBMessage(ComWriteAndxRequest(fid = fid, offset = offset, data_bytes = data_bytes)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, writeCB, errback, fid = fid, offset = offset+data_len) + else: + closeFid(tid, fid) + callback(( file_obj, offset )) # Note that this is a tuple of 2-elements + + def writeCB(write_message, **kwargs): + # To avoid crazy memory usage when saving large files, we do not save every write_message in messages_history. + if not write_message.status.hasError: + sendWrite(write_message.tid, kwargs['fid'], kwargs['offset']) + else: + messages_history.append(write_message) + closeFid(write_message.tid, kwargs['fid']) + errback(OperationFailure('Failed to store %s on %s: Write failed' % ( path, service_name ), messages_history)) + + def closeFid(tid, fid): + m = SMBMessage(ComCloseRequest(fid)) + m.tid = tid + self._sendSMBMessage(m) + messages_history.append(m) + + if service_name not in self.connected_trees: + def connectCB(connect_message, **kwargs): + messages_history.append(connect_message) + if not connect_message.status.hasError: + self.connected_trees[service_name] = connect_message.tid + sendOpen(connect_message.tid) + else: + errback(OperationFailure('Failed to store %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + + m = SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, connectCB, errback, path = service_name) + messages_history.append(m) + else: + sendOpen(self.connected_trees[service_name]) + + def _deleteFiles_SMB1(self, service_name, path_file_pattern, delete_matching_folders, callback, errback, timeout = 30): + if not self.has_authenticated: + raise NotReadyError('SMB connection not authenticated') + + expiry_time = time.time() + timeout + pattern = None + path = path_file_pattern.replace('/', '\\') + if path.startswith('\\'): + path = path[1:] + if path.endswith('\\'): + path = path[:-1] + else: + path_components = path.split('\\') + if path_components[-1].find('*') > -1 or path_components[-1].find('?') > -1: + path = '\\'.join(path_components[:-1]) + pattern = path_components[-1] + messages_history, files_queue = [ ], [ ] + + if pattern is None: + path_components = path.split('\\') + if len(path_components) > 1: + files_queue.append(( '\\'.join(path_components[:-1]), path_components[-1] )) + else: + files_queue.append(( '', path )) + + def deleteCB(path): + if files_queue: + p, filename = files_queue.pop(0) + if filename: + if p: + filename = p + '\\' + filename + self._deleteFiles_SMB1__del(service_name, self.connected_trees[service_name], filename, deleteCB, errback, timeout) + else: + self._deleteDirectory_SMB1(service_name, p, deleteCB, errback, timeout = 30) + else: + callback(path_file_pattern) + + def listCB(files_list): + files_queue.extend(files_list) + deleteCB(None) + + if service_name not in self.connected_trees: + def connectCB(connect_message, **kwargs): + messages_history.append(connect_message) + if not connect_message.status.hasError: + self.connected_trees[service_name] = connect_message.tid + if files_queue: + deleteCB(None) + else: + self._deleteFiles_SMB1__list(service_name, path, pattern, delete_matching_folders, listCB, errback, timeout) + else: + errback(OperationFailure('Failed to delete %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + + m = SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) + messages_history.append(m) + else: + if files_queue: + deleteCB(None) + else: + self._deleteFiles_SMB1__list(service_name, path, pattern, delete_matching_folders, listCB, errback, timeout) + + def _deleteFiles_SMB1__list(self, service_name, path, pattern, delete_matching_folders, callback, errback, timeout = 30): + folder_queue = [ ] + files_list = [ ] + current_path = [ path ] + search = SMB_FILE_ATTRIBUTE_READONLY | SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_DIRECTORY | SMB_FILE_ATTRIBUTE_ARCHIVE | SMB_FILE_ATTRIBUTE_INCL_NORMAL + + def listCB(results): + files = [ ] + for f in filter(lambda x: x.filename not in [ '.', '..' ], results): + if f.isDirectory: + if delete_matching_folders: + folder_queue.append(current_path[0]+'\\'+f.filename) + else: + files.append(( current_path[0], f.filename )) + if current_path[0]!=path and delete_matching_folders: + files.append(( current_path[0], None )) + + if files: + files_list[0:0] = files + + if folder_queue: + p = folder_queue.pop() + current_path[0] = p + self._listPath_SMB1(service_name, current_path[0], listCB, errback, search = search, pattern = '*', timeout = 30) + else: + callback(files_list) + + self._listPath_SMB1(service_name, path, listCB, errback, search = search, pattern = pattern, timeout = timeout) + + def _deleteFiles_SMB1__del(self, service_name, tid, path, callback, errback, timeout = 30): + messages_history = [ ] + + def sendDelete(tid): + m = SMBMessage(ComDeleteRequest(filename_pattern = path, + search_attributes = SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, deleteCB, errback) + messages_history.append(m) + + def deleteCB(delete_message, **kwargs): + messages_history.append(delete_message) + if not delete_message.status.hasError: + callback(path) + elif delete_message.status.internal_value == 0xC000000F: # [MS-ERREF]: STATUS_NO_SUCH_FILE + # If there are no matching files, we just treat as success instead of failing + callback(path_file_pattern) + elif delete_message.status.internal_value == 0xC00000BA: # [MS-ERREF]: STATUS_FILE_IS_A_DIRECTORY + errback(OperationFailure('Failed to delete %s on %s: Cannot delete a folder. Please use deleteDirectory() method or append "/*" to your path if you wish to delete all files in the folder.' % ( path, service_name ), messages_history)) + elif delete_message.status.internal_value == 0xC0000034: # [MS-ERREF]: STATUS_OBJECT_NAME_INVALID + errback(OperationFailure('Failed to delete %s on %s: Path not found' % ( path, service_name ), messages_history)) + else: + errback(OperationFailure('Failed to delete %s on %s: Delete failed' % ( path, service_name ), messages_history)) + + sendDelete(tid) + + def _resetFileAttributes_SMB1(self, service_name, path_file_pattern, callback, errback, file_attributes=ATTR_NORMAL, timeout = 30): + raise NotReadyError('resetFileAttributes is not yet implemented for SMB1') + + def _createDirectory_SMB1(self, service_name, path, callback, errback, timeout = 30): + if not self.has_authenticated: + raise NotReadyError('SMB connection not authenticated') + + path = path.replace('/', '\\') + messages_history = [ ] + + def sendCreate(tid): + m = SMBMessage(ComCreateDirectoryRequest(path)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, createCB, errback) + messages_history.append(m) + + def createCB(create_message, **kwargs): + messages_history.append(create_message) + if not create_message.status.hasError: + callback(path) + else: + errback(OperationFailure('Failed to create directory %s on %s: Create failed' % ( path, service_name ), messages_history)) + + if service_name not in self.connected_trees: + def connectCB(connect_message, **kwargs): + messages_history.append(connect_message) + if not connect_message.status.hasError: + self.connected_trees[service_name] = connect_message.tid + sendCreate(connect_message.tid) + else: + errback(OperationFailure('Failed to create directory %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + + m = SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, connectCB, errback, path = service_name) + messages_history.append(m) + else: + sendCreate(self.connected_trees[service_name]) + + def _deleteDirectory_SMB1(self, service_name, path, callback, errback, timeout = 30): + if not self.has_authenticated: + raise NotReadyError('SMB connection not authenticated') + + path = path.replace('/', '\\') + messages_history = [ ] + + def sendDelete(tid): + m = SMBMessage(ComDeleteDirectoryRequest(path)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, deleteCB, errback) + messages_history.append(m) + + def deleteCB(delete_message, **kwargs): + messages_history.append(delete_message) + if not delete_message.status.hasError: + callback(path) + else: + errback(OperationFailure('Failed to delete directory %s on %s: Delete failed' % ( path, service_name ), messages_history)) + + if service_name not in self.connected_trees: + def connectCB(connect_message, **kwargs): + messages_history.append(connect_message) + if not connect_message.status.hasError: + self.connected_trees[service_name] = connect_message.tid + sendDelete(connect_message.tid) + else: + errback(OperationFailure('Failed to delete directory %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) + + m = SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, connectCB, errback, path = service_name) + messages_history.append(m) + else: + sendDelete(self.connected_trees[service_name]) + + def _rename_SMB1(self, service_name, old_path, new_path, callback, errback, timeout = 30): + if not self.has_authenticated: + raise NotReadyError('SMB connection not authenticated') + + new_path = new_path.replace('/', '\\') + old_path = old_path.replace('/', '\\') + messages_history = [ ] + + def sendRename(tid): + m = SMBMessage(ComRenameRequest(old_path = old_path, + new_path = new_path, + search_attributes = SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, renameCB, errback) + messages_history.append(m) + + def renameCB(rename_message, **kwargs): + messages_history.append(rename_message) + if not rename_message.status.hasError: + callback(( old_path, new_path )) # Note that this is a tuple of 2-elements + else: + errback(OperationFailure('Failed to rename %s on %s: Rename failed' % ( old_path, service_name ), messages_history)) + + if service_name not in self.connected_trees: + def connectCB(connect_message, **kwargs): + messages_history.append(connect_message) + if not connect_message.status.hasError: + self.connected_trees[service_name] = connect_message.tid + sendRename(connect_message.tid) + else: + errback(OperationFailure('Failed to rename %s on %s: Unable to connect to shared device' % ( old_path, service_name ), messages_history)) + + m = SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, connectCB, errback, path = service_name) + messages_history.append(m) + else: + sendRename(self.connected_trees[service_name]) + + def _listSnapshots_SMB1(self, service_name, path, callback, errback, timeout = 30): + if not self.has_authenticated: + raise NotReadyError('SMB connection not authenticated') + + expiry_time = time.time() + timeout + path = path.replace('/', '\\') + if not path.endswith('\\'): + path += '\\' + messages_history = [ ] + results = [ ] + + def sendOpen(tid): + m = SMBMessage(ComOpenAndxRequest(filename = path, + access_mode = 0x0040, # Sharing mode: Deny nothing to others + open_mode = 0x0001, # Failed if file does not exist + search_attributes = 0, + timeout = timeout * 1000)) + m.tid = tid + self._sendSMBMessage(m) + self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, openCB, errback) + messages_history.append(m) + + def openCB(open_message, **kwargs): + messages_history.append(open_message) + if not open_message.status.hasError: + sendEnumSnapshots(open_message.tid, open_message.payload.fid) + else: + errback(OperationFailure('Failed to list snapshots %s on %s: Unable to open path' % ( path, service_name ), messages_history)) + + def sendEnumSnapshots(tid, fid): + # [MS-CIFS]: 2.2.7.2 + # [MS-SMB]: 2.2.7.2.1 + setup_bytes = struct.pack('`. + + If you encounter *SharedFile* instance where its short_name attribute is empty but the filename attribute contains a short name which does not correspond + to any files/folders on your remote shared device, it could be that the original filename on the file/folder entry on the shared device contains + one of these prohibited characters: "\/[]:+|<>=;?,* (see [MS-CIFS]: 2.2.1.1.1 for more details). + + The following attributes are available: + + * create_time : Float value in number of seconds since 1970-01-01 00:00:00 to the time of creation of this file resource on the remote server + * last_access_time : Float value in number of seconds since 1970-01-01 00:00:00 to the time of last access of this file resource on the remote server + * last_write_time : Float value in number of seconds since 1970-01-01 00:00:00 to the time of last modification of this file resource on the remote server + * last_attr_change_time : Float value in number of seconds since 1970-01-01 00:00:00 to the time of last attribute change of this file resource on the remote server + * file_size : File size in number of bytes + * alloc_size : Total number of bytes allocated to store this file + * file_attributes : A SMB_EXT_FILE_ATTR integer value. See [MS-CIFS]: 2.2.1.2.3. You can perform bit-wise tests to determine the status of the file using the ATTR_xxx constants in smb_constants.py. + * short_name : Unicode string containing the short name of this file (usually in 8.3 notation) + * filename : Unicode string containing the long filename of this file. Each OS has a limit to the length of this file name. On Windows, it is 256 characters. + * file_id : Long value representing the file reference number for the file. If the remote system does not support this field, this field will be None or 0. See [MS-FSCC]: 2.4.17 + """ + + def __init__(self, create_time, last_access_time, last_write_time, last_attr_change_time, file_size, alloc_size, file_attributes, short_name, filename, file_id=None): + self.create_time = create_time #: Float value in number of seconds since 1970-01-01 00:00:00 to the time of creation of this file resource on the remote server + self.last_access_time = last_access_time #: Float value in number of seconds since 1970-01-01 00:00:00 to the time of last access of this file resource on the remote server + self.last_write_time = last_write_time #: Float value in number of seconds since 1970-01-01 00:00:00 to the time of last modification of this file resource on the remote server + self.last_attr_change_time = last_attr_change_time #: Float value in number of seconds since 1970-01-01 00:00:00 to the time of last attribute change of this file resource on the remote server + self.file_size = file_size #: File size in number of bytes + self.alloc_size = alloc_size #: Total number of bytes allocated to store this file + self.file_attributes = file_attributes #: A SMB_EXT_FILE_ATTR integer value. See [MS-CIFS]: 2.2.1.2.3. You can perform bit-wise tests to determine the status of the file using the ATTR_xxx constants in smb_constants.py. + self.short_name = short_name #: Unicode string containing the short name of this file (usually in 8.3 notation) + self.filename = filename #: Unicode string containing the long filename of this file. Each OS has a limit to the length of this file name. On Windows, it is 256 characters. + self.file_id = file_id #: Long value representing the file reference number for the file. If the remote system does not support this field, this field will be None or 0. See [MS-FSCC]: 2.4.17 + + @property + def isDirectory(self): + """A convenience property to return True if this file resource is a directory on the remote server""" + return bool(self.file_attributes & ATTR_DIRECTORY) + + @property + def isReadOnly(self): + """A convenient property to return True if this file resource is read-only on the remote server""" + return bool(self.file_attributes & ATTR_READONLY) + + @property + def isNormal(self): + """ + A convenient property to return True if this is a normal file. + + Note that pysmb defines a normal file as a file entry that is not read-only, not hidden, not system, not archive and not a directory. + It ignores other attributes like compression, indexed, sparse, temporary and encryption. + """ + return (self.file_attributes==ATTR_NORMAL) or ((self.file_attributes & 0xff)==0) + + def __unicode__(self): + return 'Shared file: %s (FileSize:%d bytes, isDirectory:%s)' % ( self.filename, self.file_size, self.isDirectory ) + + +class _PendingRequest: + + def __init__(self, mid, expiry_time, callback, errback, **kwargs): + self.mid = mid + self.expiry_time = expiry_time + self.callback = callback + self.errback = errback + self.kwargs = kwargs diff --git a/lib/sambatools/python3/smb/ntlm.py b/lib/sambatools/python3/smb/ntlm.py new file mode 100644 index 00000000..d364f983 --- /dev/null +++ b/lib/sambatools/python3/smb/ntlm.py @@ -0,0 +1,254 @@ + +import types, hmac, binascii, struct, random, string +from .utils.rc4 import RC4_encrypt +from .utils.pyDes import des + +try: + import hashlib + hashlib.new('md4') + + def MD4(): return hashlib.new('md4') +except ( ImportError, ValueError ): + from .utils.md4 import MD4 + +try: + import hashlib + def MD5(s): return hashlib.md5(s) +except ImportError: + import md5 + def MD5(s): return md5.new(s) + +################ +# NTLMv2 Methods +################ + +# The following constants are defined in accordance to [MS-NLMP]: 2.2.2.5 + +NTLM_NegotiateUnicode = 0x00000001 +NTLM_NegotiateOEM = 0x00000002 +NTLM_RequestTarget = 0x00000004 +NTLM_Unknown9 = 0x00000008 +NTLM_NegotiateSign = 0x00000010 +NTLM_NegotiateSeal = 0x00000020 +NTLM_NegotiateDatagram = 0x00000040 +NTLM_NegotiateLanManagerKey = 0x00000080 +NTLM_Unknown8 = 0x00000100 +NTLM_NegotiateNTLM = 0x00000200 +NTLM_NegotiateNTOnly = 0x00000400 +NTLM_Anonymous = 0x00000800 +NTLM_NegotiateOemDomainSupplied = 0x00001000 +NTLM_NegotiateOemWorkstationSupplied = 0x00002000 +NTLM_Unknown6 = 0x00004000 +NTLM_NegotiateAlwaysSign = 0x00008000 +NTLM_TargetTypeDomain = 0x00010000 +NTLM_TargetTypeServer = 0x00020000 +NTLM_TargetTypeShare = 0x00040000 +NTLM_NegotiateExtendedSecurity = 0x00080000 +NTLM_NegotiateIdentify = 0x00100000 +NTLM_Unknown5 = 0x00200000 +NTLM_RequestNonNTSessionKey = 0x00400000 +NTLM_NegotiateTargetInfo = 0x00800000 +NTLM_Unknown4 = 0x01000000 +NTLM_NegotiateVersion = 0x02000000 +NTLM_Unknown3 = 0x04000000 +NTLM_Unknown2 = 0x08000000 +NTLM_Unknown1 = 0x10000000 +NTLM_Negotiate128 = 0x20000000 +NTLM_NegotiateKeyExchange = 0x40000000 +NTLM_Negotiate56 = 0x80000000 + +NTLM_FLAGS = NTLM_NegotiateUnicode | \ + NTLM_RequestTarget | \ + NTLM_NegotiateSign | \ + NTLM_NegotiateNTLM | \ + NTLM_NegotiateAlwaysSign | \ + NTLM_NegotiateExtendedSecurity | \ + NTLM_NegotiateTargetInfo | \ + NTLM_NegotiateVersion | \ + NTLM_Negotiate128 | \ + NTLM_NegotiateKeyExchange + +def generateNegotiateMessage(): + """ + References: + =========== + - [MS-NLMP]: 2.2.1.1 + """ + s = struct.pack('<8sII8s8s8s', + b'NTLMSSP\0', 0x01, NTLM_FLAGS, + b'\0' * 8, # Domain + b'\0' * 8, # Workstation + b'\x06\x00\x72\x17\x00\x00\x00\x0F') # Version [MS-NLMP]: 2.2.2.10 + return s + + +def generateAuthenticateMessage(challenge_flags, nt_response, lm_response, request_session_key, user, domain = 'WORKGROUP', workstation = 'LOCALHOST'): + """ + References: + =========== + - [MS-NLMP]: 2.2.1.3 + """ + FORMAT = '<8sIHHIHHIHHIHHIHHIHHII' + FORMAT_SIZE = struct.calcsize(FORMAT) + + # [MS-NLMP]: 3.1.5.1.2 + # http://grutz.jingojango.net/exploits/davenport-ntlm.html + session_key = session_signing_key = request_session_key + if challenge_flags & NTLM_NegotiateKeyExchange: + session_signing_key = "".join([ random.choice(string.digits+string.ascii_letters) for _ in range(16) ]).encode('ascii') + session_key = RC4_encrypt(request_session_key, session_signing_key) + + lm_response_length = len(lm_response) + lm_response_offset = FORMAT_SIZE + nt_response_length = len(nt_response) + nt_response_offset = lm_response_offset + lm_response_length + domain_unicode = domain.encode('UTF-16LE') + domain_length = len(domain_unicode) + domain_offset = nt_response_offset + nt_response_length + + padding = b'' + if domain_offset % 2 != 0: + padding = b'\0' + domain_offset += 1 + + user_unicode = user.encode('UTF-16LE') + user_length = len(user_unicode) + user_offset = domain_offset + domain_length + workstation_unicode = workstation.encode('UTF-16LE') + workstation_length = len(workstation_unicode) + workstation_offset = user_offset + user_length + session_key_length = len(session_key) + session_key_offset = workstation_offset + workstation_length + + auth_flags = challenge_flags + auth_flags &= ~NTLM_NegotiateVersion + + s = struct.pack(FORMAT, + b'NTLMSSP\0', 0x03, + lm_response_length, lm_response_length, lm_response_offset, + nt_response_length, nt_response_length, nt_response_offset, + domain_length, domain_length, domain_offset, + user_length, user_length, user_offset, + workstation_length, workstation_length, workstation_offset, + session_key_length, session_key_length, session_key_offset, + auth_flags) + + return s + lm_response + nt_response + padding + domain_unicode + user_unicode + workstation_unicode + session_key, session_signing_key + + +def decodeChallengeMessage(ntlm_data): + """ + References: + =========== + - [MS-NLMP]: 2.2.1.2 + - [MS-NLMP]: 2.2.2.1 (AV_PAIR) + """ + FORMAT = '<8sIHHII8s8sHHI' + FORMAT_SIZE = struct.calcsize(FORMAT) + + signature, message_type, \ + targetname_len, targetname_maxlen, targetname_offset, \ + flags, challenge, _, \ + targetinfo_len, targetinfo_maxlen, targetinfo_offset, \ + = struct.unpack(FORMAT, bytes(ntlm_data[:FORMAT_SIZE])) + + assert signature == b'NTLMSSP\0' + assert message_type == 0x02 + + return challenge, flags, bytes(ntlm_data[targetinfo_offset:targetinfo_offset+targetinfo_len]) + + +def generateChallengeResponseV2(password, user, server_challenge, server_info, domain = '', client_challenge = None): + client_timestamp = b'\0' * 8 + + if not client_challenge: + client_challenge = bytes([ random.getrandbits(8) for i in range(0, 8) ]) + + assert len(client_challenge) == 8 + + d = MD4() + d.update(password.encode('UTF-16LE')) + ntlm_hash = d.digest() # The NT password hash + response_key = hmac.new(ntlm_hash, (user.upper() + domain).encode('UTF-16LE'), 'md5').digest() # The NTLMv2 password hash. In [MS-NLMP], this is the result of NTOWFv2 and LMOWFv2 functions + temp = b'\x01\x01' + b'\0'*6 + client_timestamp + client_challenge + b'\0'*4 + server_info + ntproofstr = hmac.new(response_key, server_challenge + temp, 'md5').digest() + + nt_challenge_response = ntproofstr + temp + lm_challenge_response = hmac.new(response_key, server_challenge + client_challenge, 'md5').digest() + client_challenge + session_key = hmac.new(response_key, ntproofstr, 'md5').digest() + + return nt_challenge_response, lm_challenge_response, session_key + + +################ +# NTLMv1 Methods +################ + +def expandDesKey(key): + """Expand the key from a 7-byte password key into a 8-byte DES key""" + s = [ ((key[0] >> 1) & 0x7f) << 1, + ((key[0] & 0x01) << 6 | ((key[1] >> 2) & 0x3f)) << 1, + ((key[1] & 0x03) << 5 | ((key[2] >> 3) & 0x1f)) << 1, + ((key[2] & 0x07) << 4 | ((key[3] >> 4) & 0x0f)) << 1, + ((key[3] & 0x0f) << 3 | ((key[4] >> 5) & 0x07)) << 1, + ((key[4] & 0x1f) << 2 | ((key[5] >> 6) & 0x03)) << 1, + ((key[5] & 0x3f) << 1 | ((key[6] >> 7) & 0x01)) << 1, + (key[6] & 0x7f) << 1 + ] + return bytes(s) + + +def DESL(K, D): + """ + References: + =========== + - http://ubiqx.org/cifs/SMB.html (2.8.3.4) + - [MS-NLMP]: Section 6 + """ + d1 = des(expandDesKey(K[0:7])) + d2 = des(expandDesKey(K[7:14])) + d3 = des(expandDesKey(K[14:16] + b'\0' * 5)) + return d1.encrypt(D) + d2.encrypt(D) + d3.encrypt(D) + + +def generateChallengeResponseV1(password, server_challenge, has_extended_security = False, client_challenge = None): + """ + Generate a NTLMv1 response + + @param password: User password string + @param server_challange: A 8-byte challenge string sent from the server + @param has_extended_security: A boolean value indicating whether NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is enabled in the NTLM negFlag + @param client_challenge: A 8-byte string representing client challenge. If None, it will be generated randomly if needed by the response generation + @return: a tuple of ( NT challenge response string, LM challenge response string ) + + References: + =========== + - http://ubiqx.org/cifs/SMB.html (2.8.3.3 and 2.8.3.4) + - [MS-NLMP]: 3.3.1 + """ + _password = bytes((password.upper() + '\0' * 14)[:14], 'ascii') + d1 = des(expandDesKey(_password[:7])) + d2 = des(expandDesKey(_password[7:])) + lm_response_key = d1.encrypt(b"KGS!@#$%") + d2.encrypt(b"KGS!@#$%") # LM password hash. In [MS-NLMP], this is the result of LMOWFv1 function + + d = MD4() + d.update(password.encode('UTF-16LE')) + nt_response_key = d.digest() # In [MS-NLMP], this is the result of NTOWFv1 function + + if has_extended_security: + if not client_challenge: + client_challenge = bytes([ random.getrandbits(8) for i in range(0, 8) ]) + + assert len(client_challenge) == 8 + + lm_challenge_response = client_challenge + b'\0'*16 + nt_challenge_response = DESL(nt_response_key, MD5(server_challenge + client_challenge).digest()[0:8]) + else: + nt_challenge_response = DESL(nt_response_key, server_challenge) # The result after DESL is the NT response + lm_challenge_response = DESL(lm_response_key, server_challenge) # The result after DESL is the LM response + + d = MD4() + d.update(nt_response_key) + session_key = d.digest() + + return nt_challenge_response, lm_challenge_response, session_key diff --git a/lib/sambatools/python3/smb/security_descriptors.py b/lib/sambatools/python3/smb/security_descriptors.py new file mode 100644 index 00000000..44a678f3 --- /dev/null +++ b/lib/sambatools/python3/smb/security_descriptors.py @@ -0,0 +1,367 @@ +""" +This module implements security descriptors, and the partial structures +used in them, as specified in [MS-DTYP]. +""" + +import struct + + +# Security descriptor control flags +# [MS-DTYP]: 2.4.6 +SECURITY_DESCRIPTOR_OWNER_DEFAULTED = 0x0001 +SECURITY_DESCRIPTOR_GROUP_DEFAULTED = 0x0002 +SECURITY_DESCRIPTOR_DACL_PRESENT = 0x0004 +SECURITY_DESCRIPTOR_DACL_DEFAULTED = 0x0008 +SECURITY_DESCRIPTOR_SACL_PRESENT = 0x0010 +SECURITY_DESCRIPTOR_SACL_DEFAULTED = 0x0020 +SECURITY_DESCRIPTOR_SERVER_SECURITY = 0x0040 +SECURITY_DESCRIPTOR_DACL_TRUSTED = 0x0080 +SECURITY_DESCRIPTOR_DACL_COMPUTED_INHERITANCE_REQUIRED = 0x0100 +SECURITY_DESCRIPTOR_SACL_COMPUTED_INHERITANCE_REQUIRED = 0x0200 +SECURITY_DESCRIPTOR_DACL_AUTO_INHERITED = 0x0400 +SECURITY_DESCRIPTOR_SACL_AUTO_INHERITED = 0x0800 +SECURITY_DESCRIPTOR_DACL_PROTECTED = 0x1000 +SECURITY_DESCRIPTOR_SACL_PROTECTED = 0x2000 +SECURITY_DESCRIPTOR_RM_CONTROL_VALID = 0x4000 +SECURITY_DESCRIPTOR_SELF_RELATIVE = 0x8000 + +# ACE types +# [MS-DTYP]: 2.4.4.1 +ACE_TYPE_ACCESS_ALLOWED = 0x00 +ACE_TYPE_ACCESS_DENIED = 0x01 +ACE_TYPE_SYSTEM_AUDIT = 0x02 +ACE_TYPE_SYSTEM_ALARM = 0x03 +ACE_TYPE_ACCESS_ALLOWED_COMPOUND = 0x04 +ACE_TYPE_ACCESS_ALLOWED_OBJECT = 0x05 +ACE_TYPE_ACCESS_DENIED_OBJECT = 0x06 +ACE_TYPE_SYSTEM_AUDIT_OBJECT = 0x07 +ACE_TYPE_SYSTEM_ALARM_OBJECT = 0x08 +ACE_TYPE_ACCESS_ALLOWED_CALLBACK = 0x09 +ACE_TYPE_ACCESS_DENIED_CALLBACK = 0x0A +ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT = 0x0B +ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT = 0x0C +ACE_TYPE_SYSTEM_AUDIT_CALLBACK = 0x0D +ACE_TYPE_SYSTEM_ALARM_CALLBACK = 0x0E +ACE_TYPE_SYSTEM_AUDIT_CALLBACK_OBJECT = 0x0F +ACE_TYPE_SYSTEM_ALARM_CALLBACK_OBJECT = 0x10 +ACE_TYPE_SYSTEM_MANDATORY_LABEL = 0x11 +ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE = 0x12 +ACE_TYPE_SYSTEM_SCOPED_POLICY_ID = 0x13 + +# ACE flags +# [MS-DTYP]: 2.4.4.1 +ACE_FLAG_OBJECT_INHERIT = 0x01 +ACE_FLAG_CONTAINER_INHERIT = 0x02 +ACE_FLAG_NO_PROPAGATE_INHERIT = 0x04 +ACE_FLAG_INHERIT_ONLY = 0x08 +ACE_FLAG_INHERITED = 0x10 +ACE_FLAG_SUCCESSFUL_ACCESS = 0x40 +ACE_FLAG_FAILED_ACCESS = 0x80 + +# Pre-defined well-known SIDs +# [MS-DTYP]: 2.4.2.4 +SID_NULL = "S-1-0-0" +SID_EVERYONE = "S-1-1-0" +SID_LOCAL = "S-1-2-0" +SID_CONSOLE_LOGON = "S-1-2-1" +SID_CREATOR_OWNER = "S-1-3-0" +SID_CREATOR_GROUP = "S-1-3-1" +SID_OWNER_SERVER = "S-1-3-2" +SID_GROUP_SERVER = "S-1-3-3" +SID_OWNER_RIGHTS = "S-1-3-4" +SID_NT_AUTHORITY = "S-1-5" +SID_DIALUP = "S-1-5-1" +SID_NETWORK = "S-1-5-2" +SID_BATCH = "S-1-5-3" +SID_INTERACTIVE = "S-1-5-4" +SID_SERVICE = "S-1-5-6" +SID_ANONYMOUS = "S-1-5-7" +SID_PROXY = "S-1-5-8" +SID_ENTERPRISE_DOMAIN_CONTROLLERS = "S-1-5-9" +SID_PRINCIPAL_SELF = "S-1-5-10" +SID_AUTHENTICATED_USERS = "S-1-5-11" +SID_RESTRICTED_CODE = "S-1-5-12" +SID_TERMINAL_SERVER_USER = "S-1-5-13" +SID_REMOTE_INTERACTIVE_LOGON = "S-1-5-14" +SID_THIS_ORGANIZATION = "S-1-5-15" +SID_IUSR = "S-1-5-17" +SID_LOCAL_SYSTEM = "S-1-5-18" +SID_LOCAL_SERVICE = "S-1-5-19" +SID_NETWORK_SERVICE = "S-1-5-20" +SID_COMPOUNDED_AUTHENTICATION = "S-1-5-21-0-0-0-496" +SID_CLAIMS_VALID = "S-1-5-21-0-0-0-497" +SID_BUILTIN_ADMINISTRATORS = "S-1-5-32-544" +SID_BUILTIN_USERS = "S-1-5-32-545" +SID_BUILTIN_GUESTS = "S-1-5-32-546" +SID_POWER_USERS = "S-1-5-32-547" +SID_ACCOUNT_OPERATORS = "S-1-5-32-548" +SID_SERVER_OPERATORS = "S-1-5-32-549" +SID_PRINTER_OPERATORS = "S-1-5-32-550" +SID_BACKUP_OPERATORS = "S-1-5-32-551" +SID_REPLICATOR = "S-1-5-32-552" +SID_ALIAS_PREW2KCOMPACC = "S-1-5-32-554" +SID_REMOTE_DESKTOP = "S-1-5-32-555" +SID_NETWORK_CONFIGURATION_OPS = "S-1-5-32-556" +SID_INCOMING_FOREST_TRUST_BUILDERS = "S-1-5-32-557" +SID_PERFMON_USERS = "S-1-5-32-558" +SID_PERFLOG_USERS = "S-1-5-32-559" +SID_WINDOWS_AUTHORIZATION_ACCESS_GROUP = "S-1-5-32-560" +SID_TERMINAL_SERVER_LICENSE_SERVERS = "S-1-5-32-561" +SID_DISTRIBUTED_COM_USERS = "S-1-5-32-562" +SID_IIS_IUSRS = "S-1-5-32-568" +SID_CRYPTOGRAPHIC_OPERATORS = "S-1-5-32-569" +SID_EVENT_LOG_READERS = "S-1-5-32-573" +SID_CERTIFICATE_SERVICE_DCOM_ACCESS = "S-1-5-32-574" +SID_RDS_REMOTE_ACCESS_SERVERS = "S-1-5-32-575" +SID_RDS_ENDPOINT_SERVERS = "S-1-5-32-576" +SID_RDS_MANAGEMENT_SERVERS = "S-1-5-32-577" +SID_HYPER_V_ADMINS = "S-1-5-32-578" +SID_ACCESS_CONTROL_ASSISTANCE_OPS = "S-1-5-32-579" +SID_REMOTE_MANAGEMENT_USERS = "S-1-5-32-580" +SID_WRITE_RESTRICTED_CODE = "S-1-5-33" +SID_NTLM_AUTHENTICATION = "S-1-5-64-10" +SID_SCHANNEL_AUTHENTICATION = "S-1-5-64-14" +SID_DIGEST_AUTHENTICATION = "S-1-5-64-21" +SID_THIS_ORGANIZATION_CERTIFICATE = "S-1-5-65-1" +SID_NT_SERVICE = "S-1-5-80" +SID_USER_MODE_DRIVERS = "S-1-5-84-0-0-0-0-0" +SID_LOCAL_ACCOUNT = "S-1-5-113" +SID_LOCAL_ACCOUNT_AND_MEMBER_OF_ADMINISTRATORS_GROUP = "S-1-5-114" +SID_OTHER_ORGANIZATION = "S-1-5-1000" +SID_ALL_APP_PACKAGES = "S-1-15-2-1" +SID_ML_UNTRUSTED = "S-1-16-0" +SID_ML_LOW = "S-1-16-4096" +SID_ML_MEDIUM = "S-1-16-8192" +SID_ML_MEDIUM_PLUS = "S-1-16-8448" +SID_ML_HIGH = "S-1-16-12288" +SID_ML_SYSTEM = "S-1-16-16384" +SID_ML_PROTECTED_PROCESS = "S-1-16-20480" +SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY = "S-1-18-1" +SID_SERVICE_ASSERTED_IDENTITY = "S-1-18-2" +SID_FRESH_PUBLIC_KEY_IDENTITY = "S-1-18-3" +SID_KEY_TRUST_IDENTITY = "S-1-18-4" +SID_KEY_PROPERTY_MFA = "S-1-18-5" +SID_KEY_PROPERTY_ATTESTATION = "S-1-18-6" + + +class SID(object): + """ + A Windows security identifier. Represents a single principal, such a + user or a group, as a sequence of numbers consisting of the revision, + identifier authority, and a variable-length list of subauthorities. + + See [MS-DTYP]: 2.4.2 + """ + def __init__(self, revision, identifier_authority, subauthorities): + #: Revision, should always be 1. + self.revision = revision + #: An integer representing the identifier authority. + self.identifier_authority = identifier_authority + #: A list of integers representing all subauthorities. + self.subauthorities = subauthorities + + def __str__(self): + """ + String representation, as specified in [MS-DTYP]: 2.4.2.1 + """ + if self.identifier_authority >= 2**32: + id_auth = '%#x' % (self.identifier_authority,) + else: + id_auth = self.identifier_authority + auths = [self.revision, id_auth] + self.subauthorities + return 'S-' + '-'.join(str(subauth) for subauth in auths) + + def __repr__(self): + return 'SID(%r)' % (str(self),) + + @classmethod + def from_bytes(cls, data, return_tail=False): + revision, subauth_count = struct.unpack('Q', b'\x00\x00' + data[2:8])[0] + subauth_data = data[8:] + subauthorities = [struct.unpack('= size + + body = data[header_size:size] + additional_data = {} + + # In all ACE types, the mask immediately follows the header. + mask = struct.unpack('= size + + for i in range(count): + ace_size = struct.unpack(''), os.linesep )) + b.write('Status: 0x%08X %s' % ( self.status, os.linesep )) + b.write('Flags: 0x%02X %s' % ( self.flags, os.linesep )) + b.write('PID: %d %s' % ( self.pid, os.linesep )) + b.write('MID: %d %s' % ( self.mid, os.linesep )) + b.write('TID: %d %s' % ( self.tid, os.linesep )) + b.write('Data: %d bytes %s%s %s' % ( len(self.data), os.linesep, str(binascii.hexlify(self.data)), os.linesep )) + return b.getvalue() + + def reset(self): + self.raw_data = b'' + self.command = 0 + self.status = 0 + self.flags = 0 + + self.next_command_offset = 0 + self.mid = 0 + self.session_id = 0 + self.signature = b'\0'*16 + self.payload = None + self.data = b'' + + # For async SMB2 message + self.async_id = 0 + + # For sync SMB2 message + self.pid = 0 + self.tid = 0 + + # Not used in this class. Maintained for compatibility with SMBMessage class + self.flags2 = 0 + self.uid = 0 + self.security = 0 + self.parameters_data = b'' + + def encode(self): + """ + Encode this SMB2 message into a series of bytes suitable to be embedded with a NetBIOS session message. + AssertionError will be raised if this SMB message has not been initialized with a Payload instance + + @return: a string containing the encoded SMB2 message + """ + assert self.payload + + self.pid = os.getpid() + self.payload.prepare(self) + + headers_data = struct.pack(self.HEADER_STRUCT_FORMAT, + b'\xFESMB', self.HEADER_SIZE, 0, self.status, self.command, 0, self.flags) + \ + struct.pack(self.SYNC_HEADER_STRUCT_FORMAT, self.next_command_offset, self.mid, self.pid, self.tid, self.session_id, self.signature) + return headers_data + self.data + + def decode(self, buf): + """ + Decodes the SMB message in buf. + All fields of the SMB2Message object will be reset to default values before decoding. + On errors, do not assume that the fields will be reinstated back to what they are before + this method is invoked. + + References + ========== + - [MS-SMB2]: 2.2.1 + + @param buf: data containing one complete SMB2 message + @type buf: string + @return: a positive integer indicating the number of bytes used in buf to decode this SMB message + @raise ProtocolError: raised when decoding fails + """ + buf_len = len(buf) + if buf_len < 64: # All SMB2 headers must be at least 64 bytes. [MS-SMB2]: 2.2.1.1, 2.2.1.2 + raise ProtocolError('Not enough data to decode SMB2 header', buf) + + self.reset() + + protocol, struct_size, self.credit_charge, self.status, \ + self.command, self.credit_re, self.flags = struct.unpack(self.HEADER_STRUCT_FORMAT, buf[:self.HEADER_STRUCT_SIZE]) + + if protocol != b'\xFESMB': + raise ProtocolError('Invalid 4-byte SMB2 protocol field', buf) + + if struct_size != self.HEADER_SIZE: + raise ProtocolError('Invalid SMB2 header structure size') + + if self.isAsync: + if buf_len < self.HEADER_STRUCT_SIZE+self.ASYNC_HEADER_STRUCT_SIZE: + raise ProtocolError('Not enough data to decode SMB2 header', buf) + + self.next_command_offset, self.mid, self.async_id, self.session_id, \ + self.signature = struct.unpack(self.ASYNC_HEADER_STRUCT_FORMAT, + buf[self.HEADER_STRUCT_SIZE:self.HEADER_STRUCT_SIZE+self.ASYNC_HEADER_STRUCT_SIZE]) + else: + if buf_len < self.HEADER_STRUCT_SIZE+self.SYNC_HEADER_STRUCT_SIZE: + raise ProtocolError('Not enough data to decode SMB2 header', buf) + + self.next_command_offset, self.mid, self.pid, self.tid, self.session_id, \ + self.signature = struct.unpack(self.SYNC_HEADER_STRUCT_FORMAT, + buf[self.HEADER_STRUCT_SIZE:self.HEADER_STRUCT_SIZE+self.SYNC_HEADER_STRUCT_SIZE]) + + if self.next_command_offset > 0: + self.raw_data = buf[:self.next_command_offset] + self.data = buf[self.HEADER_SIZE:self.next_command_offset] + else: + self.raw_data = buf + self.data = buf[self.HEADER_SIZE:] + + self._decodeCommand() + if self.payload: + self.payload.decode(self) + + return len(self.raw_data) + + def _decodeCommand(self): + if self.command == SMB2_COM_READ: + self.payload = SMB2ReadResponse() + elif self.command == SMB2_COM_WRITE: + self.payload = SMB2WriteResponse() + elif self.command == SMB2_COM_QUERY_DIRECTORY: + self.payload = SMB2QueryDirectoryResponse() + elif self.command == SMB2_COM_CREATE: + self.payload = SMB2CreateResponse() + elif self.command == SMB2_COM_CLOSE: + self.payload = SMB2CloseResponse() + elif self.command == SMB2_COM_QUERY_INFO: + self.payload = SMB2QueryInfoResponse() + elif self.command == SMB2_COM_SET_INFO: + self.payload = SMB2SetInfoResponse() + elif self.command == SMB2_COM_IOCTL: + self.payload = SMB2IoctlResponse() + elif self.command == SMB2_COM_TREE_CONNECT: + self.payload = SMB2TreeConnectResponse() + elif self.command == SMB2_COM_SESSION_SETUP: + self.payload = SMB2SessionSetupResponse() + elif self.command == SMB2_COM_NEGOTIATE: + self.payload = SMB2NegotiateResponse() + elif self.command == SMB2_COM_ECHO: + self.payload = SMB2EchoResponse() + + @property + def isAsync(self): + return bool(self.flags & SMB2_FLAGS_ASYNC_COMMAND) + + @property + def isReply(self): + return bool(self.flags & SMB2_FLAGS_SERVER_TO_REDIR) + + +class Structure: + + def initMessage(self, message): + pass + + def prepare(self, message): + raise NotImplementedError + + def decode(self, message): + raise NotImplementedError + + +class SMB2NegotiateResponse(Structure): + """ + Contains information on the SMB2_NEGOTIATE response from server + + After calling the decode method, each instance will contain the following attributes, + - security_mode (integer) + - dialect_revision (integer) + - server_guid (string) + - max_transact_size (integer) + - max_read_size (integer) + - max_write_size (integer) + - system_time (long) + - server_start_time (long) + - security_blob (string) + + References: + =========== + - [MS-SMB2]: 2.2.4 + """ + + STRUCTURE_FORMAT = " 0 # SMB2_SESSION_FLAG_IS_GUEST + + @property + def isAnonymousSession(self): + return (self.session_flags & 0x0002) > 0 # SMB2_SESSION_FLAG_IS_NULL + + def decode(self, message): + assert message.command == SMB2_COM_SESSION_SETUP + + struct_size, self.session_flags, security_blob_offset, security_blob_len \ + = struct.unpack(self.STRUCTURE_FORMAT, message.raw_data[SMB2Message.HEADER_SIZE:SMB2Message.HEADER_SIZE+self.STRUCTURE_SIZE]) + + self.security_blob = message.raw_data[security_blob_offset:security_blob_offset+security_blob_len] + + +class SMB2TreeConnectRequest(Structure): + """ + References: + =========== + - [MS-SMB2]: 2.2.9 + """ + + STRUCTURE_FORMAT = " 0: + self.in_data = message.raw_data[input_offset:input_offset+input_len] + else: + self.in_data = b'' + + if output_len > 0: + self.out_data = message.raw_data[output_offset:output_offset+output_len] + else: + self.out_data = b'' + + +class SMB2CloseRequest(Structure): + """ + References: + =========== + - [MS-SMB2]: 2.2.15 + """ + + STRUCTURE_FORMAT = "> 24, self.internal_value & 0xFFFF ) + + @property + def hasError(self): + return self.internal_value != 0 + + +class SMBMessage: + + HEADER_STRUCT_FORMAT = "<4sBIBHHQxxHHHHB" + HEADER_STRUCT_SIZE = struct.calcsize(HEADER_STRUCT_FORMAT) + + log = logging.getLogger('SMB.SMBMessage') + protocol = 1 + + def __init__(self, payload = None): + self.reset() + if payload: + self.payload = payload + self.payload.initMessage(self) + + def __str__(self): + b = StringIO() + b.write('Command: 0x%02X (%s) %s' % ( self.command, SMB_COMMAND_NAMES.get(self.command, ''), os.linesep )) + b.write('Status: %s %s' % ( str(self.status), os.linesep )) + b.write('Flags: 0x%02X %s' % ( self.flags, os.linesep )) + b.write('Flags2: 0x%04X %s' % ( self.flags2, os.linesep )) + b.write('PID: %d %s' % ( self.pid, os.linesep )) + b.write('UID: %d %s' % ( self.uid, os.linesep )) + b.write('MID: %d %s' % ( self.mid, os.linesep )) + b.write('TID: %d %s' % ( self.tid, os.linesep )) + b.write('Security: 0x%016X %s' % ( self.security, os.linesep )) + b.write('Parameters: %d bytes %s%s %s' % ( len(self.parameters_data), os.linesep, str(binascii.hexlify(self.parameters_data)), os.linesep )) + b.write('Data: %d bytes %s%s %s' % ( len(self.data), os.linesep, str(binascii.hexlify(self.data)), os.linesep )) + return b.getvalue() + + def reset(self): + self.raw_data = b'' + self.command = 0 + self.status = SMBError() + self.flags = 0 + self.flags2 = 0 + self.pid = 0 + self.tid = 0 + self.uid = 0 + self.mid = 0 + self.security = 0 + self.parameters_data = b'' + self.data = b'' + self.payload = None + + @property + def isAsync(self): + return bool(self.flags & SMB2_FLAGS_ASYNC_COMMAND) + + @property + def isReply(self): + return bool(self.flags & SMB_FLAGS_REPLY) + + @property + def hasExtendedSecurity(self): + return bool(self.flags2 & SMB_FLAGS2_EXTENDED_SECURITY) + + def encode(self): + """ + Encode this SMB message into a series of bytes suitable to be embedded with a NetBIOS session message. + AssertionError will be raised if this SMB message has not been initialized with a Payload instance + + @return: a string containing the encoded SMB message + """ + assert self.payload + + self.pid = os.getpid() + self.payload.prepare(self) + + parameters_len = len(self.parameters_data) + assert parameters_len % 2 == 0 + + headers_data = struct.pack(self.HEADER_STRUCT_FORMAT, + b'\xFFSMB', self.command, self.status.internal_value, self.flags, + self.flags2, (self.pid >> 16) & 0xFFFF, self.security, self.tid, + self.pid & 0xFFFF, self.uid, self.mid, int(parameters_len / 2)) + return headers_data + self.parameters_data + struct.pack(' 0 and buf_len < (datalen_offset + 2 + body_len): + # Not enough data in buf to decode body + raise ProtocolError('Not enough data. Body decoding failed', buf) + + self.parameters_data = buf[offset:datalen_offset] + + if body_len > 0: + self.data = buf[datalen_offset+2:datalen_offset+2+body_len] + + self.raw_data = buf + self._decodePayload() + + return self.HEADER_STRUCT_SIZE + params_count * 2 + 2 + body_len + + def _decodePayload(self): + if self.command == SMB_COM_READ_ANDX: + self.payload = ComReadAndxResponse() + elif self.command == SMB_COM_WRITE_ANDX: + self.payload = ComWriteAndxResponse() + elif self.command == SMB_COM_TRANSACTION: + self.payload = ComTransactionResponse() + elif self.command == SMB_COM_TRANSACTION2: + self.payload = ComTransaction2Response() + elif self.command == SMB_COM_OPEN_ANDX: + self.payload = ComOpenAndxResponse() + elif self.command == SMB_COM_NT_CREATE_ANDX: + self.payload = ComNTCreateAndxResponse() + elif self.command == SMB_COM_TREE_CONNECT_ANDX: + self.payload = ComTreeConnectAndxResponse() + elif self.command == SMB_COM_ECHO: + self.payload = ComEchoResponse() + elif self.command == SMB_COM_SESSION_SETUP_ANDX: + self.payload = ComSessionSetupAndxResponse() + elif self.command == SMB_COM_NEGOTIATE: + self.payload = ComNegotiateResponse() + + if self.payload: + self.payload.decode(self) + + +class Payload: + + DEFAULT_ANDX_PARAM_HEADER = b'\xFF\x00\x00\x00' + DEFAULT_ANDX_PARAM_SIZE = 4 + + def initMessage(self, message): + # SMB_FLAGS2_UNICODE must always be enabled. Without this, almost all the Payload subclasses will need to be + # rewritten to check for OEM/Unicode strings which will be tedious. Fortunately, almost all tested CIFS services + # support SMB_FLAGS2_UNICODE by default. + assert message.payload == self + message.flags = SMB_FLAGS_CASE_INSENSITIVE | SMB_FLAGS_CANONICALIZED_PATHS + message.flags2 = SMB_FLAGS2_UNICODE | SMB_FLAGS2_NT_STATUS | SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_LONG_NAMES + + if SUPPORT_EXTENDED_SECURITY: + message.flags2 |= SMB_FLAGS2_EXTENDED_SECURITY + + def prepare(self, message): + raise NotImplementedError + + def decode(self, message): + raise NotImplementedError + + +class ComNegotiateRequest(Payload): + """ + References: + =========== + - [MS-CIFS]: 2.2.4.52.1 + - [MS-SMB]: 2.2.4.5.1 + """ + + def initMessage(self, message): + Payload.initMessage(self, message) + message.command = SMB_COM_NEGOTIATE + + def prepare(self, message): + assert message.payload == self + message.parameters_data = b'' + if SUPPORT_SMB2: + message.data = b''.join([b'\x02'+s+b'\x00' for s in DIALECTS + DIALECTS2]) + else: + message.data = b''.join([b'\x02'+s+b'\x00' for s in DIALECTS]) + + +class ComNegotiateResponse(Payload): + """ + Contains information on the SMB_COM_NEGOTIATE response from server + + After calling the decode method, each instance will contain the following attributes, + - security_mode (integer) + - max_mpx_count (integer) + - max_number_vcs (integer) + - max_buffer_size (long) + - max_raw_size (long) + - session_key (long) + - capabilities (long) + - system_time (long) + - server_time_zone (integer) + - challenge_length (integer) + + If the underlying SMB message's flag2 does not have SMB_FLAGS2_EXTENDED_SECURITY bit enabled, + then the instance will have the following additional attributes, + - challenge (string) + - domain (unicode) + + If the underlying SMB message's flags2 has SMB_FLAGS2_EXTENDED_SECURITY bit enabled, + then the instance will have the following additional attributes, + - server_guid (string) + - security_blob (string) + + References: + =========== + - [MS-SMB]: 2.2.4.5.2.1 + - [MS-CIFS]: 2.2.4.52.2 + """ + + PAYLOAD_STRUCT_FORMAT = ' 0: + if data_len >= self.challenge_length: + self.challenge = message.data[:self.challenge_length] + + s = b'' + offset = self.challenge_length + while offset < data_len: + _s = message.data[offset:offset+2] + if _s == b'\0\0': + self.domain = s.decode('UTF-16LE') + break + else: + s += _s + offset += 2 + else: + raise ProtocolError('Not enough data to decode SMB_COM_NEGOTIATE (without security extensions) Challenge field', message.raw_data, message) + else: + if data_len < 16: + raise ProtocolError('Not enough data to decode SMB_COM_NEGOTIATE (with security extensions) ServerGUID field', message.raw_data, message) + + self.server_guid = message.data[:16] + self.security_blob = message.data[16:] + + @property + def supportsExtendedSecurity(self): + return bool(self.capabilities & CAP_EXTENDED_SECURITY) + + +class ComSessionSetupAndxRequest__WithSecurityExtension(Payload): + """ + References: + =========== + - [MS-SMB]: 2.2.4.6.1 + """ + + PAYLOAD_STRUCT_FORMAT = ' 0: + params_bytes_offset = offset + offset += params_bytes_len + else: + params_bytes_offset = 0 + + padding2 = b'' + if offset % 4 != 0: + padding2 = b'\0'*(4-offset%4) + offset += (4-offset%4) + + if data_bytes_len > 0: + data_bytes_offset = offset + else: + data_bytes_offset = 0 + + message.parameters_data = \ + struct.pack(self.PAYLOAD_STRUCT_FORMAT, + self.total_params_count, + self.total_data_count, + self.max_params_count, + self.max_data_count, + self.max_setup_count, + 0x00, # Reserved1. Must be 0x00 + self.flags, + self.timeout, + 0x0000, # Reserved2. Must be 0x0000 + params_bytes_len, + params_bytes_offset, + data_bytes_len, + data_bytes_offset, + int(setup_bytes_len / 2)) + \ + self.setup_bytes + + message.data = padding0 + name + padding1 + self.params_bytes + padding2 + self.data_bytes + + +class ComTransactionResponse(Payload): + """ + Contains information about a SMB_COM_TRANSACTION response from the server + + After decoding, each instance contains the following attributes: + - total_params_count (integer) + - total_data_count (integer) + - setup_bytes (string) + - data_bytes (string) + - params_bytes (string) + + References: + =========== + - [MS-CIFS]: 2.2.4.33.2 + """ + + PAYLOAD_STRUCT_FORMAT = ' 0: + setup_bytes_len = setup_count * 2 + + if len(message.parameters_data) < self.PAYLOAD_STRUCT_SIZE + setup_bytes_len: + raise ProtocolError('Not enough data to decode SMB_COM_TRANSACTION parameters', message.raw_data, message) + + self.setup_bytes = message.parameters_data[self.PAYLOAD_STRUCT_SIZE:self.PAYLOAD_STRUCT_SIZE+setup_bytes_len] + else: + self.setup_bytes = '' + + offset = message.HEADER_STRUCT_SIZE + self.PAYLOAD_STRUCT_SIZE + setup_count * 2 + 2 # constant 2 is for the ByteCount field in the SMB header (i.e. field which indicates number of data bytes after the SMB parameters) + + if params_bytes_len > 0: + self.params_bytes = message.data[params_bytes_offset-offset:params_bytes_offset-offset+params_bytes_len] + else: + self.params_bytes = '' + + if data_bytes_len > 0: + self.data_bytes = message.data[data_bytes_offset-offset:data_bytes_offset-offset+data_bytes_len] + else: + self.data_bytes = '' + + +class ComTransaction2Request(Payload): + """ + References: + =========== + - [MS-CIFS]: 2.2.4.46.1 + """ + + PAYLOAD_STRUCT_FORMAT = 'HHHHBBHIHHHHHH' + PAYLOAD_STRUCT_SIZE = struct.calcsize(PAYLOAD_STRUCT_FORMAT) + + def __init__(self, max_params_count, max_data_count, max_setup_count, + total_params_count = 0, total_data_count = 0, + params_bytes = b'', data_bytes = b'', setup_bytes = b'', + flags = 0, timeout = 0): + self.total_params_count = total_params_count or len(params_bytes) + self.total_data_count = total_data_count or len(data_bytes) + self.max_params_count = max_params_count + self.max_data_count = max_data_count + self.max_setup_count = max_setup_count + self.flags = flags + self.timeout = timeout + self.params_bytes = params_bytes + self.data_bytes = data_bytes + self.setup_bytes = setup_bytes + + def initMessage(self, message): + Payload.initMessage(self, message) + message.command = SMB_COM_TRANSACTION2 + + def prepare(self, message): + setup_bytes_len = len(self.setup_bytes) + params_bytes_len = len(self.params_bytes) + data_bytes_len = len(self.data_bytes) + name = b'\0\0' + + padding0 = b'' + offset = message.HEADER_STRUCT_SIZE + self.PAYLOAD_STRUCT_SIZE + setup_bytes_len + 2 # constant 2 is for the ByteCount field in the SMB header (i.e. field which indicates number of data bytes after the SMB parameters) + if offset % 2 != 0: + padding0 = b'\0' + offset += 1 + + offset += 2 # For the name field + padding1 = b'' + if offset % 4 != 0: + padding1 = b'\0'*(4-offset%4) + + if params_bytes_len > 0: + params_bytes_offset = offset + offset += params_bytes_len + else: + params_bytes_offset = 0 + + padding2 = b'' + if offset % 4 != 0: + padding2 = b'\0'*(4-offset%4) + + if data_bytes_len > 0: + data_bytes_offset = offset + else: + data_bytes_offset = 0 + + message.parameters_data = \ + struct.pack(self.PAYLOAD_STRUCT_FORMAT, + self.total_params_count, + self.total_data_count, + self.max_params_count, + self.max_data_count, + self.max_setup_count, + 0x00, # Reserved1. Must be 0x00 + self.flags, + self.timeout, + 0x0000, # Reserved2. Must be 0x0000 + params_bytes_len, + params_bytes_offset, + data_bytes_len, + data_bytes_offset, + int(setup_bytes_len / 2)) + \ + self.setup_bytes + + message.data = padding0 + name + padding1 + self.params_bytes + padding2 + self.data_bytes + + +class ComTransaction2Response(Payload): + """ + Contains information about a SMB_COM_TRANSACTION2 response from the server + + After decoding, each instance contains the following attributes: + - total_params_count (integer) + - total_data_count (integer) + - setup_bytes (string) + - data_bytes (string) + - params_bytes (string) + + References: + =========== + - [MS-CIFS]: 2.2.4.46.2 + """ + + PAYLOAD_STRUCT_FORMAT = ' 0: + setup_bytes_len = setup_count * 2 + + if len(message.parameters_data) < self.PAYLOAD_STRUCT_SIZE + setup_bytes_len: + raise ProtocolError('Not enough data to decode SMB_COM_TRANSACTION parameters', message.raw_data, message) + + self.setup_bytes = message.parameters_data[self.PAYLOAD_STRUCT_SIZE:self.PAYLOAD_STRUCT_SIZE+setup_bytes_len] + else: + self.setup_bytes = '' + + offset = message.HEADER_STRUCT_SIZE + self.PAYLOAD_STRUCT_SIZE + setup_count * 2 + 2 # constant 2 is for the ByteCount field in the SMB header (i.e. field which indicates number of data bytes after the SMB parameters) + + if params_bytes_len > 0: + self.params_bytes = message.data[params_bytes_offset-offset:params_bytes_offset-offset+params_bytes_len] + else: + self.params_bytes = '' + + if data_bytes_len > 0: + self.data_bytes = message.data[data_bytes_offset-offset:data_bytes_offset-offset+data_bytes_len] + else: + self.data_bytes = '' + + +class ComCloseRequest(Payload): + """ + References: + =========== + - [MS-CIFS]: 2.2.4.5.1 + """ + + PAYLOAD_STRUCT_FORMAT = '> 32) # OffsetHigh field defined in [MS-SMB]: 2.2.4.3.1 + + message.data = b'\0' + self.data_bytes + + +class ComWriteAndxResponse(Payload): + """ + References: + =========== + - [MS-CIFS]: 2.2.4.43.2 + - [MS-SMB]: 2.2.4.3.2 + """ + + PAYLOAD_STRUCT_FORMAT = '> 32), # Note that in [MS-SMB]: 2.2.4.2.1, this field can also act as MaxCountHigh field + self.remaining, # In [MS-CIFS]: 2.2.4.42.1, this field must be set to 0x0000 + self.offset >> 32) + + message.data = b'' + + +class ComReadAndxResponse(Payload): + """ + References: + =========== + - [MS-CIFS]: 2.2.4.42.2 + - [MS-SMB]: 2.2.4.2.2 + """ + + PAYLOAD_STRUCT_FORMAT = ' 0: + params_bytes_offset = offset + else: + params_bytes_offset = 0 + + offset += params_bytes_len + padding1 = b'' + if offset % 4 != 0: + padding1 = b'\0'*(4-offset%4) + offset += (4-offset%4) + + if data_bytes_len > 0: + data_bytes_offset = offset + else: + data_bytes_offset = 0 + + message.parameters_data = \ + struct.pack(self.PAYLOAD_STRUCT_FORMAT, + self.max_setup_count, + 0x00, # Reserved1. Must be 0x00 + self.total_params_count, + self.total_data_count, + self.max_params_count, + self.max_data_count, + params_bytes_len, + params_bytes_offset, + data_bytes_len, + data_bytes_offset, + int(setup_bytes_len / 2), + self.function) + \ + self.setup_bytes + + message.data = padding0 + self.params_bytes + padding1 + self.data_bytes + + +class ComNTTransactResponse(Payload): + """ + Contains information about a SMB_COM_NT_TRANSACT response from the server + + After decoding, each instance contains the following attributes: + - total_params_count (integer) + - total_data_count (integer) + - setup_bytes (string) + - data_bytes (string) + - params_bytes (string) + + References: + =========== + - [MS-CIFS]: 2.2.4.62.2 + """ + PAYLOAD_STRUCT_FORMAT = '<3sIIIIIIIIBH' + PAYLOAD_STRUCT_SIZE = struct.calcsize(PAYLOAD_STRUCT_FORMAT) + + def decode(self, message): + assert message.command == SMB_COM_NT_TRANSACT + + if not message.status.hasError: + _, self.total_params_count, self.total_data_count, \ + params_count, params_offset, params_displ, \ + data_count, data_offset, data_displ, setup_count = struct.unpack(self.PAYLOAD_STRUCT_FORMAT, + message.parameters_data[:self.PAYLOAD_STRUCT_SIZE]) + + self.setup_bytes = message.parameters_data[self.PAYLOAD_STRUCT_SIZE:self.PAYLOAD_STRUCT_SIZE+setup_count*2] + + if params_count > 0: + params_offset -= message.HEADER_STRUCT_SIZE + self.PAYLOAD_STRUCT_SIZE + setup_count*2 + 2 + self.params_bytes = message.data[params_offset:params_offset+params_count] + else: + self.params_bytes = b'' + + if data_count > 0: + data_offset -= message.HEADER_STRUCT_SIZE + self.PAYLOAD_STRUCT_SIZE + setup_count*2 + 2 + self.data_bytes = message.data[data_offset:data_offset+data_count] + else: + self.data_bytes = b'' diff --git a/lib/sambatools/python3/smb/utils/U32.py b/lib/sambatools/python3/smb/utils/U32.py new file mode 100644 index 00000000..f08db2d4 --- /dev/null +++ b/lib/sambatools/python3/smb/utils/U32.py @@ -0,0 +1,148 @@ +# U32.py implements 32-bit unsigned int class for Python +# Version 1.0 +# Copyright (C) 2001-2002 Dmitry Rozmanov +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# e-mail: dima@xenon.spb.ru +# +#==================================================================== + +C = 0x1000000000 + +#-------------------------------------------------------------------- +def norm(n): + return n & 0xFFFFFFFF + +#==================================================================== +class U32: + v = 0 + + #-------------------------------------------------------------------- + def __init__(self, value = 0): + self.v = C + norm(abs(int(value))) + + #-------------------------------------------------------------------- + def set(self, value = 0): + self.v = C + norm(abs(int(value))) + + #-------------------------------------------------------------------- + def __repr__(self): + return hex(norm(self.v)) + + #-------------------------------------------------------------------- + def __long__(self): return int(norm(self.v)) + + #-------------------------------------------------------------------- + def __int__(self): return int(norm(self.v)) + + #-------------------------------------------------------------------- + def __chr__(self): return chr(norm(self.v)) + + #-------------------------------------------------------------------- + def __add__(self, b): + r = U32() + r.v = C + norm(self.v + b.v) + return r + + #-------------------------------------------------------------------- + def __sub__(self, b): + r = U32() + if self.v < b.v: + r.v = C + norm(0x100000000 - (b.v - self.v)) + else: r.v = C + norm(self.v - b.v) + return r + + #-------------------------------------------------------------------- + def __mul__(self, b): + r = U32() + r.v = C + norm(self.v * b.v) + return r + + #-------------------------------------------------------------------- + def __div__(self, b): + r = U32() + r.v = C + (norm(self.v) / norm(b.v)) + return r + + #-------------------------------------------------------------------- + def __mod__(self, b): + r = U32() + r.v = C + (norm(self.v) % norm(b.v)) + return r + + #-------------------------------------------------------------------- + def __neg__(self): return U32(self.v) + + #-------------------------------------------------------------------- + def __pos__(self): return U32(self.v) + + #-------------------------------------------------------------------- + def __abs__(self): return U32(self.v) + + #-------------------------------------------------------------------- + def __invert__(self): + r = U32() + r.v = C + norm(~self.v) + return r + + #-------------------------------------------------------------------- + def __lshift__(self, b): + r = U32() + r.v = C + norm(self.v << b) + return r + + #-------------------------------------------------------------------- + def __rshift__(self, b): + r = U32() + r.v = C + (norm(self.v) >> b) + return r + + #-------------------------------------------------------------------- + def __and__(self, b): + r = U32() + r.v = C + norm(self.v & b.v) + return r + + #-------------------------------------------------------------------- + def __or__(self, b): + r = U32() + r.v = C + norm(self.v | b.v) + return r + + #-------------------------------------------------------------------- + def __xor__(self, b): + r = U32() + r.v = C + norm(self.v ^ b.v) + return r + + #-------------------------------------------------------------------- + def __not__(self): + return U32(not norm(self.v)) + + #-------------------------------------------------------------------- + def truth(self): + return norm(self.v) + + #-------------------------------------------------------------------- + def __cmp__(self, b): + if norm(self.v) > norm(b.v): return 1 + elif norm(self.v) < norm(b.v): return -1 + else: return 0 + + #-------------------------------------------------------------------- + def __bool__(self): + return norm(self.v) + diff --git a/lib/sambatools/python3/smb/utils/__init__.py b/lib/sambatools/python3/smb/utils/__init__.py new file mode 100644 index 00000000..20aa5355 --- /dev/null +++ b/lib/sambatools/python3/smb/utils/__init__.py @@ -0,0 +1,3 @@ + +def convertFILETIMEtoEpoch(t): + return (t - 116444736000000000) / 10000000.0; diff --git a/lib/sambatools/python3/smb/utils/md4.py b/lib/sambatools/python3/smb/utils/md4.py new file mode 100644 index 00000000..49489045 --- /dev/null +++ b/lib/sambatools/python3/smb/utils/md4.py @@ -0,0 +1,256 @@ +# md4.py implements md4 hash class for Python +# Version 1.0 +# Copyright (C) 2001-2002 Dmitry Rozmanov +# +# based on md4.c from "the Python Cryptography Toolkit, version 1.0.0 +# Copyright (C) 1995, A.M. Kuchling" +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# e-mail: dima@xenon.spb.ru +# +#==================================================================== + +# MD4 validation data + +md4_test= [ + ('', 0x31d6cfe0d16ae931b73c59d7e0c089c0), + ("a", 0xbde52cb31de33e46245e05fbdbd6fb24), + ("abc", 0xa448017aaf21d8525fc10ae87aa6729d), + ("message digest", 0xd9130a8164549fe818874806e1c7014b), + ("abcdefghijklmnopqrstuvwxyz", 0xd79e1c308aa5bbcdeea8ed63df412da9), + ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + 0x043f8582f241db351ce627e153e7f0e4), + ("12345678901234567890123456789012345678901234567890123456789012345678901234567890", + 0xe33b4ddc9c38f2199c3e7b164fcc0536), + ] + +#==================================================================== +from .U32 import U32 + +#-------------------------------------------------------------------- +class MD4: + A = None + B = None + C = None + D = None + count, len1, len2 = None, None, None + buf = [] + + #----------------------------------------------------- + def __init__(self): + + + self.A = U32(0x67452301) + self.B = U32(0xefcdab89) + self.C = U32(0x98badcfe) + self.D = U32(0x10325476) + self.count, self.len1, self.len2 = U32(0), U32(0), U32(0) + self.buf = [0x00] * 64 + + #----------------------------------------------------- + def __repr__(self): + r = 'A = %s, \nB = %s, \nC = %s, \nD = %s.\n' % (self.A.__repr__(), self.B.__repr__(), self.C.__repr__(), self.D.__repr__()) + r = r + 'count = %s, \nlen1 = %s, \nlen2 = %s.\n' % (self.count.__repr__(), self.len1.__repr__(), self.len2.__repr__()) + for i in range(4): + for j in range(16): + r = r + '%4s ' % hex(self.buf[i+j]) + r = r + '\n' + + return r + #----------------------------------------------------- + def make_copy(self): + + dest = new() + + dest.len1 = self.len1 + dest.len2 = self.len2 + dest.A = self.A + dest.B = self.B + dest.C = self.C + dest.D = self.D + dest.count = self.count + for i in range(int(self.count)): + dest.buf[i] = self.buf[i] + + return dest + + #----------------------------------------------------- + def update(self, str): + if isinstance(str, bytes): + buf = list(str) + else: + buf = [ord(i) for i in str] + + ilen = U32(len(buf)) + + # check if the first length is out of range + # as the length is measured in bits then multiplay it by 8 + if (int(self.len1 + (ilen << 3)) < int(self.len1)): + self.len2 = self.len2 + U32(1) + + self.len1 = self.len1 + (ilen << 3) + self.len2 = self.len2 + (ilen >> 29) + + L = U32(0) + bufpos = 0 + while (int(ilen) > 0): + if (64 - int(self.count)) < int(ilen): L = U32(64 - int(self.count)) + else: L = ilen + for i in range(int(L)): self.buf[i + int(self.count)] = buf[i + bufpos] + self.count = self.count + L + ilen = ilen - L + bufpos = bufpos + int(L) + + if (int(self.count) == 64): + self.count = U32(0) + X = [] + i = 0 + for j in range(16): + X.append(U32(self.buf[i]) + (U32(self.buf[i+1]) << 8) + \ + (U32(self.buf[i+2]) << 16) + (U32(self.buf[i+3]) << 24)) + i = i + 4 + + A = self.A + B = self.B + C = self.C + D = self.D + + A = f1(A,B,C,D, 0, 3, X) + D = f1(D,A,B,C, 1, 7, X) + C = f1(C,D,A,B, 2,11, X) + B = f1(B,C,D,A, 3,19, X) + A = f1(A,B,C,D, 4, 3, X) + D = f1(D,A,B,C, 5, 7, X) + C = f1(C,D,A,B, 6,11, X) + B = f1(B,C,D,A, 7,19, X) + A = f1(A,B,C,D, 8, 3, X) + D = f1(D,A,B,C, 9, 7, X) + C = f1(C,D,A,B,10,11, X) + B = f1(B,C,D,A,11,19, X) + A = f1(A,B,C,D,12, 3, X) + D = f1(D,A,B,C,13, 7, X) + C = f1(C,D,A,B,14,11, X) + B = f1(B,C,D,A,15,19, X) + + A = f2(A,B,C,D, 0, 3, X) + D = f2(D,A,B,C, 4, 5, X) + C = f2(C,D,A,B, 8, 9, X) + B = f2(B,C,D,A,12,13, X) + A = f2(A,B,C,D, 1, 3, X) + D = f2(D,A,B,C, 5, 5, X) + C = f2(C,D,A,B, 9, 9, X) + B = f2(B,C,D,A,13,13, X) + A = f2(A,B,C,D, 2, 3, X) + D = f2(D,A,B,C, 6, 5, X) + C = f2(C,D,A,B,10, 9, X) + B = f2(B,C,D,A,14,13, X) + A = f2(A,B,C,D, 3, 3, X) + D = f2(D,A,B,C, 7, 5, X) + C = f2(C,D,A,B,11, 9, X) + B = f2(B,C,D,A,15,13, X) + + A = f3(A,B,C,D, 0, 3, X) + D = f3(D,A,B,C, 8, 9, X) + C = f3(C,D,A,B, 4,11, X) + B = f3(B,C,D,A,12,15, X) + A = f3(A,B,C,D, 2, 3, X) + D = f3(D,A,B,C,10, 9, X) + C = f3(C,D,A,B, 6,11, X) + B = f3(B,C,D,A,14,15, X) + A = f3(A,B,C,D, 1, 3, X) + D = f3(D,A,B,C, 9, 9, X) + C = f3(C,D,A,B, 5,11, X) + B = f3(B,C,D,A,13,15, X) + A = f3(A,B,C,D, 3, 3, X) + D = f3(D,A,B,C,11, 9, X) + C = f3(C,D,A,B, 7,11, X) + B = f3(B,C,D,A,15,15, X) + + self.A = self.A + A + self.B = self.B + B + self.C = self.C + C + self.D = self.D + D + + #----------------------------------------------------- + def digest(self): + + res = [0x00] * 16 + s = [0x00] * 8 + padding = [0x00] * 64 + padding[0] = 0x80 + padlen, oldlen1, oldlen2 = U32(0), U32(0), U32(0) + + temp = self.make_copy() + + oldlen1 = temp.len1 + oldlen2 = temp.len2 + if (56 <= int(self.count)): padlen = U32(56 - int(self.count) + 64) + else: padlen = U32(56 - int(self.count)) + + temp.update(int_array2str(padding[:int(padlen)])) + + s[0]= (oldlen1) & U32(0xFF) + s[1]=((oldlen1) >> 8) & U32(0xFF) + s[2]=((oldlen1) >> 16) & U32(0xFF) + s[3]=((oldlen1) >> 24) & U32(0xFF) + s[4]= (oldlen2) & U32(0xFF) + s[5]=((oldlen2) >> 8) & U32(0xFF) + s[6]=((oldlen2) >> 16) & U32(0xFF) + s[7]=((oldlen2) >> 24) & U32(0xFF) + temp.update(int_array2str(s)) + + res[ 0]= temp.A & U32(0xFF) + res[ 1]=(temp.A >> 8) & U32(0xFF) + res[ 2]=(temp.A >> 16) & U32(0xFF) + res[ 3]=(temp.A >> 24) & U32(0xFF) + res[ 4]= temp.B & U32(0xFF) + res[ 5]=(temp.B >> 8) & U32(0xFF) + res[ 6]=(temp.B >> 16) & U32(0xFF) + res[ 7]=(temp.B >> 24) & U32(0xFF) + res[ 8]= temp.C & U32(0xFF) + res[ 9]=(temp.C >> 8) & U32(0xFF) + res[10]=(temp.C >> 16) & U32(0xFF) + res[11]=(temp.C >> 24) & U32(0xFF) + res[12]= temp.D & U32(0xFF) + res[13]=(temp.D >> 8) & U32(0xFF) + res[14]=(temp.D >> 16) & U32(0xFF) + res[15]=(temp.D >> 24) & U32(0xFF) + + return int_array2str(res).encode('UTF-16LE') + +#==================================================================== +# helpers +def F(x, y, z): return (((x) & (y)) | ((~x) & (z))) +def G(x, y, z): return (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +def H(x, y, z): return ((x) ^ (y) ^ (z)) + +def ROL(x, n): return (((x) << n) | ((x) >> (32-n))) + +def f1(a, b, c, d, k, s, X): return ROL(a + F(b, c, d) + X[k], s) +def f2(a, b, c, d, k, s, X): return ROL(a + G(b, c, d) + X[k] + U32(0x5a827999), s) +def f3(a, b, c, d, k, s, X): return ROL(a + H(b, c, d) + X[k] + U32(0x6ed9eba1), s) + +#-------------------------------------------------------------------- +# helper function +def int_array2str(array): + str = '' + for i in array: + str = str + chr(i) + return str + +#-------------------------------------------------------------------- +# To be able to use md4.new() instead of md4.MD4() +new = MD4 diff --git a/lib/sambatools/python3/smb/utils/pyDes.py b/lib/sambatools/python3/smb/utils/pyDes.py new file mode 100644 index 00000000..b2135058 --- /dev/null +++ b/lib/sambatools/python3/smb/utils/pyDes.py @@ -0,0 +1,852 @@ +############################################################################# +# Documentation # +############################################################################# + +# Author: Todd Whiteman +# Date: 16th March, 2009 +# Verion: 2.0.0 +# License: Public Domain - free to do as you wish +# Homepage: http://twhiteman.netfirms.com/des.html +# +# This is a pure python implementation of the DES encryption algorithm. +# It's pure python to avoid portability issues, since most DES +# implementations are programmed in C (for performance reasons). +# +# Triple DES class is also implemented, utilising the DES base. Triple DES +# is either DES-EDE3 with a 24 byte key, or DES-EDE2 with a 16 byte key. +# +# See the README.txt that should come with this python module for the +# implementation methods used. +# +# Thanks to: +# * David Broadwell for ideas, comments and suggestions. +# * Mario Wolff for pointing out and debugging some triple des CBC errors. +# * Santiago Palladino for providing the PKCS5 padding technique. +# * Shaya for correcting the PAD_PKCS5 triple des CBC errors. +# +"""A pure python implementation of the DES and TRIPLE DES encryption algorithms. + +Class initialization +-------------------- +pyDes.des(key, [mode], [IV], [pad], [padmode]) +pyDes.triple_des(key, [mode], [IV], [pad], [padmode]) + +key -> Bytes containing the encryption key. 8 bytes for DES, 16 or 24 bytes + for Triple DES +mode -> Optional argument for encryption type, can be either + pyDes.ECB (Electronic Code Book) or pyDes.CBC (Cypher Block Chaining) +IV -> Optional Initial Value bytes, must be supplied if using CBC mode. + Length must be 8 bytes. +pad -> Optional argument, set the pad character (PAD_NORMAL) to use during + all encrypt/decrpt operations done with this instance. +padmode -> Optional argument, set the padding mode (PAD_NORMAL or PAD_PKCS5) + to use during all encrypt/decrpt operations done with this instance. + +I recommend to use PAD_PKCS5 padding, as then you never need to worry about any +padding issues, as the padding can be removed unambiguously upon decrypting +data that was encrypted using PAD_PKCS5 padmode. + +Common methods +-------------- +encrypt(data, [pad], [padmode]) +decrypt(data, [pad], [padmode]) + +data -> Bytes to be encrypted/decrypted +pad -> Optional argument. Only when using padmode of PAD_NORMAL. For + encryption, adds this characters to the end of the data block when + data is not a multiple of 8 bytes. For decryption, will remove the + trailing characters that match this pad character from the last 8 + bytes of the unencrypted data block. +padmode -> Optional argument, set the padding mode, must be one of PAD_NORMAL + or PAD_PKCS5). Defaults to PAD_NORMAL. + + +Example +------- +from pyDes import * + +data = "Please encrypt my data" +k = des("DESCRYPT", CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) +# For Python3, you'll need to use bytes, i.e.: +# data = b"Please encrypt my data" +# k = des(b"DESCRYPT", CBC, b"\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) +d = k.encrypt(data) +print "Encrypted: %r" % d +print "Decrypted: %r" % k.decrypt(d) +assert k.decrypt(d, padmode=PAD_PKCS5) == data + + +See the module source (pyDes.py) for more examples of use. +You can also run the pyDes.py file without and arguments to see a simple test. + +Note: This code was not written for high-end systems needing a fast + implementation, but rather a handy portable solution with small usage. + +""" + +import sys + +# _pythonMajorVersion is used to handle Python2 and Python3 differences. +_pythonMajorVersion = sys.version_info[0] + +# Modes of crypting / cyphering +ECB = 0 +CBC = 1 + +# Modes of padding +PAD_NORMAL = 1 +PAD_PKCS5 = 2 + +# PAD_PKCS5: is a method that will unambiguously remove all padding +# characters after decryption, when originally encrypted with +# this padding mode. +# For a good description of the PKCS5 padding technique, see: +# http://www.faqs.org/rfcs/rfc1423.html + +# The base class shared by des and triple des. +class _baseDes(object): + def __init__(self, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL): + if IV: + IV = self._guardAgainstUnicode(IV) + if pad: + pad = self._guardAgainstUnicode(pad) + self.block_size = 8 + # Sanity checking of arguments. + if pad and padmode == PAD_PKCS5: + raise ValueError("Cannot use a pad character with PAD_PKCS5") + if IV and len(IV) != self.block_size: + raise ValueError("Invalid Initial Value (IV), must be a multiple of " + str(self.block_size) + " bytes") + + # Set the passed in variables + self._mode = mode + self._iv = IV + self._padding = pad + self._padmode = padmode + + def getKey(self): + """getKey() -> bytes""" + return self.__key + + def setKey(self, key): + """Will set the crypting key for this object.""" + key = self._guardAgainstUnicode(key) + self.__key = key + + def getMode(self): + """getMode() -> pyDes.ECB or pyDes.CBC""" + return self._mode + + def setMode(self, mode): + """Sets the type of crypting mode, pyDes.ECB or pyDes.CBC""" + self._mode = mode + + def getPadding(self): + """getPadding() -> bytes of length 1. Padding character.""" + return self._padding + + def setPadding(self, pad): + """setPadding() -> bytes of length 1. Padding character.""" + if pad is not None: + pad = self._guardAgainstUnicode(pad) + self._padding = pad + + def getPadMode(self): + """getPadMode() -> pyDes.PAD_NORMAL or pyDes.PAD_PKCS5""" + return self._padmode + + def setPadMode(self, mode): + """Sets the type of padding mode, pyDes.PAD_NORMAL or pyDes.PAD_PKCS5""" + self._padmode = mode + + def getIV(self): + """getIV() -> bytes""" + return self._iv + + def setIV(self, IV): + """Will set the Initial Value, used in conjunction with CBC mode""" + if not IV or len(IV) != self.block_size: + raise ValueError("Invalid Initial Value (IV), must be a multiple of " + str(self.block_size) + " bytes") + IV = self._guardAgainstUnicode(IV) + self._iv = IV + + def _padData(self, data, pad, padmode): + # Pad data depending on the mode + if padmode is None: + # Get the default padding mode. + padmode = self.getPadMode() + if pad and padmode == PAD_PKCS5: + raise ValueError("Cannot use a pad character with PAD_PKCS5") + + if padmode == PAD_NORMAL: + if len(data) % self.block_size == 0: + # No padding required. + return data + + if not pad: + # Get the default padding. + pad = self.getPadding() + if not pad: + raise ValueError("Data must be a multiple of " + str(self.block_size) + " bytes in length. Use padmode=PAD_PKCS5 or set the pad character.") + data += (self.block_size - (len(data) % self.block_size)) * pad + + elif padmode == PAD_PKCS5: + pad_len = 8 - (len(data) % self.block_size) + if _pythonMajorVersion < 3: + data += pad_len * chr(pad_len) + else: + data += bytes([pad_len] * pad_len) + + return data + + def _unpadData(self, data, pad, padmode): + # Unpad data depending on the mode. + if not data: + return data + if pad and padmode == PAD_PKCS5: + raise ValueError("Cannot use a pad character with PAD_PKCS5") + if padmode is None: + # Get the default padding mode. + padmode = self.getPadMode() + + if padmode == PAD_NORMAL: + if not pad: + # Get the default padding. + pad = self.getPadding() + if pad: + data = data[:-self.block_size] + \ + data[-self.block_size:].rstrip(pad) + + elif padmode == PAD_PKCS5: + if _pythonMajorVersion < 3: + pad_len = ord(data[-1]) + else: + pad_len = data[-1] + data = data[:-pad_len] + + return data + + def _guardAgainstUnicode(self, data): + # Only accept byte strings or ascii unicode values, otherwise + # there is no way to correctly decode the data into bytes. + if _pythonMajorVersion < 3: + if isinstance(data, str): + raise ValueError("pyDes can only work with bytes, not Unicode strings.") + else: + if isinstance(data, str): + # Only accept ascii unicode values. + try: + return data.encode('ascii') + except UnicodeEncodeError: + pass + raise ValueError("pyDes can only work with encoded strings, not Unicode.") + return data + +############################################################################# +# DES # +############################################################################# +class des(_baseDes): + """DES encryption/decrytpion class + + Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes. + + pyDes.des(key,[mode], [IV]) + + key -> Bytes containing the encryption key, must be exactly 8 bytes + mode -> Optional argument for encryption type, can be either pyDes.ECB + (Electronic Code Book), pyDes.CBC (Cypher Block Chaining) + IV -> Optional Initial Value bytes, must be supplied if using CBC mode. + Must be 8 bytes in length. + pad -> Optional argument, set the pad character (PAD_NORMAL) to use + during all encrypt/decrpt operations done with this instance. + padmode -> Optional argument, set the padding mode (PAD_NORMAL or + PAD_PKCS5) to use during all encrypt/decrpt operations done + with this instance. + """ + + + # Permutation and translation tables for DES + __pc1 = [56, 48, 40, 32, 24, 16, 8, + 0, 57, 49, 41, 33, 25, 17, + 9, 1, 58, 50, 42, 34, 26, + 18, 10, 2, 59, 51, 43, 35, + 62, 54, 46, 38, 30, 22, 14, + 6, 61, 53, 45, 37, 29, 21, + 13, 5, 60, 52, 44, 36, 28, + 20, 12, 4, 27, 19, 11, 3 + ] + + # number left rotations of pc1 + __left_rotations = [ + 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 + ] + + # permuted choice key (table 2) + __pc2 = [ + 13, 16, 10, 23, 0, 4, + 2, 27, 14, 5, 20, 9, + 22, 18, 11, 3, 25, 7, + 15, 6, 26, 19, 12, 1, + 40, 51, 30, 36, 46, 54, + 29, 39, 50, 44, 32, 47, + 43, 48, 38, 55, 33, 52, + 45, 41, 49, 35, 28, 31 + ] + + # initial permutation IP + __ip = [57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7, + 56, 48, 40, 32, 24, 16, 8, 0, + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6 + ] + + # Expansion table for turning 32 bit blocks into 48 bits + __expansion_table = [ + 31, 0, 1, 2, 3, 4, + 3, 4, 5, 6, 7, 8, + 7, 8, 9, 10, 11, 12, + 11, 12, 13, 14, 15, 16, + 15, 16, 17, 18, 19, 20, + 19, 20, 21, 22, 23, 24, + 23, 24, 25, 26, 27, 28, + 27, 28, 29, 30, 31, 0 + ] + + # The (in)famous S-boxes + __sbox = [ + # S1 + [14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13], + + # S2 + [15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9], + + # S3 + [10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12], + + # S4 + [7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14], + + # S5 + [2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3], + + # S6 + [12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13], + + # S7 + [4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12], + + # S8 + [13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11], + ] + + + # 32-bit permutation function P used on the output of the S-boxes + __p = [ + 15, 6, 19, 20, 28, 11, + 27, 16, 0, 14, 22, 25, + 4, 17, 30, 9, 1, 7, + 23,13, 31, 26, 2, 8, + 18, 12, 29, 5, 21, 10, + 3, 24 + ] + + # final permutation IP^-1 + __fp = [ + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25, + 32, 0, 40, 8, 48, 16, 56, 24 + ] + + # Type of crypting being done + ENCRYPT = 0x00 + DECRYPT = 0x01 + + # Initialisation + def __init__(self, key, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL): + # Sanity checking of arguments. + if len(key) != 8: + raise ValueError("Invalid DES key size. Key must be exactly 8 bytes long.") + _baseDes.__init__(self, mode, IV, pad, padmode) + self.key_size = 8 + + self.L = [] + self.R = [] + self.Kn = [ [0] * 48 ] * 16 # 16 48-bit keys (K1 - K16) + self.final = [] + + self.setKey(key) + + def setKey(self, key): + """Will set the crypting key for this object. Must be 8 bytes.""" + _baseDes.setKey(self, key) + self.__create_sub_keys() + + def __String_to_BitList(self, data): + """Turn the string data, into a list of bits (1, 0)'s""" + if _pythonMajorVersion < 3: + # Turn the strings into integers. Python 3 uses a bytes + # class, which already has this behaviour. + data = [ord(c) for c in data] + l = len(data) * 8 + result = [0] * l + pos = 0 + for ch in data: + i = 7 + while i >= 0: + if ch & (1 << i) != 0: + result[pos] = 1 + else: + result[pos] = 0 + pos += 1 + i -= 1 + + return result + + def __BitList_to_String(self, data): + """Turn the list of bits -> data, into a string""" + result = [] + pos = 0 + c = 0 + while pos < len(data): + c += data[pos] << (7 - (pos % 8)) + if (pos % 8) == 7: + result.append(c) + c = 0 + pos += 1 + + if _pythonMajorVersion < 3: + return ''.join([ chr(c) for c in result ]) + else: + return bytes(result) + + def __permutate(self, table, block): + """Permutate this block with the specified table""" + return list([block[x] for x in table]) + + # Transform the secret key, so that it is ready for data processing + # Create the 16 subkeys, K[1] - K[16] + def __create_sub_keys(self): + """Create the 16 subkeys K[1] to K[16] from the given key""" + key = self.__permutate(des.__pc1, self.__String_to_BitList(self.getKey())) + i = 0 + # Split into Left and Right sections + self.L = key[:28] + self.R = key[28:] + while i < 16: + j = 0 + # Perform circular left shifts + while j < des.__left_rotations[i]: + self.L.append(self.L[0]) + del self.L[0] + + self.R.append(self.R[0]) + del self.R[0] + + j += 1 + + # Create one of the 16 subkeys through pc2 permutation + self.Kn[i] = self.__permutate(des.__pc2, self.L + self.R) + + i += 1 + + # Main part of the encryption algorithm, the number cruncher :) + def __des_crypt(self, block, crypt_type): + """Crypt the block of data through DES bit-manipulation""" + block = self.__permutate(des.__ip, block) + self.L = block[:32] + self.R = block[32:] + + # Encryption starts from Kn[1] through to Kn[16] + if crypt_type == des.ENCRYPT: + iteration = 0 + iteration_adjustment = 1 + # Decryption starts from Kn[16] down to Kn[1] + else: + iteration = 15 + iteration_adjustment = -1 + + i = 0 + while i < 16: + # Make a copy of R[i-1], this will later become L[i] + tempR = self.R[:] + + # Permutate R[i - 1] to start creating R[i] + self.R = self.__permutate(des.__expansion_table, self.R) + + # Exclusive or R[i - 1] with K[i], create B[1] to B[8] whilst here + self.R = list(map(lambda x, y: x ^ y, self.R, self.Kn[iteration])) + B = [self.R[:6], self.R[6:12], self.R[12:18], self.R[18:24], self.R[24:30], self.R[30:36], self.R[36:42], self.R[42:]] + # Optimization: Replaced below commented code with above + #j = 0 + #B = [] + #while j < len(self.R): + # self.R[j] = self.R[j] ^ self.Kn[iteration][j] + # j += 1 + # if j % 6 == 0: + # B.append(self.R[j-6:j]) + + # Permutate B[1] to B[8] using the S-Boxes + j = 0 + Bn = [0] * 32 + pos = 0 + while j < 8: + # Work out the offsets + m = (B[j][0] << 1) + B[j][5] + n = (B[j][1] << 3) + (B[j][2] << 2) + (B[j][3] << 1) + B[j][4] + + # Find the permutation value + v = des.__sbox[j][(m << 4) + n] + + # Turn value into bits, add it to result: Bn + Bn[pos] = (v & 8) >> 3 + Bn[pos + 1] = (v & 4) >> 2 + Bn[pos + 2] = (v & 2) >> 1 + Bn[pos + 3] = v & 1 + + pos += 4 + j += 1 + + # Permutate the concatination of B[1] to B[8] (Bn) + self.R = self.__permutate(des.__p, Bn) + + # Xor with L[i - 1] + self.R = list(map(lambda x, y: x ^ y, self.R, self.L)) + # Optimization: This now replaces the below commented code + #j = 0 + #while j < len(self.R): + # self.R[j] = self.R[j] ^ self.L[j] + # j += 1 + + # L[i] becomes R[i - 1] + self.L = tempR + + i += 1 + iteration += iteration_adjustment + + # Final permutation of R[16]L[16] + self.final = self.__permutate(des.__fp, self.R + self.L) + return self.final + + + # Data to be encrypted/decrypted + def crypt(self, data, crypt_type): + """Crypt the data in blocks, running it through des_crypt()""" + + # Error check the data + if not data: + return '' + if len(data) % self.block_size != 0: + if crypt_type == des.DECRYPT: # Decryption must work on 8 byte blocks + raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n.") + if not self.getPadding(): + raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n. Try setting the optional padding character") + else: + data += (self.block_size - (len(data) % self.block_size)) * self.getPadding() + # print "Len of data: %f" % (len(data) / self.block_size) + + if self.getMode() == CBC: + if self.getIV(): + iv = self.__String_to_BitList(self.getIV()) + else: + raise ValueError("For CBC mode, you must supply the Initial Value (IV) for ciphering") + + # Split the data into blocks, crypting each one seperately + i = 0 + dict = {} + result = [] + #cached = 0 + #lines = 0 + while i < len(data): + # Test code for caching encryption results + #lines += 1 + #if dict.has_key(data[i:i+8]): + #print "Cached result for: %s" % data[i:i+8] + # cached += 1 + # result.append(dict[data[i:i+8]]) + # i += 8 + # continue + + block = self.__String_to_BitList(data[i:i+8]) + + # Xor with IV if using CBC mode + if self.getMode() == CBC: + if crypt_type == des.ENCRYPT: + block = list(map(lambda x, y: x ^ y, block, iv)) + #j = 0 + #while j < len(block): + # block[j] = block[j] ^ iv[j] + # j += 1 + + processed_block = self.__des_crypt(block, crypt_type) + + if crypt_type == des.DECRYPT: + processed_block = list(map(lambda x, y: x ^ y, processed_block, iv)) + #j = 0 + #while j < len(processed_block): + # processed_block[j] = processed_block[j] ^ iv[j] + # j += 1 + iv = block + else: + iv = processed_block + else: + processed_block = self.__des_crypt(block, crypt_type) + + + # Add the resulting crypted block to our list + #d = self.__BitList_to_String(processed_block) + #result.append(d) + result.append(self.__BitList_to_String(processed_block)) + #dict[data[i:i+8]] = d + i += 8 + + # print "Lines: %d, cached: %d" % (lines, cached) + + # Return the full crypted string + if _pythonMajorVersion < 3: + return ''.join(result) + else: + return bytes.fromhex('').join(result) + + def encrypt(self, data, pad=None, padmode=None): + """encrypt(data, [pad], [padmode]) -> bytes + + data : Bytes to be encrypted + pad : Optional argument for encryption padding. Must only be one byte + padmode : Optional argument for overriding the padding mode. + + The data must be a multiple of 8 bytes and will be encrypted + with the already specified key. Data does not have to be a + multiple of 8 bytes if the padding character is supplied, or + the padmode is set to PAD_PKCS5, as bytes will then added to + ensure the be padded data is a multiple of 8 bytes. + """ + data = self._guardAgainstUnicode(data) + if pad is not None: + pad = self._guardAgainstUnicode(pad) + data = self._padData(data, pad, padmode) + return self.crypt(data, des.ENCRYPT) + + def decrypt(self, data, pad=None, padmode=None): + """decrypt(data, [pad], [padmode]) -> bytes + + data : Bytes to be encrypted + pad : Optional argument for decryption padding. Must only be one byte + padmode : Optional argument for overriding the padding mode. + + The data must be a multiple of 8 bytes and will be decrypted + with the already specified key. In PAD_NORMAL mode, if the + optional padding character is supplied, then the un-encrypted + data will have the padding characters removed from the end of + the bytes. This pad removal only occurs on the last 8 bytes of + the data (last data block). In PAD_PKCS5 mode, the special + padding end markers will be removed from the data after decrypting. + """ + data = self._guardAgainstUnicode(data) + if pad is not None: + pad = self._guardAgainstUnicode(pad) + data = self.crypt(data, des.DECRYPT) + return self._unpadData(data, pad, padmode) + + + +############################################################################# +# Triple DES # +############################################################################# +class triple_des(_baseDes): + """Triple DES encryption/decrytpion class + + This algorithm uses the DES-EDE3 (when a 24 byte key is supplied) or + the DES-EDE2 (when a 16 byte key is supplied) encryption methods. + Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes. + + pyDes.des(key, [mode], [IV]) + + key -> Bytes containing the encryption key, must be either 16 or + 24 bytes long + mode -> Optional argument for encryption type, can be either pyDes.ECB + (Electronic Code Book), pyDes.CBC (Cypher Block Chaining) + IV -> Optional Initial Value bytes, must be supplied if using CBC mode. + Must be 8 bytes in length. + pad -> Optional argument, set the pad character (PAD_NORMAL) to use + during all encrypt/decrpt operations done with this instance. + padmode -> Optional argument, set the padding mode (PAD_NORMAL or + PAD_PKCS5) to use during all encrypt/decrpt operations done + with this instance. + """ + def __init__(self, key, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL): + _baseDes.__init__(self, mode, IV, pad, padmode) + self.setKey(key) + + def setKey(self, key): + """Will set the crypting key for this object. Either 16 or 24 bytes long.""" + self.key_size = 24 # Use DES-EDE3 mode + if len(key) != self.key_size: + if len(key) == 16: # Use DES-EDE2 mode + self.key_size = 16 + else: + raise ValueError("Invalid triple DES key size. Key must be either 16 or 24 bytes long") + if self.getMode() == CBC: + if not self.getIV(): + # Use the first 8 bytes of the key + self._iv = key[:self.block_size] + if len(self.getIV()) != self.block_size: + raise ValueError("Invalid IV, must be 8 bytes in length") + self.__key1 = des(key[:8], self._mode, self._iv, + self._padding, self._padmode) + self.__key2 = des(key[8:16], self._mode, self._iv, + self._padding, self._padmode) + if self.key_size == 16: + self.__key3 = self.__key1 + else: + self.__key3 = des(key[16:], self._mode, self._iv, + self._padding, self._padmode) + _baseDes.setKey(self, key) + + # Override setter methods to work on all 3 keys. + + def setMode(self, mode): + """Sets the type of crypting mode, pyDes.ECB or pyDes.CBC""" + _baseDes.setMode(self, mode) + for key in (self.__key1, self.__key2, self.__key3): + key.setMode(mode) + + def setPadding(self, pad): + """setPadding() -> bytes of length 1. Padding character.""" + _baseDes.setPadding(self, pad) + for key in (self.__key1, self.__key2, self.__key3): + key.setPadding(pad) + + def setPadMode(self, mode): + """Sets the type of padding mode, pyDes.PAD_NORMAL or pyDes.PAD_PKCS5""" + _baseDes.setPadMode(self, mode) + for key in (self.__key1, self.__key2, self.__key3): + key.setPadMode(mode) + + def setIV(self, IV): + """Will set the Initial Value, used in conjunction with CBC mode""" + _baseDes.setIV(self, IV) + for key in (self.__key1, self.__key2, self.__key3): + key.setIV(IV) + + def encrypt(self, data, pad=None, padmode=None): + """encrypt(data, [pad], [padmode]) -> bytes + + data : bytes to be encrypted + pad : Optional argument for encryption padding. Must only be one byte + padmode : Optional argument for overriding the padding mode. + + The data must be a multiple of 8 bytes and will be encrypted + with the already specified key. Data does not have to be a + multiple of 8 bytes if the padding character is supplied, or + the padmode is set to PAD_PKCS5, as bytes will then added to + ensure the be padded data is a multiple of 8 bytes. + """ + ENCRYPT = des.ENCRYPT + DECRYPT = des.DECRYPT + data = self._guardAgainstUnicode(data) + if pad is not None: + pad = self._guardAgainstUnicode(pad) + # Pad the data accordingly. + data = self._padData(data, pad, padmode) + if self.getMode() == CBC: + self.__key1.setIV(self.getIV()) + self.__key2.setIV(self.getIV()) + self.__key3.setIV(self.getIV()) + i = 0 + result = [] + while i < len(data): + block = self.__key1.crypt(data[i:i+8], ENCRYPT) + block = self.__key2.crypt(block, DECRYPT) + block = self.__key3.crypt(block, ENCRYPT) + self.__key1.setIV(block) + self.__key2.setIV(block) + self.__key3.setIV(block) + result.append(block) + i += 8 + if _pythonMajorVersion < 3: + return ''.join(result) + else: + return bytes.fromhex('').join(result) + else: + data = self.__key1.crypt(data, ENCRYPT) + data = self.__key2.crypt(data, DECRYPT) + return self.__key3.crypt(data, ENCRYPT) + + def decrypt(self, data, pad=None, padmode=None): + """decrypt(data, [pad], [padmode]) -> bytes + + data : bytes to be encrypted + pad : Optional argument for decryption padding. Must only be one byte + padmode : Optional argument for overriding the padding mode. + + The data must be a multiple of 8 bytes and will be decrypted + with the already specified key. In PAD_NORMAL mode, if the + optional padding character is supplied, then the un-encrypted + data will have the padding characters removed from the end of + the bytes. This pad removal only occurs on the last 8 bytes of + the data (last data block). In PAD_PKCS5 mode, the special + padding end markers will be removed from the data after + decrypting, no pad character is required for PAD_PKCS5. + """ + ENCRYPT = des.ENCRYPT + DECRYPT = des.DECRYPT + data = self._guardAgainstUnicode(data) + if pad is not None: + pad = self._guardAgainstUnicode(pad) + if self.getMode() == CBC: + self.__key1.setIV(self.getIV()) + self.__key2.setIV(self.getIV()) + self.__key3.setIV(self.getIV()) + i = 0 + result = [] + while i < len(data): + iv = data[i:i+8] + block = self.__key3.crypt(iv, DECRYPT) + block = self.__key2.crypt(block, ENCRYPT) + block = self.__key1.crypt(block, DECRYPT) + self.__key1.setIV(iv) + self.__key2.setIV(iv) + self.__key3.setIV(iv) + result.append(block) + i += 8 + if _pythonMajorVersion < 3: + data = ''.join(result) + else: + data = bytes.fromhex('').join(result) + else: + data = self.__key3.crypt(data, DECRYPT) + data = self.__key2.crypt(data, ENCRYPT) + data = self.__key1.crypt(data, DECRYPT) + return self._unpadData(data, pad, padmode) diff --git a/lib/sambatools/python3/smb/utils/rc4.py b/lib/sambatools/python3/smb/utils/rc4.py new file mode 100644 index 00000000..037c1d31 --- /dev/null +++ b/lib/sambatools/python3/smb/utils/rc4.py @@ -0,0 +1,22 @@ + +def RC4_encrypt(key, data): + S = list(range(256)) + j = 0 + + key_len = len(key) + for i in list(range(256)): + j = (j + S[i] + key[i % key_len]) % 256 + S[i], S[j] = S[j], S[i] + + j = 0 + y = 0 + out = [] + + for char in data: + j = (j + 1) % 256 + y = (y + S[j]) % 256 + S[j], S[y] = S[y], S[j] + + out.append(char ^ S[(S[j] + S[y]) % 256]) + + return bytes(out) diff --git a/lib/sambatools/python3/smb/utils/sha256.py b/lib/sambatools/python3/smb/utils/sha256.py new file mode 100644 index 00000000..574a6394 --- /dev/null +++ b/lib/sambatools/python3/smb/utils/sha256.py @@ -0,0 +1,109 @@ +__author__ = 'Thomas Dixon' +__license__ = 'MIT' + +import copy, struct, sys + +digest_size = 32 +blocksize = 1 + +def new(m=None): + return sha256(m) + +class sha256(object): + _k = (0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2) + _h = (0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19) + _output_size = 8 + + blocksize = 1 + block_size = 64 + digest_size = 32 + + def __init__(self, m=None): + self._buffer = '' + self._counter = 0 + + if m is not None: + if type(m) is not str: + raise TypeError('%s() argument 1 must be string, not %s' % (self.__class__.__name__, type(m).__name__)) + self.update(m) + + def _rotr(self, x, y): + return ((x >> y) | (x << (32-y))) & 0xFFFFFFFF + + def _sha256_process(self, c): + w = [0]*64 + w[0:15] = struct.unpack('!16L', c) + + for i in range(16, 64): + s0 = self._rotr(w[i-15], 7) ^ self._rotr(w[i-15], 18) ^ (w[i-15] >> 3) + s1 = self._rotr(w[i-2], 17) ^ self._rotr(w[i-2], 19) ^ (w[i-2] >> 10) + w[i] = (w[i-16] + s0 + w[i-7] + s1) & 0xFFFFFFFF + + a,b,c,d,e,f,g,h = self._h + + for i in range(64): + s0 = self._rotr(a, 2) ^ self._rotr(a, 13) ^ self._rotr(a, 22) + maj = (a & b) ^ (a & c) ^ (b & c) + t2 = s0 + maj + s1 = self._rotr(e, 6) ^ self._rotr(e, 11) ^ self._rotr(e, 25) + ch = (e & f) ^ ((~e) & g) + t1 = h + s1 + ch + self._k[i] + w[i] + + h = g + g = f + f = e + e = (d + t1) & 0xFFFFFFFF + d = c + c = b + b = a + a = (t1 + t2) & 0xFFFFFFFF + + self._h = [(x+y) & 0xFFFFFFFF for x,y in zip(self._h, [a,b,c,d,e,f,g,h])] + + def update(self, m): + if not m: + return + if type(m) is not str: + raise TypeError('%s() argument 1 must be string, not %s' % (sys._getframe().f_code.co_name, type(m).__name__)) + + self._buffer += m + self._counter += len(m) + + while len(self._buffer) >= 64: + self._sha256_process(self._buffer[:64]) + self._buffer = self._buffer[64:] + + def digest(self): + mdi = self._counter & 0x3F + length = struct.pack('!Q', self._counter<<3) + + if mdi < 56: + padlen = 55-mdi + else: + padlen = 119-mdi + + r = self.copy() + r.update('\x80'+('\x00'*padlen)+length) + return ''.join([struct.pack('!L', i) for i in r._h[:self._output_size]]) + + def hexdigest(self): + return self.digest().encode('hex') + + def copy(self): + return copy.deepcopy(self) diff --git a/lib/simplejson/__init__.py b/lib/simplejson/__init__.py deleted file mode 100644 index d5b4d399..00000000 --- a/lib/simplejson/__init__.py +++ /dev/null @@ -1,318 +0,0 @@ -r"""JSON (JavaScript Object Notation) is a subset of -JavaScript syntax (ECMA-262 3rd edition) used as a lightweight data -interchange format. - -:mod:`simplejson` exposes an API familiar to users of the standard library -:mod:`marshal` and :mod:`pickle` modules. It is the externally maintained -version of the :mod:`json` library contained in Python 2.6, but maintains -compatibility with Python 2.4 and Python 2.5 and (currently) has -significant performance advantages, even without using the optional C -extension for speedups. - -Encoding basic Python object hierarchies:: - - >>> import simplejson as json - >>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}]) - '["foo", {"bar": ["baz", null, 1.0, 2]}]' - >>> print json.dumps("\"foo\bar") - "\"foo\bar" - >>> print json.dumps(u'\u1234') - "\u1234" - >>> print json.dumps('\\') - "\\" - >>> print json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True) - {"a": 0, "b": 0, "c": 0} - >>> from StringIO import StringIO - >>> io = StringIO() - >>> json.dump(['streaming API'], io) - >>> io.getvalue() - '["streaming API"]' - -Compact encoding:: - - >>> import simplejson as json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) - '[1,2,3,{"4":5,"6":7}]' - -Pretty printing:: - - >>> import simplejson as json - >>> s = json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4) - >>> print '\n'.join([l.rstrip() for l in s.splitlines()]) - { - "4": 5, - "6": 7 - } - -Decoding JSON:: - - >>> import simplejson as json - >>> obj = [u'foo', {u'bar': [u'baz', None, 1.0, 2]}] - >>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') == obj - True - >>> json.loads('"\\"foo\\bar"') == u'"foo\x08ar' - True - >>> from StringIO import StringIO - >>> io = StringIO('["streaming API"]') - >>> json.load(io)[0] == 'streaming API' - True - -Specializing JSON object decoding:: - - >>> import simplejson as json - >>> def as_complex(dct): - ... if '__complex__' in dct: - ... return complex(dct['real'], dct['imag']) - ... return dct - ... - >>> json.loads('{"__complex__": true, "real": 1, "imag": 2}', - ... object_hook=as_complex) - (1+2j) - >>> import decimal - >>> json.loads('1.1', parse_float=decimal.Decimal) == decimal.Decimal('1.1') - True - -Specializing JSON object encoding:: - - >>> import simplejson as json - >>> def encode_complex(obj): - ... if isinstance(obj, complex): - ... return [obj.real, obj.imag] - ... raise TypeError(repr(o) + " is not JSON serializable") - ... - >>> json.dumps(2 + 1j, default=encode_complex) - '[2.0, 1.0]' - >>> json.JSONEncoder(default=encode_complex).encode(2 + 1j) - '[2.0, 1.0]' - >>> ''.join(json.JSONEncoder(default=encode_complex).iterencode(2 + 1j)) - '[2.0, 1.0]' - - -Using simplejson.tool from the shell to validate and pretty-print:: - - $ echo '{"json":"obj"}' | python -m simplejson.tool - { - "json": "obj" - } - $ echo '{ 1.2:3.4}' | python -m simplejson.tool - Expecting property name: line 1 column 2 (char 2) -""" -__version__ = '2.0.9' -__all__ = [ - 'dump', 'dumps', 'load', 'loads', - 'JSONDecoder', 'JSONEncoder', -] - -__author__ = 'Bob Ippolito ' - -from decoder import JSONDecoder -from encoder import JSONEncoder - -_default_encoder = JSONEncoder( - skipkeys=False, - ensure_ascii=True, - check_circular=True, - allow_nan=True, - indent=None, - separators=None, - encoding='utf-8', - default=None, -) - -def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, - allow_nan=True, cls=None, indent=None, separators=None, - encoding='utf-8', default=None, **kw): - """Serialize ``obj`` as a JSON formatted stream to ``fp`` (a - ``.write()``-supporting file-like object). - - If ``skipkeys`` is true then ``dict`` keys that are not basic types - (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``) - will be skipped instead of raising a ``TypeError``. - - If ``ensure_ascii`` is false, then the some chunks written to ``fp`` - may be ``unicode`` instances, subject to normal Python ``str`` to - ``unicode`` coercion rules. Unless ``fp.write()`` explicitly - understands ``unicode`` (as in ``codecs.getwriter()``) this is likely - to cause an error. - - If ``check_circular`` is false, then the circular reference check - for container types will be skipped and a circular reference will - result in an ``OverflowError`` (or worse). - - If ``allow_nan`` is false, then it will be a ``ValueError`` to - serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) - in strict compliance of the JSON specification, instead of using the - JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). - - If ``indent`` is a non-negative integer, then JSON array elements and object - members will be pretty-printed with that indent level. An indent level - of 0 will only insert newlines. ``None`` is the most compact representation. - - If ``separators`` is an ``(item_separator, dict_separator)`` tuple - then it will be used instead of the default ``(', ', ': ')`` separators. - ``(',', ':')`` is the most compact JSON representation. - - ``encoding`` is the character encoding for str instances, default is UTF-8. - - ``default(obj)`` is a function that should return a serializable version - of obj or raise TypeError. The default simply raises TypeError. - - To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the - ``.default()`` method to serialize additional types), specify it with - the ``cls`` kwarg. - - """ - # cached encoder - if (not skipkeys and ensure_ascii and - check_circular and allow_nan and - cls is None and indent is None and separators is None and - encoding == 'utf-8' and default is None and not kw): - iterable = _default_encoder.iterencode(obj) - else: - if cls is None: - cls = JSONEncoder - iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii, - check_circular=check_circular, allow_nan=allow_nan, indent=indent, - separators=separators, encoding=encoding, - default=default, **kw).iterencode(obj) - # could accelerate with writelines in some versions of Python, at - # a debuggability cost - for chunk in iterable: - fp.write(chunk) - - -def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, - allow_nan=True, cls=None, indent=None, separators=None, - encoding='utf-8', default=None, **kw): - """Serialize ``obj`` to a JSON formatted ``str``. - - If ``skipkeys`` is false then ``dict`` keys that are not basic types - (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``) - will be skipped instead of raising a ``TypeError``. - - If ``ensure_ascii`` is false, then the return value will be a - ``unicode`` instance subject to normal Python ``str`` to ``unicode`` - coercion rules instead of being escaped to an ASCII ``str``. - - If ``check_circular`` is false, then the circular reference check - for container types will be skipped and a circular reference will - result in an ``OverflowError`` (or worse). - - If ``allow_nan`` is false, then it will be a ``ValueError`` to - serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in - strict compliance of the JSON specification, instead of using the - JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). - - If ``indent`` is a non-negative integer, then JSON array elements and - object members will be pretty-printed with that indent level. An indent - level of 0 will only insert newlines. ``None`` is the most compact - representation. - - If ``separators`` is an ``(item_separator, dict_separator)`` tuple - then it will be used instead of the default ``(', ', ': ')`` separators. - ``(',', ':')`` is the most compact JSON representation. - - ``encoding`` is the character encoding for str instances, default is UTF-8. - - ``default(obj)`` is a function that should return a serializable version - of obj or raise TypeError. The default simply raises TypeError. - - To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the - ``.default()`` method to serialize additional types), specify it with - the ``cls`` kwarg. - - """ - # cached encoder - if (not skipkeys and ensure_ascii and - check_circular and allow_nan and - cls is None and indent is None and separators is None and - encoding == 'utf-8' and default is None and not kw): - return _default_encoder.encode(obj) - if cls is None: - cls = JSONEncoder - return cls( - skipkeys=skipkeys, ensure_ascii=ensure_ascii, - check_circular=check_circular, allow_nan=allow_nan, indent=indent, - separators=separators, encoding=encoding, default=default, - **kw).encode(obj) - - -_default_decoder = JSONDecoder(encoding=None, object_hook=None) - - -def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None, - parse_int=None, parse_constant=None, **kw): - """Deserialize ``fp`` (a ``.read()``-supporting file-like object containing - a JSON document) to a Python object. - - If the contents of ``fp`` is encoded with an ASCII based encoding other - than utf-8 (e.g. latin-1), then an appropriate ``encoding`` name must - be specified. Encodings that are not ASCII based (such as UCS-2) are - not allowed, and should be wrapped with - ``codecs.getreader(fp)(encoding)``, or simply decoded to a ``unicode`` - object and passed to ``loads()`` - - ``object_hook`` is an optional function that will be called with the - result of any object literal decode (a ``dict``). The return value of - ``object_hook`` will be used instead of the ``dict``. This feature - can be used to implement custom decoders (e.g. JSON-RPC class hinting). - - To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` - kwarg. - - """ - return loads(fp.read(), - encoding=encoding, cls=cls, object_hook=object_hook, - parse_float=parse_float, parse_int=parse_int, - parse_constant=parse_constant, **kw) - - -def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, - parse_int=None, parse_constant=None, **kw): - """Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON - document) to a Python object. - - If ``s`` is a ``str`` instance and is encoded with an ASCII based encoding - other than utf-8 (e.g. latin-1) then an appropriate ``encoding`` name - must be specified. Encodings that are not ASCII based (such as UCS-2) - are not allowed and should be decoded to ``unicode`` first. - - ``object_hook`` is an optional function that will be called with the - result of any object literal decode (a ``dict``). The return value of - ``object_hook`` will be used instead of the ``dict``. This feature - can be used to implement custom decoders (e.g. JSON-RPC class hinting). - - ``parse_float``, if specified, will be called with the string - of every JSON float to be decoded. By default this is equivalent to - float(num_str). This can be used to use another datatype or parser - for JSON floats (e.g. decimal.Decimal). - - ``parse_int``, if specified, will be called with the string - of every JSON int to be decoded. By default this is equivalent to - int(num_str). This can be used to use another datatype or parser - for JSON integers (e.g. float). - - ``parse_constant``, if specified, will be called with one of the - following strings: -Infinity, Infinity, NaN, null, true, false. - This can be used to raise an exception if invalid JSON numbers - are encountered. - - To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` - kwarg. - - """ - if (cls is None and encoding is None and object_hook is None and - parse_int is None and parse_float is None and - parse_constant is None and not kw): - return _default_decoder.decode(s) - if cls is None: - cls = JSONDecoder - if object_hook is not None: - kw['object_hook'] = object_hook - if parse_float is not None: - kw['parse_float'] = parse_float - if parse_int is not None: - kw['parse_int'] = parse_int - if parse_constant is not None: - kw['parse_constant'] = parse_constant - return cls(encoding=encoding, **kw).decode(s) diff --git a/lib/simplejson/decoder.py b/lib/simplejson/decoder.py deleted file mode 100644 index b769ea48..00000000 --- a/lib/simplejson/decoder.py +++ /dev/null @@ -1,354 +0,0 @@ -"""Implementation of JSONDecoder -""" -import re -import sys -import struct - -from simplejson.scanner import make_scanner -try: - from simplejson._speedups import scanstring as c_scanstring -except ImportError: - c_scanstring = None - -__all__ = ['JSONDecoder'] - -FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL - -def _floatconstants(): - _BYTES = '7FF80000000000007FF0000000000000'.decode('hex') - if sys.byteorder != 'big': - _BYTES = _BYTES[:8][::-1] + _BYTES[8:][::-1] - nan, inf = struct.unpack('dd', _BYTES) - return nan, inf, -inf - -NaN, PosInf, NegInf = _floatconstants() - - -def linecol(doc, pos): - lineno = doc.count('\n', 0, pos) + 1 - if lineno == 1: - colno = pos - else: - colno = pos - doc.rindex('\n', 0, pos) - return lineno, colno - - -def errmsg(msg, doc, pos, end=None): - # Note that this function is called from _speedups - lineno, colno = linecol(doc, pos) - if end is None: - #fmt = '{0}: line {1} column {2} (char {3})' - #return fmt.format(msg, lineno, colno, pos) - fmt = '%s: line %d column %d (char %d)' - return fmt % (msg, lineno, colno, pos) - endlineno, endcolno = linecol(doc, end) - #fmt = '{0}: line {1} column {2} - line {3} column {4} (char {5} - {6})' - #return fmt.format(msg, lineno, colno, endlineno, endcolno, pos, end) - fmt = '%s: line %d column %d - line %d column %d (char %d - %d)' - return fmt % (msg, lineno, colno, endlineno, endcolno, pos, end) - - -_CONSTANTS = { - '-Infinity': NegInf, - 'Infinity': PosInf, - 'NaN': NaN, -} - -STRINGCHUNK = re.compile(r'(.*?)(["\\\x00-\x1f])', FLAGS) -BACKSLASH = { - '"': u'"', '\\': u'\\', '/': u'/', - 'b': u'\b', 'f': u'\f', 'n': u'\n', 'r': u'\r', 't': u'\t', -} - -DEFAULT_ENCODING = "utf-8" - -def py_scanstring(s, end, encoding=None, strict=True, _b=BACKSLASH, _m=STRINGCHUNK.match): - """Scan the string s for a JSON string. End is the index of the - character in s after the quote that started the JSON string. - Unescapes all valid JSON string escape sequences and raises ValueError - on attempt to decode an invalid string. If strict is False then literal - control characters are allowed in the string. - - Returns a tuple of the decoded string and the index of the character in s - after the end quote.""" - if encoding is None: - encoding = DEFAULT_ENCODING - chunks = [] - _append = chunks.append - begin = end - 1 - while 1: - chunk = _m(s, end) - if chunk is None: - raise ValueError( - errmsg("Unterminated string starting at", s, begin)) - end = chunk.end() - content, terminator = chunk.groups() - # Content is contains zero or more unescaped string characters - if content: - if not isinstance(content, unicode): - content = unicode(content, encoding) - _append(content) - # Terminator is the end of string, a literal control character, - # or a backslash denoting that an escape sequence follows - if terminator == '"': - break - elif terminator != '\\': - if strict: - msg = "Invalid control character %r at" % (terminator,) - #msg = "Invalid control character {0!r} at".format(terminator) - raise ValueError(errmsg(msg, s, end)) - else: - _append(terminator) - continue - try: - esc = s[end] - except IndexError: - raise ValueError( - errmsg("Unterminated string starting at", s, begin)) - # If not a unicode escape sequence, must be in the lookup table - if esc != 'u': - try: - char = _b[esc] - except KeyError: - msg = "Invalid \\escape: " + repr(esc) - raise ValueError(errmsg(msg, s, end)) - end += 1 - else: - # Unicode escape sequence - esc = s[end + 1:end + 5] - next_end = end + 5 - if len(esc) != 4: - msg = "Invalid \\uXXXX escape" - raise ValueError(errmsg(msg, s, end)) - uni = int(esc, 16) - # Check for surrogate pair on UCS-4 systems - if 0xd800 <= uni <= 0xdbff and sys.maxunicode > 65535: - msg = "Invalid \\uXXXX\\uXXXX surrogate pair" - if not s[end + 5:end + 7] == '\\u': - raise ValueError(errmsg(msg, s, end)) - esc2 = s[end + 7:end + 11] - if len(esc2) != 4: - raise ValueError(errmsg(msg, s, end)) - uni2 = int(esc2, 16) - uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00)) - next_end += 6 - char = unichr(uni) - end = next_end - # Append the unescaped character - _append(char) - return u''.join(chunks), end - - -# Use speedup if available -scanstring = c_scanstring or py_scanstring - -WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS) -WHITESPACE_STR = ' \t\n\r' - -def JSONObject((s, end), encoding, strict, scan_once, object_hook, _w=WHITESPACE.match, _ws=WHITESPACE_STR): - pairs = {} - # Use a slice to prevent IndexError from being raised, the following - # check will raise a more specific ValueError if the string is empty - nextchar = s[end:end + 1] - # Normally we expect nextchar == '"' - if nextchar != '"': - if nextchar in _ws: - end = _w(s, end).end() - nextchar = s[end:end + 1] - # Trivial empty object - if nextchar == '}': - return pairs, end + 1 - elif nextchar != '"': - raise ValueError(errmsg("Expecting property name", s, end)) - end += 1 - while True: - key, end = scanstring(s, end, encoding, strict) - - # To skip some function call overhead we optimize the fast paths where - # the JSON key separator is ": " or just ":". - if s[end:end + 1] != ':': - end = _w(s, end).end() - if s[end:end + 1] != ':': - raise ValueError(errmsg("Expecting : delimiter", s, end)) - - end += 1 - - try: - if s[end] in _ws: - end += 1 - if s[end] in _ws: - end = _w(s, end + 1).end() - except IndexError: - pass - - try: - value, end = scan_once(s, end) - except StopIteration: - raise ValueError(errmsg("Expecting object", s, end)) - pairs[key] = value - - try: - nextchar = s[end] - if nextchar in _ws: - end = _w(s, end + 1).end() - nextchar = s[end] - except IndexError: - nextchar = '' - end += 1 - - if nextchar == '}': - break - elif nextchar != ',': - raise ValueError(errmsg("Expecting , delimiter", s, end - 1)) - - try: - nextchar = s[end] - if nextchar in _ws: - end += 1 - nextchar = s[end] - if nextchar in _ws: - end = _w(s, end + 1).end() - nextchar = s[end] - except IndexError: - nextchar = '' - - end += 1 - if nextchar != '"': - raise ValueError(errmsg("Expecting property name", s, end - 1)) - - if object_hook is not None: - pairs = object_hook(pairs) - return pairs, end - -def JSONArray((s, end), scan_once, _w=WHITESPACE.match, _ws=WHITESPACE_STR): - values = [] - nextchar = s[end:end + 1] - if nextchar in _ws: - end = _w(s, end + 1).end() - nextchar = s[end:end + 1] - # Look-ahead for trivial empty array - if nextchar == ']': - return values, end + 1 - _append = values.append - while True: - try: - value, end = scan_once(s, end) - except StopIteration: - raise ValueError(errmsg("Expecting object", s, end)) - _append(value) - nextchar = s[end:end + 1] - if nextchar in _ws: - end = _w(s, end + 1).end() - nextchar = s[end:end + 1] - end += 1 - if nextchar == ']': - break - elif nextchar != ',': - raise ValueError(errmsg("Expecting , delimiter", s, end)) - - try: - if s[end] in _ws: - end += 1 - if s[end] in _ws: - end = _w(s, end + 1).end() - except IndexError: - pass - - return values, end - -class JSONDecoder(object): - """Simple JSON decoder - - Performs the following translations in decoding by default: - - +---------------+-------------------+ - | JSON | Python | - +===============+===================+ - | object | dict | - +---------------+-------------------+ - | array | list | - +---------------+-------------------+ - | string | unicode | - +---------------+-------------------+ - | number (int) | int, long | - +---------------+-------------------+ - | number (real) | float | - +---------------+-------------------+ - | true | True | - +---------------+-------------------+ - | false | False | - +---------------+-------------------+ - | null | None | - +---------------+-------------------+ - - It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as - their corresponding ``float`` values, which is outside the JSON spec. - - """ - - def __init__(self, encoding=None, object_hook=None, parse_float=None, - parse_int=None, parse_constant=None, strict=True): - """``encoding`` determines the encoding used to interpret any ``str`` - objects decoded by this instance (utf-8 by default). It has no - effect when decoding ``unicode`` objects. - - Note that currently only encodings that are a superset of ASCII work, - strings of other encodings should be passed in as ``unicode``. - - ``object_hook``, if specified, will be called with the result - of every JSON object decoded and its return value will be used in - place of the given ``dict``. This can be used to provide custom - deserializations (e.g. to support JSON-RPC class hinting). - - ``parse_float``, if specified, will be called with the string - of every JSON float to be decoded. By default this is equivalent to - float(num_str). This can be used to use another datatype or parser - for JSON floats (e.g. decimal.Decimal). - - ``parse_int``, if specified, will be called with the string - of every JSON int to be decoded. By default this is equivalent to - int(num_str). This can be used to use another datatype or parser - for JSON integers (e.g. float). - - ``parse_constant``, if specified, will be called with one of the - following strings: -Infinity, Infinity, NaN. - This can be used to raise an exception if invalid JSON numbers - are encountered. - - """ - self.encoding = encoding - self.object_hook = object_hook - self.parse_float = parse_float or float - self.parse_int = parse_int or int - self.parse_constant = parse_constant or _CONSTANTS.__getitem__ - self.strict = strict - self.parse_object = JSONObject - self.parse_array = JSONArray - self.parse_string = scanstring - self.scan_once = make_scanner(self) - - def decode(self, s, _w=WHITESPACE.match): - """Return the Python representation of ``s`` (a ``str`` or ``unicode`` - instance containing a JSON document) - - """ - obj, end = self.raw_decode(s, idx=_w(s, 0).end()) - end = _w(s, end).end() - if end != len(s): - raise ValueError(errmsg("Extra data", s, end, len(s))) - return obj - - def raw_decode(self, s, idx=0): - """Decode a JSON document from ``s`` (a ``str`` or ``unicode`` beginning - with a JSON document) and return a 2-tuple of the Python - representation and the index in ``s`` where the document ended. - - This can be used to decode a JSON document from a string that may - have extraneous data at the end. - - """ - try: - obj, end = self.scan_once(s, idx) - except StopIteration: - raise ValueError("No JSON object could be decoded") - return obj, end diff --git a/lib/simplejson/encoder.py b/lib/simplejson/encoder.py deleted file mode 100644 index cf582903..00000000 --- a/lib/simplejson/encoder.py +++ /dev/null @@ -1,440 +0,0 @@ -"""Implementation of JSONEncoder -""" -import re - -try: - from simplejson._speedups import encode_basestring_ascii as c_encode_basestring_ascii -except ImportError: - c_encode_basestring_ascii = None -try: - from simplejson._speedups import make_encoder as c_make_encoder -except ImportError: - c_make_encoder = None - -ESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]') -ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])') -HAS_UTF8 = re.compile(r'[\x80-\xff]') -ESCAPE_DCT = { - '\\': '\\\\', - '"': '\\"', - '\b': '\\b', - '\f': '\\f', - '\n': '\\n', - '\r': '\\r', - '\t': '\\t', -} -for i in range(0x20): - #ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i)) - ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,)) - -# Assume this produces an infinity on all machines (probably not guaranteed) -INFINITY = float('1e66666') -FLOAT_REPR = repr - -def encode_basestring(s): - """Return a JSON representation of a Python string - - """ - def replace(match): - return ESCAPE_DCT[match.group(0)] - return '"' + ESCAPE.sub(replace, s) + '"' - - -def py_encode_basestring_ascii(s): - """Return an ASCII-only JSON representation of a Python string - - """ - if isinstance(s, str) and HAS_UTF8.search(s) is not None: - s = s.decode('utf-8') - def replace(match): - s = match.group(0) - try: - return ESCAPE_DCT[s] - except KeyError: - n = ord(s) - if n < 0x10000: - #return '\\u{0:04x}'.format(n) - return '\\u%04x' % (n,) - else: - # surrogate pair - n -= 0x10000 - s1 = 0xd800 | ((n >> 10) & 0x3ff) - s2 = 0xdc00 | (n & 0x3ff) - #return '\\u{0:04x}\\u{1:04x}'.format(s1, s2) - return '\\u%04x\\u%04x' % (s1, s2) - return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"' - - -encode_basestring_ascii = c_encode_basestring_ascii or py_encode_basestring_ascii - -class JSONEncoder(object): - """Extensible JSON encoder for Python data structures. - - Supports the following objects and types by default: - - +-------------------+---------------+ - | Python | JSON | - +===================+===============+ - | dict | object | - +-------------------+---------------+ - | list, tuple | array | - +-------------------+---------------+ - | str, unicode | string | - +-------------------+---------------+ - | int, long, float | number | - +-------------------+---------------+ - | True | true | - +-------------------+---------------+ - | False | false | - +-------------------+---------------+ - | None | null | - +-------------------+---------------+ - - To extend this to recognize other objects, subclass and implement a - ``.default()`` method with another method that returns a serializable - object for ``o`` if possible, otherwise it should call the superclass - implementation (to raise ``TypeError``). - - """ - item_separator = ', ' - key_separator = ': ' - def __init__(self, skipkeys=False, ensure_ascii=True, - check_circular=True, allow_nan=True, sort_keys=False, - indent=None, separators=None, encoding='utf-8', default=None): - """Constructor for JSONEncoder, with sensible defaults. - - If skipkeys is false, then it is a TypeError to attempt - encoding of keys that are not str, int, long, float or None. If - skipkeys is True, such items are simply skipped. - - If ensure_ascii is true, the output is guaranteed to be str - objects with all incoming unicode characters escaped. If - ensure_ascii is false, the output will be unicode object. - - If check_circular is true, then lists, dicts, and custom encoded - objects will be checked for circular references during encoding to - prevent an infinite recursion (which would cause an OverflowError). - Otherwise, no such check takes place. - - If allow_nan is true, then NaN, Infinity, and -Infinity will be - encoded as such. This behavior is not JSON specification compliant, - but is consistent with most JavaScript based encoders and decoders. - Otherwise, it will be a ValueError to encode such floats. - - If sort_keys is true, then the output of dictionaries will be - sorted by key; this is useful for regression tests to ensure - that JSON serializations can be compared on a day-to-day basis. - - If indent is a non-negative integer, then JSON array - elements and object members will be pretty-printed with that - indent level. An indent level of 0 will only insert newlines. - None is the most compact representation. - - If specified, separators should be a (item_separator, key_separator) - tuple. The default is (', ', ': '). To get the most compact JSON - representation you should specify (',', ':') to eliminate whitespace. - - If specified, default is a function that gets called for objects - that can't otherwise be serialized. It should return a JSON encodable - version of the object or raise a ``TypeError``. - - If encoding is not None, then all input strings will be - transformed into unicode using that encoding prior to JSON-encoding. - The default is UTF-8. - - """ - - self.skipkeys = skipkeys - self.ensure_ascii = ensure_ascii - self.check_circular = check_circular - self.allow_nan = allow_nan - self.sort_keys = sort_keys - self.indent = indent - if separators is not None: - self.item_separator, self.key_separator = separators - if default is not None: - self.default = default - self.encoding = encoding - - def default(self, o): - """Implement this method in a subclass such that it returns - a serializable object for ``o``, or calls the base implementation - (to raise a ``TypeError``). - - For example, to support arbitrary iterators, you could - implement default like this:: - - def default(self, o): - try: - iterable = iter(o) - except TypeError: - pass - else: - return list(iterable) - return JSONEncoder.default(self, o) - - """ - raise TypeError(repr(o) + " is not JSON serializable") - - def encode(self, o): - """Return a JSON string representation of a Python data structure. - - >>> JSONEncoder().encode({"foo": ["bar", "baz"]}) - '{"foo": ["bar", "baz"]}' - - """ - # This is for extremely simple cases and benchmarks. - if isinstance(o, basestring): - if isinstance(o, str): - _encoding = self.encoding - if (_encoding is not None - and not (_encoding == 'utf-8')): - o = o.decode(_encoding) - if self.ensure_ascii: - return encode_basestring_ascii(o) - else: - return encode_basestring(o) - # This doesn't pass the iterator directly to ''.join() because the - # exceptions aren't as detailed. The list call should be roughly - # equivalent to the PySequence_Fast that ''.join() would do. - chunks = self.iterencode(o, _one_shot=True) - if not isinstance(chunks, (list, tuple)): - chunks = list(chunks) - return ''.join(chunks) - - def iterencode(self, o, _one_shot=False): - """Encode the given object and yield each string - representation as available. - - For example:: - - for chunk in JSONEncoder().iterencode(bigobject): - mysocket.write(chunk) - - """ - if self.check_circular: - markers = {} - else: - markers = None - if self.ensure_ascii: - _encoder = encode_basestring_ascii - else: - _encoder = encode_basestring - if self.encoding != 'utf-8': - def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding): - if isinstance(o, str): - o = o.decode(_encoding) - return _orig_encoder(o) - - def floatstr(o, allow_nan=self.allow_nan, _repr=FLOAT_REPR, _inf=INFINITY, _neginf=-INFINITY): - # Check for specials. Note that this type of test is processor- and/or - # platform-specific, so do tests which don't depend on the internals. - - if o != o: - text = 'NaN' - elif o == _inf: - text = 'Infinity' - elif o == _neginf: - text = '-Infinity' - else: - return _repr(o) - - if not allow_nan: - raise ValueError( - "Out of range float values are not JSON compliant: " + - repr(o)) - - return text - - - if _one_shot and c_make_encoder is not None and not self.indent and not self.sort_keys: - _iterencode = c_make_encoder( - markers, self.default, _encoder, self.indent, - self.key_separator, self.item_separator, self.sort_keys, - self.skipkeys, self.allow_nan) - else: - _iterencode = _make_iterencode( - markers, self.default, _encoder, self.indent, floatstr, - self.key_separator, self.item_separator, self.sort_keys, - self.skipkeys, _one_shot) - return _iterencode(o, 0) - -def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot, - ## HACK: hand-optimized bytecode; turn globals into locals - False=False, - True=True, - ValueError=ValueError, - basestring=basestring, - dict=dict, - float=float, - id=id, - int=int, - isinstance=isinstance, - list=list, - long=long, - str=str, - tuple=tuple, - ): - - def _iterencode_list(lst, _current_indent_level): - if not lst: - yield '[]' - return - if markers is not None: - markerid = id(lst) - if markerid in markers: - raise ValueError("Circular reference detected") - markers[markerid] = lst - buf = '[' - if _indent is not None: - _current_indent_level += 1 - newline_indent = '\n' + (' ' * (_indent * _current_indent_level)) - separator = _item_separator + newline_indent - buf += newline_indent - else: - newline_indent = None - separator = _item_separator - first = True - for value in lst: - if first: - first = False - else: - buf = separator - if isinstance(value, basestring): - yield buf + _encoder(value) - elif value is None: - yield buf + 'null' - elif value is True: - yield buf + 'true' - elif value is False: - yield buf + 'false' - elif isinstance(value, (int, long)): - yield buf + str(value) - elif isinstance(value, float): - yield buf + _floatstr(value) - else: - yield buf - if isinstance(value, (list, tuple)): - chunks = _iterencode_list(value, _current_indent_level) - elif isinstance(value, dict): - chunks = _iterencode_dict(value, _current_indent_level) - else: - chunks = _iterencode(value, _current_indent_level) - for chunk in chunks: - yield chunk - if newline_indent is not None: - _current_indent_level -= 1 - yield '\n' + (' ' * (_indent * _current_indent_level)) - yield ']' - if markers is not None: - del markers[markerid] - - def _iterencode_dict(dct, _current_indent_level): - if not dct: - yield '{}' - return - if markers is not None: - markerid = id(dct) - if markerid in markers: - raise ValueError("Circular reference detected") - markers[markerid] = dct - yield '{' - if _indent is not None: - _current_indent_level += 1 - newline_indent = '\n' + (' ' * (_indent * _current_indent_level)) - item_separator = _item_separator + newline_indent - yield newline_indent - else: - newline_indent = None - item_separator = _item_separator - first = True - if _sort_keys: - items = dct.items() - items.sort(key=lambda kv: kv[0]) - else: - items = dct.iteritems() - for key, value in items: - if isinstance(key, basestring): - pass - # JavaScript is weakly typed for these, so it makes sense to - # also allow them. Many encoders seem to do something like this. - elif isinstance(key, float): - key = _floatstr(key) - elif key is True: - key = 'true' - elif key is False: - key = 'false' - elif key is None: - key = 'null' - elif isinstance(key, (int, long)): - key = str(key) - elif _skipkeys: - continue - else: - raise TypeError("key " + repr(key) + " is not a string") - if first: - first = False - else: - yield item_separator - yield _encoder(key) - yield _key_separator - if isinstance(value, basestring): - yield _encoder(value) - elif value is None: - yield 'null' - elif value is True: - yield 'true' - elif value is False: - yield 'false' - elif isinstance(value, (int, long)): - yield str(value) - elif isinstance(value, float): - yield _floatstr(value) - else: - if isinstance(value, (list, tuple)): - chunks = _iterencode_list(value, _current_indent_level) - elif isinstance(value, dict): - chunks = _iterencode_dict(value, _current_indent_level) - else: - chunks = _iterencode(value, _current_indent_level) - for chunk in chunks: - yield chunk - if newline_indent is not None: - _current_indent_level -= 1 - yield '\n' + (' ' * (_indent * _current_indent_level)) - yield '}' - if markers is not None: - del markers[markerid] - - def _iterencode(o, _current_indent_level): - if isinstance(o, basestring): - yield _encoder(o) - elif o is None: - yield 'null' - elif o is True: - yield 'true' - elif o is False: - yield 'false' - elif isinstance(o, (int, long)): - yield str(o) - elif isinstance(o, float): - yield _floatstr(o) - elif isinstance(o, (list, tuple)): - for chunk in _iterencode_list(o, _current_indent_level): - yield chunk - elif isinstance(o, dict): - for chunk in _iterencode_dict(o, _current_indent_level): - yield chunk - else: - if markers is not None: - markerid = id(o) - if markerid in markers: - raise ValueError("Circular reference detected") - markers[markerid] = o - o = _default(o) - for chunk in _iterencode(o, _current_indent_level): - yield chunk - if markers is not None: - del markers[markerid] - - return _iterencode diff --git a/lib/simplejson/scanner.py b/lib/simplejson/scanner.py deleted file mode 100644 index adbc6ec9..00000000 --- a/lib/simplejson/scanner.py +++ /dev/null @@ -1,65 +0,0 @@ -"""JSON token scanner -""" -import re -try: - from simplejson._speedups import make_scanner as c_make_scanner -except ImportError: - c_make_scanner = None - -__all__ = ['make_scanner'] - -NUMBER_RE = re.compile( - r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?', - (re.VERBOSE | re.MULTILINE | re.DOTALL)) - -def py_make_scanner(context): - parse_object = context.parse_object - parse_array = context.parse_array - parse_string = context.parse_string - match_number = NUMBER_RE.match - encoding = context.encoding - strict = context.strict - parse_float = context.parse_float - parse_int = context.parse_int - parse_constant = context.parse_constant - object_hook = context.object_hook - - def _scan_once(string, idx): - try: - nextchar = string[idx] - except IndexError: - raise StopIteration - - if nextchar == '"': - return parse_string(string, idx + 1, encoding, strict) - elif nextchar == '{': - return parse_object((string, idx + 1), encoding, strict, _scan_once, object_hook) - elif nextchar == '[': - return parse_array((string, idx + 1), _scan_once) - elif nextchar == 'n' and string[idx:idx + 4] == 'null': - return None, idx + 4 - elif nextchar == 't' and string[idx:idx + 4] == 'true': - return True, idx + 4 - elif nextchar == 'f' and string[idx:idx + 5] == 'false': - return False, idx + 5 - - m = match_number(string, idx) - if m is not None: - integer, frac, exp = m.groups() - if frac or exp: - res = parse_float(integer + (frac or '') + (exp or '')) - else: - res = parse_int(integer) - return res, m.end() - elif nextchar == 'N' and string[idx:idx + 3] == 'NaN': - return parse_constant('NaN'), idx + 3 - elif nextchar == 'I' and string[idx:idx + 8] == 'Infinity': - return parse_constant('Infinity'), idx + 8 - elif nextchar == '-' and string[idx:idx + 9] == '-Infinity': - return parse_constant('-Infinity'), idx + 9 - else: - raise StopIteration - - return _scan_once - -make_scanner = c_make_scanner or py_make_scanner diff --git a/lib/simplejson/tool.py b/lib/simplejson/tool.py deleted file mode 100644 index 90443317..00000000 --- a/lib/simplejson/tool.py +++ /dev/null @@ -1,37 +0,0 @@ -r"""Command-line tool to validate and pretty-print JSON - -Usage:: - - $ echo '{"json":"obj"}' | python -m simplejson.tool - { - "json": "obj" - } - $ echo '{ 1.2:3.4}' | python -m simplejson.tool - Expecting property name: line 1 column 2 (char 2) - -""" -import sys -import simplejson - -def main(): - if len(sys.argv) == 1: - infile = sys.stdin - outfile = sys.stdout - elif len(sys.argv) == 2: - infile = open(sys.argv[1], 'rb') - outfile = sys.stdout - elif len(sys.argv) == 3: - infile = open(sys.argv[1], 'rb') - outfile = open(sys.argv[2], 'wb') - else: - raise SystemExit(sys.argv[0] + " [infile [outfile]]") - try: - obj = simplejson.load(infile) - except ValueError, e: - raise SystemExit(e) - simplejson.dump(obj, outfile, sort_keys=True, indent=4) - outfile.write('\n') - - -if __name__ == '__main__': - main() diff --git a/lib/torrentool/__init__.py b/lib/torrentool/__init__.py deleted file mode 100644 index f7f572ba..00000000 --- a/lib/torrentool/__init__.py +++ /dev/null @@ -1 +0,0 @@ -VERSION = (1, 0, 2) \ No newline at end of file diff --git a/lib/torrentool/api.py b/lib/torrentool/api.py deleted file mode 100644 index baac4b3b..00000000 --- a/lib/torrentool/api.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -Exposes commonly used classes and functions. - -""" -from .bencode import Bencode -from .torrent import Torrent -from .utils import upload_to_cache_server, get_open_trackers_from_local, get_open_trackers_from_remote diff --git a/lib/torrentool/bencode.py b/lib/torrentool/bencode.py deleted file mode 100644 index 6d431d13..00000000 --- a/lib/torrentool/bencode.py +++ /dev/null @@ -1,204 +0,0 @@ -from collections import OrderedDict -from operator import itemgetter -from codecs import encode -from sys import version_info - -from .exceptions import BencodeDecodingError, BencodeEncodingError - - -PY3 = version_info >= (3, 0) - -if PY3: - str_type = str - byte_types = (bytes, bytearray) - chr_ = chr - int_types = int -else: - str_type = basestring - byte_types = bytes - chr_ = lambda ch: ch - int_types = (int, long) - - -class Bencode(object): - """Exposes utilities for bencoding.""" - - @classmethod - def encode(cls, value): - """Encodes a value into bencoded bytes. - - :param value: Python object to be encoded (str, int, list, dict). - :param str val_encoding: Encoding used by strings in a given object. - :rtype: bytes - """ - val_encoding = 'utf-8' - - def encode_str(v): - try: - v_enc = encode(v, val_encoding) - - except UnicodeDecodeError: - if PY3: - raise - else: - # Suppose bytestring - v_enc = v - - prefix = encode('%s:' % len(v_enc), val_encoding) - return prefix + v_enc - - def encode_(val): - if isinstance(val, str_type): - result = encode_str(val) - - elif isinstance(val, int_types): - result = encode(('i%se' % val), val_encoding) - - elif isinstance(val, (list, set, tuple)): - result = encode('l', val_encoding) - for item in val: - result += encode_(item) - result += encode('e', val_encoding) - - elif isinstance(val, dict): - result = encode('d', val_encoding) - - # Dictionaries are expected to be sorted by key. - for k, v in OrderedDict(sorted(val.items(), key=itemgetter(0))).items(): - result += (encode_str(k) + encode_(v)) - - result += encode('e', val_encoding) - - elif isinstance(val, byte_types): - result = encode('%s:' % len(val), val_encoding) - result += val - - else: - raise BencodeEncodingError('Unable to encode `%s` %s' % (type(val), val)) - - return result - - return encode_(value) - - @classmethod - def decode(cls, encoded): - """Decodes bencoded data introduced as bytes. - - Returns decoded structure(s). - - :param bytes encoded: - """ - def create_dict(items): - # Let's guarantee that dictionaries are sorted. - k_v_pair = zip(*[iter(items)] * 2) - return OrderedDict(sorted(k_v_pair, key=itemgetter(0))) - - def create_list(items): - return list(items) - - stack_items = [] - stack_containers = [] - - def compress_stack(): - target_container = stack_containers.pop() - subitems = [] - - while True: - subitem = stack_items.pop() - subitems.append(subitem) - if subitem is target_container: - break - - container_creator = subitems.pop() - container = container_creator(reversed(subitems)) - stack_items.append(container) - - def parse_forward(till_char, sequence): - number = '' - char_sub_idx = 0 - - for char_sub_idx, char_sub in enumerate(sequence): - char_sub = chr_(char_sub) - if char_sub == till_char: - break - - number += char_sub - - number = int(number or 0) - char_sub_idx += 1 - - return number, char_sub_idx - - while encoded: - char = encoded[0] - char = chr_(char) - - if char == 'd': # Dictionary - stack_items.append(create_dict) - stack_containers.append(create_dict) - encoded = encoded[1:] - - elif char == 'l': # List - stack_items.append(create_list) - stack_containers.append(create_list) - encoded = encoded[1:] - - elif char == 'i': # Integer - number, char_sub_idx = parse_forward('e', encoded[1:]) - char_sub_idx += 1 - - stack_items.append(number) - encoded = encoded[char_sub_idx:] - - elif char.isdigit(): # String - str_len, char_sub_idx = parse_forward(':', encoded) - last_char_idx = char_sub_idx + str_len - - string = encoded[char_sub_idx:last_char_idx] - try: - string = string.decode('utf-8') - except UnicodeDecodeError: - # Considered bytestring (e.g. `pieces` hashes concatenation). - pass - - stack_items.append(string) - encoded = encoded[last_char_idx:] - - elif char == 'e': # End of a dictionary or a list. - compress_stack() - encoded = encoded[1:] - - else: - raise BencodeDecodingError('Unable to interpret `%s` char.' % char) - - if len(stack_items) == 1: - stack_items = stack_items.pop() - - return stack_items - - @classmethod - def read_string(cls, string): - """Decodes a given bencoded string or bytestring. - - Returns decoded structure(s). - - :param str string: - :rtype: list - """ - if PY3 and not isinstance(string, byte_types): - string = string.encode() - - return cls.decode(string) - - @classmethod - def read_file(cls, filepath): - """Decodes bencoded data of a given file. - - Returns decoded structure(s). - - :param str filepath: - :rtype: list - """ - with open(filepath, mode='rb') as f: - contents = f.read() - return cls.decode(contents) diff --git a/lib/torrentool/cli.py b/lib/torrentool/cli.py deleted file mode 100644 index d07a8ee3..00000000 --- a/lib/torrentool/cli.py +++ /dev/null @@ -1,94 +0,0 @@ -from __future__ import division -import click -from os import path, getcwd - -from . import VERSION -from .api import Torrent -from .utils import humanize_filesize, upload_to_cache_server, get_open_trackers_from_remote, \ - get_open_trackers_from_local -from .exceptions import RemoteUploadError, RemoteDownloadError - - -@click.group() -@click.version_option(version='.'.join(map(str, VERSION))) -def start(): - """Torrentool command line utilities.""" - - -@start.group() -def torrent(): - """Torrent-related commands.""" - - -@torrent.command() -@click.argument('torrent_path', type=click.Path(exists=True, writable=False, dir_okay=False)) -def info(torrent_path): - """Print out information from .torrent file.""" - - my_torrent = Torrent.from_file(torrent_path) - - size = my_torrent.total_size - - click.secho('Name: %s' % my_torrent.name, fg='blue') - click.secho('Files:') - for file_tuple in my_torrent.files: - click.secho(file_tuple.name) - - click.secho('Hash: %s' % my_torrent.info_hash, fg='blue') - click.secho('Size: %s (%s)' % (humanize_filesize(size), size), fg='blue') - click.secho('Magnet: %s' % my_torrent.get_magnet(), fg='yellow') - - -@torrent.command() -@click.argument('source', type=click.Path(exists=True, writable=False)) -@click.option('--dest', default=getcwd, type=click.Path(file_okay=False), help='Destination path to put .torrent file into. Default: current directory.') -@click.option('--tracker', default=None, help='Tracker announce URL (multiple comma-separated values supported).') -@click.option('--open_trackers', default=False, is_flag=True, help='Add open trackers announce URLs.') -@click.option('--comment', default=None, help='Arbitrary comment.') -@click.option('--cache', default=False, is_flag=True, help='Upload file to torrent cache services.') -def create(source, dest, tracker, open_trackers, comment, cache): - """Create torrent file from a single file or a directory.""" - - source_title = path.basename(source).replace('.', '_').replace(' ', '_') - dest = '%s.torrent' % path.join(dest, source_title) - - click.secho('Creating torrent from %s ...' % source) - - my_torrent = Torrent.create_from(source) - - if comment: - my_torrent.comment = comment - - urls = [] - - if tracker: - urls = tracker.split(',') - - if open_trackers: - click.secho('Fetching an up-to-date open tracker list ...') - try: - urls.extend(get_open_trackers_from_remote()) - except RemoteDownloadError: - click.secho('Failed. Using built-in open tracker list.', fg='red', err=True) - urls.extend(get_open_trackers_from_local()) - - if urls: - my_torrent.announce_urls = urls - - my_torrent.to_file(dest) - - click.secho('Torrent file created: %s' % dest, fg='green') - click.secho('Torrent info hash: %s' % my_torrent.info_hash, fg='blue') - - if cache: - click.secho('Uploading to %s torrent cache service ...') - try: - result = upload_to_cache_server(dest) - click.secho('Cached torrent URL: %s' % result, fg='yellow') - - except RemoteUploadError as e: - click.secho('Failed: %s' % e, fg='red', err=True) - - -def main(): - start(obj={}) diff --git a/lib/torrentool/exceptions.py b/lib/torrentool/exceptions.py deleted file mode 100644 index 53118482..00000000 --- a/lib/torrentool/exceptions.py +++ /dev/null @@ -1,27 +0,0 @@ - -class TorrentoolException(Exception): - """Base torrentool exception. All others are inherited from it.""" - - -class BencodeError(TorrentoolException): - """Base exception for bencode related errors.""" - - -class BencodeDecodingError(BencodeError): - """Raised when torrentool is unable to decode bencoded data.""" - - -class BencodeEncodingError(BencodeError): - """Raised when torrentool is unable to encode data into bencode.""" - - -class TorrentError(TorrentoolException): - """Base exception for Torrent object related errors.""" - - -class RemoteUploadError(TorrentoolException): - """Base class for upload to remotes related issues.""" - - -class RemoteDownloadError(TorrentoolException): - """Base class for issues related to downloads from remotes.""" diff --git a/lib/torrentool/repo/open_trackers.ini b/lib/torrentool/repo/open_trackers.ini deleted file mode 100644 index c0ca0aa0..00000000 --- a/lib/torrentool/repo/open_trackers.ini +++ /dev/null @@ -1,8 +0,0 @@ -udp://tracker.coppersurfer.tk:6969/announce -udp://tracker.internetwarriors.net:1337/announce -udp://tracker.leechers-paradise.org:6969/announce -udp://tracker.opentrackr.org:1337/announce -udp://tracker.openbittorrent.com:80/announce -udp://tracker.sktorrent.net:6969/announce -udp://tracker.zer0day.to:1337/announce -udp://exodus.desync.com:6969/announce diff --git a/lib/torrentool/torrent.py b/lib/torrentool/torrent.py deleted file mode 100644 index 8472c8cb..00000000 --- a/lib/torrentool/torrent.py +++ /dev/null @@ -1,436 +0,0 @@ -from calendar import timegm -from collections import namedtuple -from datetime import datetime -from functools import reduce -from hashlib import sha1 -from os import walk, sep -from os.path import join, isdir, getsize, normpath, basename - -try: - from urllib.parse import urlencode -except ImportError: # Py2 - from urllib import urlencode - -from .bencode import Bencode -from .exceptions import TorrentError -from .utils import get_app_version - - -_ITERABLE_TYPES = (list, tuple, set) - - -TorrentFile = namedtuple('TorrentFile', ['name', 'length']) - - -class Torrent(object): - """Represents a torrent file, and exposes utilities to work with it.""" - - _filepath = None - - def __init__(self, dict_struct=None): - dict_struct = dict_struct or {'info': {}} - self._struct = dict_struct - - def __str__(self): - return 'Torrent: %s' % self.name - - announce_urls = property() - """List of lists of tracker announce URLs.""" - - comment = property() - """Optional. Free-form textual comments of the author.""" - - creation_date = property() - """Optional. The creation time of the torrent, in standard UNIX epoch format. UTC.""" - - created_by = property() - """Optional. Name and version of the program used to create the .torrent""" - - private = property() - """Optional. If True the client MUST publish its presence to get other peers - ONLY via the trackers explicitly described in the metainfo file. If False or is not present, - the client may obtain peer from other means, e.g. PEX peer exchange, dht. - - """ - - name = property() - """Torrent name (title).""" - - webseeds = property() - """A list of URLs where torrent data can be retrieved. - - See also: Torrent.httpseeds - - http://bittorrent.org/beps/bep_0019.html - """ - - httpseeds = property() - """A list of URLs where torrent data can be retrieved. - - See also and prefer Torrent.webseeds - - http://bittorrent.org/beps/bep_0017.html - """ - - def _list_getter(self, key): - return self._struct.get(key, []) - - def _list_setter(self, key, val): - if val is None: - try: - del self._struct[key] - return - except KeyError: - return - - if not isinstance(val, _ITERABLE_TYPES): - val = [val] - - self._struct[key] = val - - @webseeds.getter - def webseeds(self): - return self._list_getter('url-list') - - @webseeds.setter - def webseeds(self, val): - self._list_setter('url-list', val) - - @httpseeds.getter - def httpseeds(self): - return self._list_getter('httpseeds') - - @httpseeds.setter - def httpseeds(self, val): - self._list_setter('httpseeds', val) - - @property - def files(self): - """Files in torrent. - - List of namedtuples (filepath, size). - - :rtype: list[TorrentFile] - """ - files = [] - info = self._struct.get('info') - - if not info: - return files - - if 'files' in info: - base = info['name'] - - for f in info['files']: - files.append(TorrentFile(join(base, *f['path']), f['length'])) - - else: - files.append(TorrentFile(info['name'], info['length'])) - - return files - - @property - def total_size(self): - """Total size of all files in torrent.""" - return reduce(lambda prev, curr: prev + curr[1], self.files, 0) - - @property - def info_hash(self): - """Hash of torrent file info section. Also known as torrent hash.""" - info = self._struct.get('info') - - if not info: - return None - - return sha1(Bencode.encode(info)).hexdigest() - - @property - def magnet_link(self): - """Magnet link using BTIH (BitTorrent Info Hash) URN.""" - return self.get_magnet(detailed=False) - - @announce_urls.getter - def announce_urls(self): - """List of lists of announce (tracker) URLs. - - First inner list is considered as primary announcers list, - the following lists as back-ups. - - http://bittorrent.org/beps/bep_0012.html - - """ - urls = self._struct.get('announce-list') - - if not urls: - urls = self._struct.get('announce') - if not urls: - return [] - urls = [[urls]] - - return urls - - @announce_urls.setter - def announce_urls(self, val): - self._struct['announce'] = '' - self._struct['announce-list'] = [] - - def set_single(val): - del self._struct['announce-list'] - self._struct['announce'] = val - - if isinstance(val, _ITERABLE_TYPES): - length = len(val) - - if length: - if length == 1: - set_single(val[0]) - else: - for item in val: - if not isinstance(item, _ITERABLE_TYPES): - item = [item] - self._struct['announce-list'].append(item) - self._struct['announce'] = val[0] - - else: - set_single(val) - - @comment.getter - def comment(self): - return self._struct.get('comment') - - @comment.setter - def comment(self, val): - self._struct['comment'] = val - - @creation_date.getter - def creation_date(self): - date = self._struct.get('creation date') - if date is not None: - date = datetime.utcfromtimestamp(int(date)) - return date - - @creation_date.setter - def creation_date(self, val): - self._struct['creation date'] = timegm(val.timetuple()) - - @created_by.getter - def created_by(self): - return self._struct.get('created by') - - @created_by.setter - def created_by(self, val): - self._struct['created by'] = val - - @private.getter - def private(self): - return self._struct.get('info', {}).get('private', False) - - @private.setter - def private(self, val): - if not val: - try: - del self._struct['info']['private'] - except KeyError: - pass - else: - self._struct['info']['private'] = 1 - - @name.getter - def name(self): - return self._struct.get('info', {}).get('name', None) - - @name.setter - def name(self, val): - self._struct['info']['name'] = val - - def get_magnet(self, detailed=True): - """Returns torrent magnet link, consisting of BTIH (BitTorrent Info Hash) URN - anr optional other information. - - :param bool|list|tuple|set detailed: - For boolean - whether additional info (such as trackers) should be included. - For iterable - expected allowed parameter names: - tr - trackers - ws - webseeds - - """ - result = 'magnet:?xt=urn:btih:' + self.info_hash - - def add_tr(): - urls = self.announce_urls - if not urls: - return - - trackers = [] - - urls = urls[0] # Only primary announcers are enough. - for url in urls: - trackers.append(('tr', url)) - - if trackers: - return urlencode(trackers) - - def add_ws(): - webseeds = [('ws', url) for url in self.webseeds] - if webseeds: - return urlencode(webseeds) - - params_map = { - 'tr': add_tr, - 'ws': add_ws, - } - - if detailed: - details = [] - - if isinstance(detailed, _ITERABLE_TYPES): - requested_params = detailed - else: - requested_params = params_map.keys() - - for param in requested_params: - param_val = params_map[param]() - param_val and details.append(param_val) - - if details: - result += '&%s' % '&'.join(details) - - return result - - def to_file(self, filepath=None): - """Writes Torrent object into file, either - - :param filepath: - """ - if filepath is None and self._filepath is None: - raise TorrentError('Unable to save torrent to file: no filepath supplied.') - - if filepath is not None: - self._filepath = filepath - - with open(self._filepath, mode='wb') as f: - f.write(self.to_string()) - - def to_string(self): - """Returns bytes representing torrent file. - - :param str encoding: Encoding used by strings in Torrent object. - :rtype: bytearray - """ - return Bencode.encode(self._struct) - - @classmethod - def _get_target_files_info(cls, src_path): - src_path = u'%s' % src_path # Force walk() to return unicode names. - - is_dir = isdir(src_path) - target_files = [] - - if is_dir: - for base, _, files in walk(src_path): - target_files.extend([join(base, fname) for fname in sorted(files)]) - - else: - target_files.append(src_path) - - target_files_ = [] - total_size = 0 - for fpath in target_files: - file_size = getsize(fpath) - if not file_size: - continue - target_files_.append((fpath, file_size, normpath(fpath.replace(src_path, '')).strip(sep).split(sep))) - total_size += file_size - - return target_files_, total_size - - @classmethod - def create_from(cls, src_path): - """Returns Torrent object created from a file or a directory. - - :param str src_path: - :rtype: Torrent - """ - is_dir = isdir(src_path) - target_files, size_data = cls._get_target_files_info(src_path) - - SIZE_MIN = 32768 # 32 KiB - SIZE_DEFAULT = 262144 # 256 KiB - SIZE_MAX = 1048576 # 1 MiB - - CHUNKS_MIN = 1000 # todo use those limits as advised - CHUNKS_MAX = 2200 - - size_piece = SIZE_MIN - if size_data > SIZE_MIN: - size_piece = SIZE_DEFAULT - - if size_piece > SIZE_MAX: - size_piece = SIZE_MAX - - def read(filepath): - with open(filepath, 'rb') as f: - while True: - chunk = f.read(size_piece - len(pieces_buffer)) - chunk_size = len(chunk) - if chunk_size == 0: - break - yield chunk - - pieces = bytearray() - pieces_buffer = bytearray() - - for fpath, _, _ in target_files: - for chunk in read(fpath): - pieces_buffer += chunk - - if len(pieces_buffer) == size_piece: - pieces += sha1(pieces_buffer).digest()[:20] - pieces_buffer = bytearray() - - if len(pieces_buffer): - pieces += sha1(pieces_buffer).digest()[:20] - pieces_buffer = bytearray() - - info = { - 'name': basename(src_path), - 'pieces': bytes(pieces), - 'piece length': size_piece, - } - - if is_dir: - files = [] - - for _, length, path in target_files: - files.append({'length': length, 'path': path}) - - info['files'] = files - - else: - info['length'] = target_files[0][1] - - torrent = cls({'info': info}) - torrent.created_by = get_app_version() - torrent.creation_date = datetime.utcnow() - - return torrent - - @classmethod - def from_string(cls, string): - """Alternative constructor to get Torrent object from string. - - :param str string: - :rtype: Torrent - """ - return cls(Bencode.read_string(string)) - - @classmethod - def from_file(cls, filepath): - """Alternative constructor to get Torrent object from file. - - :param str filepath: - :rtype: Torrent - """ - torrent = cls(Bencode.read_file(filepath)) - torrent._filepath = filepath - return torrent diff --git a/lib/torrentool/utils.py b/lib/torrentool/utils.py deleted file mode 100644 index 7d346cd7..00000000 --- a/lib/torrentool/utils.py +++ /dev/null @@ -1,91 +0,0 @@ -import math -from os import path - -from .exceptions import RemoteUploadError, RemoteDownloadError - - -OPEN_TRACKERS_FILENAME = 'open_trackers.ini' -REMOTE_TIMEOUT = 4 - - -def get_app_version(): - """Returns full version string including application name - suitable for putting into Torrent.created_by. - - """ - from torrentool import VERSION - return 'torrentool/%s' % '.'.join(map(str, VERSION)) - - -def humanize_filesize(bytes_size): - """Returns human readable filesize. - - :param int bytes_size: - :rtype: str - """ - if not bytes_size: - return '0 B' - - names = ('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB') - - name_idx = int(math.floor(math.log(bytes_size, 1024))) - size = round(bytes_size / math.pow(1024, name_idx), 2) - - return '%s %s' % (size, names[name_idx]) - - -def upload_to_cache_server(fpath): - """Uploads .torrent file to a cache server. - - Returns upload file URL. - - :rtype: str - """ - url_base = 'http://torrage.info' - url_upload = '%s/autoupload.php' % url_base - url_download = '%s/torrent.php?h=' % url_base - file_field = 'torrent' - - try: - import requests - - response = requests.post(url_upload, files={file_field: open(fpath, 'rb')}, timeout=REMOTE_TIMEOUT) - response.raise_for_status() - - info_cache = response.text - return url_download + info_cache - - except (ImportError, requests.RequestException) as e: - - # Now trace is lost. `raise from` to consider. - raise RemoteUploadError('Unable to upload to %s: %s' % (url_upload, e)) - - -def get_open_trackers_from_remote(): - """Returns open trackers announce URLs list from remote repo.""" - - url_base = 'https://raw.githubusercontent.com/idlesign/torrentool/master/torrentool/repo' - url = '%s/%s' % (url_base, OPEN_TRACKERS_FILENAME) - - try: - import requests - - response = requests.get(url, timeout=REMOTE_TIMEOUT) - response.raise_for_status() - - open_trackers = response.text.splitlines() - - except (ImportError, requests.RequestException) as e: - - # Now trace is lost. `raise from` to consider. - raise RemoteDownloadError('Unable to download from %s: %s' % (url, e)) - - return open_trackers - - -def get_open_trackers_from_local(): - """Returns open trackers announce URLs list from local backup.""" - with open(path.join(path.dirname(__file__), 'repo', OPEN_TRACKERS_FILENAME)) as f: - open_trackers = map(str.strip, f.readlines()) - - return list(open_trackers) diff --git a/lib/unshortenit.py b/lib/unshortenit.py index a4e421ea..0bcb8c87 100644 --- a/lib/unshortenit.py +++ b/lib/unshortenit.py @@ -539,11 +539,7 @@ class UnshortenIt(object): uri = '' logger.error('IP bannato da vcrypt, aspetta un ora') else: - prev_uri = uri uri = r.headers['location'] - if uri == prev_uri: - logger.info('Use Cloudscraper') - uri = httptools.downloadpage(uri, timeout=self._timeout, headers=headers, follow_redirects=False, cf=True).headers['location'] if "snip." in uri: new_uri = '' if 'out_generator' in uri: diff --git a/servers/torrent.py b/servers/torrent.py index 78bd3d74..6947ba2f 100755 --- a/servers/torrent.py +++ b/servers/torrent.py @@ -5,7 +5,6 @@ import re, os, sys, time, requests, xbmc, xbmcaddon from core import filetools, jsontools from core.support import info, match from platformcode import config, platformtools -from torrentool.api import Torrent from lib.guessit import guessit if sys.version_info[0] >= 3: diff --git a/service.py b/service.py index 378efb86..d85bbf81 100644 --- a/service.py +++ b/service.py @@ -354,48 +354,49 @@ class AddonMonitor(xbmc.Monitor): def onSettingsChanged(self): logger.debug('settings changed') settings_post = config.get_all_settings_addon() - if settings_post: # backup settings + if settings_post: + # backup settings filetools.copy(os.path.join(config.get_data_path(), "settings.xml"), os.path.join(config.get_data_path(), "settings.bak"), True) logger.debug({k: self.settings_pre[k] for k in self.settings_pre if k in settings_post and self.settings_pre[k] != settings_post[k]}) - from platformcode import xbmc_videolibrary + from platformcode import xbmc_videolibrary - if self.settings_pre.get('downloadpath', None) != settings_post.get('downloadpath', None): - xbmc_videolibrary.update_sources(settings_post.get('downloadpath', None), - self.settings_pre.get('downloadpath', None)) + if self.settings_pre.get('downloadpath', None) != settings_post.get('downloadpath', None): + xbmc_videolibrary.update_sources(settings_post.get('downloadpath', None), + self.settings_pre.get('downloadpath', None)) - # If the path of the video library has been changed, we call to check directories so that it creates it and automatically asks if to configure the video library - if self.settings_pre.get("videolibrarypath", None) and self.settings_pre.get("videolibrarypath", None) != settings_post.get("videolibrarypath", None) or \ - self.settings_pre.get("folder_movies", None) and self.settings_pre.get("folder_movies", None) != settings_post.get("folder_movies", None) or \ - self.settings_pre.get("folder_tvshows", None) and self.settings_pre.get("folder_tvshows", None) != settings_post.get("folder_tvshows", None): - videolibrary.move_videolibrary(self.settings_pre.get("videolibrarypath", ''), - settings_post.get("videolibrarypath", ''), - self.settings_pre.get("folder_movies", ''), - settings_post.get("folder_movies", ''), - self.settings_pre.get("folder_tvshows", ''), - settings_post.get("folder_tvshows", '')) + # If the path of the video library has been changed, we call to check directories so that it creates it and automatically asks if to configure the video library + if self.settings_pre.get("videolibrarypath", None) and self.settings_pre.get("videolibrarypath", None) != settings_post.get("videolibrarypath", None) or \ + self.settings_pre.get("folder_movies", None) and self.settings_pre.get("folder_movies", None) != settings_post.get("folder_movies", None) or \ + self.settings_pre.get("folder_tvshows", None) and self.settings_pre.get("folder_tvshows", None) != settings_post.get("folder_tvshows", None): + videolibrary.move_videolibrary(self.settings_pre.get("videolibrarypath", ''), + settings_post.get("videolibrarypath", ''), + self.settings_pre.get("folder_movies", ''), + settings_post.get("folder_movies", ''), + self.settings_pre.get("folder_tvshows", ''), + settings_post.get("folder_tvshows", '')) - # if you want to autoconfigure and the video library directory had been created - if not self.settings_pre.get("videolibrary_kodi", None) and settings_post.get("videolibrary_kodi", None): - xbmc_videolibrary.ask_set_content(silent=True) - elif self.settings_pre.get("videolibrary_kodi", None) and not settings_post.get("videolibrary_kodi", None): - xbmc_videolibrary.clean() + # if you want to autoconfigure and the video library directory had been created + if not self.settings_pre.get("videolibrary_kodi", None) and settings_post.get("videolibrary_kodi", None): + xbmc_videolibrary.ask_set_content(silent=True) + elif self.settings_pre.get("videolibrary_kodi", None) and not settings_post.get("videolibrary_kodi", None): + xbmc_videolibrary.clean() - if self.settings_pre.get('addon_update_timer') != settings_post.get('addon_update_timer'): - schedule.clear('updater') - self.scheduleUpdater() + if self.settings_pre.get('addon_update_timer') != settings_post.get('addon_update_timer'): + schedule.clear('updater') + self.scheduleUpdater() - if self.update_setting != config.get_setting("update", "videolibrary") or self.update_hour != config.get_setting("everyday_delay", "videolibrary") * 4: - schedule.clear('videolibrary') - self.scheduleVideolibrary() + if self.update_setting != config.get_setting("update", "videolibrary") or self.update_hour != config.get_setting("everyday_delay", "videolibrary") * 4: + schedule.clear('videolibrary') + self.scheduleVideolibrary() - if self.settings_pre.get('elementum_on_seed') != settings_post.get('elementum_on_seed') and settings_post.get('elementum_on_seed'): - if not platformtools.dialog_yesno(config.get_localized_string(70805), config.get_localized_string(70806)): - config.set_setting('elementum_on_seed', False) - if self.settings_pre.get("shortcut_key", '') != settings_post.get("shortcut_key", ''): - xbmc.executebuiltin('Action(reloadkeymaps)') - self.settings_pre = settings_post + if self.settings_pre.get('elementum_on_seed') != settings_post.get('elementum_on_seed') and settings_post.get('elementum_on_seed'): + if not platformtools.dialog_yesno(config.get_localized_string(70805), config.get_localized_string(70806)): + config.set_setting('elementum_on_seed', False) + if self.settings_pre.get("shortcut_key", '') != settings_post.get("shortcut_key", ''): + xbmc.executebuiltin('Action(reloadkeymaps)') + self.settings_pre = settings_post def onScreensaverActivated(self): logger.debug('screensaver activated, un-scheduling screen-on jobs') diff --git a/updatetvshow.py b/updatetvshow.py index 1b39f173..f0b9287f 100644 --- a/updatetvshow.py +++ b/updatetvshow.py @@ -1,6 +1,11 @@ # -*- coding: utf-8 -*- -import xbmc, sys, base64, json, xbmcgui, os, xbmcvfs, traceback +import xbmc, sys, xbmcgui, os, xbmcvfs, traceback from platformcode import config, logger + +librerias = xbmc.translatePath(os.path.join(config.get_runtime_path(), 'lib')) +sys.path.insert(0, librerias) + +from core.item import Item from lib.sambatools import libsmb as samba from core import scrapertools @@ -86,7 +91,7 @@ def execute_sql(sql): records = [] conn.close() - logger.debug("Query executed. Records: %s" % nun_records) + logger.debug("Query executed. Records: %s" % len(records)) except: logger.error("Error executing sql query") @@ -101,11 +106,12 @@ def execute_sql(sql): if __name__ == '__main__': path = search_paths(sys.listitem.getVideoInfoTag().getDbId()) if path: - item = {"action": "update_tvshow", "channel": "videolibrary", 'path':path} - xbmc.executebuiltin("RunPlugin(plugin://plugin.video.kod/?" + base64.b64encode(json.dumps(item).encode()) + ")") + item = Item(action="update_tvshow", channel="videolibrary", path=path) + item.tourl() + xbmc.executebuiltin("RunPlugin(plugin://plugin.video.kod/?" + item.tourl() + ")") else: dialog = xbmcgui.Dialog() title = sys.listitem.getVideoInfoTag().getTitle() if dialog.yesno(title, config.get_localized_string(70817) % title, nolabel=config.get_localized_string(70170), yeslabel=config.get_localized_string(30022)): - item = {"action": "new_search", "channel": "search", "mode":"tvshow", "search_text": sys.listitem.getVideoInfoTag().getTitle()} - xbmc.executebuiltin("ActivateWindow(10025,plugin://plugin.video.kod/?" + base64.b64encode(json.dumps(item).encode()) + ")") \ No newline at end of file + item = Item(action="new_search", channel="search", mode="tvshow", search_text=sys.listitem.getVideoInfoTag().getTitle()) + xbmc.executebuiltin("ActivateWindow(10025,plugin://plugin.video.kod/?" + item.tourl() + ")")