From 7ce8a4fc4556b6441d404ca097a24e48f7873f2d Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 16 Sep 2012 13:21:01 +0200 Subject: [PATCH 01/92] Show proper date in update info --- couchpotato/static/scripts/page/about.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/static/scripts/page/about.js b/couchpotato/static/scripts/page/about.js index 8ac38ba6..d155800f 100644 --- a/couchpotato/static/scripts/page/about.js +++ b/couchpotato/static/scripts/page/about.js @@ -116,7 +116,7 @@ var AboutSettingTab = new Class({ if(!json) return; var self = this; var date = new Date(json.version.date * 1000); - self.version_text.set('text', json.version.hash + ' ('+date.toUTCString()+')'); + self.version_text.set('text', json.version.hash + (json.version.date ? ' ('+date.toLocaleString()+')' : '')); self.updater_type.set('text', json.version.type); } From 4be8d02cbb80a0b62778371006f5a2023fccca5b Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 16 Sep 2012 17:47:14 +0200 Subject: [PATCH 02/92] Added CP search & info provider --- .../providers/movie/couchpotatoapi/main.py | 55 ++++++++++++++++--- .../core/providers/movie/themoviedb/main.py | 4 +- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/couchpotato/core/providers/movie/couchpotatoapi/main.py b/couchpotato/core/providers/movie/couchpotatoapi/main.py index d1c13380..ed574a24 100644 --- a/couchpotato/core/providers/movie/couchpotatoapi/main.py +++ b/couchpotato/core/providers/movie/couchpotatoapi/main.py @@ -1,10 +1,12 @@ from couchpotato import get_session from couchpotato.core.event import addEvent, fireEvent +from couchpotato.core.helpers.encoding import tryUrlencode from couchpotato.core.helpers.request import jsonified, getParams from couchpotato.core.logger import CPLog from couchpotato.core.providers.movie.base import MovieProvider from couchpotato.core.settings.model import Movie from flask.helpers import json +import traceback log = CPLog(__name__) @@ -12,28 +14,57 @@ log = CPLog(__name__) class CouchPotatoApi(MovieProvider): api_url = 'http://couchpota.to/api/%s/' + urls = { + 'search': 'https://couchpota.to/api/search/%s/', + 'info': 'https://couchpota.to/api/info/%s/', + 'eta': 'https://couchpota.to/api/eta/%s/', + } http_time_between_calls = 0 + api_version = 1 def __init__(self): #addApiView('movie.suggest', self.suggestView) - addEvent('movie.info', self.getInfo) + addEvent('movie.info', self.getInfo, priority = 1) + addEvent('movie.search', self.search, priority = 1) addEvent('movie.release_date', self.getReleaseDate) + def search(self, q, limit = 12): + + cache_key = 'cpapi.cache.%s' % q + cached = self.getCache(cache_key, self.urls['search'] % tryUrlencode(q), timeout = 3) + + if cached: + try: + movies = json.loads(cached) + return movies + except: + log.error('Failed parsing search results: %s', traceback.format_exc()) + + return [] + def getInfo(self, identifier = None): - return { - 'release_date': self.getReleaseDate(identifier) - } + + if not identifier: + return + + cache_key = 'cpapi.cache.info.%s' % identifier + cached = self.getCache(cache_key, self.urls['info'] % identifier, timeout = 3) + + if cached: + try: + movie = json.loads(cached) + return movie + except: + log.error('Failed parsing info results: %s', traceback.format_exc()) + + return {} def getReleaseDate(self, identifier = None): if identifier is None: return {} try: - headers = { - 'X-CP-Version': fireEvent('app.version', single = True), - 'X-CP-API': 1, - } - data = self.urlopen((self.api_url % ('eta')) + (identifier + '/'), headers = headers) + data = self.urlopen((self.api_url % ('eta')) + (identifier + '/'), headers = self.getRequestHeaders()) dates = json.loads(data) log.debug('Found ETA for %s: %s', (identifier, dates)) return dates @@ -71,3 +102,9 @@ class CouchPotatoApi(MovieProvider): 'count': len(suggestions), 'suggestions': suggestions }) + + def getRequestHeaders(self): + return { + 'X-CP-Version': fireEvent('app.version', single = True), + 'X-CP-API': self.api_version, + } diff --git a/couchpotato/core/providers/movie/themoviedb/main.py b/couchpotato/core/providers/movie/themoviedb/main.py index 9f9fe4fe..8b15a5c4 100644 --- a/couchpotato/core/providers/movie/themoviedb/main.py +++ b/couchpotato/core/providers/movie/themoviedb/main.py @@ -11,8 +11,8 @@ class TheMovieDb(MovieProvider): def __init__(self): addEvent('movie.by_hash', self.byHash) - addEvent('movie.search', self.search, priority = 1) - addEvent('movie.info', self.getInfo, priority = 1) + addEvent('movie.search', self.search, priority = 2) + addEvent('movie.info', self.getInfo, priority = 2) addEvent('movie.info_by_tmdb', self.getInfoByTMDBId) # Use base wrapper From ef7fc62c66e797f96ffba44c6958ad86edc15252 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 16 Sep 2012 19:25:53 +0200 Subject: [PATCH 03/92] Download fanart en bigger poster when needed --- couchpotato/core/plugins/library/main.py | 10 ++++++---- couchpotato/core/providers/metadata/base.py | 9 +++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/couchpotato/core/plugins/library/main.py b/couchpotato/core/plugins/library/main.py index d24dfca6..ae142299 100644 --- a/couchpotato/core/plugins/library/main.py +++ b/couchpotato/core/plugins/library/main.py @@ -111,18 +111,20 @@ class LibraryPlugin(Plugin): # Files images = info.get('images', []) - for type in images: - for image in images[type]: - if not isinstance(image, str): + for image_type in ['poster']: + for image in images.get(image_type, []): + if not isinstance(image, (str, unicode)): continue file_path = fireEvent('file.download', url = image, single = True) if file_path: - file_obj = fireEvent('file.add', path = file_path, type_tuple = ('image', type), single = True) + file_obj = fireEvent('file.add', path = file_path, type_tuple = ('image', image_type), single = True) try: file_obj = db.query(File).filter_by(id = file_obj.get('id')).one() library.files.append(file_obj) db.commit() + + break except: log.debug('Failed to attach to library: %s', traceback.format_exc()) diff --git a/couchpotato/core/providers/metadata/base.py b/couchpotato/core/providers/metadata/base.py index a10f9c82..cf2e303f 100644 --- a/couchpotato/core/providers/metadata/base.py +++ b/couchpotato/core/providers/metadata/base.py @@ -74,9 +74,18 @@ class MetaDataBase(Plugin): if file_type.get('identifier') == wanted_file_type: break + # See if it is in current files for cur_file in data['library'].get('files', []): if cur_file.get('type_id') is file_type.get('id') and os.path.isfile(cur_file.get('path')): return cur_file.get('path') + # Download using existing info + try: + images = data['library']['info']['images'][wanted_file_type] + file_path = fireEvent('file.download', url = images[0], single = True) + return file_path + except: + pass + def getFanart(self, movie_info = {}, data = {}): return self.getThumbnail(movie_info = movie_info, data = data, wanted_file_type = 'backdrop_original') From ce3efd3a3c941b5aab26cd19fb670daa361e1f56 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 16 Sep 2012 20:02:15 +0200 Subject: [PATCH 04/92] Cleanup cache on startup --- couchpotato/core/plugins/file/main.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/couchpotato/core/plugins/file/main.py b/couchpotato/core/plugins/file/main.py index 5f381198..40427e44 100644 --- a/couchpotato/core/plugins/file/main.py +++ b/couchpotato/core/plugins/file/main.py @@ -8,6 +8,7 @@ from couchpotato.core.plugins.base import Plugin from couchpotato.core.settings.model import FileType, File from couchpotato.environment import Env import os.path +import time import traceback log = CPLog(__name__) @@ -28,6 +29,25 @@ class FileManager(Plugin): 'return': {'type': 'file'} }) + addEvent('app.load', self.cleanup) + + def cleanup(self): + + # Wait a bit after starting before cleanup + time.sleep(3) + log.debug('Cleaning up unused files') + + try: + db = get_session() + for root, dirs, walk_files in os.walk(Env.get('cache_dir')): + for filename in walk_files: + file_path = os.path.join(root, filename) + f = db.query(File).filter(File.path == toUnicode(file_path)).first() + if not f: + os.remove(file_path) + except: + log.error('Failed removing unused file: %s', traceback.format_exc()) + def showCacheFile(self, filename = ''): cache_dir = Env.get('cache_dir') From 8fb24bb101bc7443440bca9f956c1c486c728573 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 16 Sep 2012 20:20:47 +0200 Subject: [PATCH 05/92] Couldn't test Synoindex. fix #814 --- couchpotato/core/notifications/synoindex/main.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/notifications/synoindex/main.py b/couchpotato/core/notifications/synoindex/main.py index 93d6cdbd..89c54de7 100644 --- a/couchpotato/core/notifications/synoindex/main.py +++ b/couchpotato/core/notifications/synoindex/main.py @@ -1,4 +1,5 @@ from couchpotato.core.event import addEvent +from couchpotato.core.helpers.request import jsonified from couchpotato.core.logger import CPLog from couchpotato.core.notifications.base import Notification import subprocess @@ -9,13 +10,14 @@ log = CPLog(__name__) class Synoindex(Notification): def __init__(self): + super(Synoindex, self).__init__() addEvent('renamer.after', self.addToLibrary) def addToLibrary(self, group = {}): if self.isDisabled(): return - command = ['/usr/syno/bin/synoindex', '-A', group.get('destination_dir')] - log.info(u'Executing synoindex command: %s ', command) + command = ['/usr/syno/bin/synoindex', '-A', group.get('destination_dir', '')] + log.info('Executing synoindex command: %s ', command) try: p = subprocess.Popen(command, stdout = subprocess.PIPE, stderr = subprocess.STDOUT) out = p.communicate() @@ -26,3 +28,7 @@ class Synoindex(Notification): return False return True + + def test(self): + success = self.addToLibrary() + return jsonified({'success': success}) From 20f81d06c06ef8c47ec644557f35a501b3d47624 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 16 Sep 2012 20:44:10 +0200 Subject: [PATCH 06/92] Send headers with CPAPI --- couchpotato/core/providers/movie/couchpotatoapi/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/providers/movie/couchpotatoapi/main.py b/couchpotato/core/providers/movie/couchpotatoapi/main.py index ed574a24..0ada5c9f 100644 --- a/couchpotato/core/providers/movie/couchpotatoapi/main.py +++ b/couchpotato/core/providers/movie/couchpotatoapi/main.py @@ -32,7 +32,7 @@ class CouchPotatoApi(MovieProvider): def search(self, q, limit = 12): cache_key = 'cpapi.cache.%s' % q - cached = self.getCache(cache_key, self.urls['search'] % tryUrlencode(q), timeout = 3) + cached = self.getCache(cache_key, self.urls['search'] % tryUrlencode(q), timeout = 3, headers = self.getRequestHeaders()) if cached: try: @@ -49,7 +49,7 @@ class CouchPotatoApi(MovieProvider): return cache_key = 'cpapi.cache.info.%s' % identifier - cached = self.getCache(cache_key, self.urls['info'] % identifier, timeout = 3) + cached = self.getCache(cache_key, self.urls['info'] % identifier, timeout = 3, headers = self.getRequestHeaders()) if cached: try: From d295b881afcf8947f736a951f4cbac0222646222 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 16 Sep 2012 21:58:58 +0200 Subject: [PATCH 07/92] Use new CP url for api --- couchpotato/core/providers/movie/couchpotatoapi/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/providers/movie/couchpotatoapi/main.py b/couchpotato/core/providers/movie/couchpotatoapi/main.py index 0ada5c9f..702521fa 100644 --- a/couchpotato/core/providers/movie/couchpotatoapi/main.py +++ b/couchpotato/core/providers/movie/couchpotatoapi/main.py @@ -13,11 +13,11 @@ log = CPLog(__name__) class CouchPotatoApi(MovieProvider): - api_url = 'http://couchpota.to/api/%s/' urls = { 'search': 'https://couchpota.to/api/search/%s/', 'info': 'https://couchpota.to/api/info/%s/', 'eta': 'https://couchpota.to/api/eta/%s/', + 'suggest': 'https://couchpota.to/api/suggest/%s/%s/', } http_time_between_calls = 0 api_version = 1 @@ -64,7 +64,7 @@ class CouchPotatoApi(MovieProvider): if identifier is None: return {} try: - data = self.urlopen((self.api_url % ('eta')) + (identifier + '/'), headers = self.getRequestHeaders()) + data = self.urlopen(self.urls['eta'] % identifier, headers = self.getRequestHeaders()) dates = json.loads(data) log.debug('Found ETA for %s: %s', (identifier, dates)) return dates @@ -75,7 +75,7 @@ class CouchPotatoApi(MovieProvider): def suggest(self, movies = [], ignore = []): try: - data = self.urlopen((self.api_url % ('suggest')) + ','.join(movies) + '/' + ','.join(ignore) + '/') + data = self.urlopen(self.urls['suggest'] % (','.join(movies), ','.join(ignore))) suggestions = json.loads(data) log.info('Found Suggestions for %s', (suggestions)) except Exception, e: From ad7de32e70fcea503c43e41a107e946907c62d4e Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 19 Sep 2012 13:23:40 +0200 Subject: [PATCH 08/92] Send time with API requests --- couchpotato/core/providers/movie/couchpotatoapi/main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/couchpotato/core/providers/movie/couchpotatoapi/main.py b/couchpotato/core/providers/movie/couchpotatoapi/main.py index 702521fa..8e890484 100644 --- a/couchpotato/core/providers/movie/couchpotatoapi/main.py +++ b/couchpotato/core/providers/movie/couchpotatoapi/main.py @@ -6,6 +6,7 @@ from couchpotato.core.logger import CPLog from couchpotato.core.providers.movie.base import MovieProvider from couchpotato.core.settings.model import Movie from flask.helpers import json +import time import traceback log = CPLog(__name__) @@ -107,4 +108,5 @@ class CouchPotatoApi(MovieProvider): return { 'X-CP-Version': fireEvent('app.version', single = True), 'X-CP-API': self.api_version, + 'X-CP-Time': time.time(), } From f47496222592f6c50a5ceb089408d367d8913f1b Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 19 Sep 2012 15:31:27 +0200 Subject: [PATCH 09/92] Just check for synoindex file on test. --- couchpotato/core/notifications/synoindex/main.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/notifications/synoindex/main.py b/couchpotato/core/notifications/synoindex/main.py index 89c54de7..6c4966df 100644 --- a/couchpotato/core/notifications/synoindex/main.py +++ b/couchpotato/core/notifications/synoindex/main.py @@ -2,6 +2,7 @@ from couchpotato.core.event import addEvent from couchpotato.core.helpers.request import jsonified from couchpotato.core.logger import CPLog from couchpotato.core.notifications.base import Notification +import os import subprocess log = CPLog(__name__) @@ -9,6 +10,8 @@ log = CPLog(__name__) class Synoindex(Notification): + index_path = '/usr/syno/bin/synoindex' + def __init__(self): super(Synoindex, self).__init__() addEvent('renamer.after', self.addToLibrary) @@ -16,7 +19,7 @@ class Synoindex(Notification): def addToLibrary(self, group = {}): if self.isDisabled(): return - command = ['/usr/syno/bin/synoindex', '-A', group.get('destination_dir', '')] + command = [self.index_path, '-A', group.get('destination_dir')] log.info('Executing synoindex command: %s ', command) try: p = subprocess.Popen(command, stdout = subprocess.PIPE, stderr = subprocess.STDOUT) @@ -30,5 +33,4 @@ class Synoindex(Notification): return True def test(self): - success = self.addToLibrary() - return jsonified({'success': success}) + return jsonified({'success': os.path.isfile(self.index_path)}) From 5cc7250528d3cb123dfa1604e53223268fe288ea Mon Sep 17 00:00:00 2001 From: Ruud Date: Thu, 20 Sep 2012 09:16:03 +0200 Subject: [PATCH 10/92] Image optimize --- couchpotato/static/images/couch.png | Bin 68742 -> 59075 bytes couchpotato/static/images/gear.png | Bin 2362 -> 1196 bytes couchpotato/static/images/homescreen.png | Bin 6575 -> 5966 bytes couchpotato/static/images/icon.attention.png | Bin 49032 -> 573 bytes couchpotato/static/images/icon.check.png | Bin 451 -> 352 bytes couchpotato/static/images/icon.delete.png | Bin 228 -> 220 bytes couchpotato/static/images/icon.download.png | Bin 502 -> 306 bytes couchpotato/static/images/icon.edit.png | Bin 624 -> 511 bytes couchpotato/static/images/icon.files.png | Bin 840 -> 763 bytes couchpotato/static/images/icon.folder.gif | Bin 757 -> 690 bytes couchpotato/static/images/icon.imdb.png | Bin 159 -> 152 bytes couchpotato/static/images/icon.info.png | Bin 778 -> 724 bytes couchpotato/static/images/icon.rating.png | Bin 283 -> 239 bytes couchpotato/static/images/icon.refresh.png | Bin 674 -> 568 bytes couchpotato/static/images/icon.spinner.gif | Bin 1539 -> 1382 bytes couchpotato/static/images/icon.trailer.png | Bin 596 -> 435 bytes couchpotato/static/images/icon.undo.png | Bin 587 -> 585 bytes couchpotato/static/images/imdb_watchlist.png | Bin 42410 -> 37523 bytes couchpotato/static/images/right.arrow.png | Bin 223 -> 151 bytes couchpotato/static/images/sprite.png | Bin 2291 -> 1889 bytes couchpotato/static/images/toTop.gif | Bin 838 -> 56 bytes 21 files changed, 0 insertions(+), 0 deletions(-) diff --git a/couchpotato/static/images/couch.png b/couchpotato/static/images/couch.png index 0910c5cb5e76a8072747cd2600e6524f1ca5a9df..3bc445e77a44115918249238cec208db12b5dc53 100644 GIT binary patch literal 59075 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 literal 68742 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 A^#A|> diff --git a/couchpotato/static/images/gear.png b/couchpotato/static/images/gear.png index 75d0a68fe39f7ce0fa2a74761043223f797aaa54..f1d63badebeb9080b4daa052a673f24a1889b28b 100644 GIT binary patch delta 1123 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 diff --git a/couchpotato/static/images/homescreen.png b/couchpotato/static/images/homescreen.png index d8028a4c4473fc9a6c33f76be4fbea4a664682e6..491be66d0086eb8cbbb33f99949776244ae47440 100644 GIT binary patch literal 5966 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 diff --git a/couchpotato/static/images/icon.attention.png b/couchpotato/static/images/icon.attention.png index 9878676c885b3480bbb3192301b8d1ca63acd9fe..ff10b97643db48a2e4f4b242d868628f18fc3c78 100644 GIT binary patch delta 550 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 MYrU0RY`Ht?4~Jtpd;kCd diff --git a/couchpotato/static/images/icon.check.png b/couchpotato/static/images/icon.check.png index c277e6b4043b2b9a7c7388e076d2c493a23272c7..e99e575f59bbe97761a5af3587a1f2f6e475e74b 100644 GIT binary patch delta 326 zcmV-M0lEIe1KGk647ZiD!f__HxL(A+@q1`-sq z%+l$}0mO~CQNe%)6^#aoW+9lRB7=~LF@n42>smCV32K{ykEyAy?{y1+u?Vh(vcMw$ zso8Bo_p74VK3IMpln@<=^76TXHA)UecaKIveEPuW{NBQYv1JQ|KhnSk+ zzP|>}?e3IYYWG)(9>B?4Tz)UYobl#U%5^Ijo$PLI_Eumnxo{z9qy@~BglMnxi1V1= zn_gi^)>>k~d76c}<`b{D%x^8pTC|TiGYvt#JB@i?*5V+?gX6bJ#CH^$47ydc=ScB4BYyxHbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUz zWl2OqRCwBA{Qv(y16_ezC&PabCQGwp8^iy1KPG}Ph)uHQCtsTX&)UQQ#!tUCf?dKw ztmege%?#U*)G{!zGB7X##lHW4hpNaOXqr0~zc~Rl-~L?me}C2@aYp!gghefonxs%9Wyf%}JcXv!47F)CU`Y_0feGkmAXZbc zW2l(6kzrpIgMSH7>MYCvkbYyAHik2$sk#i0pIm16_m6=AmbMsyvP?kDvNF01U9&GU z>_yWI0zi8ip5NQcu;qo|t276DS%x1!J~8|U*$R|l2F8(yge=2^Ik&NDMh765{9pN; z`~Tb<3}6gmyP)}*5HNNHYFPb}8;o5^)C@Po6Bsj|og?IFh8sexW=2Z0GeCd=09I_l UwP68e#{d8T07*qoM6N<$g4)5unE(I) diff --git a/couchpotato/static/images/icon.delete.png b/couchpotato/static/images/icon.delete.png index 276ea15f86fea8576ccc28c13f8644612a8338a3..5fbfe36d0d7466fdf69ec848fa17a8612c4abf5d 100644 GIT binary patch delta 192 zcmV;x06+ia0o(zQB!8nxL_t(|+QpNx34}lpMXx8zFf%pR0<-{25KOH>FtZDduAO&$ zWVqpO+zn2+;KB0$&I8xo2k;a337$nEa99>~p#ZiGjsy1nQ=&|r_9!P748zGh!@8P8 zYh~6a1bzQznqXOk*1o$G2x!|B$ulsZu0w1%FX%d`Dvz?PKsmrTo`SOUC{vgDjZNc+ uBZ>B09^%)4vN+ER{P%|4ZCCmKuki&8Jfo9Biqwq&0000)MprGpv;|TM7 zoT$dS_RZshwmlgJm?nc7TUktCBz2u6bqA-UEQ8qhk`^=#6hVcHtlben-y1=myQrGX z(rv7&@Mc>g*TlQvZ8+K(sQ(mP9?}iLv#0#pZ~OoZJfo9~#x*4X0000J-d5+d_+3dZ)<($juu*K-Bw&k4I?#7?sgVpQ0m)d%{=A+T- zwYTPbH{8c7oGPm;e9(2XsR{#J2 zcS%G+RCr!(&B+pjAQVK=Jj66J&a+AW|10Aw3X6qz*JsnOhlnINNt6L+2;oElV~lYu zVX@XOB{WK@ri4~&-QFO9&KT1HG6DK^aLx^Dj|4U5$$LM|s1t|^+y2=%R3ZUga{P{K o=NFbQ?+h%wZyR8F3u1Wa59b^OGL0;AssI2007*qoM6N<$f-p*l$p8QV delta 487 zcmV!t8Gi-<001BJ|6u?C010qNS#tmY3ljhU3ljkVnw%H_000DMK}|sb z0I`mI`%#ks001CkNK#Dz0D2_=0Dyx40Qvs_0D$QL0Cg|`0P0`>06Lfe02gnPU&TfM z00C@CL_t(|+N6^|NCHtD$G`8m?Fc8EYzem(M+pKap%$gVNq<^Jak(L!nwq4cO}R~? zQH7S%F$l`hrL`dg(;MQEc7LAUuSKuB>msZl{NVi_zu)J*-}n6~tAAl?Yzkbi(lb|BsuV7VIt{Oa>1$A@crNqouIIRv2T7gO@9UrN`IP318WV_2^3 z`9zG7P32Ka*ARYU4`9zkOB>W7L5Ag+Fzqk591{{`XoEWJnP^1<8U?*-jCi*{Y$Ks0 z!CVQJZGyQH5=s*NVH?JXcN+!0>Ibm(RIMgaDQcOk_+U=#_+al4FZ>CK*e>oKdoV`4 zdtJIc0Wc4YKM^7HAC#h&>8N^+9;Q7~^&AzoOb37xt|6jGKmZah4gmMrc$Y^;7wO zFV*b-%~Y%ZyRKjTzxv7*upx&F*$5l5)k9SLppWwZo6*MqU4MK${@Xaa{@--{+W#lV zlm0(!W%z%pnwhX6o82|m1|%l^ubMvNzh{{D|FcWY{(svm@c;jt=@3Jzh%f{g@;3hQ zG5@cWGW`E`RQ3PYElmHv?BazRa*`NBKmg=qm?0lGG5!Czjr0Hi%gUq~ad)+MoU5N*hZodW;gtYP~9W&^~Kdo2uqw&b!un&!;MMA(or zhRGvSO2%VEcEYOKal{UymO!wV#wu*OlO`hXT0_1^twMQsx$x3 zPxoC%bV}V<%=~|SI>XPog`xk?&F}pG_~5etbFw186JKq>Y)>B9x$zdCCnf~^n~)On zcTsuD{}^wlzl8Kj0x>98>Hx7ZD>IY1o4Q13v8TmuUwiBSa&mJ28At#EKr9BtDnP6W cH58oX0pfG}c*Ib=TmS$707*qoM6N<$f+*$(mH+?% delta 600 zcmV-e0;m1|1MmcpBYy%nNkl#DY*E z7-SSw3n2)CECP#eitNH$Er=q53Pk3GiQ&c2ToUHm67434D00MXlUBHmW^QxNHTUgw z91=lu+Y1i|-oyFv!a0Y*MoqNt5YpxCN_LAdk(Hf3@0{_Ygnwc-4y(nAZNcVi_XSH| z=WyV~I zgD{?|1zGZe2&IrV-pwH)iX6&={MUHb#S%%H&mn7zK7bQJrqd!Y=F5xZ9c$_qM-v*={6-{-rL_v6HTO`Q*P9aMe$dxAIcv(;4U)*Odjzva`K9n~%S)v3FQX_a@p(Zks z$!>IxPO__!A0rof9oC}2dbw_}B$nXQza(wKhWdk08FiQ#cBC#nc_uCi=sQ-f6R7uj z5{yPlI8lyNDCB}ypZ(dvaTi+%sG@W5pvLf!%MIJ1L{qXLM75#O=BW9C?&R1nq+5ovYXw>e7x`LK=#n9 z_&o4G37)Zjb$xlEw|Xr;olHvArMbF#sxQBgEi5fo7JvG!{(s{)-~I3{xrrV>JkU%D z3Ln0`vhn$iPj8N^tqa|ycj{8Wqp@P4>=ETTQFe+(QMNSux9)uX#pdS6$A^cSf<>WL zt8_p4?5oWa>3c1&L6j;=j?J9sGGF#tY0lD{Yg6(Xw4U#+cUIRfx0jaV-8)+*7|%5%PpB>@8%*uQu8HU*n=CJ2I1V9}HkDFsppq>xly zi-za0Qh)VGvYdm#DceWU@ZsLheF`>(Tp2SMJPAv};lv2?9GcSL=9*atEDFY8w8qI& z{@A{ES7lj3!Di|x9EQzU^0!W~Y#T4p%zK6)*EC!kS3s6#glW#7yE|J+JTVk(rUv0K zn0<6pKM9=h>8KirxfiYFm)0-Z?u;cZi^hyYOHI| delta 818 zcmV-21I_&V1;_@FBYy)ANkl#VzT^*X5} zedt3kJRhE!=l#9>|IhPK_|HTAndHpM@g`@EnI8#Dl3?>V?0;&zHfgM!>`4>To;TQi zx9`+eL(zjRP0iXcz?#LQ^9m2`y4Y(=OwaHvwbSJ5*IpILRvtk`K~N4ug9pbi1Ama|jmxg_z5nnz+zOBAMstsXbkPdY%tGY3-w>7sMXEJjheROX+B$kR ztzSFZ065|~XXEReou6VBIK&jRN@lnTK&NR4PDR+5$MZJ%6$R zU>J)3)>zs7h0W&T*);S~47_#$Hme0avWk!X5Gam=oqsbSfu$jZB|QKBBd}}XH1{BY zZSb9I>2^&`QZyGbY!)Pl0;~d$n5@9}y$gPwCK4z^hK15m_vk@&#lC{og8=5~t;3CK z_Nr`EPa)=6A@F8chH-pEBFFH2pz&4ZCktPaqfjdq2X$8Sd-E{l1ut zR(}wcwNDsG6=ET{+Jc@^=RR w+AGF?Y%OPZx-#6E<8zwc)Zd5^{rx|F0TPuQ*e>a8)&Kwi07*qoM6N<$f~7B!NB{r; diff --git a/couchpotato/static/images/icon.folder.gif b/couchpotato/static/images/icon.folder.gif index e19ce53aa6c6129b5836d19b2ff45af23b8d311f..9fbb12fb1156283fbf781a97516219496c7fcf8e 100644 GIT binary patch delta 667 zcmV;M0%ZO51+oQ@BYy&UNkl zinIMwIZoCEh6cX#>l-51yQrQ=sks$p48u8gMPdVdsmsgd#C>GdCX{ug-v zjZ=s7u6_H~nbZ4s&A7wh!WQcveR|#{=?@a@qQds&TZ4;VoVzx>3wVGRP8{3JrF?Mk z+Z94tVsT2|NXT0Y96WenwUy_`dcDO{i`}JH+Rg6UtNW72pImN|uyv~iw+kagB^(sGozrkc&u>8O>Yfm3#VY!b>Jowao`T4oyzie(i19VaVjU|K$ zowld*$SPKkD93%uVn9_^%()4%5JbTzDWmZOQ(XW^0i0G43#=}1^%S*8=8d$|WueND@_W&_itn+G8prT;5dnktCaEJ)1hD(&rd;=1{2Mqr#2bZ?CS9*&ryiZUJiAq$# z&7;eU&80&R_u1cXlQldffH-glD5epg zHfI0$g?sbP%a0unl^pkpd!pTHJlSq$E4^;h9a`zpZZ#;1$l0$qh97^m)%#E2-+ArC zk$yJUTvLS?c0calIyc#AlrJd}6#c+kDOI9%F4$7c#O;a6_tk#_ z?p_@qupIUJ`kjfcCX-iDn4iPsgU2&WGv0|vElOZvd8@GaYf)Es%NqY=mOD>uK6;*)RH;76J5FsT75CJ9VHqGf#5xEqQ1fU-Z)70Sm zp=<(pEr9f0s;xk9QmK^zt&N~RRRxElkWxV-XYIBHLpQ<}fD2i5OIj3o)DEc_Cbi>( zN2Dx8y?@_Ev7%stQ4ZOvM+?9s#X~FbTv{h*N;MA(mC?yyWR~I|VO6>$=I;}-88EXNyw~J#_uRe|m&QEnD?7>Xh?&#m2 zLsu>VGe$}pC6RTox--H{PRAiu`|U3LI&NM#JXa6}Vno;2(L_9UEMc47S;uDm-C58a zuFEm?a<=&J#a#BUfIr9O(E~ZN%^s3UoNl+w<7EHP+Gh3IlbQKP|9hM91BB8^``K0s QtN;K207*qoM6N<$f-D700RR91 diff --git a/couchpotato/static/images/icon.imdb.png b/couchpotato/static/images/icon.imdb.png index 72fa34080924181116c3c8b47c86a2aeed0a0e14..a9903c49f3d2d3c9679f2f069873652bd0ab2213 100644 GIT binary patch delta 123 zcmV->0EGXa0hj@hBy?X%L_t(|+Rc+O4!|%B0vY_)zP5j&(A2TQDqTI}LLJ`i~UR8*Be z#z}x^Z3RFzT`_wgui~g?2o{LQP|Yv-0>Of|U=73o>kej$&Gl^rx{>HN%)s~0f|Mv;Y7A diff --git a/couchpotato/static/images/icon.info.png b/couchpotato/static/images/icon.info.png index 12cd1aef900803abba99b26920337ec01ad5c267..f61dc86814abf99ef378aca02d9bd40f207ce8e6 100644 GIT binary patch delta 701 zcmV;u0z&D~?^iSx0J85lt&|I4h@=ZI)tYMm{ zt#lP;gH?)&_ys6nLoh$`gYpYXQiKFv$=;BU(9|~vX3*AFCy=!)e?8KMwOl72Tqn<- z`?{as?&m%P;6VIykf&eCJgE&!bJZdKc(X5&t>h9}$^|}4>3@|TyT@k!S0K;+%E+Orn}g(m4+GC5INS6L zRAIj?Ey!-=c#}N}jfKbc9zUv$K2#Yv^f}kjOQ`5#f1~%1SV8EfS3nmS`Ly7uoZT8< zc#qn?0O|A!mG`~mG7A9MA&9kZly%GzT)3=v!^}oNF@K#~X#p*BZjE_2ceAECmFqmD z$b)e7Gm>AoQQGcANt*)~31YPaBlAQcRR1Zk^9DN)#p5MZ>b($mx^YP}hu4u$MDQKO z${7@s+@dBMYPwlyY$4F6+W9>}jZIdha$?98MWvR7SmlC^+rW>XJE;hPw;xd?w-PMq zdJ;y#t$$G>Xp`*;u8w8UVsq@yh#$T7HI%9x5H(NZykZJP^%k6~n?PaRI9f)0WW4j_ z`HC1VRHVn4f)Wifhx1KI=^zKw%nBq1H+k|?TxhVOTI+z$5`?6W1udvgl454xuS^w~ z7%IOje&+ThG*e4>=;jG)Xt#!tS8E0(Xo%CoMmFZZ%S4~nWl~Isl*&`{l&~p52^tfm jBTtYX5!Ua!Ob6l@IEKsYY(Vsf00000NkvXXu0mjfuj)yl delta 755 zcmVm0Y z@4ffyLP&hH8$HV}Up^c-=NMJxeN^-2A#-&!Ex{dE7fx2Kv^WhYp$Orocj3<9*-sw6 z`fpx!@WqvpjJ0yHBcaKjwniG(t^r^natsxoaDRGv2BZDC^Pgqk0vx`a&)7(A9NJbF z-`!fz)SRWb5P#u=lBiolDzT2jvoZreKU}7UQ@IO=vnzn!OZPiP+|Z$|@znN~dU9hW zoD=r6HGwLBj?H6YhF!_^{4-zXr@Mt|G<=%7cJxsUK!WS*XwcM-WCO#6=h(<1)j;pZ zNqW0eh!bqplAkQmzA-`9)`pZu(gzR&u->28*WS!naeoOBL4wBz$B)AkWQQlPVzJJ$ z6h(~BE^=UR8^+obD=FB>wl>w*P?#y?$%&_lD1882mzdOWPdw5KWw6IT`m1b_8=lS5jt8D3=RDa z=&jWzR-)S@56WMslZ~mKu1)-wpXB>rNBQ>NU#K`#1B&v|_AQK;7I~B}OdGiUT9LX> zf0xm6<;Lea@j4`qP+`yUae{KPw=c_AeReu}}Ckd4nG+>M= l0yhnE=Z}GN|39X8(F>?Qf_quEA-Mnm002ovPDHLkV1ky!Ww`(V diff --git a/couchpotato/static/images/icon.rating.png b/couchpotato/static/images/icon.rating.png index 174a4677e603e18885b04634de07965cb24e83bb..f5e07adf323d43546a42ba9196447488cc89c4e1 100644 GIT binary patch delta 125 zcmV-@0D}LU0`CEkB#}v2b6!bAK~#9!UCluPfFKA&QAkrj&HLXrq_Fhw=4}T0mP08U zAg)lD%L2%ZA5Z{JDM26uOutZp+Bs{aU^2JDki%-^FZqEyZ=+bzp^h=oA&3A~5D70_ fnYu>#GT6ESAdd?_-YRC^00000NkvXXu0mjfAhk3N delta 167 zcmV;Y09gO;0h#2}DsTW*>hQU;EwTHy&&_@T1^^(B V3qMHc5##^>002ovPDHLkV1h`PM4$iw diff --git a/couchpotato/static/images/icon.refresh.png b/couchpotato/static/images/icon.refresh.png index 257cfee396d5cbebd839de85ce07de888f4ea206..906887ed24874fa307d1b63dd1b093dbf135abb2 100644 GIT binary patch delta 544 zcmV+*0^j|j1-Jx|BYy$^Nkl`epyI@&@)_(}B<}m0Di3p%Y^nusl z)zDr($>z{M@P-ILB{_N>Q2-4h zwMHMt+Qkl8Mi@WkTmoxbEq$*zD8YZ;++xW2xfA(m{_W1R6I@R&M=wp;B29TAB(b!9-H>kFiZ7t zPNGN0bs>L`FH&v}ya78OfPsggf_!1HsR!>IZItC8(b>NktEZkf$iYfJlShkZMDWLX iRrzmJZyAl{@P7gG?MVskIne?D0000c5r#tc9wCFE4rIa-!1q-0q!CnSZU;eK_!N&pE$)&;Oo- z5Q228%FndhN6J8*|5*9iPMhD`Nk!A25KY}c)3oJ{eJyku0%DFJSuCJt<`WV2%(x-N)+LL+8qj7;7kCo>Owc0HHwpXYhQ62zP!xmyrN z_mp9=ykm5J8h_7!llPkQ{c=^BR~pGNaE6U2n$>3^A}WcjRJQXa3auZZaS4V;iR zzV`~^SXB)@fmd|bg_IPf($;u<)W%|**j7sRCMWbfS`l&iO1tG-A9o+dus&o*`3w=+ zKuQmL9#}J>q!^0qWM7I&k@5J6}Uh zj82Wy|5@Hbx@RKrQvzahya-(6+;Z6|hDkxh+p$h@q{FG4u2oi&6#bWJbgAj{v=B}^ lY5y2!b=uZ+`M(4h0H#Ie$NWKnJpcdz07*qoL^?JqHF{9>sEv&MFg?6k$x0MRDMK&uGQ;Cvdbt}_o4J?Z2 z*4EZlsI?+)%82|B4e&s zS!xc%K9fB`_&oMjVeCP%+kn>5bT}4^Of{WEGf1BroY%a=&sM=!3}4>9&W_ZgM8PgqAXLQJN36UT|GmJ zv0J(>S<0s#CdJj73hi_3vk?LWicwqb+qvhBkvzMySF8<~LsOM~)&@MW6q4tZEO8F4uY)0C<+rR&?A{@>k~oi`;WY-e#iZnnTsfz+*thQS%+vL-^G zb}I|+>9Y63UTd6;U>j`$c)sw$@u;I;DFJKTRfp!!`k?9>;-4v_7^q0V0Rr}?te!&= z?korgqOJRSF?1<)uRCkFT50*RiL4L~nuF3nEFoT*gHpSWbOa@Skpa1eMN)q-Z>`l` zH@+x0&gu!1dZjci4LekRSCFZac!6YSXri;1KtJX|ZC46P_{-oyK*hx^%&twF?I*X2 zi@ddJiVXf(=y6b~ISXS~J%COz_{J_-eALCf+f+JZoQZ*LEuXa!C2iKxa_Q1Z?3^*U z>jHAwkXl5m1JV9ViGgtCV7dKSWwhDSD6J#-uE$>>0JWHA~XF=PA`}B6+91&rt=zHExciU zyzbbEsZp=G%_6_GMk_-DF$W+@kd>ZnN&y-@IP7IYjh)?8b!HFn*5)b?%>mc#n`bh2CQaDZB!>!Op+zk8>V%vtksa>VLBGB#*;~UubNZlY zG5^UQT)myX<~TFAald>_fJlRd%+-c8MvV2np_}dQhVNzT=zhyc$8R^J12(uXic#E0 Y_jgODWWv|Du$t71;BCq+N*T!i2RLV?%>V!Z literal 1539 zcmb7^drVVT9LH-PaQnWuz4!KJQ_|kvmeK($ZNVy4X=$~k<=rwMn3c8?ltpDQdBy-% zEl@kkKtKsgkUB;`iro=Cr_z&27%3fy9l+Qo(b|Pl|EOm`R+oYN2~4g|z7=q+bd?Sms|8k%a6hXR zE(MoOCIvm&Nba4+!9cLvF(n0i4}~oDI*GU4cV?l@uQ^Nf8YX@qBFgL5lnR-RFSeQa zDzq3mfFnBvAX1JF`ejFsRyZt#0NTm#hU(LDTVc7#7~d>cAs~n&83HR@Y#op_dTXki#R4dUUnA*LW5eo%JZ*73)PU@W zS&)?N%nx3OE`iGTGwO81rgJ^5-t-_ijVBcK|mK`66C?WU0!Thd>A`)2CUaYrn49{q8@xn zL;F`)oiQ3L`vpyo?qPWlBNi`)ZoB%cz+1PL7XC6oH>~ZHpS>G|3cjClB1q*CGs*Lk4i9O;7;y^0p$}+OC6| zMmy9tfk9feq>^}{=OqwG+C&0KoLGBu9iG~|nm*V)c869ft+P8HsT)IDyS6avn{#(s zLl~2G(8h4`JmCmgx4@uT^U01e9_6EbUxz#i+o+EX=-xk3KQnPpUJXTyO5BU^BYze# zJ92VaR9@J8Iccf8r&2yhmCCb?sF%LpJtr*erPS%Br$MK6d)P6qPt>ZT|L|s}CidgwVmFy?u8&gMX;8l9F>$(2CRJ9FD`{$}VTuh<#@-pIB-@V(8Ga83xz zz@$*>TouekQ9ermv)DMIJE%;InS^nGDuSP+V$$S{R5i|FB#ts(^jA^- zUnD3hkeDBQF)$>_by9&edX!L7Qv|H8A})r2jhIqGg}6+F)!Be2Cu1Bs2C{mo6X8a`|5To#gbKDnesVvw{!9rIbaTTciT$(jq`IJ znFS5Am%@e%Y3AE7Ig$6SghNI{Kc9|!pI6Yoq?{YANk>K{9&3|`zAzp@XahLaZ^8VUP+_33{rF=Ol)R4UG8wea0&3j*3CDilQEy+d}H VUXux$WCCcH0)v{;PRGpW{te?{(zO5p diff --git a/couchpotato/static/images/icon.trailer.png b/couchpotato/static/images/icon.trailer.png index 6a382dc7409ffde6f65e7faa3242af11db919bc3..8bdd71715d82c1c0a1649c4c79190cc9704901a9 100644 GIT binary patch delta 410 zcmV;L0cHNw1hWH>BYy#UNklymh(M-nB4EM9$()qjdgGBurS)d#Pf%L0)| z1dT=m!<`Z3!K~OtTvRZ3t{_=fu~JpBCTU1Zy3V;Q5Dtf7LO;EeL{Y|kv5O?#<;zc` zX&_VAuyI2a&Sim6C}dQJyIt>)!&@0gcN&iGbrhO?oIGeKJ@p~AzIvR?0>NMq7TIER zuz&H0-AW7DYJVF$*A%IZy;>UwwP%%cSs)My7}eoUZdN)I>t!;YDiFs~jyM)h>E_93 zDo@7J;tS`pfZy-OA7BBW&u3KW+MbbfS-|V{!o>EBoXY|pkH@IewLK%}vVb56FtI%& z=dys??KY}(ZO_QLEZ}mvU}Ael&Se3o(+O*T1OMk6rW0O#0nE||UjP6A07*qoM6N<$ Ef*^>w8vpk~Y1JneNBYyxHbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUz z_DMuRRCwB?lfR1-K@`Wo^JDimSrf22j2J?&w^1=5i1s0swGgWm0c`>aLP(p!CPfM% z*lJ}+tN{Zli{=X2&Vh~pTe(FpB!8|7CY|7zohmk)Onc7N**TCJ7~SQ~{w0K=#>s(?0Y z4HWoZ;1WzO2icV!@Bb<#scQ&T%RtC*x(*>-JMNc4?^Kngb zSHjvTsFL_t(|+J(|;2 z$6^vDjcTK`$a(9sHFpbL#2iMr%b7Nu+d4mcN3En7u4T6*$s7&m8~Fby|==U?Qb(!2p3-a1Jc zEsV@q@#*_ByjUE<>(Ar(`ZFQU(Re@DPmv)f;Ow>9LW=sQFJkU}5R>zEOvKHydw&T# zo-YRQ@?#XfsV;CA>yvtn&35IuJMX|$!UN8wXrmmU@2k#KPsz&> zEnH)VVI0^m*5IQv!uXs8p$9$Sj8hKK*(BumRTaLE*v;rPTlX3#t}{=W3)C@eg-oeIWxHJ1Zn&A9&b}^ZtFp$=+)49h)3* zK)*pjsZ;JMw0n08-k1@O--IM$Zyc-<^sepTY?9W<0kyhy5}l^K3`ZSX&`>&1nGbsv z;M@|`ueeBio7OH<(hqfq0?p2H=-pd|W=A>HoeHp*q`I7|T+>*bshDi^ijWp36N%5x Z^arn0EiiJs+l2rC002ovPDHLkV1lv)2E+gW delta 537 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 QDF6Tf07*qoM6N<$f~h)~i2wiq literal 42410 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 diff --git a/couchpotato/static/images/sprite.png b/couchpotato/static/images/sprite.png index 6af04a7e88dde73701b9889744c1c3c71f15b29b..5ba4d00e5d69aec715fa6b681d6e86169cf6babf 100644 GIT binary patch delta 1838 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 Rgd_j}002ovPDHLkV1gh{U+Mq= diff --git a/couchpotato/static/images/toTop.gif b/couchpotato/static/images/toTop.gif index cde291a44056ae03f528c32d69fdacb8d35d0181..110534a2f23b6161d49c76f487c2707c5de3ddd5 100644 GIT binary patch literal 56 zcmZ?wbh9u|6krfw_`twmn0)U4|NlA+KmZb9U=r`?UwQiNe1-RZaks1Oz3_t+N3k)3E49pxd9vc=MY~~QwiirRU hwK2+A#aI|Va_*4O4w|wfaDiKof^(OQrhx*3H2|G>3ylB( From c0012c9243cf0a631a48ad0589c54016c095e40b Mon Sep 17 00:00:00 2001 From: Ruud Date: Thu, 20 Sep 2012 11:25:38 +0200 Subject: [PATCH 11/92] Properly use newer_than. fix #850 --- couchpotato/core/plugins/scanner/main.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/couchpotato/core/plugins/scanner/main.py b/couchpotato/core/plugins/scanner/main.py index 0bc47681..b22b6265 100644 --- a/couchpotato/core/plugins/scanner/main.py +++ b/couchpotato/core/plugins/scanner/main.py @@ -320,17 +320,20 @@ class Scanner(Plugin): # Only process movies newer than x if newer_than and newer_than > 0: + has_new_files = False for cur_file in group['unsorted_files']: file_time = [os.path.getmtime(cur_file), os.path.getctime(cur_file)] - if file_time[0] > time.time() or file_time[1] > time.time(): + if file_time[0] > newer_than or file_time[1] > newer_than: + has_new_files = True break - log.debug('None of the files have changed since %s for %s, skipping.', (time.ctime(newer_than), identifier)) + if not has_new_files: + log.debug('None of the files have changed since %s for %s, skipping.', (time.ctime(newer_than), identifier)) - # Delete the unsorted list - del group['unsorted_files'] + # Delete the unsorted list + del group['unsorted_files'] - continue + continue # Group extra (and easy) files first # images = self.getImages(group['unsorted_files']) From 6f7d2caa9b9d6652d795b67e7b2cd1ec5717c076 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 21 Sep 2012 12:16:36 +0200 Subject: [PATCH 12/92] Properly update release dates. --- couchpotato/core/plugins/library/main.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/couchpotato/core/plugins/library/main.py b/couchpotato/core/plugins/library/main.py index ae142299..df158bb6 100644 --- a/couchpotato/core/plugins/library/main.py +++ b/couchpotato/core/plugins/library/main.py @@ -1,6 +1,7 @@ from couchpotato import get_session from couchpotato.core.event import addEvent, fireEventAsync, fireEvent from couchpotato.core.helpers.encoding import toUnicode, simplifyString +from couchpotato.core.helpers.variable import mergeDicts from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin from couchpotato.core.settings.model import Library, LibraryTitle, File @@ -138,26 +139,26 @@ class LibraryPlugin(Plugin): library = db.query(Library).filter_by(identifier = identifier).first() if not library.info: - library_dict = self.update(identifier) - dates = library_dict.get('info', {}).get('release_dates') + library_dict = self.update(identifier, force = True) + dates = library_dict.get('info', {}).get('release_date') else: dates = library.info.get('release_date') - if dates and dates.get('expires', 0) < time.time(): + if dates and dates.get('expires', 0) < time.time() or not dates: dates = fireEvent('movie.release_date', identifier = identifier, merge = True) - library.info['release_date'] = dates - library.info = library.info + library.info = mergeDicts(library.info, {'release_date': dates }) db.commit() - dates = library.info.get('release_date', {}) - #db.close() - return dates def simplifyTitle(self, title): + dates = library.info.get('release_date', {}) + dates = library.info.get('release_date', {}) + title = toUnicode(title) + nr_prefix = '' if title[0] in ascii_letters else '#' title = simplifyString(title) From a5fa503970f0e88658ad1b3a5c69967aabc3fa5b Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 21 Sep 2012 12:33:22 +0200 Subject: [PATCH 13/92] Copy paste error. --- couchpotato/core/plugins/library/main.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/couchpotato/core/plugins/library/main.py b/couchpotato/core/plugins/library/main.py index df158bb6..95dda2ff 100644 --- a/couchpotato/core/plugins/library/main.py +++ b/couchpotato/core/plugins/library/main.py @@ -154,9 +154,6 @@ class LibraryPlugin(Plugin): def simplifyTitle(self, title): - dates = library.info.get('release_date', {}) - dates = library.info.get('release_date', {}) - title = toUnicode(title) nr_prefix = '' if title[0] in ascii_letters else '#' From f82e2a3e6e586e3d30287fc90bb46d5c1fbd4f25 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 21 Sep 2012 12:38:38 +0200 Subject: [PATCH 14/92] Limit sabnzbd history check. --- couchpotato/core/downloaders/sabnzbd/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index abff97d7..cd5b5047 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -100,6 +100,7 @@ class Sabnzbd(Downloader): params = { 'apikey': self.conf('api_key'), 'mode': 'history', + 'limit': 15, 'output': 'json' } url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params) From 5776b2caad9fa39ac6980d723c0f989c81edb7a3 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 22 Sep 2012 09:05:44 +0200 Subject: [PATCH 15/92] Convert torrent hash to uppercase --- couchpotato/core/downloaders/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/downloaders/base.py b/couchpotato/core/downloaders/base.py index 504ddac8..6fa6a915 100644 --- a/couchpotato/core/downloaders/base.py +++ b/couchpotato/core/downloaders/base.py @@ -56,7 +56,7 @@ class Downloader(Plugin): return is_correct def magnetToTorrent(self, magnet_link): - torrent_hash = re.findall('urn:btih:([\w]{32,40})', magnet_link)[0] + torrent_hash = re.findall('urn:btih:([\w]{32,40})', magnet_link)[0].upper() # Convert base 32 to hex if len(torrent_hash) == 32: From 6fc9d383ded02cb6d572ef1fa7242e59bda530e7 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 22 Sep 2012 09:20:37 +0200 Subject: [PATCH 16/92] Add some error handling to sabnzbd statuscheck --- couchpotato/core/downloaders/sabnzbd/main.py | 84 +++++++++++--------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index cd5b5047..0151cc47 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -2,8 +2,8 @@ from couchpotato.core.downloaders.base import Downloader from couchpotato.core.helpers.encoding import tryUrlencode from couchpotato.core.helpers.variable import cleanHost from couchpotato.core.logger import CPLog -import traceback import json +import traceback log = CPLog(__name__) @@ -91,10 +91,13 @@ class Sabnzbd(Downloader): log.error('Failed parsing json status: %s', traceback.format_exc()) return False - for slot in history['queue']['slots']: - log.debug('Found %s in SabNZBd queue, which is %s, with %s left', (slot['filename'], slot['status'], slot['timeleft'])) - if slot['filename'] == nzbname: - return slot['status'].lower() + try: + for slot in history['queue']['slots']: + log.debug('Found %s in SabNZBd queue, which is %s, with %s left', (slot['filename'], slot['status'], slot['timeleft'])) + if slot['filename'] == nzbname: + return slot['status'].lower() + except: + log.debug('No items in queue: %s', (traceback.format_exc())) # Go through history items params = { @@ -118,45 +121,48 @@ class Sabnzbd(Downloader): log.error('Failed parsing history json: %s', traceback.format_exc()) return - for slot in history['history']['slots']: - log.debug('Found %s in SabNZBd history, which has %s', (slot['name'], slot['status'])) - if slot['name'] == nzbname: - # Note: if post process even if failed is on in SabNZBd, it will complete with a fail message - if slot['status'] == 'Failed' or (slot['status'] == 'Completed' and slot['fail_message'].strip()): + try: + for slot in history['history']['slots']: + log.debug('Found %s in SabNZBd history, which has %s', (slot['name'], slot['status'])) + if slot['name'] == nzbname: + # Note: if post process even if failed is on in SabNZBd, it will complete with a fail message + if slot['status'] == 'Failed' or (slot['status'] == 'Completed' and slot['fail_message'].strip()): - # Delete failed download - if self.conf('delete_failed', default = True): + # Delete failed download + if self.conf('delete_failed', default = True): - log.info('%s failed downloading, deleting...', slot['name']) - params = { - 'apikey': self.conf('api_key'), - 'mode': 'history', - 'name': 'delete', - 'del_files': '1', - 'value': slot['nzo_id'] - } - url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params) + log.info('%s failed downloading, deleting...', slot['name']) + params = { + 'apikey': self.conf('api_key'), + 'mode': 'history', + 'name': 'delete', + 'del_files': '1', + 'value': slot['nzo_id'] + } + url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params) - try: - sab = self.urlopen(url, timeout = 60, show_error = False) - except: - log.error('Failed deleting: %s', traceback.format_exc()) - return False + try: + sab = self.urlopen(url, timeout = 60, show_error = False) + except: + log.error('Failed deleting: %s', traceback.format_exc()) + return False - result = sab.strip() - if not result: - log.error("SABnzbd didn't return anything.") + result = sab.strip() + if not result: + log.error("SABnzbd didn't return anything.") - log.debug("Result text from SAB: " + result[:40]) - if result == "ok": - log.info('SabNZBd deleted failed release %s successfully.', slot['name']) - elif result == "Missing authentication": - log.error("Incorrect username/password or API?.") - else: - log.error("Unknown error: " + result[:40]) + log.debug("Result text from SAB: " + result[:40]) + if result == "ok": + log.info('SabNZBd deleted failed release %s successfully.', slot['name']) + elif result == "Missing authentication": + log.error("Incorrect username/password or API?.") + else: + log.error("Unknown error: " + result[:40]) - return 'failed' - else: - return slot['status'].lower() + return 'failed' + else: + return slot['status'].lower() + except: + log.debug('No items in history: %s', (traceback.format_exc())) return 'not_found' From d4600635e1efad5e619d4f7fadd57981bc07c524 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 24 Sep 2012 17:35:13 +0200 Subject: [PATCH 17/92] Use sudo in readme. Thanks jbillo --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b0e4222d..91223f18 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Linux (ubuntu / debian): * 'cd' to the folder of your choosing. * Run `git clone https://github.com/RuudBurger/CouchPotatoServer.git` * Then do `python CouchPotatoServer/CouchPotato.py` to start -* To run on boot copy the init script. `cp CouchPotatoServer/init/ubuntu /etc/init.d/couchpotato` -* Change the paths inside the init script. `nano /etc/init.d/couchpotato` -* Make it executable. `chmod +x /etc/init.d/couchpotato` +* To run on boot copy the init script. `sudo cp CouchPotatoServer/init/ubuntu /etc/init.d/couchpotato` +* Change the paths inside the init script. `sudo nano /etc/init.d/couchpotato` +* Make it executable. `sudo chmod +x /etc/init.d/couchpotato` * Add it to defaults. `sudo update-rc.d couchpotato defaults` From 3d26a53fbdef0996d11c99850b9b1f56d6e05871 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 24 Sep 2012 21:59:36 +0200 Subject: [PATCH 18/92] Don't capitalize labels in settings --- couchpotato/static/scripts/page/settings.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/couchpotato/static/scripts/page/settings.js b/couchpotato/static/scripts/page/settings.js index 576ad44c..4352fb2c 100644 --- a/couchpotato/static/scripts/page/settings.js +++ b/couchpotato/static/scripts/page/settings.js @@ -211,7 +211,7 @@ Page.Settings = new Class({ if(self.tabs[tab_name] && self.tabs[tab_name].tab) return self.tabs[tab_name].tab - var label = (tab.label || tab.name || tab_name).capitalize() + var label = tab.label || (tab.name || tab_name).capitalize() var tab_el = new Element('li.t_'+tab_name).adopt( new Element('a', { 'href': App.createUrl(self.name+'/'+tab_name), @@ -244,7 +244,7 @@ Page.Settings = new Class({ if(!parent_tab.subtabs_el) parent_tab.subtabs_el = new Element('ul.subtabs').inject(parent_tab.tab); - var label = (tab.label || tab.name || tab_name).capitalize() + var label = tab.label || (tab.name || tab_name).capitalize() var tab_el = new Element('li.t_'+tab_name).adopt( new Element('a', { 'href': App.createUrl(self.name+'/'+parent_tab_name+'/'+tab_name), @@ -274,7 +274,7 @@ Page.Settings = new Class({ 'class': (group.advanced ? 'inlineLabels advanced' : 'inlineLabels') + ' group_' + (group.name || '') + ' subtab_' + (group.subtab || '') }).adopt( new Element('h2', { - 'text': (group.label || group.name).capitalize() + 'text': group.label || (group.name).capitalize() }).adopt( new Element('span.hint', { 'html': group.description || '' From 8eee2af49b7d25b0a668a0a6d1cca1c379aab426 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 24 Sep 2012 22:23:15 +0200 Subject: [PATCH 19/92] Renamer fileinput. fix #861 --- couchpotato/static/style/page/settings.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/static/style/page/settings.css b/couchpotato/static/style/page/settings.css index 686c3b21..475e61e6 100644 --- a/couchpotato/static/style/page/settings.css +++ b/couchpotato/static/style/page/settings.css @@ -324,7 +324,7 @@ cursor: text; width: 30%; margin: 0 !important; - height: 27px; + min-height: 27px; line-height: 0; display: inline-block; } From 0f1e8eeff901d4d87d90435d4c20d26c48a4c565 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 10:43:46 +0200 Subject: [PATCH 20/92] Make sure to always search for old movies --- couchpotato/core/plugins/searcher/main.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 567b84ea..670841f2 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -410,6 +410,11 @@ class Searcher(Plugin): if not dates or (dates.get('theater', 0) == 0 and dates.get('dvd', 0) == 0): return True else: + + # For movies before 1972 + if dates.get('theater', 0) < 0 or dates.get('dvd', 0) < 0: + return True + if wanted_quality in pre_releases: # Prerelease 1 week before theaters if dates.get('theater') - 604800 < now: From 0132012276e41ba7c7b67b687171aa8136bfeb3e Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 11:10:49 +0200 Subject: [PATCH 21/92] Hide ip change --- couchpotato/core/_base/_core/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/couchpotato/core/_base/_core/__init__.py b/couchpotato/core/_base/_core/__init__.py index 2aca8e2b..8d702f18 100644 --- a/couchpotato/core/_base/_core/__init__.py +++ b/couchpotato/core/_base/_core/__init__.py @@ -27,6 +27,7 @@ config = [{ 'name': 'host', 'advanced': True, 'default': '0.0.0.0', + 'hidden': True, 'label': 'IP', 'description': 'Host that I should listen to. "0.0.0.0" listens to all ips.', }, From d40ad1ddf2e7160da28b55cfbfc592f985b5d920 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 12:43:22 +0200 Subject: [PATCH 22/92] Improved wizard --- .../core/downloaders/nzbget/__init__.py | 1 - .../core/downloaders/pneumatic/__init__.py | 1 - .../core/plugins/wizard/static/wizard.css | 21 +- .../core/plugins/wizard/static/wizard.js | 484 ++++++++++-------- .../torrent/kickasstorrents/__init__.py | 1 + .../torrent/thepiratebay/__init__.py | 1 + 6 files changed, 289 insertions(+), 220 deletions(-) diff --git a/couchpotato/core/downloaders/nzbget/__init__.py b/couchpotato/core/downloaders/nzbget/__init__.py index 5015437e..8b68c95f 100644 --- a/couchpotato/core/downloaders/nzbget/__init__.py +++ b/couchpotato/core/downloaders/nzbget/__init__.py @@ -11,7 +11,6 @@ config = [{ 'name': 'nzbget', 'label': 'NZBGet', 'description': 'Send NZBs to your NZBGet installation.', - 'wizard': True, 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/downloaders/pneumatic/__init__.py b/couchpotato/core/downloaders/pneumatic/__init__.py index dedcde19..004821c5 100644 --- a/couchpotato/core/downloaders/pneumatic/__init__.py +++ b/couchpotato/core/downloaders/pneumatic/__init__.py @@ -12,7 +12,6 @@ config = [{ 'name': 'pneumatic', 'label': 'Pneumatic', 'description': 'Download the .strm file to a specific folder.', - 'wizard': True, 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/plugins/wizard/static/wizard.css b/couchpotato/core/plugins/wizard/static/wizard.css index d1aa99c8..dd73a654 100644 --- a/couchpotato/core/plugins/wizard/static/wizard.css +++ b/couchpotato/core/plugins/wizard/static/wizard.css @@ -14,12 +14,13 @@ .page.wizard .tab_wrapper { background: #5c697b; - padding: 18px 0; - font-size: 23px; + padding: 10px 0; + font-size: 18px; position: fixed; top: 0; margin: 0; width: 100%; + min-width: 960px; left: 0; z-index: 2; box-shadow: 0 0 50px rgba(0,0,0,0.55); @@ -36,7 +37,7 @@ display: inline-block; } .page.wizard .tabs li a { - padding: 20px 30px; + padding: 20px 10px; } .page.wizard .tab_wrapper .pointer { @@ -45,7 +46,7 @@ border-top: 10px solid #5c697b; display: block; position: absolute; - top: 60px; + top: 44px; } .page.wizard .tab_content { @@ -58,11 +59,21 @@ .page.wizard .wgroup_finish { height: 300px; } + .page.wizard .wgroup_finish h1 { + text-align: center; + } + .page.wizard .wgroup_finish .wizard_support, + .page.wizard .wgroup_finish .description { + font-size: 25px; + line-height: 120%; + margin: 20px 0; + text-align: center; + } .page.wizard .button.green { padding: 20px; font-size: 25px; - margin: 10px 30px; + margin: 10px 30px 80px; display: block; text-align: center; } \ No newline at end of file diff --git a/couchpotato/core/plugins/wizard/static/wizard.js b/couchpotato/core/plugins/wizard/static/wizard.js index a4438cba..a3fe938c 100644 --- a/couchpotato/core/plugins/wizard/static/wizard.js +++ b/couchpotato/core/plugins/wizard/static/wizard.js @@ -1,214 +1,272 @@ -Page.Wizard = new Class({ - - Extends: Page.Settings, - - name: 'wizard', - has_tab: false, - wizard_only: true, - - headers: { - 'welcome': { - 'title': 'Welcome to the new CouchPotato', - 'description': 'To get started, fill in each of the following settings as much as your can.
Maybe first start with importing your movies from the previous CouchPotato', - 'content': new Element('div', { - 'styles': { - 'margin': '0 0 0 30px' - } - }).adopt( - new Element('div', { - 'html': 'Select the data.db. It should be in your CouchPotato root directory.' - }), - self.import_iframe = new Element('iframe', { - 'styles': { - 'height': 40, - 'width': 300, - 'border': 0, - 'overflow': 'hidden' - } - }) - ), - 'event': function(){ - self.import_iframe.set('src', Api.createUrl('v1.import')) - } - }, - 'general': { - 'title': 'General', - 'description': 'If you want to access CP from outside your local network, you better secure it a bit with a username & password.' - }, - 'downloaders': { - 'title': 'What download apps are you using?', - 'description': 'If you don\'t have any of these listed, you have to use Blackhole. Or drop me a line, maybe I\'ll support your download app.' - }, - 'providers': { - 'title': 'Are you registered at any of these sites?', - 'description': 'CP uses these sites to search for movies. A few free are enabled by default, but it\'s always better to have a few more.' - }, - 'renamer': { - 'title': 'Move & rename the movies after downloading?', - 'description': '' - }, - 'finish': { - 'title': 'Finish Up', - 'description': 'Are you done? Did you fill in everything as much as possible? Yes, ok gogogo!', - 'content': new Element('div').adopt( - new Element('a.button.green', { - 'text': 'I\'m ready to start the awesomeness, wow this button is big and green!', - 'events': { - 'click': function(e){ - (e).preventDefault(); - Api.request('settings.save', { - 'data': { - 'section': 'core', - 'name': 'show_wizard', - 'value': 0 - }, - 'useSpinner': true, - 'spinnerOptions': { - 'target': self.el - }, - 'onComplete': function(){ - window.location = App.createUrl(); - } - }); - } - } - }) - ) - } - }, - groups: ['welcome', 'general', 'downloaders', 'searcher', 'providers', 'renamer', 'finish'], - - open: function(action, params){ - var self = this; - - if(!self.initialized){ - App.fireEvent('unload'); - App.getBlock('header').hide(); - - self.parent(action, params); - - self.addEvent('create', function(){ - self.order(); - }); - - self.initialized = true; - - self.scroll = new Fx.Scroll(document.body, { - 'transition': 'quint:in:out' - }); - } - else - (function(){ - var sc = self.el.getElement('.wgroup_'+action); - self.scroll.start(0, sc.getCoordinates().top-80); - }).delay(1) - }, - - order: function(){ - var self = this; - - var form = self.el.getElement('.uniForm'); - var tabs = self.el.getElement('.tabs'); - - self.groups.each(function(group){ - if(self.headers[group]){ - group_container = new Element('.wgroup_'+group, { - 'styles': { - 'opacity': 0.2 - }, - 'tween': { - 'duration': 350 - } - }); - group_container.adopt( - new Element('h1', { - 'text': self.headers[group].title - }), - self.headers[group].description ? new Element('span.description', { - 'html': self.headers[group].description - }) : null, - self.headers[group].content ? self.headers[group].content : null - ).inject(form); - } - - var tab_navigation = tabs.getElement('.t_'+group); - if(tab_navigation && group_container){ - tab_navigation.inject(tabs); // Tab navigation - self.el.getElement('.tab_'+group).inject(group_container); // Tab content - if(self.headers[group]){ - var a = tab_navigation.getElement('a'); - a.set('text', (self.headers[group].label || group).capitalize()); - var url_split = a.get('href').split('wizard')[1].split('/'); - if(url_split.length > 3) - a.set('href', a.get('href').replace(url_split[url_split.length-3]+'/', '')); - - } - } - else { - new Element('li.t_'+group).adopt( - new Element('a', { - 'href': App.createUrl('wizard/'+group), - 'text': (self.headers[group].label || group).capitalize() - }) - ).inject(tabs); - } - - if(self.headers[group] && self.headers[group].event) - self.headers[group].event.call() - }); - - // Remove toggle - self.el.getElement('.advanced_toggle').destroy(); - - // Hide retention - self.el.getElement('.tab_searcher').hide(); - self.el.getElement('.t_searcher').hide(); - - // Add pointer - new Element('.tab_wrapper').wraps(tabs).adopt( - self.pointer = new Element('.pointer', { - 'tween': { - 'transition': 'quint:in:out' - } - }) - ); - - // Add nav - var minimum = self.el.getSize().y-window.getSize().y; - self.groups.each(function(group, nr){ - - var g = self.el.getElement('.wgroup_'+group); - if(!g || !g.isVisible()) return; - var t = self.el.getElement('.t_'+group); - if(!t) return; - - var func = function(){ - var ct = t.getCoordinates(); - self.pointer.tween('left', ct.left+(ct.width/2)-(self.pointer.getWidth()/2)); - g.tween('opacity', 1); - } - - if(nr == 0) - func(); - - - var ss = new ScrollSpy( { - min: function(){ - var c = g.getCoordinates(); - var top = c.top-(window.getSize().y/2); - return top > minimum ? minimum : top - }, - max: function(){ - var c = g.getCoordinates(); - return c.top+(c.height/2) - }, - onEnter: func, - onLeave: function(){ - g.tween('opacity', 0.2) - } - }); - }); - - } - +Page.Wizard = new Class({ + + Extends: Page.Settings, + + name: 'wizard', + has_tab: false, + wizard_only: true, + + headers: { + 'welcome': { + 'title': 'Welcome to the new CouchPotato', + 'description': 'To get started, fill in each of the following settings as much as your can.
Maybe first start with importing your movies from the previous CouchPotato', + 'content': new Element('div', { + 'styles': { + 'margin': '0 0 0 30px' + } + }).adopt( + new Element('div', { + 'html': 'Select the data.db. It should be in your CouchPotato root directory.' + }), + self.import_iframe = new Element('iframe', { + 'styles': { + 'height': 40, + 'width': 300, + 'border': 0, + 'overflow': 'hidden' + } + }) + ), + 'event': function(){ + self.import_iframe.set('src', Api.createUrl('v1.import')) + } + }, + 'general': { + 'title': 'General', + 'description': 'If you want to access CP from outside your local network, you better secure it a bit with a username & password.' + }, + 'downloaders': { + 'title': 'What download apps are you using?', + 'description': 'CP needs an external download app to work with. Choose one below. For more downloaders check settings after you have filled in the wizard. If your download app isn\'t in the list, use Blackhole.' + }, + 'providers': { + 'title': 'Are you registered at any of these sites?', + 'description': 'CP uses these sites to search for movies. A few free are enabled by default, but it\'s always better to have a few more. Check settings for the full list of available providers.' + }, + 'renamer': { + 'title': 'Move & rename the movies after downloading?', + 'description': 'The coolest part of CP is that it can move and organize your downloaded movies automagically. Check settings and you can even download trailers, subtitles and other data when it has finished downloading. It\'s awesome!' + }, + 'automation': { + 'title': 'Easily add movies to your wanted list!', + 'description': 'You can easily add movies from your favorite movie site, like IMDB, Rotten Tomatoes, Apple Trailers and more. Just install the userscript or drag the bookmarklet to your browsers bookmarks.' + + '
Once installed, just click the bookmarklet on a movie page and watch the magic happen ;)', + 'content': function(){ + + // See if userscript can be installed + var userscript = false; + try { + if(Components.interfaces.gmIGreasemonkeyService) + userscript = true + } + catch(e){ + userscript = Browser.chrome === true; + } + + var host_url = window.location.protocol + '//' + window.location.host; + + var el = new Element('div.group_userscript').adopt( + + (userscript ? [new Element('a.userscript.button', { + 'text': 'Install userscript', + 'href': Api.createUrl('userscript.get')+randomString()+'/couchpotato.user.js', + 'target': '_self' + }), new Element('span.or[text=or]')] : null), + new Element('span.bookmarklet').adopt( + new Element('a.button.orange', { + 'text': '+CouchPotato', + 'href': "javascript:void((function(){var e=document.createElement('script');e.setAttribute('type','text/javascript');e.setAttribute('charset','UTF-8');e.setAttribute('src','" + + host_url + Api.createUrl('userscript.bookmark') + + "?host="+ encodeURI(host_url + Api.createUrl('userscript.get')+randomString()+'/') + + "&r='+Math.random()*99999999);document.body.appendChild(e)})());", + 'target': '', + 'events': { + 'click': function(e){ + (e).stop() + alert('Drag it to your bookmark ;)') + } + } + }), + new Element('span', { + 'text': '⇽ Drag this to your bookmarks' + }) + ) + ).setStyles({ + 'background-image': "url('"+Api.createUrl('static/userscript/userscript.png')+"')" + }); + + return el + } + }, + 'finish': { + 'title': 'Finishing Up', + 'description': 'Are you done? Did you fill in everything as much as possible?' + + '
Be sure to check the settings to see what more CP can do!

' + + '
', + 'content': new Element('div').adopt( + new Element('a.button.green', { + 'styles': { + 'margin-top': 20 + }, + 'text': 'I\'m ready to start the awesomeness, wow this button is big and green!', + 'events': { + 'click': function(e){ + (e).preventDefault(); + Api.request('settings.save', { + 'data': { + 'section': 'core', + 'name': 'show_wizard', + 'value': 0 + }, + 'useSpinner': true, + 'spinnerOptions': { + 'target': self.el + }, + 'onComplete': function(){ + window.location = App.createUrl(); + } + }); + } + } + }) + ) + } + }, + groups: ['welcome', 'general', 'downloaders', 'searcher', 'providers', 'renamer', 'automation', 'finish'], + + open: function(action, params){ + var self = this; + + if(!self.initialized){ + App.fireEvent('unload'); + App.getBlock('header').hide(); + + self.parent(action, params); + + self.addEvent('create', function(){ + self.order(); + }); + + self.initialized = true; + + self.scroll = new Fx.Scroll(document.body, { + 'transition': 'quint:in:out' + }); + } + else + (function(){ + var sc = self.el.getElement('.wgroup_'+action); + self.scroll.start(0, sc.getCoordinates().top-80); + }).delay(1) + }, + + order: function(){ + var self = this; + + var form = self.el.getElement('.uniForm'); + var tabs = self.el.getElement('.tabs'); + + self.groups.each(function(group, nr){ + if(self.headers[group]){ + group_container = new Element('.wgroup_'+group, { + 'styles': { + 'opacity': 0.2 + }, + 'tween': { + 'duration': 350 + } + }); + + var content = self.headers[group].content + group_container.adopt( + new Element('h1', { + 'text': self.headers[group].title + }), + self.headers[group].description ? new Element('span.description', { + 'html': self.headers[group].description + }) : null, + content ? (typeOf(content) == 'function' ? content() : content) : null + ).inject(form); + } + + var tab_navigation = tabs.getElement('.t_'+group); + if(tab_navigation && group_container){ + tab_navigation.inject(tabs); // Tab navigation + self.el.getElement('.tab_'+group).inject(group_container); // Tab content + if(self.headers[group]){ + var a = tab_navigation.getElement('a'); + a.set('text', (self.headers[group].label || group).capitalize()); + var url_split = a.get('href').split('wizard')[1].split('/'); + if(url_split.length > 3) + a.set('href', a.get('href').replace(url_split[url_split.length-3]+'/', '')); + + } + } + else { + new Element('li.t_'+group).adopt( + new Element('a', { + 'href': App.createUrl('wizard/'+group), + 'text': (self.headers[group].label || group).capitalize() + }) + ).inject(tabs); + } + + if(self.headers[group] && self.headers[group].event) + self.headers[group].event.call() + }); + + // Remove toggle + self.el.getElement('.advanced_toggle').destroy(); + + // Hide retention + self.el.getElement('.tab_searcher').hide(); + self.el.getElement('.t_searcher').hide(); + + // Add pointer + new Element('.tab_wrapper').wraps(tabs).adopt( + self.pointer = new Element('.pointer', { + 'tween': { + 'transition': 'quint:in:out' + } + }) + ); + + // Add nav + var minimum = self.el.getSize().y-window.getSize().y; + self.groups.each(function(group, nr){ + + var g = self.el.getElement('.wgroup_'+group); + if(!g || !g.isVisible()) return; + var t = self.el.getElement('.t_'+group); + if(!t) return; + + var func = function(){ + var ct = t.getCoordinates(); + self.pointer.tween('left', ct.left+(ct.width/2)-(self.pointer.getWidth()/2)); + g.tween('opacity', 1); + } + + if(nr == 0) + func(); + + + var ss = new ScrollSpy( { + min: function(){ + var c = g.getCoordinates(); + var top = c.top-(window.getSize().y/2); + return top > minimum ? minimum : top + }, + max: function(){ + var c = g.getCoordinates(); + return c.top+(c.height/2) + }, + onEnter: func, + onLeave: function(){ + g.tween('opacity', 0.2) + } + }); + }); + + } + }); \ No newline at end of file diff --git a/couchpotato/core/providers/torrent/kickasstorrents/__init__.py b/couchpotato/core/providers/torrent/kickasstorrents/__init__.py index 2401f95a..9f0ab122 100644 --- a/couchpotato/core/providers/torrent/kickasstorrents/__init__.py +++ b/couchpotato/core/providers/torrent/kickasstorrents/__init__.py @@ -11,6 +11,7 @@ config = [{ 'subtab': 'providers', 'name': 'KickAssTorrents', 'description': 'See KickAssTorrents', + 'wizard': True, 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/providers/torrent/thepiratebay/__init__.py b/couchpotato/core/providers/torrent/thepiratebay/__init__.py index 2f8872e4..9a7beef5 100644 --- a/couchpotato/core/providers/torrent/thepiratebay/__init__.py +++ b/couchpotato/core/providers/torrent/thepiratebay/__init__.py @@ -10,6 +10,7 @@ config = [{ 'subtab': 'providers', 'name': 'ThePirateBay', 'description': 'The world\'s largest bittorrent tracker. See ThePirateBay', + 'wizard': True, 'options': [ { 'name': 'enabled', From 08ae51dbe615e7d847adbfd9f770d4b6db87a749 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 14:22:48 +0200 Subject: [PATCH 23/92] Improved folder select --- couchpotato/core/plugins/browser/main.py | 25 ++++++++++- couchpotato/static/scripts/page/settings.js | 46 ++++++++++++++------- couchpotato/static/style/page/settings.css | 13 ++++++ 3 files changed, 68 insertions(+), 16 deletions(-) diff --git a/couchpotato/core/plugins/browser/main.py b/couchpotato/core/plugins/browser/main.py index aa11b220..b84284b1 100644 --- a/couchpotato/core/plugins/browser/main.py +++ b/couchpotato/core/plugins/browser/main.py @@ -27,6 +27,8 @@ class FileBrowser(Plugin): }, 'return': {'type': 'object', 'example': """{ 'is_root': bool, //is top most folder + 'parent': string, //parent folder of requested path + 'home': string, //user home folder 'empty': bool, //directory is empty 'dirs': array, //directory names }"""} @@ -64,14 +66,35 @@ class FileBrowser(Plugin): path = getParam('path', '/') + # Set proper home dir for some systems + try: + import pwd + os.environ['HOME'] = pwd.getpwuid(os.geteuid()).pw_dir + except: + pass + + home = os.path.expanduser('~') + + if not path: + path = home + try: dirs = self.getDirectories(path = path, show_hidden = getParam('show_hidden', True)) except: dirs = [] + parent = os.path.dirname(path.rstrip(os.path.sep)) + if parent == path.rstrip(os.path.sep): + parent = '/' + elif parent != '/' and parent[-2:] != ':\\': + parent += os.path.sep + return jsonified({ - 'is_root': path == '/' or not path, + 'is_root': path == '/', 'empty': len(dirs) == 0, + 'parent': parent, + 'home': home + os.path.sep, + 'platform': os.name, 'dirs': dirs, }) diff --git a/couchpotato/static/scripts/page/settings.js b/couchpotato/static/scripts/page/settings.js index 4352fb2c..161da685 100644 --- a/couchpotato/static/scripts/page/settings.js +++ b/couchpotato/static/scripts/page/settings.js @@ -635,7 +635,7 @@ Option.Directory = new Class({ ), self.dir_list = new Element('ul', { 'events': { - 'click:relay(li)': function(e, el){ + 'click:relay(li:not(.empty))': function(e, el){ (e).preventDefault(); self.selectDirectory(el.get('data-value')) }, @@ -701,12 +701,24 @@ Option.Directory = new Class({ fillBrowser: function(json){ var self = this; - var v = self.input.get('text'); + self.data = json; + + var v = self.getValue(); var previous_dir = self.getParentDir(); + if(v == '') + self.input.set('text', json.home); + if(previous_dir != v && previous_dir.length >= 1 && !json.is_root){ + + var prev_dirname = self.getCurrentDirname(previous_dir); + if(previous_dir == json.home) + prev_dirname = 'Home'; + else if (previous_dir == '/' && json.platform == 'nt') + prev_dirname = 'Computer'; + self.back_button.set('data-value', previous_dir) - self.back_button.set('html', '« '+self.getCurrentDirname(previous_dir)) + self.back_button.set('html', '« '+prev_dirname) self.back_button.show() } else { @@ -719,23 +731,24 @@ Option.Directory = new Class({ else self.cached[v] = json; - setTimeout(function(){ - self.dir_list.empty(); + self.dir_list.empty(); + if(json.dirs.length > 0) json.dirs.each(function(dir){ - if(dir.indexOf(v) != -1){ - new Element('li', { - 'data-value': dir, - 'text': self.getCurrentDirname(dir) - }).inject(self.dir_list) - } + new Element('li', { + 'data-value': dir, + 'text': self.getCurrentDirname(dir) + }).inject(self.dir_list) }); - }, 50); + else + new Element('li.empty', { + 'text': 'Selected folder is empty' + }).inject(self.dir_list) }, getDirs: function(){ var self = this; - var c = self.input.get('text'); + var c = self.getValue(); if(self.cached[c] && self.use_cache){ self.fillBrowser() @@ -754,7 +767,10 @@ Option.Directory = new Class({ getParentDir: function(dir){ var self = this; - var v = dir || self.input.get('text'); + if(!dir && self.data && self.data.parent) + return self.data.parent; + + var v = dir || self.getValue(); var sep = Api.getOption('path_sep'); var dirs = v.split(sep); if(dirs.pop() == '') @@ -941,7 +957,7 @@ Option.Choice = new Class({ mtches.append([value == matchsplit ? match : matchsplit]); }); }); - + if(mtches.length == 0 && value != '') mtches.include(value); diff --git a/couchpotato/static/style/page/settings.css b/couchpotato/static/style/page/settings.css index 475e61e6..89f81e74 100644 --- a/couchpotato/static/style/page/settings.css +++ b/couchpotato/static/style/page/settings.css @@ -235,6 +235,19 @@ .page .directory_list li:hover { background-color: #515c68; } + + .page .directory_list li.empty { + background: none; + height: 100px; + text-align: center; + font-style: italic; + border: none; + line-height: 100px; + cursor: default; + color: #BBB; + text-shadow: none; + font-size: 12px; + } .page .directory_list .actions { clear: both; From 952f29918e3292570536a3a7a5161c0b37eeed7c Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 14:30:35 +0200 Subject: [PATCH 24/92] Hide git command when not using git Re-order automation --- couchpotato/core/_base/updater/__init__.py | 3 +++ couchpotato/core/plugins/automation/__init__.py | 5 ++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/_base/updater/__init__.py b/couchpotato/core/_base/updater/__init__.py index 7aae0b2e..a304f9e7 100644 --- a/couchpotato/core/_base/updater/__init__.py +++ b/couchpotato/core/_base/updater/__init__.py @@ -1,4 +1,6 @@ from .main import Updater +from couchpotato.environment import Env +import os def start(): return Updater() @@ -33,6 +35,7 @@ config = [{ { 'name': 'git_command', 'default': 'git', + 'hidden': not os.path.isdir(os.path.join(Env.get('app_dir'), '.git')), 'advanced': True }, ], diff --git a/couchpotato/core/plugins/automation/__init__.py b/couchpotato/core/plugins/automation/__init__.py index 75e0d28f..b7b1ab28 100644 --- a/couchpotato/core/plugins/automation/__init__.py +++ b/couchpotato/core/plugins/automation/__init__.py @@ -5,13 +5,12 @@ def start(): config = [{ 'name': 'automation', - 'order': 30, + 'order': 101, 'groups': [ { 'tab': 'automation', 'name': 'automation', - 'label': 'Automation', - 'description': 'Minimal movie requirements', + 'label': 'Minimal movie requirements', 'options': [ { 'name': 'year', From 24ad9759175f3e797cd630227c799e5fc646f6e5 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 15:09:35 +0200 Subject: [PATCH 25/92] Movie providers in their own subgroup --- couchpotato/core/plugins/subtitle/__init__.py | 4 +- couchpotato/core/plugins/trailer/__init__.py | 4 +- .../core/providers/nzb/mysterbin/__init__.py | 2 +- .../core/providers/nzb/newzbin/__init__.py | 2 +- .../core/providers/nzb/newznab/__init__.py | 3 +- .../core/providers/nzb/nzbclub/__init__.py | 2 +- .../core/providers/nzb/nzbindex/__init__.py | 2 +- .../core/providers/nzb/nzbmatrix/__init__.py | 2 +- .../core/providers/nzb/nzbsrus/__init__.py | 2 +- .../torrent/kickasstorrents/__init__.py | 2 +- .../torrent/passthepopcorn/__init__.py | 58 ++++++++++--------- .../providers/torrent/publichd/__init__.py | 2 +- .../providers/torrent/sceneaccess/__init__.py | 2 +- .../providers/torrent/scenehd/__init__.py | 2 +- .../torrent/thepiratebay/__init__.py | 42 +++++++------- .../torrent/torrentleech/__init__.py | 2 +- couchpotato/static/scripts/page/settings.js | 2 +- 17 files changed, 70 insertions(+), 65 deletions(-) diff --git a/couchpotato/core/plugins/subtitle/__init__.py b/couchpotato/core/plugins/subtitle/__init__.py index 858ce9d6..686d385e 100644 --- a/couchpotato/core/plugins/subtitle/__init__.py +++ b/couchpotato/core/plugins/subtitle/__init__.py @@ -8,9 +8,9 @@ config = [{ 'groups': [ { 'tab': 'renamer', - 'subtab': 'subtitles', 'name': 'subtitle', - 'label': 'Download subtitles after rename', + 'label': 'Download subtitles', + 'description': 'after rename', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/plugins/trailer/__init__.py b/couchpotato/core/plugins/trailer/__init__.py index 033df088..3ae454da 100644 --- a/couchpotato/core/plugins/trailer/__init__.py +++ b/couchpotato/core/plugins/trailer/__init__.py @@ -8,9 +8,9 @@ config = [{ 'groups': [ { 'tab': 'renamer', - 'subtab': 'trailer', 'name': 'trailer', - 'label': 'Download trailer after rename', + 'label': 'Download trailer', + 'description': 'after rename', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/providers/nzb/mysterbin/__init__.py b/couchpotato/core/providers/nzb/mysterbin/__init__.py index 3f0d1d33..b34f72fc 100644 --- a/couchpotato/core/providers/nzb/mysterbin/__init__.py +++ b/couchpotato/core/providers/nzb/mysterbin/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'nzb_providers', 'name': 'Mysterbin', 'description': 'Free provider, less accurate. See Mysterbin', 'options': [ diff --git a/couchpotato/core/providers/nzb/newzbin/__init__.py b/couchpotato/core/providers/nzb/newzbin/__init__.py index 06b25486..11292339 100644 --- a/couchpotato/core/providers/nzb/newzbin/__init__.py +++ b/couchpotato/core/providers/nzb/newzbin/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'nzb_providers', 'name': 'newzbin', 'description': 'See Newzbin', 'wizard': True, diff --git a/couchpotato/core/providers/nzb/newznab/__init__.py b/couchpotato/core/providers/nzb/newznab/__init__.py index e54db343..712f03e5 100644 --- a/couchpotato/core/providers/nzb/newznab/__init__.py +++ b/couchpotato/core/providers/nzb/newznab/__init__.py @@ -8,8 +8,9 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'nzb_providers', 'name': 'newznab', + 'order': 10, 'description': 'Enable multiple NewzNab providers such as NZB.su and nzbs.org', 'wizard': True, 'options': [ diff --git a/couchpotato/core/providers/nzb/nzbclub/__init__.py b/couchpotato/core/providers/nzb/nzbclub/__init__.py index e3387a3e..fc7b7ef2 100644 --- a/couchpotato/core/providers/nzb/nzbclub/__init__.py +++ b/couchpotato/core/providers/nzb/nzbclub/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'nzb_providers', 'name': 'NZBClub', 'description': 'Free provider, less accurate. See NZBClub', 'options': [ diff --git a/couchpotato/core/providers/nzb/nzbindex/__init__.py b/couchpotato/core/providers/nzb/nzbindex/__init__.py index 59b2730d..5bf5cd4d 100644 --- a/couchpotato/core/providers/nzb/nzbindex/__init__.py +++ b/couchpotato/core/providers/nzb/nzbindex/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'nzb_providers', 'name': 'nzbindex', 'description': 'Free provider, less accurate. See NZBIndex', 'options': [ diff --git a/couchpotato/core/providers/nzb/nzbmatrix/__init__.py b/couchpotato/core/providers/nzb/nzbmatrix/__init__.py index 8fc6b408..c3a5bfaa 100644 --- a/couchpotato/core/providers/nzb/nzbmatrix/__init__.py +++ b/couchpotato/core/providers/nzb/nzbmatrix/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'nzb_providers', 'name': 'nzbmatrix', 'label': 'NZBMatrix', 'description': 'See NZBMatrix', diff --git a/couchpotato/core/providers/nzb/nzbsrus/__init__.py b/couchpotato/core/providers/nzb/nzbsrus/__init__.py index 70f3e3f0..cd4d6691 100644 --- a/couchpotato/core/providers/nzb/nzbsrus/__init__.py +++ b/couchpotato/core/providers/nzb/nzbsrus/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'nzb_providers', 'name': 'nzbsrus', 'label': 'Nzbsrus', 'description': 'See NZBsRus', diff --git a/couchpotato/core/providers/torrent/kickasstorrents/__init__.py b/couchpotato/core/providers/torrent/kickasstorrents/__init__.py index 9f0ab122..ffa3934c 100644 --- a/couchpotato/core/providers/torrent/kickasstorrents/__init__.py +++ b/couchpotato/core/providers/torrent/kickasstorrents/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'torrent_providers', 'name': 'KickAssTorrents', 'description': 'See KickAssTorrents', 'wizard': True, diff --git a/couchpotato/core/providers/torrent/passthepopcorn/__init__.py b/couchpotato/core/providers/torrent/passthepopcorn/__init__.py index 67bf6665..44d98cb7 100644 --- a/couchpotato/core/providers/torrent/passthepopcorn/__init__.py +++ b/couchpotato/core/providers/torrent/passthepopcorn/__init__.py @@ -5,32 +5,34 @@ def start(): config = [{ 'name': 'passthepopcorn', - 'groups': [{ - 'tab': 'searcher', - 'subtab': 'providers', - 'name': 'PassThePopcorn', - 'description': 'See PassThePopcorn.me', - 'options': [ - { - 'name': 'enabled', - 'type': 'enabler', - 'default': False - }, - { - 'name': 'domain', - 'advanced': True, - 'label': 'Proxy server', - 'description': 'Domain for requests (HTTPS only!), keep empty to use default (tls.passthepopcorn.me).', - }, - { - 'name': 'username', - 'default': '', - }, - { - 'name': 'password', - 'default': '', - 'type': 'password', - } - ], - }] + 'groups': [ + { + 'tab': 'searcher', + 'subtab': 'torrent_providers', + 'name': 'PassThePopcorn', + 'description': 'See PassThePopcorn.me', + 'options': [ + { + 'name': 'enabled', + 'type': 'enabler', + 'default': False + }, + { + 'name': 'domain', + 'advanced': True, + 'label': 'Proxy server', + 'description': 'Domain for requests (HTTPS only!), keep empty to use default (tls.passthepopcorn.me).', + }, + { + 'name': 'username', + 'default': '', + }, + { + 'name': 'password', + 'default': '', + 'type': 'password', + } + ], +} + ] }] diff --git a/couchpotato/core/providers/torrent/publichd/__init__.py b/couchpotato/core/providers/torrent/publichd/__init__.py index 94d0825e..edffeba8 100644 --- a/couchpotato/core/providers/torrent/publichd/__init__.py +++ b/couchpotato/core/providers/torrent/publichd/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'torrent_providers', 'name': 'PublicHD', 'description': 'Public Torrent site with only HD content. See PublicHD', 'options': [ diff --git a/couchpotato/core/providers/torrent/sceneaccess/__init__.py b/couchpotato/core/providers/torrent/sceneaccess/__init__.py index 28b7ca33..e59f89b1 100644 --- a/couchpotato/core/providers/torrent/sceneaccess/__init__.py +++ b/couchpotato/core/providers/torrent/sceneaccess/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'torrent_providers', 'name': 'SceneAccess', 'description': 'See SceneAccess', 'options': [ diff --git a/couchpotato/core/providers/torrent/scenehd/__init__.py b/couchpotato/core/providers/torrent/scenehd/__init__.py index c9f18be8..a3d03130 100644 --- a/couchpotato/core/providers/torrent/scenehd/__init__.py +++ b/couchpotato/core/providers/torrent/scenehd/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'torrent_providers', 'name': 'SceneHD', 'description': 'See SceneHD', 'options': [ diff --git a/couchpotato/core/providers/torrent/thepiratebay/__init__.py b/couchpotato/core/providers/torrent/thepiratebay/__init__.py index 9a7beef5..9c56eb8f 100644 --- a/couchpotato/core/providers/torrent/thepiratebay/__init__.py +++ b/couchpotato/core/providers/torrent/thepiratebay/__init__.py @@ -5,24 +5,26 @@ def start(): config = [{ 'name': 'thepiratebay', - 'groups': [{ - 'tab': 'searcher', - 'subtab': 'providers', - 'name': 'ThePirateBay', - 'description': 'The world\'s largest bittorrent tracker. See ThePirateBay', - 'wizard': True, - 'options': [ - { - 'name': 'enabled', - 'type': 'enabler', - 'default': False - }, - { - 'name': 'domain', - 'advanced': True, - 'label': 'Proxy server', - 'description': 'Domain for requests, keep empty to let CouchPotato pick.', - } - ], - }] + 'groups': [ + { + 'tab': 'searcher', + 'subtab': 'torrent_providers', + 'name': 'ThePirateBay', + 'description': 'The world\'s largest bittorrent tracker. See ThePirateBay', + 'wizard': True, + 'options': [ + { + 'name': 'enabled', + 'type': 'enabler', + 'default': False + }, + { + 'name': 'domain', + 'advanced': True, + 'label': 'Proxy server', + 'description': 'Domain for requests, keep empty to let CouchPotato pick.', + } + ], + } + ] }] diff --git a/couchpotato/core/providers/torrent/torrentleech/__init__.py b/couchpotato/core/providers/torrent/torrentleech/__init__.py index 482dfda7..b808a005 100644 --- a/couchpotato/core/providers/torrent/torrentleech/__init__.py +++ b/couchpotato/core/providers/torrent/torrentleech/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'torrent_providers', 'name': 'TorrentLeech', 'description': 'See TorrentLeech', 'options': [ diff --git a/couchpotato/static/scripts/page/settings.js b/couchpotato/static/scripts/page/settings.js index 161da685..f4afc84d 100644 --- a/couchpotato/static/scripts/page/settings.js +++ b/couchpotato/static/scripts/page/settings.js @@ -244,7 +244,7 @@ Page.Settings = new Class({ if(!parent_tab.subtabs_el) parent_tab.subtabs_el = new Element('ul.subtabs').inject(parent_tab.tab); - var label = tab.label || (tab.name || tab_name).capitalize() + var label = tab.label || (tab.name || tab_name.replace('_', ' ')).capitalize() var tab_el = new Element('li.t_'+tab_name).adopt( new Element('a', { 'href': App.createUrl(self.name+'/'+parent_tab_name+'/'+tab_name), From 7e3a6eeb83a699e0acbb9aed04f80b93e4074794 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 15:47:50 +0200 Subject: [PATCH 26/92] Make sure top quality is always checked. --- .../core/plugins/profile/static/profile.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/plugins/profile/static/profile.js b/couchpotato/core/plugins/profile/static/profile.js index 470fda8f..947da1d3 100644 --- a/couchpotato/core/plugins/profile/static/profile.js +++ b/couchpotato/core/plugins/profile/static/profile.js @@ -86,7 +86,10 @@ var Profile = new Class({ }, 'onComplete': function(json){ if(json.success){ - self.data = json.profile + self.data = json.profile; + self.type_container.getElement('li:first-child input[type=checkbox]') + .set('checked', true) + .getParent().addClass('checked'); } } }); @@ -241,7 +244,15 @@ Profile.Type = new Class({ self.finish = new Element('input.inlay.finish[type=checkbox]', { 'checked': data.finish, 'events': { - 'change': self.fireEvent.bind(self, 'change') + 'change': function(e){ + if(self.el == self.el.getParent().getElement(':first-child')){ + self.finish_class.check(); + alert('Top quality always finishes the search') + return; + } + + self.fireEvent('change'); + } } }) ), @@ -255,7 +266,7 @@ Profile.Type = new Class({ self.el[self.data.quality_id > 0 ? 'removeClass' : 'addClass']('is_empty'); - new Form.Check(self.finish); + self.finish_class = new Form.Check(self.finish); }, From 08ef153bbf4ad69a9fc497486c74a20e5c815cc4 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 16:03:31 +0200 Subject: [PATCH 27/92] remove dropdown arrow --- couchpotato/static/style/main.css | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/couchpotato/static/style/main.css b/couchpotato/static/style/main.css index 183374b9..e187593e 100644 --- a/couchpotato/static/style/main.css +++ b/couchpotato/static/style/main.css @@ -376,22 +376,12 @@ body > .spinner, .mask{ font-weight: bold; } - .select .list:before { - content: ' '; - height: 0; - position: absolute; - width: 0; - border: 6px solid transparent; - border-bottom-color: #282d34; - margin: -11px 0 0 70px; - } - .select .list { display: none; background: #282d34; border: 1px solid #1f242b; position: absolute; - margin: 30px 0 0 0; + margin: 28px 0 0 0; box-shadow: 0 20px 20px -10px rgba(0,0,0,0.4); border-radius:3px; z-index: 3; From 3fa352e7c8abb46e2faa6eee7786e9fa4ce489b5 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 19:02:28 +0200 Subject: [PATCH 28/92] Firefox fix for directory input --- couchpotato/static/style/page/settings.css | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/couchpotato/static/style/page/settings.css b/couchpotato/static/style/page/settings.css index 89f81e74..f17e6183 100644 --- a/couchpotato/static/style/page/settings.css +++ b/couchpotato/static/style/page/settings.css @@ -332,7 +332,6 @@ .page .tag_input > ul { list-style: none; - padding: 3px 0; border-radius: 3px; cursor: text; width: 30%; @@ -352,7 +351,7 @@ min-width: 2px; font-size: 12px; padding: 0; - margin: 0 !important; + margin: 4px 0 0 !important; border-width: 0; background: 0; line-height: 20px; @@ -413,7 +412,7 @@ margin: -9px 0 0 -16px; border-radius: 30px 30px 0 0; cursor: pointer; - background: url('../../images/icon.delete.png') no-repeat center 2px, -webkit-linear-gradient( + background: url('../../images/icon.delete.png') no-repeat center 2px, linear-gradient( 270deg, #5b9bd1 0%, #5b9bd1 100% From 3a3a4fb1f3973ac275a4080ad8ca5c80656db822 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 23:11:27 +0200 Subject: [PATCH 29/92] Cleanup javascript events on movie delete --- couchpotato/core/plugins/movie/static/list.js | 12 ++++++---- .../core/plugins/movie/static/movie.js | 23 +++++++++++++++++-- .../core/plugins/movie/static/search.js | 2 +- couchpotato/static/scripts/page/wanted.js | 2 +- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/couchpotato/core/plugins/movie/static/list.js b/couchpotato/core/plugins/movie/static/list.js index 38fc7109..0aff0bde 100644 --- a/couchpotato/core/plugins/movie/static/list.js +++ b/couchpotato/core/plugins/movie/static/list.js @@ -86,18 +86,18 @@ var MovieList = new Class({ Object.each(movies, function(movie){ self.createMovie(movie); }); - + self.setCounter(total); }, - + setCounter: function(count){ var self = this; - + if(!self.navigation_counter) return; - + self.navigation_counter.set('text', (count || 0)); - + }, createMovie: function(movie, inject_at){ @@ -309,6 +309,8 @@ var MovieList = new Class({ erase_movies.each(function(movie){ self.movies.erase(movie); + + movie.destroy() }); self.calculateSelected(); diff --git a/couchpotato/core/plugins/movie/static/movie.js b/couchpotato/core/plugins/movie/static/movie.js index abaea65c..f5cd41e1 100644 --- a/couchpotato/core/plugins/movie/static/movie.js +++ b/couchpotato/core/plugins/movie/static/movie.js @@ -16,16 +16,35 @@ var Movie = new Class({ self.profile = Quality.getProfile(data.profile_id) || {}; self.parent(self, options); - App.addEvent('movie.update.'+data.id, self.update.bind(self)); + self.addEvents(); + }, + + addEvents: function(){ + var self = this; + + App.addEvent('movie.update.'+self.data.id, self.update.bind(self)); ['movie.busy', 'searcher.started'].each(function(listener){ - App.addEvent(listener+'.'+data.id, function(notification){ + App.addEvent(listener+'.'+self.data.id, function(notification){ if(notification.data) self.busy(true) }); }) }, + destroy: function(){ + var self = this; + + self.el.destroy(); + delete self.list.movies_added[self.get('id')]; + + // Remove events + App.removeEvents('movie.update.'+self.data.id); + ['movie.busy', 'searcher.started'].each(function(listener){ + App.removeEvents(listener+'.'+self.data.id); + }) + }, + busy: function(set_busy){ var self = this; diff --git a/couchpotato/core/plugins/movie/static/search.js b/couchpotato/core/plugins/movie/static/search.js index 6c6c94e9..63cab349 100644 --- a/couchpotato/core/plugins/movie/static/search.js +++ b/couchpotato/core/plugins/movie/static/search.js @@ -324,7 +324,7 @@ Block.Search.Item = new Class({ var self = this; if(!self.options.hasClass('set')){ - + if(self.info.in_library){ var in_library = []; self.info.in_library.releases.each(function(release){ diff --git a/couchpotato/static/scripts/page/wanted.js b/couchpotato/static/scripts/page/wanted.js index 3ef10d7a..a50b1bd7 100644 --- a/couchpotato/static/scripts/page/wanted.js +++ b/couchpotato/static/scripts/page/wanted.js @@ -222,7 +222,7 @@ window.addEvent('domready', function(){ movie.set('tween', { 'duration': 300, 'onComplete': function(){ - movie.destroy(); + self.movie.destroy() } }); movie.tween('height', 0); From ba36c738c7d6c345e728f957ab997f1c32f89a86 Mon Sep 17 00:00:00 2001 From: clinton-hall Date: Wed, 26 Sep 2012 16:46:10 +0930 Subject: [PATCH 30/92] Added def remove Allows renamer to request deletion of failed downloads --- couchpotato/core/downloaders/base.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/couchpotato/core/downloaders/base.py b/couchpotato/core/downloaders/base.py index 6fa6a915..6ca29f6d 100644 --- a/couchpotato/core/downloaders/base.py +++ b/couchpotato/core/downloaders/base.py @@ -24,6 +24,7 @@ class Downloader(Plugin): def __init__(self): addEvent('download', self.download) addEvent('download.status', self.getDownloadStatus) + addEvent('download.remove', self.remove) def download(self, data = {}, movie = {}, manual = False, filedata = None): pass @@ -31,6 +32,9 @@ class Downloader(Plugin): def getDownloadStatus(self, data = {}, movie = {}): return False + def remove(self, name = {}, nzo_id = {}): + return False + def createNzbName(self, data, movie): tag = self.cpTag(movie) return '%s%s' % (toSafeString(data.get('name')[:127 - len(tag)]), tag) From ef945597d2036217bb78a4fc166dbb55dec80e88 Mon Sep 17 00:00:00 2001 From: clinton-hall Date: Wed, 26 Sep 2012 16:51:51 +0930 Subject: [PATCH 31/92] Removed checking of status results from here getDownloadStatus is only called once from renamer and all results are passed back. Def remove is added so that renamer can request a failed downlaod to be deleted from SABnzbd if enabled. --- couchpotato/core/downloaders/sabnzbd/main.py | 96 ++++++++------------ 1 file changed, 38 insertions(+), 58 deletions(-) diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index 0151cc47..f05f0d50 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -67,8 +67,7 @@ class Sabnzbd(Downloader): if self.isDisabled(manual = True) or not self.isCorrectType(data.get('type')): return - nzbname = self.createNzbName(data, movie) - log.info('Checking download status of "%s" at SABnzbd.', nzbname) + log.info('Checking SABnzbd download status.') # Go through Queue params = { @@ -85,20 +84,12 @@ class Sabnzbd(Downloader): return False try: - history = json.loads(sab) + queue = json.loads(sab) except: log.debug("Result text from SAB: " + sab[:40]) log.error('Failed parsing json status: %s', traceback.format_exc()) return False - try: - for slot in history['queue']['slots']: - log.debug('Found %s in SabNZBd queue, which is %s, with %s left', (slot['filename'], slot['status'], slot['timeleft'])) - if slot['filename'] == nzbname: - return slot['status'].lower() - except: - log.debug('No items in queue: %s', (traceback.format_exc())) - # Go through history items params = { 'apikey': self.conf('api_key'), @@ -112,57 +103,46 @@ class Sabnzbd(Downloader): sab = self.urlopen(url, timeout = 60, show_error = False) except: log.error('Failed getting history: %s', traceback.format_exc()) - return + return False try: history = json.loads(sab) except: log.debug("Result text from SAB: " + sab[:40]) log.error('Failed parsing history json: %s', traceback.format_exc()) + return False + + return queue, history + + def remove(self, name = {}, nzo_id = {}): + # Delete failed download + if self.conf('delete_failed', default = True): + + log.info('%s failed downloading, deleting...', name) + params = { + 'apikey': self.conf('api_key'), + 'mode': 'history', + 'name': 'delete', + 'del_files': '1', + 'value': nzo_id + } + url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params) + + try: + sab = self.urlopen(url, timeout = 60, show_error = False) + except: + log.error('Failed deleting: %s', traceback.format_exc()) + return False + + result = sab.strip() + if not result: + log.error("SABnzbd didn't return anything.") + + log.debug("Result text from SAB: " + result[:40]) + if result == "ok": + log.info('SabNZBd deleted failed release %s successfully.', name) + elif result == "Missing authentication": + log.error("Incorrect username/password or API?.") + else: + log.error("Unknown error: " + result[:40]) return - - try: - for slot in history['history']['slots']: - log.debug('Found %s in SabNZBd history, which has %s', (slot['name'], slot['status'])) - if slot['name'] == nzbname: - # Note: if post process even if failed is on in SabNZBd, it will complete with a fail message - if slot['status'] == 'Failed' or (slot['status'] == 'Completed' and slot['fail_message'].strip()): - - # Delete failed download - if self.conf('delete_failed', default = True): - - log.info('%s failed downloading, deleting...', slot['name']) - params = { - 'apikey': self.conf('api_key'), - 'mode': 'history', - 'name': 'delete', - 'del_files': '1', - 'value': slot['nzo_id'] - } - url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params) - - try: - sab = self.urlopen(url, timeout = 60, show_error = False) - except: - log.error('Failed deleting: %s', traceback.format_exc()) - return False - - result = sab.strip() - if not result: - log.error("SABnzbd didn't return anything.") - - log.debug("Result text from SAB: " + result[:40]) - if result == "ok": - log.info('SabNZBd deleted failed release %s successfully.', slot['name']) - elif result == "Missing authentication": - log.error("Incorrect username/password or API?.") - else: - log.error("Unknown error: " + result[:40]) - - return 'failed' - else: - return slot['status'].lower() - except: - log.debug('No items in history: %s', (traceback.format_exc())) - - return 'not_found' From c6cba2f6e55f5f594738e9ac4b227dc99ef34979 Mon Sep 17 00:00:00 2001 From: clinton-hall Date: Wed, 26 Sep 2012 16:59:36 +0930 Subject: [PATCH 32/92] Only request SABnzbd status once Performs the checking of queue and history here. Requests delete of failed downlaods via download.remove event. --- couchpotato/core/plugins/renamer/main.py | 27 ++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index a696265c..aedc40c2 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -506,9 +506,11 @@ class Renamer(Plugin): if rels: log.debug('Checking status snatched releases...') + # get queue and history (once) from SABnzbd + queue, history = fireEvent('download.status', data = {}, movie = {}, single = True) scan_required = False - + for rel in rels: # Get current selected title @@ -530,7 +532,28 @@ class Renamer(Plugin): movie_dict = fireEvent('movie.get', rel.movie_id, single = True) # check status - downloadstatus = fireEvent('download.status', data = item, movie = movie_dict, single = True) + try: + for slot in queue['queue']['slots']: + log.debug('Found %s in SabNZBd queue, which is %s, with %s left', (slot['filename'], slot['status'], slot['timeleft'])) + if slot['filename'] == nzbname: + downloadstatus =['status'].lower() + except: + log.debug('No items in queue: %s', (traceback.format_exc())) + try: + for slot in history['history']['slots']: + log.debug('Found %s in SabNZBd history, which has %s', (slot['name'], slot['status'])) + if slot['name'] == nzbname: + # Note: if post process even if failed is on in SabNZBd, it will complete with a fail message + if slot['status'] == 'Failed' or (slot['status'] == 'Completed' and slot['fail_message'].strip()): + + # Delete failed download + rel_remove = fireEvent('download.remove', name = slot['name'], nzo_id = slot['nzo_id'], single = True) + downloadstatus = 'failed' + else: + downloadstatus = slot['status'].lower() + except: + log.debug('No items in history: %s', (traceback.format_exc())) + if not downloadstatus: log.debug('Download status functionality is not implemented for active downloaders.') scan_required = True From dc63796e4864454204bb7f88ee6383022004e2e6 Mon Sep 17 00:00:00 2001 From: clinton-hall Date: Wed, 26 Sep 2012 17:12:19 +0930 Subject: [PATCH 33/92] Added nzbname previously defined in Downloader. I forgot to bring this across. --- couchpotato/core/plugins/renamer/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index aedc40c2..2f579113 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -532,6 +532,7 @@ class Renamer(Plugin): movie_dict = fireEvent('movie.get', rel.movie_id, single = True) # check status + nzbname = self.createNzbName(item, movie_dict) try: for slot in queue['queue']['slots']: log.debug('Found %s in SabNZBd queue, which is %s, with %s left', (slot['filename'], slot['status'], slot['timeleft'])) From 08b450fc0aae80da7af2af1fd07729fdf76d02cb Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 26 Sep 2012 17:10:34 +0200 Subject: [PATCH 34/92] Remove trailer feature not implemented yet. --- couchpotato/core/plugins/trailer/__init__.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/couchpotato/core/plugins/trailer/__init__.py b/couchpotato/core/plugins/trailer/__init__.py index 3ae454da..f3aa59de 100644 --- a/couchpotato/core/plugins/trailer/__init__.py +++ b/couchpotato/core/plugins/trailer/__init__.py @@ -24,12 +24,6 @@ config = [{ 'type': 'dropdown', 'values': [('1080P', '1080p'), ('720P', '720p'), ('480P', '480p')], }, - { - 'name': 'automatic', - 'default': False, - 'type': 'bool', - 'description': 'Automaticly search & download for movies in library', - }, ], }, ], From 95c5d16991b2eb63c748af07791e30506541dcf8 Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 26 Sep 2012 19:35:59 +0200 Subject: [PATCH 35/92] Don't check retention when it's 0 --- couchpotato/core/plugins/searcher/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 670841f2..5bf7aebb 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -254,7 +254,7 @@ class Searcher(Plugin): imdb_results = kwargs.get('imdb_results', False) retention = Env.setting('retention', section = 'nzb') - if nzb.get('seeds') is None and retention < nzb.get('age', 0): + if nzb.get('seeds') is None and 0 < retention < nzb.get('age', 0): log.info('Wrong: Outside retention, age is %s, needs %s or lower: %s', (nzb['age'], retention, nzb['name'])) return False From 39c2567d5abb6cc01c70a7d0bfebf57ebe464d20 Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 26 Sep 2012 20:11:19 +0200 Subject: [PATCH 36/92] Also listen to search ended per movie. --- couchpotato/core/plugins/movie/static/movie.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/couchpotato/core/plugins/movie/static/movie.js b/couchpotato/core/plugins/movie/static/movie.js index f5cd41e1..78b9dc93 100644 --- a/couchpotato/core/plugins/movie/static/movie.js +++ b/couchpotato/core/plugins/movie/static/movie.js @@ -30,6 +30,11 @@ var Movie = new Class({ self.busy(true) }); }) + + App.addEvent('searcher.ended.'+self.data.id, function(notification){ + if(notification.data) + self.busy(false) + }); }, destroy: function(){ From 3da0b1a80410ebe166e9089d54c48c0e94dc9620 Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 26 Sep 2012 20:12:03 +0200 Subject: [PATCH 37/92] Let user know to report weird errors --- couchpotato/core/plugins/searcher/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 5bf7aebb..41ae0d9c 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -65,6 +65,7 @@ class Searcher(Plugin): try: self.single(movie_dict) except IndexError: + log.error('Forcing library update for %s, if you see this often, please report: %s', (movie_dict['library']['identifier'], traceback.format_exc())) fireEvent('library.update', movie_dict['library']['identifier'], force = True) except: log.error('Search failed for %s: %s', (movie_dict['library']['identifier'], traceback.format_exc())) From ed0e54d64dbecda13ae704f9841e282c8f1da7fd Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 26 Sep 2012 20:59:03 +0200 Subject: [PATCH 38/92] Add force full search options to wanted list --- .../core/plugins/movie/static/movie.css | 2 +- couchpotato/core/plugins/searcher/main.py | 36 +++++++++++++- couchpotato/static/scripts/page/wanted.js | 49 ++++++++++++++++++- 3 files changed, 84 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/plugins/movie/static/movie.css b/couchpotato/core/plugins/movie/static/movie.css index f809c579..0979ccf0 100644 --- a/couchpotato/core/plugins/movie/static/movie.css +++ b/couchpotato/core/plugins/movie/static/movie.css @@ -534,5 +534,5 @@ } .movies .alph_nav .more_menu > a { - background-position: center -157px; + background-position: center -158px; } diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 41ae0d9c..76ee24d8 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -1,6 +1,6 @@ from couchpotato import get_session from couchpotato.api import addApiView -from couchpotato.core.event import addEvent, fireEvent +from couchpotato.core.event import addEvent, fireEvent, fireEventAsync from couchpotato.core.helpers.encoding import simplifyString, toUnicode from couchpotato.core.helpers.request import jsonified, getParam from couchpotato.core.helpers.variable import md5, getTitle @@ -36,9 +36,35 @@ class Searcher(Plugin): }, }) + addApiView('searcher.full_search', self.allMoviesView, docs = { + 'desc': 'Starts a full search for all wanted movies', + }) + + addApiView('searcher.progress', self.getProgress, docs = { + 'desc': 'Get the progress of current full search', + }) + # Schedule cronjob fireEvent('schedule.cron', 'searcher.all', self.allMovies, day = self.conf('cron_day'), hour = self.conf('cron_hour'), minute = self.conf('cron_minute')) + def allMoviesView(self): + + in_progress = self.in_progress + if not in_progress: + fireEventAsync('searcher.all') + fireEvent('notify.frontend', type = 'searcher.started', data = True, message = 'Full search started') + else: + fireEvent('notify.frontend', type = 'searcher.already_started', data = True, message = 'Full search already in progress') + + return jsonified({ + 'success': not in_progress + }) + + def getProgress(self): + + return jsonified({ + 'progress': self.in_progress + }) def allMovies(self): @@ -54,6 +80,11 @@ class Searcher(Plugin): Movie.status.has(identifier = 'active') ).all() + self.in_progress = { + 'total': len(movies), + 'to_go': len(movies), + } + for movie in movies: movie_dict = movie.to_dict({ 'profile': {'types': {'quality': {}}}, @@ -70,6 +101,9 @@ class Searcher(Plugin): except: log.error('Search failed for %s: %s', (movie_dict['library']['identifier'], traceback.format_exc())) + self.in_progress['to_go'] -= 1 + time.sleep(10) + # Break if CP wants to shut down if self.shuttingDown(): break diff --git a/couchpotato/static/scripts/page/wanted.js b/couchpotato/static/scripts/page/wanted.js index a50b1bd7..69743247 100644 --- a/couchpotato/static/scripts/page/wanted.js +++ b/couchpotato/static/scripts/page/wanted.js @@ -10,16 +10,63 @@ Page.Wanted = new Class({ if(!self.wanted){ + self.manual_search = new Element('a', { + 'title': 'Force a search for the full wanted list', + 'text': 'Search all wanted', + 'events':{ + 'click': self.doFullSearch.bind(self, true) + } + }); + // Wanted movies self.wanted = new MovieList({ 'identifier': 'wanted', 'status': 'active', 'actions': MovieActions, - 'add_new': true + 'add_new': true, + 'menu': [self.manual_search] }); $(self.wanted).inject(self.el); + + // Check if search is in progress + self.startProgressInterval(); } + }, + + doFullSearch: function(full){ + var self = this; + + if(!self.search_in_progress){ + + Api.request('searcher.full_search'); + self.startProgressInterval(); + + } + + }, + + startProgressInterval: function(){ + var self = this; + + var start_text = self.manual_search.get('text'); + self.progress_interval = setInterval(function(){ + Api.request('searcher.progress', { + 'onComplete': function(json){ + self.search_in_progress = true; + if(!json.progress){ + clearInterval(self.progress_interval); + self.search_in_progress = false; + self.manual_search.set('text', start_text); + } + else { + var progress = json.progress; + self.manual_search.set('text', 'Searching.. (' + (((progress.total-progress.to_go)/progress.total)*100).round() + '%)'); + } + } + }) + }, 1000); + } }); From 86bf08cbd4ffa3234c87de95e613f028e8fbcddf Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 26 Sep 2012 21:01:48 +0200 Subject: [PATCH 39/92] Add documentation to progress api --- couchpotato/core/plugins/searcher/main.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 76ee24d8..f165f6a9 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -42,6 +42,9 @@ class Searcher(Plugin): addApiView('searcher.progress', self.getProgress, docs = { 'desc': 'Get the progress of current full search', + 'return': {'type': 'object', 'example': """{ + 'progress': False || object, total & to_go, +}"""}, }) # Schedule cronjob From 2ac2b0ff0603df2300f5b9c6a5656c6b1add63fa Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 26 Sep 2012 21:12:14 +0200 Subject: [PATCH 40/92] Remove debug sleep --- couchpotato/core/plugins/searcher/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index f165f6a9..03dfd70b 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -105,7 +105,6 @@ class Searcher(Plugin): log.error('Search failed for %s: %s', (movie_dict['library']['identifier'], traceback.format_exc())) self.in_progress['to_go'] -= 1 - time.sleep(10) # Break if CP wants to shut down if self.shuttingDown(): From 0e23413069074bc018ef4c1fc2e2e4bb2a0719ef Mon Sep 17 00:00:00 2001 From: Ruud Date: Thu, 27 Sep 2012 08:39:07 +0200 Subject: [PATCH 41/92] Mark movie snatched on manual download --- .../core/plugins/movie/static/movie.js | 32 ++++++++++++------- couchpotato/core/plugins/release/main.py | 5 +++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/couchpotato/core/plugins/movie/static/movie.js b/couchpotato/core/plugins/movie/static/movie.js index 78b9dc93..bb081cd1 100644 --- a/couchpotato/core/plugins/movie/static/movie.js +++ b/couchpotato/core/plugins/movie/static/movie.js @@ -421,19 +421,11 @@ var ReleaseAction = new Class({ var status = Status.get(release.status_id), quality = Quality.getProfile(release.quality_id) || {}, info = release.info; - - if( status.identifier == 'ignored' || status.identifier == 'failed'){ - self.last_release = release; - } - else if(!self.next_release && status.identifier == 'available'){ - self.next_release = release; - } + release.status = status; // Create release new Element('div', { - 'class': 'item '+status.identifier + - (self.next_release && self.next_release.id == release.id ? ' next_release' : '') + - (self.last_release && self.last_release.id == release.id ? ' last_release' : ''), + 'class': 'item '+status.identifier, 'id': 'release_'+release.id }).adopt( new Element('span.name', {'text': self.get(release, 'name'), 'title': self.get(release, 'name')}), @@ -466,11 +458,27 @@ var ReleaseAction = new Class({ } }) ).inject(self.release_container) + + if(status.identifier == 'ignored' || status.identifier == 'failed' || status.identifier == 'snatched'){ + if(!self.last_release || (self.last_release && self.last_release.status.identifier != 'snatched' && status.identifier == 'snatched')) + self.last_release = release; + } + else if(!self.next_release && status.identifier == 'available'){ + self.next_release = release; + } }); + + if(self.last_release){ + self.release_container.getElement('#release_'+self.last_release.id).addClass('last_release'); + } + + if(self.next_release){ + self.release_container.getElement('#release_'+self.next_release.id).addClass('next_release'); + } self.trynext_container.adopt( new Element('span.or', { - 'text': 'Download' + 'text': 'This movie is snatched, if anything went wrong, download' }), self.last_release ? new Element('a.button.orange', { 'text': 'the same release again', @@ -479,7 +487,7 @@ var ReleaseAction = new Class({ } }) : null, self.next_release && self.last_release ? new Element('span.or', { - 'text': 'or' + 'text': ',' }) : null, self.next_release ? [new Element('a.button.green', { 'text': self.last_release ? 'another release' : 'the best release', diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index 9046034c..9e945a87 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -161,6 +161,7 @@ class Release(Plugin): db = get_session() id = getParam('id') + status_snatched = fireEvent('status.add', 'snatched', single = True) rel = db.query(Relea).filter_by(id = id).first() if rel: @@ -181,6 +182,10 @@ class Release(Plugin): 'files': {} }), manual = True, single = True) + if success: + rel.status_id = status_snatched.get('id') + db.commit() + #db.close() return jsonified({ 'success': success From ce0bf7b51ac851387430546c53e4eac037355a41 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 28 Sep 2012 13:10:58 +0200 Subject: [PATCH 42/92] Standardized checking snatched --- couchpotato/core/downloaders/base.py | 27 +--- couchpotato/core/downloaders/sabnzbd/main.py | 134 ++++++++++--------- couchpotato/core/helpers/variable.py | 12 +- couchpotato/core/plugins/base.py | 19 ++- couchpotato/core/plugins/renamer/main.py | 133 +++++++++--------- 5 files changed, 169 insertions(+), 156 deletions(-) diff --git a/couchpotato/core/downloaders/base.py b/couchpotato/core/downloaders/base.py index 6ca29f6d..776976d8 100644 --- a/couchpotato/core/downloaders/base.py +++ b/couchpotato/core/downloaders/base.py @@ -1,10 +1,7 @@ from base64 import b32decode, b16encode from couchpotato.core.event import addEvent -from couchpotato.core.helpers.encoding import toSafeString from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin -from couchpotato.environment import Env -import os import random import re @@ -23,34 +20,18 @@ class Downloader(Plugin): def __init__(self): addEvent('download', self.download) - addEvent('download.status', self.getDownloadStatus) - addEvent('download.remove', self.remove) + addEvent('download.status', self.getAllDownloadStatus) + addEvent('download.remove_failed', self.removeFailed) def download(self, data = {}, movie = {}, manual = False, filedata = None): pass - def getDownloadStatus(self, data = {}, movie = {}): + def getAllDownloadStatus(self): return False - def remove(self, name = {}, nzo_id = {}): + def removeFailed(self, name = {}, nzo_id = {}): return False - def createNzbName(self, data, movie): - tag = self.cpTag(movie) - return '%s%s' % (toSafeString(data.get('name')[:127 - len(tag)]), tag) - - def createFileName(self, data, filedata, movie): - name = os.path.join(self.createNzbName(data, movie)) - if data.get('type') == 'nzb' and 'DOCTYPE nzb' not in filedata and '' not in filedata: - return '%s.%s' % (name, 'rar') - return '%s.%s' % (name, data.get('type')) - - def cpTag(self, movie): - if Env.setting('enabled', 'renamer'): - return '.cp(' + movie['library'].get('identifier') + ')' if movie['library'].get('identifier') else '' - - return '' - def isCorrectType(self, item_type): is_correct = item_type in self.type diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index f05f0d50..eaf91b56 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -1,6 +1,6 @@ from couchpotato.core.downloaders.base import Downloader from couchpotato.core.helpers.encoding import tryUrlencode -from couchpotato.core.helpers.variable import cleanHost +from couchpotato.core.helpers.variable import cleanHost, mergeDicts from couchpotato.core.logger import CPLog import json import traceback @@ -63,86 +63,92 @@ class Sabnzbd(Downloader): log.error("Unknown error: " + result[:40]) return False - def getDownloadStatus(self, data = {}, movie = {}): - if self.isDisabled(manual = True) or not self.isCorrectType(data.get('type')): - return - - log.info('Checking SABnzbd download status.') - - # Go through Queue - params = { - 'apikey': self.conf('api_key'), - 'mode': 'queue', - 'output': 'json' - } - url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params) - - try: - sab = self.urlopen(url, timeout = 60, show_error = False) - except: - log.error('Failed checking status: %s', traceback.format_exc()) + def getAllDownloadStatus(self): + if self.isDisabled(manual = False): return False + log.debug('Checking SABnzbd download status.') + + # Go through Queue try: - queue = json.loads(sab) + queue = self.call({ + 'mode': 'queue', + }) except: - log.debug("Result text from SAB: " + sab[:40]) - log.error('Failed parsing json status: %s', traceback.format_exc()) + log.error('Failed getting queue: %s', traceback.format_exc()) return False # Go through history items - params = { - 'apikey': self.conf('api_key'), - 'mode': 'history', - 'limit': 15, - 'output': 'json' - } - url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params) - try: - sab = self.urlopen(url, timeout = 60, show_error = False) + history = self.call({ + 'mode': 'history', + 'limit': 15, + }) except: - log.error('Failed getting history: %s', traceback.format_exc()) + log.error('Failed getting history json: %s', traceback.format_exc()) return False - try: - history = json.loads(sab) - except: - log.debug("Result text from SAB: " + sab[:40]) - log.error('Failed parsing history json: %s', traceback.format_exc()) + statuses = [] + + # Get busy releases + for item in queue.get('slots', []): + statuses.append({ + 'id': item['nzo_id'], + 'name': item['filename'], + 'status': 'busy', + 'original_status': item['status'], + 'timeleft': item['timeleft'] if not queue['paused'] else -1, + }) + + # Get old releases + for item in history.get('slots', []): + + status = 'busy' + if item['status'] == 'Failed' or (item['status'] == 'Completed' and item['fail_message'].strip()): + status = 'failed' + elif item['status'] == 'Completed': + status = 'completed' + + statuses.append({ + 'id': item['nzo_id'], + 'name': item['name'], + 'status': status, + 'original_status': item['status'], + 'timeleft': 0, + }) + + return statuses + + def removeFailed(self, item): + + if not self.conf('delete_failed', default = True): return False - return queue, history + log.info('%s failed downloading, deleting...', item['name']) - def remove(self, name = {}, nzo_id = {}): - # Delete failed download - if self.conf('delete_failed', default = True): - - log.info('%s failed downloading, deleting...', name) - params = { - 'apikey': self.conf('api_key'), + try: + self.call({ 'mode': 'history', 'name': 'delete', 'del_files': '1', - 'value': nzo_id - } - url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params) + 'value': item['id'] + }, use_json = False) + except: + log.error('Failed deleting: %s', traceback.format_exc()) + return False - try: - sab = self.urlopen(url, timeout = 60, show_error = False) - except: - log.error('Failed deleting: %s', traceback.format_exc()) - return False + return True - result = sab.strip() - if not result: - log.error("SABnzbd didn't return anything.") + def call(self, params, use_json = True): + + url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(mergeDicts(params, { + 'apikey': self.conf('api_key'), + 'output': 'json' + })) + + data = self.urlopen(url, timeout = 60, show_error = False) + if use_json: + return json.loads(data)[params['mode']] + else: + return data - log.debug("Result text from SAB: " + result[:40]) - if result == "ok": - log.info('SabNZBd deleted failed release %s successfully.', name) - elif result == "Missing authentication": - log.error("Incorrect username/password or API?.") - else: - log.error("Unknown error: " + result[:40]) - return diff --git a/couchpotato/core/helpers/variable.py b/couchpotato/core/helpers/variable.py index 5312177c..2578d2c2 100644 --- a/couchpotato/core/helpers/variable.py +++ b/couchpotato/core/helpers/variable.py @@ -118,8 +118,16 @@ def getTitle(library_dict): try: return library_dict['titles'][0]['title'] except: - log.error('Could not get title for %s', library_dict['identifier']) - return None + try: + for title in library_dict.titles: + if title.default: + return title.title + except: + log.error('Could not get title for %s', library_dict.identifier) + return None + + log.error('Could not get title for %s', library_dict['identifier']) + return None except: log.error('Could not get title for library item: %s', library_dict) return None diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index 40189ef1..8a1e0767 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -1,7 +1,8 @@ from StringIO import StringIO from couchpotato import addView from couchpotato.core.event import fireEvent, addEvent -from couchpotato.core.helpers.encoding import tryUrlencode, simplifyString, ss +from couchpotato.core.helpers.encoding import tryUrlencode, simplifyString, ss, \ + toSafeString from couchpotato.core.helpers.variable import getExt from couchpotato.core.logger import CPLog from couchpotato.environment import Env @@ -245,6 +246,22 @@ class Plugin(object): Env.get('cache').set(cache_key, value, timeout) return value + def createNzbName(self, data, movie): + tag = self.cpTag(movie) + return '%s%s' % (toSafeString(data.get('name')[:127 - len(tag)]), tag) + + def createFileName(self, data, filedata, movie): + name = os.path.join(self.createNzbName(data, movie)) + if data.get('type') == 'nzb' and 'DOCTYPE nzb' not in filedata and '' not in filedata: + return '%s.%s' % (name, 'rar') + return '%s.%s' % (name, data.get('type')) + + def cpTag(self, movie): + if Env.setting('enabled', 'renamer'): + return '.cp(' + movie['library'].get('identifier') + ')' if movie['library'].get('identifier') else '' + + return '' + def isDisabled(self): return not self.isEnabled() diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 2f579113..1b722298 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -20,6 +20,7 @@ log = CPLog(__name__) class Renamer(Plugin): renaming_started = False + checking_snatched = False def __init__(self): @@ -33,6 +34,7 @@ class Renamer(Plugin): addEvent('app.load', self.scan) fireEvent('schedule.interval', 'renamer.check_snatched', self.checkSnatched, minutes = self.conf('run_every')) + fireEvent('schedule.interval', 'renamer.check_snatched_forced', self.scan, hours = 2) def scanView(self): @@ -495,6 +497,11 @@ class Renamer(Plugin): loge('Couldn\'t remove empty directory %s: %s', (folder, traceback.format_exc())) def checkSnatched(self): + if self.checking_snatched: + log.debug('Already checking snatched') + + self.checking_snatched = True + snatched_status = fireEvent('status.get', 'snatched', single = True) ignored_status = fireEvent('status.get', 'ignored', single = True) failed_status = fireEvent('status.get', 'failed', single = True) @@ -504,81 +511,75 @@ class Renamer(Plugin): db = get_session() rels = db.query(Release).filter_by(status_id = snatched_status.get('id')).all() + scan_required = False + if rels: + self.checking_snatched = True log.debug('Checking status snatched releases...') # get queue and history (once) from SABnzbd - queue, history = fireEvent('download.status', data = {}, movie = {}, single = True) - - scan_required = False - - for rel in rels: - - # Get current selected title - default_title = '' - for title in rel.movie.library.titles: - if title.default: default_title = title.title - - # Check if movie has already completed and is manage tab (legacy db correction) - if rel.movie.status_id == done_status.get('id'): - log.debug('Found a completed movie with a snatched release : %s. Setting release status to ignored...' , default_title) - rel.status_id = ignored_status.get('id') - db.commit() - continue - - item = {} - for info in rel.info: - item[info.identifier] = info.value - - movie_dict = fireEvent('movie.get', rel.movie_id, single = True) - - # check status - nzbname = self.createNzbName(item, movie_dict) - try: - for slot in queue['queue']['slots']: - log.debug('Found %s in SabNZBd queue, which is %s, with %s left', (slot['filename'], slot['status'], slot['timeleft'])) - if slot['filename'] == nzbname: - downloadstatus =['status'].lower() - except: - log.debug('No items in queue: %s', (traceback.format_exc())) - try: - for slot in history['history']['slots']: - log.debug('Found %s in SabNZBd history, which has %s', (slot['name'], slot['status'])) - if slot['name'] == nzbname: - # Note: if post process even if failed is on in SabNZBd, it will complete with a fail message - if slot['status'] == 'Failed' or (slot['status'] == 'Completed' and slot['fail_message'].strip()): - - # Delete failed download - rel_remove = fireEvent('download.remove', name = slot['name'], nzo_id = slot['nzo_id'], single = True) - downloadstatus = 'failed' - else: - downloadstatus = slot['status'].lower() - except: - log.debug('No items in history: %s', (traceback.format_exc())) - - if not downloadstatus: + statuses = fireEvent('download.status', merge = True) + if not statuses: log.debug('Download status functionality is not implemented for active downloaders.') scan_required = True - else: - log.debug('Download status: %s' , downloadstatus) - if downloadstatus == 'failed': - if self.conf('next_on_failed'): - fireEvent('searcher.try_next_release', movie_id = rel.movie_id) - else: - rel.status_id = failed_status.get('id') + try: + for rel in rels: + rel_dict = rel.to_dict({'info': {}}) + + # Get current selected title + default_title = getTitle(rel.movie.library) + + # Check if movie has already completed and is manage tab (legacy db correction) + if rel.movie.status_id == done_status.get('id'): + log.debug('Found a completed movie with a snatched release : %s. Setting release status to ignored...' , default_title) + rel.status_id = ignored_status.get('id') + db.commit() + continue + + movie_dict = fireEvent('movie.get', rel.movie_id, single = True) + + # check status + nzbname = self.createNzbName(rel_dict['info'], movie_dict) + + found = False + for item in statuses: + if item['name'] == nzbname: + + timeleft = 'N/A' if item['timeleft'] == -1 else item['timeleft'] + log.debug('Found %s: %s, time to go: %s', (item['name'], item['status'].upper(), timeleft)) + + if item['status'] == 'busy': + pass + elif item['status'] == 'failed': + if item['delete']: + fireEvent('download.remove_failed', item, single = True) + + if self.conf('next_on_failed'): + fireEvent('searcher.try_next_release', movie_id = rel.movie_id) + else: + rel.status_id = failed_status.get('id') + db.commit() + elif item['status'] == 'completed': + log.info('Download of %s completed!', item['name']) + scan_required = True + + found = True + break + + if not found: + log.info('%s not found in downloaders', nzbname) + rel.status_id = ignored_status.get('id') db.commit() - log.info('Download of %s failed.', item['name']) + if self.conf('next_on_failed'): + fireEvent('searcher.try_next_release', movie_id = rel.movie_id) - elif downloadstatus == 'completed': - log.info('Download of %s completed!', item['name']) - scan_required = True + except: + log.error('Failed checking for release in downloader: %s', traceback.format_exc()) - elif downloadstatus == 'not_found': - log.info('%s not found in downloaders', item['name']) - rel.status_id = ignored_status.get('id') - db.commit() - - # Note that Queued, Downloading, Paused, Repair and Unpackimg are also available as status for SabNZBd if scan_required: fireEvent('renamer.scan') + + self.checking_snatched = False + + return True From 9184a97fcdf22a0bd50dfe83c01c9094a12f5da8 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 30 Sep 2012 15:56:51 +0200 Subject: [PATCH 43/92] Don't loop over releases when download doesn't support check snatched. fix #887 --- couchpotato/core/plugins/renamer/main.py | 86 ++++++++++++------------ 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 1b722298..87bcad6d 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -521,61 +521,61 @@ class Renamer(Plugin): if not statuses: log.debug('Download status functionality is not implemented for active downloaders.') scan_required = True + else: + try: + for rel in rels: + rel_dict = rel.to_dict({'info': {}}) - try: - for rel in rels: - rel_dict = rel.to_dict({'info': {}}) + # Get current selected title + default_title = getTitle(rel.movie.library) - # Get current selected title - default_title = getTitle(rel.movie.library) + # Check if movie has already completed and is manage tab (legacy db correction) + if rel.movie.status_id == done_status.get('id'): + log.debug('Found a completed movie with a snatched release : %s. Setting release status to ignored...' , default_title) + rel.status_id = ignored_status.get('id') + db.commit() + continue - # Check if movie has already completed and is manage tab (legacy db correction) - if rel.movie.status_id == done_status.get('id'): - log.debug('Found a completed movie with a snatched release : %s. Setting release status to ignored...' , default_title) - rel.status_id = ignored_status.get('id') - db.commit() - continue + movie_dict = fireEvent('movie.get', rel.movie_id, single = True) - movie_dict = fireEvent('movie.get', rel.movie_id, single = True) + # check status + nzbname = self.createNzbName(rel_dict['info'], movie_dict) - # check status - nzbname = self.createNzbName(rel_dict['info'], movie_dict) + found = False + for item in statuses: + if item['name'] == nzbname: - found = False - for item in statuses: - if item['name'] == nzbname: + timeleft = 'N/A' if item['timeleft'] == -1 else item['timeleft'] + log.debug('Found %s: %s, time to go: %s', (item['name'], item['status'].upper(), timeleft)) - timeleft = 'N/A' if item['timeleft'] == -1 else item['timeleft'] - log.debug('Found %s: %s, time to go: %s', (item['name'], item['status'].upper(), timeleft)) + if item['status'] == 'busy': + pass + elif item['status'] == 'failed': + if item['delete']: + fireEvent('download.remove_failed', item, single = True) - if item['status'] == 'busy': - pass - elif item['status'] == 'failed': - if item['delete']: - fireEvent('download.remove_failed', item, single = True) + if self.conf('next_on_failed'): + fireEvent('searcher.try_next_release', movie_id = rel.movie_id) + else: + rel.status_id = failed_status.get('id') + db.commit() + elif item['status'] == 'completed': + log.info('Download of %s completed!', item['name']) + scan_required = True - if self.conf('next_on_failed'): - fireEvent('searcher.try_next_release', movie_id = rel.movie_id) - else: - rel.status_id = failed_status.get('id') - db.commit() - elif item['status'] == 'completed': - log.info('Download of %s completed!', item['name']) - scan_required = True + found = True + break - found = True - break + if not found: + log.info('%s not found in downloaders', nzbname) + rel.status_id = ignored_status.get('id') + db.commit() - if not found: - log.info('%s not found in downloaders', nzbname) - rel.status_id = ignored_status.get('id') - db.commit() + if self.conf('next_on_failed'): + fireEvent('searcher.try_next_release', movie_id = rel.movie_id) - if self.conf('next_on_failed'): - fireEvent('searcher.try_next_release', movie_id = rel.movie_id) - - except: - log.error('Failed checking for release in downloader: %s', traceback.format_exc()) + except: + log.error('Failed checking for release in downloader: %s', traceback.format_exc()) if scan_required: fireEvent('renamer.scan') From d38bd03422cabbf6518eaa5833c8ce2187e9bcad Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 30 Sep 2012 17:15:47 +0200 Subject: [PATCH 44/92] Use finish by default when adding new type --- couchpotato/core/plugins/profile/static/profile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/profile/static/profile.js b/couchpotato/core/plugins/profile/static/profile.js index 947da1d3..3bb44989 100644 --- a/couchpotato/core/plugins/profile/static/profile.js +++ b/couchpotato/core/plugins/profile/static/profile.js @@ -242,7 +242,7 @@ Profile.Type = new Class({ ), new Element('span.finish').adopt( self.finish = new Element('input.inlay.finish[type=checkbox]', { - 'checked': data.finish, + 'checked': data.finish !== undefined ? data.finish : 1, 'events': { 'change': function(e){ if(self.el == self.el.getParent().getElement(':first-child')){ From a3b3b9c2189336a77c2f523f6b1479c2ab1a4c47 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 30 Sep 2012 17:33:51 +0200 Subject: [PATCH 45/92] Don't use cached in_wanted when re-adding movie --- couchpotato/core/plugins/movie/static/search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/movie/static/search.js b/couchpotato/core/plugins/movie/static/search.js index 63cab349..2115ef4d 100644 --- a/couchpotato/core/plugins/movie/static/search.js +++ b/couchpotato/core/plugins/movie/static/search.js @@ -339,7 +339,7 @@ Block.Search.Item = new Class({ 'height': null, 'width': null }) : null, - self.info.in_wanted ? new Element('span.in_wanted', { + self.info.in_wanted && self.info.in_wanted.profile ? new Element('span.in_wanted', { 'text': 'Already in wanted list: ' + self.info.in_wanted.profile.label }) : (in_library ? new Element('span.in_library', { 'text': 'Already in library: ' + in_library.join(', ') From 50a2bca4593d88d3fef05cb41b328e408a92f551 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 30 Sep 2012 17:34:09 +0200 Subject: [PATCH 46/92] Don't open releases when all are ignored --- couchpotato/core/plugins/movie/static/movie.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/movie/static/movie.js b/couchpotato/core/plugins/movie/static/movie.js index bb081cd1..b406e4e3 100644 --- a/couchpotato/core/plugins/movie/static/movie.js +++ b/couchpotato/core/plugins/movie/static/movie.js @@ -383,7 +383,7 @@ var ReleaseAction = new Class({ var status = Status.get(release.status_id); - if((status.identifier == 'ignored' || status.identifier == 'failed') || (!self.next_release && status.identifier == 'available')){ + if((self.next_release && (status.identifier == 'ignored' || status.identifier == 'failed')) || (!self.next_release && status.identifier == 'available')){ self.hide_on_click = false; self.show(); buttons_done = true; From 7f90135947082c99507562e338cf9f463d10ba6a Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 2 Oct 2012 22:16:21 +0200 Subject: [PATCH 47/92] checksnatched debug code leftover. fix #892 --- couchpotato/core/plugins/renamer/main.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 87bcad6d..9e372363 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -551,8 +551,7 @@ class Renamer(Plugin): if item['status'] == 'busy': pass elif item['status'] == 'failed': - if item['delete']: - fireEvent('download.remove_failed', item, single = True) + fireEvent('download.remove_failed', item, single = True) if self.conf('next_on_failed'): fireEvent('searcher.try_next_release', movie_id = rel.movie_id) From 799b665f15d93072fea2f9860ec640fe0fc5a4e8 Mon Sep 17 00:00:00 2001 From: Tristan Fischer Date: Tue, 9 Oct 2012 00:18:31 +0300 Subject: [PATCH 48/92] fix audio scoring The elements of name_scores are compared to a lower-cased version of the release name so they need to be also lower cased. --- couchpotato/core/plugins/score/scores.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/score/scores.py b/couchpotato/core/plugins/score/scores.py index 385e3a95..8afa129c 100644 --- a/couchpotato/core/plugins/score/scores.py +++ b/couchpotato/core/plugins/score/scores.py @@ -10,7 +10,7 @@ name_scores = [ # Video 'x264:1', 'h264:1', # Audio - 'DTS:4', 'AC3:2', + 'dts:4', 'ac3:2', # Quality '720p:10', '1080p:10', 'bluray:10', 'dvd:1', 'dvdrip:1', 'brrip:1', 'bdrip:1', 'bd50:1', 'bd25:1', # Language / Subs From 8874bd4e2b901a34d7fddd40effdf7086024df4e Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 12 Oct 2012 13:15:40 +0200 Subject: [PATCH 49/92] Wrongly assuming quality when no quality in the name. fix #901 --- couchpotato/core/plugins/searcher/main.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 03dfd70b..80f24708 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -391,9 +391,11 @@ class Searcher(Plugin): year_name = fireEvent('scanner.name_year', name, single = True) if movie_year < datetime.datetime.now().year - 3 and not year_name.get('year', None): if size > 3000: # Assume dvdr - return 'dvdr' == preferred_quality['identifier'] + log.info('Quality was missing in name, assuming it\'s a DVD-R based on the size: %s', (size)) + found['dvdr'] = True else: # Assume dvdrip - return 'dvdrip' == preferred_quality['identifier'] + log.info('Quality was missing in name, assuming it\'s a DVD-Rip based on the size: %s', (size)) + found['dvdrip'] = True # Allow other qualities for allowed in preferred_quality.get('allow'): From 27635caa1db6a8e977cf07befb310cfaed466cc2 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 12 Oct 2012 18:50:57 +0200 Subject: [PATCH 50/92] Simpler options for events --- couchpotato/core/event.py | 62 +++++++++++++-------------------------- 1 file changed, 21 insertions(+), 41 deletions(-) diff --git a/couchpotato/core/event.py b/couchpotato/core/event.py index 8319150a..4842aadb 100644 --- a/couchpotato/core/event.py +++ b/couchpotato/core/event.py @@ -46,49 +46,29 @@ def fireEvent(name, *args, **kwargs): #log.debug('Firing event %s', name) try: - # Fire after event - is_after_event = False - try: - del kwargs['is_after_event'] - is_after_event = True - except: pass + options = { + 'is_after_event': False, # Fire after event + 'on_complete': False, # onComplete event + 'single': False, # Return single handler + 'merge': False, # Merge items + 'in_order': False, # Fire them in specific order, waits for the other to finish + } - # onComplete event - on_complete = False - try: - on_complete = kwargs['on_complete'] - del kwargs['on_complete'] - except: pass - - # Return single handler - single = False - try: - del kwargs['single'] - single = True - except: pass - - # Merge items - merge = False - try: - del kwargs['merge'] - merge = True - except: pass - - # Merge items - in_order = False - try: - del kwargs['in_order'] - in_order = True - except: pass + # Do options + for x in options: + try: + del kwargs[x] + options[x] = True + except: pass e = events[name] - if not in_order: e.lock.acquire() + if not options['in_order']: e.lock.acquire() e.asynchronous = False - e.in_order = in_order + e.in_order = options['in_order'] result = e(*args, **kwargs) - if not in_order: e.lock.release() + if not options['in_order']: e.lock.release() - if single and not merge: + if options['single'] and not options['merge']: results = None # Loop over results, stop when first not None result is found. @@ -112,7 +92,7 @@ def fireEvent(name, *args, **kwargs): errorHandler(r[1]) # Merge - if merge and len(results) > 0: + if options['merge'] and len(results) > 0: # Dict if type(results[0]) == dict: merged = {} @@ -133,11 +113,11 @@ def fireEvent(name, *args, **kwargs): log.debug('Return modified results for %s', name) results = modified_results - if not is_after_event: + if not options['is_after_event']: fireEvent('%s.after' % name, is_after_event = True) - if on_complete: - on_complete() + if options['on_complete']: + options['on_complete']() return results except KeyError, e: From f3e3632dd3327ac96e5837a99bbb83d150f5e904 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 12 Oct 2012 18:52:44 +0200 Subject: [PATCH 51/92] Use less db.commits when adding quality and profiles. --- couchpotato/core/plugins/profile/main.py | 4 +-- couchpotato/core/plugins/quality/main.py | 41 +++++++++++++----------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/couchpotato/core/plugins/profile/main.py b/couchpotato/core/plugins/profile/main.py index 76fb37c5..64ee231f 100644 --- a/couchpotato/core/plugins/profile/main.py +++ b/couchpotato/core/plugins/profile/main.py @@ -181,10 +181,10 @@ class ProfilePlugin(Plugin): ) p.types.append(profile_type) - db.commit() quality_order += 1 order += 1 - #db.close() + db.commit() + return True diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index 84ac80a8..eaeb6002 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -9,6 +9,7 @@ from couchpotato.core.plugins.base import Plugin from couchpotato.core.settings.model import Quality, Profile, ProfileType import os.path import re +import time log = CPLog(__name__) @@ -113,46 +114,48 @@ class QualityPlugin(Plugin): for q in self.qualities: # Create quality - quality = db.query(Quality).filter_by(identifier = q.get('identifier')).first() + qual = db.query(Quality).filter_by(identifier = q.get('identifier')).first() - if not quality: + if not qual: log.info('Creating quality: %s', q.get('label')) - quality = Quality() - db.add(quality) + qual = Quality() + qual.order = order + qual.identifier = q.get('identifier') + qual.label = toUnicode(q.get('label')) + qual.size_min, qual.size_max = q.get('size') - quality.order = order - quality.identifier = q.get('identifier') - quality.label = toUnicode(q.get('label')) - quality.size_min, quality.size_max = q.get('size') + db.add(qual) # Create single quality profile - profile = db.query(Profile).filter( + prof = db.query(Profile).filter( Profile.core == True ).filter( - Profile.types.any(quality = quality) + Profile.types.any(quality = qual) ).all() - if not profile: + if not prof: log.info('Creating profile: %s', q.get('label')) - profile = Profile( + prof = Profile( core = True, - label = toUnicode(quality.label), + label = toUnicode(qual.label), order = order ) - db.add(profile) + db.add(prof) profile_type = ProfileType( - quality = quality, - profile = profile, + quality = qual, + profile = prof, finish = True, order = 0 ) - profile.types.append(profile_type) + prof.types.append(profile_type) order += 1 - db.commit() - #db.close() + db.commit() + + time.sleep(0.3) # Wait a moment + return True def guess(self, files, extra = {}): From 378d1ccd1cbddde693daf2e578892edeeaf9755e Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 12 Oct 2012 19:03:44 +0200 Subject: [PATCH 52/92] Check if db exists before loading plugins --- couchpotato/runner.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/couchpotato/runner.py b/couchpotato/runner.py index 31a8ce32..569ff57e 100644 --- a/couchpotato/runner.py +++ b/couchpotato/runner.py @@ -170,18 +170,17 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En log.warning('%s %s %s line:%s', (category, message, filename, lineno)) warnings.showwarning = customwarn + # Check if database exists + db = Env.get('db_path') + db_exists = os.path.isfile(db_path) # Load configs & plugins loader = Env.get('loader') loader.preload(root = base_path) loader.run() - # Load migrations - initialize = True - db = Env.get('db_path') - if os.path.isfile(db_path): - initialize = False + if db_exists: from migrate.versioning.api import version_control, db_version, version, upgrade repo = os.path.join(base_path, 'couchpotato', 'core', 'migration') @@ -201,7 +200,8 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En from couchpotato.core.settings.model import setup setup() - if initialize: + # Fill database with needed stuff + if not db_exists: fireEvent('app.initialize', in_order = True) # Create app From 269e98b0491e00b53beaf7c0ac1d092323f2fe49 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 12 Oct 2012 19:09:57 +0200 Subject: [PATCH 53/92] Removed all commented out db.close --- couchpotato/core/notifications/core/main.py | 3 --- couchpotato/core/plugins/file/main.py | 2 -- couchpotato/core/plugins/library/main.py | 1 - couchpotato/core/plugins/profile/main.py | 6 ------ couchpotato/core/plugins/quality/main.py | 3 --- couchpotato/core/plugins/release/main.py | 6 ------ couchpotato/core/plugins/renamer/main.py | 1 - couchpotato/core/plugins/scanner/main.py | 1 - couchpotato/core/plugins/searcher/main.py | 3 --- couchpotato/core/plugins/subtitle/main.py | 2 -- couchpotato/core/providers/movie/_modifier/main.py | 1 - couchpotato/core/providers/movie/couchpotatoapi/main.py | 1 - couchpotato/core/settings/__init__.py | 2 -- 13 files changed, 32 deletions(-) diff --git a/couchpotato/core/notifications/core/main.py b/couchpotato/core/notifications/core/main.py index e0af50de..33f90d5a 100644 --- a/couchpotato/core/notifications/core/main.py +++ b/couchpotato/core/notifications/core/main.py @@ -79,7 +79,6 @@ class CoreNotifier(Notification): q.update({Notif.read: True}) db.commit() - #db.close() return jsonified({ 'success': True @@ -107,7 +106,6 @@ class CoreNotifier(Notification): ndict['type'] = 'notification' notifications.append(ndict) - #db.close() return jsonified({ 'success': True, 'empty': len(notifications) == 0, @@ -133,7 +131,6 @@ class CoreNotifier(Notification): self.frontend(type = listener, data = data) - #db.close() return True def frontend(self, type = 'notification', data = {}, message = None): diff --git a/couchpotato/core/plugins/file/main.py b/couchpotato/core/plugins/file/main.py index 40427e44..0658911f 100644 --- a/couchpotato/core/plugins/file/main.py +++ b/couchpotato/core/plugins/file/main.py @@ -109,7 +109,6 @@ class FileManager(Plugin): db.commit() type_dict = ft.to_dict() - #db.close() return type_dict def getTypes(self): @@ -122,5 +121,4 @@ class FileManager(Plugin): for type_object in results: types.append(type_object.to_dict()) - #db.close() return types diff --git a/couchpotato/core/plugins/library/main.py b/couchpotato/core/plugins/library/main.py index 95dda2ff..aa1611dd 100644 --- a/couchpotato/core/plugins/library/main.py +++ b/couchpotato/core/plugins/library/main.py @@ -53,7 +53,6 @@ class LibraryPlugin(Plugin): library_dict = l.to_dict(self.default_dict) - #db.close() return library_dict def update(self, identifier, default_title = '', force = False): diff --git a/couchpotato/core/plugins/profile/main.py b/couchpotato/core/plugins/profile/main.py index 64ee231f..4caa54f7 100644 --- a/couchpotato/core/plugins/profile/main.py +++ b/couchpotato/core/plugins/profile/main.py @@ -47,7 +47,6 @@ class ProfilePlugin(Plugin): for profile in profiles: temp.append(profile.to_dict(self.to_dict)) - #db.close() return temp def save(self): @@ -84,7 +83,6 @@ class ProfilePlugin(Plugin): profile_dict = p.to_dict(self.to_dict) - #db.close() return jsonified({ 'success': True, 'profile': profile_dict @@ -95,7 +93,6 @@ class ProfilePlugin(Plugin): db = get_session() default = db.query(Profile).first() default_dict = default.to_dict(self.to_dict) - #db.close() return default_dict @@ -113,7 +110,6 @@ class ProfilePlugin(Plugin): order += 1 db.commit() - #db.close() return jsonified({ 'success': True @@ -137,8 +133,6 @@ class ProfilePlugin(Plugin): except Exception, e: message = log.error('Failed deleting Profile: %s', e) - #db.close() - return jsonified({ 'success': success, 'message': message diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index eaeb6002..7964fb18 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -69,7 +69,6 @@ class QualityPlugin(Plugin): q = mergeDicts(self.getQuality(quality.identifier), quality.to_dict()) temp.append(q) - #db.close() return temp def single(self, identifier = ''): @@ -81,7 +80,6 @@ class QualityPlugin(Plugin): if quality: quality_dict = dict(self.getQuality(quality.identifier), **quality.to_dict()) - #db.close() return quality_dict def getQuality(self, identifier): @@ -101,7 +99,6 @@ class QualityPlugin(Plugin): setattr(quality, params.get('value_type'), params.get('value')) db.commit() - #db.close() return jsonified({ 'success': True }) diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index 9e945a87..8f408543 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -88,8 +88,6 @@ class Release(Plugin): fireEvent('movie.restatus', movie.id) - #db.close() - return True @@ -108,7 +106,6 @@ class Release(Plugin): release_id = getParam('id') - #db.close() return jsonified({ 'success': self.delete(release_id) }) @@ -152,7 +149,6 @@ class Release(Plugin): rel.status_id = available_status.get('id') if rel.status_id is ignored_status.get('id') else ignored_status.get('id') db.commit() - #db.close() return jsonified({ 'success': True }) @@ -186,14 +182,12 @@ class Release(Plugin): rel.status_id = status_snatched.get('id') db.commit() - #db.close() return jsonified({ 'success': success }) else: log.error('Couldn\'t find release with id: %s', id) - #db.close() return jsonified({ 'success': False }) diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 9e372363..993575ca 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -388,7 +388,6 @@ class Renamer(Plugin): if self.shuttingDown(): break - #db.close() self.renaming_started = False def getRenameExtras(self, extra_type = '', replacements = {}, folder_name = '', file_name = '', destination = '', group = {}, current_file = ''): diff --git a/couchpotato/core/plugins/scanner/main.py b/couchpotato/core/plugins/scanner/main.py index b22b6265..4c639e2d 100644 --- a/couchpotato/core/plugins/scanner/main.py +++ b/couchpotato/core/plugins/scanner/main.py @@ -542,7 +542,6 @@ class Scanner(Plugin): break except: pass - #db.close() # Search based on OpenSubtitleHash if not imdb_id and not group['is_dvd']: diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 80f24708..66a2e87e 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -110,7 +110,6 @@ class Searcher(Plugin): if self.shuttingDown(): break - #db.close() self.in_progress = False def single(self, movie): @@ -229,7 +228,6 @@ class Searcher(Plugin): fireEvent('notify.frontend', type = 'searcher.ended.%s' % movie['id'], data = True) - #db.close() return ret def download(self, data, movie, manual = False): @@ -280,7 +278,6 @@ class Searcher(Plugin): except Exception, e: log.error('Failed marking movie finished: %s %s', (e, traceback.format_exc())) - #db.close() return True log.info('Tried to download, but none of the downloaders are enabled') diff --git a/couchpotato/core/plugins/subtitle/main.py b/couchpotato/core/plugins/subtitle/main.py index 9ff39f47..3a66a8bc 100644 --- a/couchpotato/core/plugins/subtitle/main.py +++ b/couchpotato/core/plugins/subtitle/main.py @@ -40,8 +40,6 @@ class Subtitle(Plugin): # get subtitles for those files subliminal.list_subtitles(files, cache_dir = Env.get('cache_dir'), multi = True, languages = self.getLanguages(), services = self.services) - #db.close() - def searchSingle(self, group): if self.isDisabled(): return diff --git a/couchpotato/core/providers/movie/_modifier/main.py b/couchpotato/core/providers/movie/_modifier/main.py index 5af1659e..7346480e 100644 --- a/couchpotato/core/providers/movie/_modifier/main.py +++ b/couchpotato/core/providers/movie/_modifier/main.py @@ -70,7 +70,6 @@ class MovieResultModifier(Plugin): except: log.error('Tried getting more info on searched movies: %s', traceback.format_exc()) - #db.close() return temp def checkLibrary(self, result): diff --git a/couchpotato/core/providers/movie/couchpotatoapi/main.py b/couchpotato/core/providers/movie/couchpotatoapi/main.py index 8e890484..5d6a35ba 100644 --- a/couchpotato/core/providers/movie/couchpotatoapi/main.py +++ b/couchpotato/core/providers/movie/couchpotatoapi/main.py @@ -94,7 +94,6 @@ class CouchPotatoApi(MovieProvider): db = get_session() active_movies = db.query(Movie).filter(Movie.status.has(identifier = 'active')).all() movies = [x.library.identifier for x in active_movies] - #db.close() suggestions = self.suggest(movies, ignore) diff --git a/couchpotato/core/settings/__init__.py b/couchpotato/core/settings/__init__.py index c530a275..366a101c 100644 --- a/couchpotato/core/settings/__init__.py +++ b/couchpotato/core/settings/__init__.py @@ -204,7 +204,6 @@ class Settings(object): except: pass - #db.close() return prop def setProperty(self, identifier, value = ''): @@ -221,4 +220,3 @@ class Settings(object): p.value = toUnicode(value) db.commit() - #db.close() From ef6d0e04c0b977d18d8a60b7dc60d067b42af35d Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 12 Oct 2012 21:04:49 +0200 Subject: [PATCH 54/92] Use event value --- couchpotato/core/event.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/event.py b/couchpotato/core/event.py index 4842aadb..3a5b9009 100644 --- a/couchpotato/core/event.py +++ b/couchpotato/core/event.py @@ -57,8 +57,9 @@ def fireEvent(name, *args, **kwargs): # Do options for x in options: try: + val = kwargs[x] del kwargs[x] - options[x] = True + options[x] = val except: pass e = events[name] From fef3eb1b84403dfb9662078c567e3b43c59ccc18 Mon Sep 17 00:00:00 2001 From: clinton-hall Date: Fri, 12 Oct 2012 13:29:41 -0700 Subject: [PATCH 55/92] Added replacement of uid and key for nzbsrus Prevent people posting log files with their account information --- couchpotato/core/logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/logger.py b/couchpotato/core/logger.py index 8d8c9f59..7a357b36 100644 --- a/couchpotato/core/logger.py +++ b/couchpotato/core/logger.py @@ -5,7 +5,7 @@ import traceback class CPLog(object): context = '' - replace_private = ['api', 'apikey', 'api_key', 'password', 'username', 'h'] + replace_private = ['api', 'apikey', 'api_key', 'password', 'username', 'h', 'uid', 'key'] def __init__(self, context = ''): if context.endswith('.main'): From 84f5dcc134115162b4ccdb5c9e28c53863de7f45 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 12 Oct 2012 23:34:13 +0200 Subject: [PATCH 56/92] Wizard fix --- .../core/plugins/wizard/static/wizard.css | 6 +- .../core/plugins/wizard/static/wizard.js | 92 +++++++++---------- couchpotato/static/scripts/couchpotato.js | 41 +++++++++ 3 files changed, 89 insertions(+), 50 deletions(-) diff --git a/couchpotato/core/plugins/wizard/static/wizard.css b/couchpotato/core/plugins/wizard/static/wizard.css index dd73a654..a24f2b9e 100644 --- a/couchpotato/core/plugins/wizard/static/wizard.css +++ b/couchpotato/core/plugins/wizard/static/wizard.css @@ -76,4 +76,8 @@ margin: 10px 30px 80px; display: block; text-align: center; - } \ No newline at end of file + } + +.page.wizard .tab_nzb_providers { + margin: 20px 0 0 0; +} diff --git a/couchpotato/core/plugins/wizard/static/wizard.js b/couchpotato/core/plugins/wizard/static/wizard.js index a3fe938c..5d087add 100644 --- a/couchpotato/core/plugins/wizard/static/wizard.js +++ b/couchpotato/core/plugins/wizard/static/wizard.js @@ -41,7 +41,8 @@ Page.Wizard = new Class({ }, 'providers': { 'title': 'Are you registered at any of these sites?', - 'description': 'CP uses these sites to search for movies. A few free are enabled by default, but it\'s always better to have a few more. Check settings for the full list of available providers.' + 'description': 'CP uses these sites to search for movies. A few free are enabled by default, but it\'s always better to have a few more. Check settings for the full list of available providers.', + 'include': ['nzb_providers', 'torrent_providers'] }, 'renamer': { 'title': 'Move & rename the movies after downloading?', @@ -49,59 +50,18 @@ Page.Wizard = new Class({ }, 'automation': { 'title': 'Easily add movies to your wanted list!', - 'description': 'You can easily add movies from your favorite movie site, like IMDB, Rotten Tomatoes, Apple Trailers and more. Just install the userscript or drag the bookmarklet to your browsers bookmarks.' + + 'description': 'You can easily add movies from your favorite movie site, like IMDB, Rotten Tomatoes, Apple Trailers and more. Just install the userscript or drag the bookmarklet to your browsers bookmarks.' + '
Once installed, just click the bookmarklet on a movie page and watch the magic happen ;)', 'content': function(){ - - // See if userscript can be installed - var userscript = false; - try { - if(Components.interfaces.gmIGreasemonkeyService) - userscript = true - } - catch(e){ - userscript = Browser.chrome === true; - } - - var host_url = window.location.protocol + '//' + window.location.host; - - var el = new Element('div.group_userscript').adopt( - - (userscript ? [new Element('a.userscript.button', { - 'text': 'Install userscript', - 'href': Api.createUrl('userscript.get')+randomString()+'/couchpotato.user.js', - 'target': '_self' - }), new Element('span.or[text=or]')] : null), - new Element('span.bookmarklet').adopt( - new Element('a.button.orange', { - 'text': '+CouchPotato', - 'href': "javascript:void((function(){var e=document.createElement('script');e.setAttribute('type','text/javascript');e.setAttribute('charset','UTF-8');e.setAttribute('src','" + - host_url + Api.createUrl('userscript.bookmark') + - "?host="+ encodeURI(host_url + Api.createUrl('userscript.get')+randomString()+'/') + - "&r='+Math.random()*99999999);document.body.appendChild(e)})());", - 'target': '', - 'events': { - 'click': function(e){ - (e).stop() - alert('Drag it to your bookmark ;)') - } - } - }), - new Element('span', { - 'text': '⇽ Drag this to your bookmarks' - }) - ) - ).setStyles({ + return App.createUserscriptButtons().setStyles({ 'background-image': "url('"+Api.createUrl('static/userscript/userscript.png')+"')" - }); - - return el + }) } }, 'finish': { 'title': 'Finishing Up', 'description': 'Are you done? Did you fill in everything as much as possible?' + - '
Be sure to check the settings to see what more CP can do!

' + + '
Be sure to check the settings to see what more CP can do!

' + '
After you\'ve used CP for a while, and you like it (which of course you will), consider supporting CP. Maybe even by writing some code.
Or by getting a subscription at Usenet Server or Newshosting.
', 'content': new Element('div').adopt( new Element('a.button.green', { @@ -167,6 +127,7 @@ Page.Wizard = new Class({ var tabs = self.el.getElement('.tabs'); self.groups.each(function(group, nr){ + if(self.headers[group]){ group_container = new Element('.wgroup_'+group, { 'styles': { @@ -177,6 +138,12 @@ Page.Wizard = new Class({ } }); + if(self.headers[group].include){ + self.headers[group].include.each(function(inc){ + group_container.addClass('wgroup_'+inc); + }) + } + var content = self.headers[group].content group_container.adopt( new Element('h1', { @@ -190,10 +157,35 @@ Page.Wizard = new Class({ } var tab_navigation = tabs.getElement('.t_'+group); + + if(!tab_navigation && self.headers[group] && self.headers[group].include){ + tab_navigation = [] + self.headers[group].include.each(function(inc){ + tab_navigation.include(tabs.getElement('.t_'+inc)); + }) + } + if(tab_navigation && group_container){ - tab_navigation.inject(tabs); // Tab navigation - self.el.getElement('.tab_'+group).inject(group_container); // Tab content - if(self.headers[group]){ + tabs.adopt(tab_navigation); // Tab navigation + + if(self.headers[group] && self.headers[group].include){ + + self.headers[group].include.each(function(inc){ + self.el.getElement('.tab_'+inc).inject(group_container); + }) + + new Element('li.t_'+group).adopt( + new Element('a', { + 'href': App.createUrl('wizard/'+group), + 'text': (self.headers[group].label || group).capitalize() + }) + ).inject(tabs); + + } + else + self.el.getElement('.tab_'+group).inject(group_container); // Tab content + + if(tab_navigation.getElement && self.headers[group]){ var a = tab_navigation.getElement('a'); a.set('text', (self.headers[group].label || group).capitalize()); var url_split = a.get('href').split('wizard')[1].split('/'); @@ -221,6 +213,8 @@ Page.Wizard = new Class({ // Hide retention self.el.getElement('.tab_searcher').hide(); self.el.getElement('.t_searcher').hide(); + self.el.getElement('.t_nzb_providers').hide(); + self.el.getElement('.t_torrent_providers').hide(); // Add pointer new Element('.tab_wrapper').wraps(tabs).adopt( diff --git a/couchpotato/static/scripts/couchpotato.js b/couchpotato/static/scripts/couchpotato.js index 61ee45bd..a94f5d4e 100644 --- a/couchpotato/static/scripts/couchpotato.js +++ b/couchpotato/static/scripts/couchpotato.js @@ -281,6 +281,47 @@ var CouchPotato = new Class({ window.open(url); else window.location = url; + }, + + createUserscriptButtons: function(){ + + var userscript = false; + try { + if(Components.interfaces.gmIGreasemonkeyService) + userscript = true + } + catch(e){ + userscript = Browser.chrome === true; + } + + var host_url = window.location.protocol + '//' + window.location.host; + + return new Element('div.group_userscript').adopt( + (userscript ? [new Element('a.userscript.button', { + 'text': 'Install userscript', + 'href': Api.createUrl('userscript.get')+randomString()+'/couchpotato.user.js', + 'target': '_self' + }), new Element('span.or[text=or]')] : null), + new Element('span.bookmarklet').adopt( + new Element('a.button.orange', { + 'text': '+CouchPotato', + 'href': "javascript:void((function(){var e=document.createElement('script');e.setAttribute('type','text/javascript');e.setAttribute('charset','UTF-8');e.setAttribute('src','" + + host_url + Api.createUrl('userscript.bookmark') + + "?host="+ encodeURI(host_url + Api.createUrl('userscript.get')+randomString()+'/') + + "&r='+Math.random()*99999999);document.body.appendChild(e)})());", + 'target': '', + 'events': { + 'click': function(e){ + (e).stop() + alert('Drag it to your bookmark ;)') + } + } + }), + new Element('span', { + 'text': '⇽ Drag this to your bookmarks' + }) + ) + ); } }); From 1011e2e9b82ff8e2838174a21496977c8586802a Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 12 Oct 2012 23:34:39 +0200 Subject: [PATCH 57/92] Show "how to" when wanted list is empty --- couchpotato/core/plugins/movie/main.py | 6 +++ couchpotato/core/plugins/movie/static/list.js | 37 ++++++++++++++++++ .../core/plugins/movie/static/movie.js | 7 +++- couchpotato/static/images/emptylist.png | Bin 0 -> 146717 bytes couchpotato/static/scripts/page/wanted.js | 12 +++++- 5 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 couchpotato/static/images/emptylist.png diff --git a/couchpotato/core/plugins/movie/main.py b/couchpotato/core/plugins/movie/main.py index a1016066..d86b97c9 100644 --- a/couchpotato/core/plugins/movie/main.py +++ b/couchpotato/core/plugins/movie/main.py @@ -431,9 +431,11 @@ class MoviePlugin(Plugin): movie = db.query(Movie).filter_by(id = movie_id).first() if movie: + deleted = False if delete_from == 'all': db.delete(movie) db.commit() + deleted = True else: done_status = fireEvent('status.get', 'done', single = True) @@ -456,6 +458,7 @@ class MoviePlugin(Plugin): if total_releases == total_deleted: db.delete(movie) db.commit() + deleted = True elif new_movie_status: new_status = fireEvent('status.get', new_movie_status, single = True) movie.profile_id = None @@ -464,6 +467,9 @@ class MoviePlugin(Plugin): else: fireEvent('movie.restatus', movie.id, single = True) + if deleted: + fireEvent('notify.frontend', type = 'movie.deleted', data = movie.to_dict()) + #db.close() return True diff --git a/couchpotato/core/plugins/movie/static/list.js b/couchpotato/core/plugins/movie/static/list.js index 0aff0bde..51b0f4c5 100644 --- a/couchpotato/core/plugins/movie/static/list.js +++ b/couchpotato/core/plugins/movie/static/list.js @@ -35,6 +35,17 @@ var MovieList = new Class({ if(options.add_new) App.addEvent('movie.added', self.movieAdded.bind(self)) + + App.addEvent('movie.deleted', self.movieDeleted.bind(self)) + }, + + movieDeleted: function(notification){ + var self = this; + + if(!self.movies_added[notification.data.id]) + self.movies_added[notification.data.id].destroy(); + + self.checkIfEmpty(); }, movieAdded: function(notification){ @@ -43,6 +54,8 @@ var MovieList = new Class({ if(!self.movies_added[notification.data.id]) self.createMovie(notification.data, 'top'); + + self.checkIfEmpty(); }, create: function(){ @@ -460,6 +473,8 @@ var MovieList = new Class({ self.addMovies(json.movies, json.total); self.load_more.set('text', 'load more movies'); if(self.scrollspy) self.scrollspy.start(); + + self.checkIfEmpty() } }); }, @@ -477,6 +492,28 @@ var MovieList = new Class({ }, + checkIfEmpty: function(){ + var self = this; + + var is_empty = self.movies.length == 0; + + if(is_empty && self.options.on_empty_element){ + self.el.grab(self.options.on_empty_element); + + if(self.navigation) + self.navigation.hide(); + + self.empty_element = self.options.on_empty_element; + } + else if(self.empty_element){ + self.empty_element.destroy(); + + if(self.navigation) + self.navigation.show(); + } + + }, + toElement: function(){ return this.el; } diff --git a/couchpotato/core/plugins/movie/static/movie.js b/couchpotato/core/plugins/movie/static/movie.js index b406e4e3..b10b5b1b 100644 --- a/couchpotato/core/plugins/movie/static/movie.js +++ b/couchpotato/core/plugins/movie/static/movie.js @@ -42,6 +42,9 @@ var Movie = new Class({ self.el.destroy(); delete self.list.movies_added[self.get('id')]; + self.list.movies.erase(self) + + self.list.checkIfEmpty(); // Remove events App.removeEvents('movie.update.'+self.data.id); @@ -467,11 +470,11 @@ var ReleaseAction = new Class({ self.next_release = release; } }); - + if(self.last_release){ self.release_container.getElement('#release_'+self.last_release.id).addClass('last_release'); } - + if(self.next_release){ self.release_container.getElement('#release_'+self.next_release.id).addClass('next_release'); } diff --git a/couchpotato/static/images/emptylist.png b/couchpotato/static/images/emptylist.png new file mode 100644 index 0000000000000000000000000000000000000000..08db6537361c9c3db791bd153dd7c2339162f697 GIT binary patch literal 146717 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π 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%0ADi9& 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 Date: Sat, 13 Oct 2012 10:52:35 +0200 Subject: [PATCH 58/92] CSS gradient "fix" --- .../static/scripts/library/prefix_free.js | 25 +++++++++++++------ couchpotato/static/style/main.css | 10 ++++---- couchpotato/static/style/page/settings.css | 8 +++--- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/couchpotato/static/scripts/library/prefix_free.js b/couchpotato/static/scripts/library/prefix_free.js index a918d048..8dd99e2e 100644 --- a/couchpotato/static/scripts/library/prefix_free.js +++ b/couchpotato/static/scripts/library/prefix_free.js @@ -1,5 +1,5 @@ /** - * StyleFix 1.0.3 + * StyleFix 1.0.3 & PrefixFree 1.0.7 * @author Lea Verou * MIT license */ @@ -122,9 +122,9 @@ var self = window.StyleFix = { .splice(index === undefined? self.fixers.length : index, 0, fixer); }, - fix: function(css, raw) { + fix: function(css, raw, element) { for(var i=0; i -1) { + // Gradients are supported with a prefix, convert angles to legacy + css = css.replace(/(\s|:|,)(repeating-)?linear-gradient\(\s*(-?\d*\.?\d*)deg/ig, function ($0, delim, repeating, deg) { + return delim + (repeating || '') + 'linear-gradient(' + (90-deg) + 'deg'; + }); + } + css = fix('functions', '(\\s|:|,)', '\\s*\\(', '$1' + prefix + '$2(', css); css = fix('keywords', '(\\s|:)', '(\\s|;|\\}|$)', '$1' + prefix + '$2$3', css); css = fix('properties', '(^|\\{|\\s|;)', '\\s*:', '$1' + prefix + '$2:', css); @@ -205,6 +211,9 @@ var self = window.PrefixFree = { // Fix double prefixing css = css.replace(RegExp('-' + prefix, 'g'), '-'); + // Prefix wildcard + css = css.replace(/-\*-(?=[a-z]+)/gi, self.prefix); + return css; }, diff --git a/couchpotato/static/style/main.css b/couchpotato/static/style/main.css index e187593e..97ca1837 100644 --- a/couchpotato/static/style/main.css +++ b/couchpotato/static/style/main.css @@ -271,7 +271,7 @@ body > .spinner, .mask{ box-shadow: inset 0 1px 0 rgba(255,255,255,.6), 0 0 3px rgba(0,0,0,.7); background-color: #1b79b8; text-shadow: none; - background-image: linear-gradient(0deg, rgba(255,255,255,.3) 0%, rgba(255,255,255,.1) 100%); + background-image: -*-linear-gradient(0deg, rgba(255,255,255,.3) 0%, rgba(255,255,255,.1) 100%); } .header .notification_menu .wrapper { @@ -355,7 +355,7 @@ body > .spinner, .mask{ border-radius:30px; box-shadow: 0 1px 1px rgba(0,0,0,0.35), inset 0 1px 0px rgba(255,255,255,0.20); - background: url('../images/sprite.png') no-repeat 94% -53px, linear-gradient( + background: url('../images/sprite.png') no-repeat 94% -53px, -*-linear-gradient( 270deg, #5b9bd1 0%, #406db8 100% @@ -431,7 +431,7 @@ body > .spinner, .mask{ border: 1px solid #252930; box-shadow: inset 0 1px 0px rgba(255,255,255,0.20), 0 0 3px rgba(0,0,0, 0.2); background: rgb(55,62,74); - background-image: linear-gradient( + background-image: -*-linear-gradient( 90deg, rgb(55,62,74) 0%, rgb(73,83,98) 100% @@ -520,7 +520,7 @@ body > .spinner, .mask{ text-align: center; color: #000; text-shadow: none; - background-image: linear-gradient( + background-image: -*-linear-gradient( 45deg, rgb(200,200,200) 0%, rgb(255,255,255) 100% @@ -592,7 +592,7 @@ body > .spinner, .mask{ overflow: hidden; transition: all .6s cubic-bezier(0.9,0,0.1,1); box-shadow: 0 1px 1px rgba(0,0,0,0.35), inset 0 1px 0px rgba(255,255,255,0.20); - background-image: linear-gradient( + background-image: -*-linear-gradient( 270deg, #5b9bd1 0%, #406db8 100% diff --git a/couchpotato/static/style/page/settings.css b/couchpotato/static/style/page/settings.css index f17e6183..571e5a68 100644 --- a/couchpotato/static/style/page/settings.css +++ b/couchpotato/static/style/page/settings.css @@ -16,7 +16,7 @@ padding: 40px 0; margin: 0; min-height: 470px; - background-image: linear-gradient( + background-image: -*-linear-gradient( 20deg, rgba(0,0,0,0) 50%, rgba(0,0,0,0.3) 100% @@ -365,7 +365,7 @@ border-radius: 2px; } .page .tag_input > ul:hover > li.choice { - background: linear-gradient( + background: -*-linear-gradient( 270deg, rgba(255,255,255,0.3) 0%, rgba(255,255,255,0.1) 100% @@ -373,7 +373,7 @@ } .page .tag_input > ul > li.choice:hover, .page .tag_input > ul > li.choice.selected { - background: linear-gradient( + background: -*-linear-gradient( 270deg, #5b9bd1 0%, #406db8 100% @@ -412,7 +412,7 @@ margin: -9px 0 0 -16px; border-radius: 30px 30px 0 0; cursor: pointer; - background: url('../../images/icon.delete.png') no-repeat center 2px, linear-gradient( + background: url('../../images/icon.delete.png') no-repeat center 2px, -*-linear-gradient( 270deg, #5b9bd1 0%, #5b9bd1 100% From 19ddd032045762b677176167aad90b7d22070ded Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 13 Oct 2012 11:23:13 +0200 Subject: [PATCH 59/92] Improved movie year matching --- couchpotato/core/plugins/searcher/main.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 66a2e87e..f0bccc71 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -409,12 +409,17 @@ class Searcher(Plugin): return False - def correctYear(self, haystack, year, range): + def correctYear(self, haystack, year, year_range): for string in haystack: - if str(year) in string or str(int(year) + range) in string or str(int(year) - range) in string: # 1 year of is fine too + + year_name = fireEvent('scanner.name_year', string, single = True) + + if year_name and ((year - year_range) <= year_name.get('year') <= (year + year_range)): + log.debug('Movie year matches range: %s looking for %s', (year_name.get('year'), year)) return True + log.debug('Movie year doesn\'t matche range: %s looking for %s', (year_name.get('year'), year)) return False def correctName(self, check_name, movie_name): From 2cd887b70a2dc4617738c767d6d3d5915ab2d83f Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 13 Oct 2012 12:00:47 +0200 Subject: [PATCH 60/92] Empty list styling --- .../core/plugins/movie/static/movie.css | 36 +++++++++++++------ couchpotato/static/scripts/page/manage.js | 15 +++++++- couchpotato/static/scripts/page/wanted.js | 11 +----- couchpotato/static/style/page/wanted.css | 0 couchpotato/templates/_desktop.html | 1 - 5 files changed, 40 insertions(+), 23 deletions(-) delete mode 100644 couchpotato/static/style/page/wanted.css diff --git a/couchpotato/core/plugins/movie/static/movie.css b/couchpotato/core/plugins/movie/static/movie.css index 0979ccf0..bd831771 100644 --- a/couchpotato/core/plugins/movie/static/movie.css +++ b/couchpotato/core/plugins/movie/static/movie.css @@ -24,7 +24,7 @@ .movies .movie.list_view:hover, .movies .movie.mass_edit_view:hover { background: rgba(255,255,255,0.03); } - + .movies .movie_container { overflow: hidden; } @@ -313,7 +313,7 @@ padding-bottom: 4px; height: auto; } - + .movies .movie .trailer_container { width: 100%; background: #000; @@ -324,7 +324,7 @@ .movies .movie .trailer_container.hide { height: 0 !important; } - + .movies .movie .hide_trailer { position: absolute; top: 0; @@ -340,12 +340,12 @@ .movies .movie .hide_trailer.hide { top: -30px; } - + .movies .movie .try_container { padding: 5px 10px; text-align: center; } - + .movies .movie .try_container a { margin: 0 5px; padding: 2px 5px; @@ -354,15 +354,15 @@ .movies .movie .releases .next_release { border-left: 6px solid #2aa300; } - + .movies .movie .releases .next_release > :first-child { margin-left: -6px; } - + .movies .movie .releases .last_release { border-left: 6px solid #ffa200; } - + .movies .movie .releases .last_release > :first-child { margin-left: -6px; } @@ -394,8 +394,8 @@ border-radius: 0; } -.movies .alph_nav ul.numbers, -.movies .alph_nav .counter, +.movies .alph_nav ul.numbers, +.movies .alph_nav .counter, .movies .alph_nav ul.actions { list-style: none; padding: 0 0 1px; @@ -518,7 +518,7 @@ padding: 3px 7px; } - .movies .alph_nav .mass_edit_form .refresh, + .movies .alph_nav .mass_edit_form .refresh, .movies .alph_nav .mass_edit_form .delete { float: left; padding: 8px 0 0 8px; @@ -536,3 +536,17 @@ .movies .alph_nav .more_menu > a { background-position: center -158px; } + +.movies .empty_wanted { + background-image: url('../images/emptylist.png'); + height: 750px; + width: 800px; + padding-top: 260px; + margin-top: -50px; +} + +.movies .empty_manage { + text-align: center; + font-size: 25px; + line-height: 150%; +} diff --git a/couchpotato/static/scripts/page/manage.js b/couchpotato/static/scripts/page/manage.js index aefbb42e..9ac0f34e 100644 --- a/couchpotato/static/scripts/page/manage.js +++ b/couchpotato/static/scripts/page/manage.js @@ -29,7 +29,20 @@ Page.Manage = new Class({ 'identifier': 'manage', 'status': 'done', 'actions': MovieActions, - 'menu': [self.refresh_button, self.refresh_quick] + 'menu': [self.refresh_button, self.refresh_quick], + 'on_empty_element': new Element('div.empty_manage').adopt( + new Element('div', { + 'text': 'Seems like you don\'t have anything in your library yet.' + }), + new Element('div', { + 'text': 'Add your existing movie folders in ' + }).adopt( + new Element('a', { + 'text': 'Settings > Manage', + 'href': App.createUrl('settings/manage') + }) + ) + ) }); $(self.list).inject(self.el); } diff --git a/couchpotato/static/scripts/page/wanted.js b/couchpotato/static/scripts/page/wanted.js index 599e7814..32887ea2 100644 --- a/couchpotato/static/scripts/page/wanted.js +++ b/couchpotato/static/scripts/page/wanted.js @@ -18,9 +18,6 @@ Page.Wanted = new Class({ } }); - // See if userscript can be installed - - // Wanted movies self.wanted = new MovieList({ 'identifier': 'wanted', @@ -28,13 +25,7 @@ Page.Wanted = new Class({ 'actions': MovieActions, 'add_new': true, 'menu': [self.manual_search], - 'on_empty_element': App.createUserscriptButtons().setStyles({ - 'background-image': "url('"+Api.createUrl('static/images/emptylist.png')+"')", - 'height': 750, - 'width': 800, - 'padding-top': 260, - 'margin-top': -50 - }) + 'on_empty_element': App.createUserscriptButtons().addClass('empty_wanted') }); $(self.wanted).inject(self.el); diff --git a/couchpotato/static/style/page/wanted.css b/couchpotato/static/style/page/wanted.css deleted file mode 100644 index e69de29b..00000000 diff --git a/couchpotato/templates/_desktop.html b/couchpotato/templates/_desktop.html index 80a095e3..77ace530 100644 --- a/couchpotato/templates/_desktop.html +++ b/couchpotato/templates/_desktop.html @@ -6,7 +6,6 @@ - From a5534c4bd242f8275214b6b953a87b667efc7bef Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 13 Oct 2012 21:16:05 +0200 Subject: [PATCH 61/92] Create file types on load --- couchpotato/core/plugins/file/main.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/couchpotato/core/plugins/file/main.py b/couchpotato/core/plugins/file/main.py index 0658911f..49256201 100644 --- a/couchpotato/core/plugins/file/main.py +++ b/couchpotato/core/plugins/file/main.py @@ -5,6 +5,7 @@ from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.variable import md5, getExt from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin +from couchpotato.core.plugins.scanner.main import Scanner from couchpotato.core.settings.model import FileType, File from couchpotato.environment import Env import os.path @@ -30,6 +31,12 @@ class FileManager(Plugin): }) addEvent('app.load', self.cleanup) + addEvent('app.load', self.init) + + def init(self): + + for type_tuple in Scanner.file_types.values(): + self.getType(type_tuple) def cleanup(self): From 981ba61458d0fa72de6491d164816690a76e5e75 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 13 Oct 2012 21:17:42 +0200 Subject: [PATCH 62/92] Progress bars for manage updates --- contribute.md | 1 + couchpotato/core/plugins/manage/main.py | 159 ++++++++++++++---- couchpotato/core/plugins/movie/main.py | 9 +- couchpotato/core/plugins/movie/static/list.js | 16 +- .../core/plugins/movie/static/movie.css | 48 ++++++ couchpotato/core/plugins/scanner/main.py | 56 +----- couchpotato/static/scripts/page/manage.js | 67 +++++++- couchpotato/static/scripts/page/wanted.js | 2 +- 8 files changed, 268 insertions(+), 90 deletions(-) create mode 100644 contribute.md diff --git a/contribute.md b/contribute.md new file mode 100644 index 00000000..fce79f7f --- /dev/null +++ b/contribute.md @@ -0,0 +1 @@ +So you feel like \ No newline at end of file diff --git a/couchpotato/core/plugins/manage/main.py b/couchpotato/core/plugins/manage/main.py index aa46d70a..a5d41fd1 100644 --- a/couchpotato/core/plugins/manage/main.py +++ b/couchpotato/core/plugins/manage/main.py @@ -2,22 +2,33 @@ from couchpotato.api import addApiView from couchpotato.core.event import fireEvent, addEvent, fireEventAsync from couchpotato.core.helpers.encoding import ss from couchpotato.core.helpers.request import jsonified, getParam +from couchpotato.core.helpers.variable import getTitle from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin from couchpotato.environment import Env import os import time +import traceback log = CPLog(__name__) class Manage(Plugin): + in_progress = False + def __init__(self): fireEvent('scheduler.interval', identifier = 'manage.update_library', handle = self.updateLibrary, hours = 2) addEvent('manage.update', self.updateLibrary) + addEvent('manage.scan_files', self.scanFilesToLibrary) + + # Add files after renaming + def after_rename(group): + return self.scanFilesToLibrary(folder = group['destination_dir'], files = group['renamed_files']) + addEvent('renamer.after', after_rename) + addApiView('manage.update', self.updateLibraryView, docs = { 'desc': 'Update the library by scanning for new movies', 'params': { @@ -25,11 +36,23 @@ class Manage(Plugin): } }) + addApiView('manage.progress', self.getProgress, docs = { + 'desc': 'Get the progress of current manage update', + 'return': {'type': 'object', 'example': """{ + 'progress': False || object, total & to_go, +}"""}, + }) + if not Env.get('dev'): def updateLibrary(): self.updateLibrary(full = False) addEvent('app.load', updateLibrary) + def getProgress(self): + return jsonified({ + 'progress': self.in_progress + }) + def updateLibraryView(self): full = getParam('full', default = 1) @@ -43,49 +66,127 @@ class Manage(Plugin): def updateLibrary(self, full = True): last_update = float(Env.prop('manage.last_update', default = 0)) - if self.isDisabled() or (last_update > time.time() - 20): + if self.in_progress: + log.info('Already updating library: %s', self.in_progress) + return + elif self.isDisabled() or (last_update > time.time() - 20): return - directories = self.directories() - added_identifiers = [] + self.in_progress = {} + fireEvent('notify.frontend', type = 'manage.updating', data = True) - for directory in directories: + try: - if not os.path.isdir(directory): - if len(directory) > 0: - log.error('Directory doesn\'t exist: %s', directory) - continue + directories = self.directories() + added_identifiers = [] - log.info('Updating manage library: %s', directory) - identifiers = fireEvent('scanner.folder', folder = directory, newer_than = last_update if not full else 0, single = True) - if identifiers: - added_identifiers.extend(identifiers) + # Add some progress + self.in_progress = {} + for directory in directories: + self.in_progress[os.path.normpath(directory)] = { + 'total': None, + 'to_go': None, + } - # Break if CP wants to shut down - if self.shuttingDown(): + for directory in directories: + folder = os.path.normpath(directory) + + if not os.path.isdir(folder): + if len(directory) > 0: + log.error('Directory doesn\'t exist: %s', folder) + continue + + log.info('Updating manage library: %s', folder) + fireEvent('notify.frontend', type = 'manage.update', data = True, message = 'Scanning for movies in "%s"' % folder) + + onFound = self.createAddToLibrary(folder, added_identifiers) + fireEvent('scanner.scan', folder = folder, simple = True, newer_than = last_update if not full else 0, on_found = onFound, single = True) + + # Break if CP wants to shut down + if self.shuttingDown(): + break + + # If cleanup option is enabled, remove offline files from database + if self.conf('cleanup') and full and not self.shuttingDown(): + + # Get movies with done status + total_movies, done_movies = fireEvent('movie.list', status = 'done', single = True) + + for done_movie in done_movies: + if done_movie['library']['identifier'] not in added_identifiers: + fireEvent('movie.delete', movie_id = done_movie['id'], delete_from = 'all') + else: + for release in done_movie.get('releases', []): + for release_file in release.get('files', []): + # Remove release not available anymore + if not os.path.isfile(ss(release_file['path'])): + fireEvent('release.clean', release['id']) + break + + Env.prop('manage.last_update', time.time()) + except: + log.error('Failed updating library: %s', (traceback.format_exc())) + + while True and not self.shuttingDown(): + + delete_me = {} + + for folder in self.in_progress: + if self.in_progress[folder]['to_go'] <= 0: + delete_me[folder] = True + + for delete in delete_me: + del self.in_progress[delete] + + if len(self.in_progress) == 0: break - # If cleanup option is enabled, remove offline files from database - if self.conf('cleanup') and full and not self.shuttingDown(): + time.sleep(1) - # Get movies with done status - total_movies, done_movies = fireEvent('movie.list', status = 'done', single = True) + fireEvent('notify.frontend', type = 'manage.updating', data = False) + self.in_progress = False - for done_movie in done_movies: - if done_movie['library']['identifier'] not in added_identifiers: - fireEvent('movie.delete', movie_id = done_movie['id'], delete_from = 'all') - else: - for release in done_movie.get('releases', []): - for release_file in release.get('files', []): - # Remove release not available anymore - if not os.path.isfile(ss(release_file['path'])): - fireEvent('release.clean', release['id']) - break + def createAddToLibrary(self, folder, added_identifiers = []): + def addToLibrary(group, total_found, to_go): + if self.in_progress[folder]['total'] is None: + self.in_progress[folder] = { + 'total': total_found, + 'to_go': total_found, + } - Env.prop('manage.last_update', time.time()) + if group['library']: + identifier = group['library'].get('identifier') + added_identifiers.append(identifier) + + # Add it to release and update the info + fireEvent('release.add', group = group) + fireEventAsync('library.update', identifier = identifier, on_complete = self.createAfterUpdate(folder, identifier)) + + return addToLibrary + + def createAfterUpdate(self, folder, identifier): + + # Notify frontend + def afterUpdate(): + self.in_progress[folder]['to_go'] = self.in_progress[folder]['to_go'] - 1 + total = self.in_progress[folder]['total'] + movie_dict = fireEvent('movie.get', identifier, single = True) + fireEvent('notify.frontend', type = 'movie.added', data = movie_dict, message = None if total > 5 else 'Added "%s" to manage.' % getTitle(movie_dict['library'])) + + return afterUpdate def directories(self): try: return [x.strip() for x in self.conf('library', default = '').split('::')] except: return [] + + def scanFilesToLibrary(self, folder = None, files = None): + + folder = os.path.normpath(folder) + + groups = fireEvent('scanner.scan', folder = folder, files = files, single = True) + + for group in groups.itervalues(): + if group['library']: + fireEvent('release.add', group = group) diff --git a/couchpotato/core/plugins/movie/main.py b/couchpotato/core/plugins/movie/main.py index d86b97c9..cee17f40 100644 --- a/couchpotato/core/plugins/movie/main.py +++ b/couchpotato/core/plugins/movie/main.py @@ -107,13 +107,18 @@ class MoviePlugin(Plugin): def get(self, movie_id): db = get_session() - m = db.query(Movie).filter_by(id = movie_id).first() + + imdb_id = getImdb(str(movie_id)) + + if(imdb_id): + m = db.query(Movie).filter(Movie.library.has(identifier = imdb_id)).first() + else: + m = db.query(Movie).filter_by(id = movie_id).first() results = None if m: results = m.to_dict(self.default_dict) - #db.close() return results def list(self, status = ['active'], limit_offset = None, starts_with = None, search = None): diff --git a/couchpotato/core/plugins/movie/static/list.js b/couchpotato/core/plugins/movie/static/list.js index 51b0f4c5..452f519b 100644 --- a/couchpotato/core/plugins/movie/static/list.js +++ b/couchpotato/core/plugins/movie/static/list.js @@ -33,17 +33,21 @@ var MovieList = new Class({ ); self.getMovies(); - if(options.add_new) - App.addEvent('movie.added', self.movieAdded.bind(self)) - + App.addEvent('movie.added', self.movieAdded.bind(self)) App.addEvent('movie.deleted', self.movieDeleted.bind(self)) }, movieDeleted: function(notification){ var self = this; - if(!self.movies_added[notification.data.id]) - self.movies_added[notification.data.id].destroy(); + if(self.movies_added[notification.data.id]){ + self.movies.each(function(movie){ + if(movie.get('id') == notification.data.id){ + movie.destroy(); + delete self.movies_added[notification.data.id] + } + }) + } self.checkIfEmpty(); }, @@ -52,7 +56,7 @@ var MovieList = new Class({ var self = this; window.scroll(0,0); - if(!self.movies_added[notification.data.id]) + if(self.options.add_new && !self.movies_added[notification.data.id] && notification.data.status.identifier == self.options.status) self.createMovie(notification.data, 'top'); self.checkIfEmpty(); diff --git a/couchpotato/core/plugins/movie/static/movie.css b/couchpotato/core/plugins/movie/static/movie.css index bd831771..49958496 100644 --- a/couchpotato/core/plugins/movie/static/movie.css +++ b/couchpotato/core/plugins/movie/static/movie.css @@ -550,3 +550,51 @@ font-size: 25px; line-height: 150%; } + + .movies .empty_manage .after_manage { + margin-top: 30px; + font-size: 16px; + } + + .movies .progress { + border-radius: 2px; + padding: 10px; + margin: 5px 0; + text-align: left; + } + + .movies .progress > div { + padding: 5px 10px; + font-size: 12px; + line-height: 12px; + text-align: left; + display: inline-block; + width: 49%; + background: rgba(255, 255, 255, 0.05); + margin: 2px 0.5%; + border-radius: 3px; + } + + .movies .progress > div .folder { + display: inline-block; + padding: 5px 20px 5px 0; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + width: 85%; + direction: rtl; + vertical-align: middle; + } + + .movies .progress > div .percentage { + font-weight: bold; + display: inline-block; + text-transform: uppercase; + text-shadow: none; + font-weight: normal; + font-size: 20px; + border-left: 1px solid rgba(255, 255, 255, .2); + width: 15%; + text-align: right; + vertical-align: middle; + } diff --git a/couchpotato/core/plugins/scanner/main.py b/couchpotato/core/plugins/scanner/main.py index 4c639e2d..6528af74 100644 --- a/couchpotato/core/plugins/scanner/main.py +++ b/couchpotato/core/plugins/scanner/main.py @@ -34,6 +34,7 @@ class Scanner(Plugin): 'subtitle_extra': ['idx'], 'trailer': ['mov', 'mp4', 'flv'] } + file_types = { 'subtitle': ('subtitle', 'subtitle'), 'subtitle_extra': ('subtitle', 'subtitle_extra'), @@ -42,6 +43,8 @@ class Scanner(Plugin): 'movie': ('video', 'movie'), 'movie_extra': ('movie', 'movie_extra'), 'backdrop': ('image', 'backdrop'), + 'poster': ('image', 'poster'), + 'thumbnail': ('image', 'thumbnail'), 'leftover': ('leftover', 'leftover'), } @@ -80,55 +83,10 @@ class Scanner(Plugin): addEvent('scanner.remove_cptag', self.removeCPTag) addEvent('scanner.scan', self.scan) - addEvent('scanner.files', self.scanFilesToLibrary) - addEvent('scanner.folder', self.scanFolderToLibrary) addEvent('scanner.name_year', self.getReleaseNameYear) addEvent('scanner.partnumber', self.getPartNumber) - def after_rename(group): - return self.scanFilesToLibrary(folder = group['destination_dir'], files = group['renamed_files']) - - addEvent('renamer.after', after_rename) - - def scanFilesToLibrary(self, folder = None, files = None): - - folder = os.path.normpath(folder) - - groups = self.scan(folder = folder, files = files) - - for group in groups.itervalues(): - if group['library']: - fireEvent('release.add', group = group) - - def scanFolderToLibrary(self, folder = None, newer_than = 0, simple = True): - - folder = os.path.normpath(folder) - - if not os.path.isdir(folder): - return - - groups = self.scan(folder = folder, simple = simple, newer_than = newer_than) - - added_identifier = [] - while True and not self.shuttingDown(): - try: - identifier, group = groups.popitem() - except: - break - - # Save to DB - if group['library']: - - # Add release - fireEvent('release.add', group = group) - library_item = fireEvent('library.update', identifier = group['library'].get('identifier'), single = True) - if library_item: - added_identifier.append(library_item['identifier']) - - return added_identifier - - - def scan(self, folder = None, files = [], simple = False, newer_than = 0): + def scan(self, folder = None, files = [], simple = False, newer_than = 0, on_found = None): folder = ss(os.path.normpath(folder)) @@ -281,6 +239,7 @@ class Scanner(Plugin): # Determine file types processed_movies = {} + total_found = len(movie_files) while True and not self.shuttingDown(): try: identifier, group = movie_files.popitem() @@ -395,9 +354,12 @@ class Scanner(Plugin): movie = db.query(Movie).filter_by(library_id = group['library']['id']).first() group['movie_id'] = None if not movie else movie.id - processed_movies[identifier] = group + # Notify parent & progress on something found + if on_found: + on_found(group, total_found, total_found - len(processed_movies)) + if len(processed_movies) > 0: log.info('Found %s movies in the folder %s', (len(processed_movies), folder)) else: diff --git a/couchpotato/static/scripts/page/manage.js b/couchpotato/static/scripts/page/manage.js index 9ac0f34e..7ec7b4c6 100644 --- a/couchpotato/static/scripts/page/manage.js +++ b/couchpotato/static/scripts/page/manage.js @@ -41,10 +41,23 @@ Page.Manage = new Class({ 'text': 'Settings > Manage', 'href': App.createUrl('settings/manage') }) + ), + new Element('div.after_manage', { + 'text': 'When you\'ve done that, hit this button → ' + }).adopt( + new Element('a.button.green', { + 'text': 'Hit me, but not to hard', + 'events':{ + 'click': self.refresh.bind(self, true) + } + }) ) ) }); $(self.list).inject(self.el); + + // Check if search is in progress + self.startProgressInterval(); } }, @@ -52,11 +65,55 @@ Page.Manage = new Class({ refresh: function(full){ var self = this; - Api.request('manage.update', { - 'data': { - 'full': +full - } - }) + if(!self.update_in_progress){ + + Api.request('manage.update', { + 'data': { + 'full': +full + } + }) + + self.startProgressInterval(); + + } + + }, + + startProgressInterval: function(){ + var self = this; + + self.progress_interval = setInterval(function(){ + + Api.request('manage.progress', { + 'onComplete': function(json){ + self.update_in_progress = true; + + if(!json.progress){ + clearInterval(self.progress_interval); + self.update_in_progress = false; + if(self.progress_container){ + self.progress_container.destroy(); + self.list.update(); + } + } + else { + if(!self.progress_container) + self.progress_container = new Element('div.progress').inject(self.list.navigation, 'after') + + self.progress_container.empty(); + + Object.each(json.progress, function(progress, folder){ + new Element('div').adopt( + new Element('span.folder', {'text': folder}), + new Element('span.percentage', {'text': progress.total ? (((progress.total-progress.to_go)/progress.total)*100).round() + '%' : '0%'}) + ).inject(self.progress_container) + }); + + } + } + }) + + }, 1000); } diff --git a/couchpotato/static/scripts/page/wanted.js b/couchpotato/static/scripts/page/wanted.js index 32887ea2..3f6e065b 100644 --- a/couchpotato/static/scripts/page/wanted.js +++ b/couchpotato/static/scripts/page/wanted.js @@ -136,7 +136,7 @@ window.addEvent('domready', function(){ 'text': profile.label ? profile.label : profile.data.label }).inject(self.profile_select); - if(self.movie.profile && self.movie.profile.data.id == profile_id) + if(self.movie.profile && self.movie.profile.data && self.movie.profile.data.id == profile_id) self.profile_select.set('value', profile_id); }); From 6106fd4e8206e3bc95c8737d74befbb250f64c35 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 13 Oct 2012 21:19:56 +0200 Subject: [PATCH 63/92] Only scroll back to top when added --- couchpotato/core/plugins/movie/static/list.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/plugins/movie/static/list.js b/couchpotato/core/plugins/movie/static/list.js index 452f519b..fcc446bb 100644 --- a/couchpotato/core/plugins/movie/static/list.js +++ b/couchpotato/core/plugins/movie/static/list.js @@ -54,12 +54,13 @@ var MovieList = new Class({ movieAdded: function(notification){ var self = this; - window.scroll(0,0); - if(self.options.add_new && !self.movies_added[notification.data.id] && notification.data.status.identifier == self.options.status) + if(self.options.add_new && !self.movies_added[notification.data.id] && notification.data.status.identifier == self.options.status){ + window.scroll(0,0); self.createMovie(notification.data, 'top'); - self.checkIfEmpty(); + self.checkIfEmpty(); + } }, create: function(){ From d3ebe531d578e7f495144eb73b3480686ed77a57 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 14 Oct 2012 14:13:10 +0200 Subject: [PATCH 64/92] Don't use 2 events after rename --- couchpotato/core/notifications/base.py | 6 +++--- couchpotato/core/notifications/core/main.py | 2 +- couchpotato/core/notifications/nmj/main.py | 8 ++++---- couchpotato/core/notifications/plex/main.py | 2 +- couchpotato/core/notifications/synoindex/main.py | 2 +- couchpotato/core/notifications/xbmc/main.py | 4 ++-- couchpotato/core/plugins/manage/main.py | 3 +-- couchpotato/core/plugins/renamer/main.py | 7 ++----- couchpotato/core/plugins/trailer/main.py | 2 +- couchpotato/core/providers/metadata/base.py | 12 ++++++------ 10 files changed, 22 insertions(+), 26 deletions(-) diff --git a/couchpotato/core/notifications/base.py b/couchpotato/core/notifications/base.py index c1c63503..52582b56 100644 --- a/couchpotato/core/notifications/base.py +++ b/couchpotato/core/notifications/base.py @@ -14,7 +14,7 @@ class Notification(Plugin): test_message = 'ZOMG Lazors Pewpewpew!' listen_to = [ - 'movie.downloaded', 'movie.snatched', + 'renamer.after', 'movie.snatched', 'updater.available', 'updater.updated', ] dont_listen_to = [] @@ -30,10 +30,10 @@ class Notification(Plugin): addEvent(listener, self.createNotifyHandler(listener)) def createNotifyHandler(self, listener): - def notify(message, data): + def notify(message = None, group = {}): if not self.conf('on_snatch', default = True) and listener == 'movie.snatched': return - return self.notify(message = message, data = data, listener = listener) + return self.notify(message = message, data = group, listener = listener) return notify diff --git a/couchpotato/core/notifications/core/main.py b/couchpotato/core/notifications/core/main.py index 33f90d5a..f965b92a 100644 --- a/couchpotato/core/notifications/core/main.py +++ b/couchpotato/core/notifications/core/main.py @@ -22,7 +22,7 @@ class CoreNotifier(Notification): listeners = [] listen_to = [ - 'movie.downloaded', 'movie.snatched', + 'renamer.after', 'movie.snatched', 'updater.available', 'updater.updated', ] diff --git a/couchpotato/core/notifications/nmj/main.py b/couchpotato/core/notifications/nmj/main.py index 1a794fbe..cdf531dc 100644 --- a/couchpotato/core/notifications/nmj/main.py +++ b/couchpotato/core/notifications/nmj/main.py @@ -69,7 +69,7 @@ class NMJ(Notification): 'mount': mount, }) - def addToLibrary(self, group = {}): + def addToLibrary(self, message = None, group = {}): if self.isDisabled(): return host = self.conf('host') @@ -114,8 +114,8 @@ class NMJ(Notification): def failed(self): return jsonified({'success': False}) - + def test(self): return jsonified({'success': self.addToLibrary()}) - - + + diff --git a/couchpotato/core/notifications/plex/main.py b/couchpotato/core/notifications/plex/main.py index fed9f5e1..9790ccfe 100644 --- a/couchpotato/core/notifications/plex/main.py +++ b/couchpotato/core/notifications/plex/main.py @@ -17,7 +17,7 @@ class Plex(Notification): super(Plex, self).__init__() addEvent('renamer.after', self.addToLibrary) - def addToLibrary(self, group = {}): + def addToLibrary(self, message = None, group = {}): if self.isDisabled(): return log.info('Sending notification to Plex') diff --git a/couchpotato/core/notifications/synoindex/main.py b/couchpotato/core/notifications/synoindex/main.py index 6c4966df..01bd2fc8 100644 --- a/couchpotato/core/notifications/synoindex/main.py +++ b/couchpotato/core/notifications/synoindex/main.py @@ -16,7 +16,7 @@ class Synoindex(Notification): super(Synoindex, self).__init__() addEvent('renamer.after', self.addToLibrary) - def addToLibrary(self, group = {}): + def addToLibrary(self, message = None, group = {}): if self.isDisabled(): return command = [self.index_path, '-A', group.get('destination_dir')] diff --git a/couchpotato/core/notifications/xbmc/main.py b/couchpotato/core/notifications/xbmc/main.py index 1c83bdd5..f59de608 100644 --- a/couchpotato/core/notifications/xbmc/main.py +++ b/couchpotato/core/notifications/xbmc/main.py @@ -8,7 +8,7 @@ log = CPLog(__name__) class XBMC(Notification): - listen_to = ['movie.downloaded'] + listen_to = ['renamer.after'] def notify(self, message = '', data = {}, listener = None): if self.isDisabled(): return @@ -21,7 +21,7 @@ class XBMC(Notification): if self.send({'command': 'ExecBuiltIn', 'parameter': 'XBMC.updatelibrary(video)'}, host): successful += 1 - return successful == len(hosts)*2 + return successful == len(hosts) * 2 def send(self, command, host): diff --git a/couchpotato/core/plugins/manage/main.py b/couchpotato/core/plugins/manage/main.py index a5d41fd1..c5f3828f 100644 --- a/couchpotato/core/plugins/manage/main.py +++ b/couchpotato/core/plugins/manage/main.py @@ -22,10 +22,9 @@ class Manage(Plugin): fireEvent('scheduler.interval', identifier = 'manage.update_library', handle = self.updateLibrary, hours = 2) addEvent('manage.update', self.updateLibrary) - addEvent('manage.scan_files', self.scanFilesToLibrary) # Add files after renaming - def after_rename(group): + def after_rename(message = None, group = {}): return self.scanFilesToLibrary(folder = group['destination_dir'], files = group['renamed_files']) addEvent('renamer.after', after_rename) diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 993575ca..60692a57 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -377,12 +377,9 @@ class Renamer(Plugin): except: log.error('Failed removing %s: %s', (group['parentdir'], traceback.format_exc())) - # Search for trailers etc - fireEventAsync('renamer.after', group) - - # Notify on download + # Notify on download, search for trailers etc download_message = 'Downloaded %s (%s)' % (movie_title, replacements['quality']) - fireEventAsync('movie.downloaded', message = download_message, data = group) + fireEventAsync('renamer.after', message = download_message, group = group) # Break if CP wants to shut down if self.shuttingDown(): diff --git a/couchpotato/core/plugins/trailer/main.py b/couchpotato/core/plugins/trailer/main.py index 05246845..8b9f1e1c 100644 --- a/couchpotato/core/plugins/trailer/main.py +++ b/couchpotato/core/plugins/trailer/main.py @@ -12,7 +12,7 @@ class Trailer(Plugin): def __init__(self): addEvent('renamer.after', self.searchSingle) - def searchSingle(self, group): + def searchSingle(self, message = None, group = {}): if self.isDisabled() or len(group['files']['trailer']) > 0: return diff --git a/couchpotato/core/providers/metadata/base.py b/couchpotato/core/providers/metadata/base.py index cf2e303f..078d7e1d 100644 --- a/couchpotato/core/providers/metadata/base.py +++ b/couchpotato/core/providers/metadata/base.py @@ -16,23 +16,23 @@ class MetaDataBase(Plugin): def __init__(self): addEvent('renamer.after', self.create) - def create(self, release): + def create(self, message = None, group = {}): if self.isDisabled(): return log.info('Creating %s metadata.', self.getName()) # Update library to get latest info try: - updated_library = fireEvent('library.update', release['library']['identifier'], force = True, single = True) - release['library'] = mergeDicts(release['library'], updated_library) + updated_library = fireEvent('library.update', group['library']['identifier'], force = True, single = True) + group['library'] = mergeDicts(group['library'], updated_library) except: log.error('Failed to update movie, before creating metadata: %s', traceback.format_exc()) - root_name = self.getRootName(release) + root_name = self.getRootName(group) meta_name = os.path.basename(root_name) root = os.path.dirname(root_name) - movie_info = release['library'].get('info') + movie_info = group['library'].get('info') for file_type in ['nfo', 'thumbnail', 'fanart']: try: @@ -42,7 +42,7 @@ class MetaDataBase(Plugin): if name and self.conf('meta_' + file_type): # Get file content - content = getattr(self, 'get' + file_type.capitalize())(movie_info = movie_info, data = release) + content = getattr(self, 'get' + file_type.capitalize())(movie_info = movie_info, data = group) if content: log.debug('Creating %s file: %s', (file_type, name)) if os.path.isfile(content): From f204309ed7c7982f8edbb9a9c59fb6f4298376c6 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 14 Oct 2012 14:37:02 +0200 Subject: [PATCH 65/92] Remove unused file before counting them --- couchpotato/core/plugins/scanner/main.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/plugins/scanner/main.py b/couchpotato/core/plugins/scanner/main.py index 6528af74..a25a31c7 100644 --- a/couchpotato/core/plugins/scanner/main.py +++ b/couchpotato/core/plugins/scanner/main.py @@ -237,9 +237,9 @@ class Scanner(Plugin): del path_identifiers[identifier] del delete_identifiers - # Determine file types - processed_movies = {} - total_found = len(movie_files) + + # Make sure we remove older / still extracting files + valid_files = {} while True and not self.shuttingDown(): try: identifier, group = movie_files.popitem() @@ -294,6 +294,19 @@ class Scanner(Plugin): continue + valid_files[identifier] = group + + del movie_files + + # Determine file types + processed_movies = {} + total_found = len(valid_files) + while True and not self.shuttingDown(): + try: + identifier, group = valid_files.popitem() + except: + break + # Group extra (and easy) files first # images = self.getImages(group['unsorted_files']) group['files'] = { From 3ffc6e122ee8d7ded3ab92d349bb86e3e5640795 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 14 Oct 2012 15:28:26 +0200 Subject: [PATCH 66/92] Double genres because of trailing spaces --- couchpotato/core/helpers/variable.py | 2 ++ couchpotato/core/notifications/core/main.py | 6 +++--- couchpotato/core/notifications/notifymyandroid/main.py | 3 ++- couchpotato/core/notifications/notifymywp/main.py | 3 ++- couchpotato/core/notifications/xbmc/main.py | 3 ++- couchpotato/core/plugins/movie/main.py | 10 +++++----- couchpotato/core/plugins/subtitle/main.py | 3 ++- couchpotato/core/providers/movie/imdbapi/main.py | 10 +++++----- couchpotato/core/providers/nzb/newznab/main.py | 8 ++++---- 9 files changed, 27 insertions(+), 21 deletions(-) diff --git a/couchpotato/core/helpers/variable.py b/couchpotato/core/helpers/variable.py index 2578d2c2..dea01686 100644 --- a/couchpotato/core/helpers/variable.py +++ b/couchpotato/core/helpers/variable.py @@ -135,3 +135,5 @@ def getTitle(library_dict): def randomString(size = 8, chars = string.ascii_uppercase + string.digits): return ''.join(random.choice(chars) for x in range(size)) +def splitString(str, split_on = ','): + return [x.strip() for x in str.split(split_on)] diff --git a/couchpotato/core/notifications/core/main.py b/couchpotato/core/notifications/core/main.py index f965b92a..bc8bd860 100644 --- a/couchpotato/core/notifications/core/main.py +++ b/couchpotato/core/notifications/core/main.py @@ -3,7 +3,7 @@ from couchpotato.api import addApiView, addNonBlockApiView from couchpotato.core.event import addEvent from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.request import jsonified, getParam -from couchpotato.core.helpers.variable import tryInt +from couchpotato.core.helpers.variable import tryInt, splitString from couchpotato.core.logger import CPLog from couchpotato.core.notifications.base import Notification from couchpotato.core.settings.model import Notification as Notif @@ -67,7 +67,7 @@ class CoreNotifier(Notification): ids = None if getParam('ids'): - ids = [x.strip() for x in getParam('ids').split(',')] + ids = splitString(getParam('ids')) db = get_session() @@ -92,7 +92,7 @@ class CoreNotifier(Notification): q = db.query(Notif) if limit_offset: - splt = [x.strip() for x in limit_offset.split(',')] + splt = splitString(limit_offset) limit = splt[0] offset = 0 if len(splt) is 1 else splt[1] q = q.limit(limit).offset(offset) diff --git a/couchpotato/core/notifications/notifymyandroid/main.py b/couchpotato/core/notifications/notifymyandroid/main.py index 299d475c..cc6ef662 100644 --- a/couchpotato/core/notifications/notifymyandroid/main.py +++ b/couchpotato/core/notifications/notifymyandroid/main.py @@ -1,3 +1,4 @@ +from couchpotato.core.helpers.variable import splitString from couchpotato.core.logger import CPLog from couchpotato.core.notifications.base import Notification import pynma @@ -11,7 +12,7 @@ class NotifyMyAndroid(Notification): if self.isDisabled(): return nma = pynma.PyNMA() - keys = [x.strip() for x in self.conf('api_key').split(',')] + keys = splitString(self.conf('api_key')) nma.addkey(keys) nma.developerkey(self.conf('dev_key')) diff --git a/couchpotato/core/notifications/notifymywp/main.py b/couchpotato/core/notifications/notifymywp/main.py index fafffd55..3258e85f 100644 --- a/couchpotato/core/notifications/notifymywp/main.py +++ b/couchpotato/core/notifications/notifymywp/main.py @@ -1,3 +1,4 @@ +from couchpotato.core.helpers.variable import splitString from couchpotato.core.logger import CPLog from couchpotato.core.notifications.base import Notification from pynmwp import PyNMWP @@ -10,7 +11,7 @@ class NotifyMyWP(Notification): def notify(self, message = '', data = {}, listener = None): if self.isDisabled(): return - keys = [x.strip() for x in self.conf('api_key').split(',')] + keys = splitString(self.conf('api_key')) p = PyNMWP(keys, self.conf('dev_key')) response = p.push(application = self.default_title, event = message, description = message, priority = self.conf('priority'), batch_mode = len(keys) > 1) diff --git a/couchpotato/core/notifications/xbmc/main.py b/couchpotato/core/notifications/xbmc/main.py index f59de608..30759716 100644 --- a/couchpotato/core/notifications/xbmc/main.py +++ b/couchpotato/core/notifications/xbmc/main.py @@ -1,4 +1,5 @@ from couchpotato.core.helpers.encoding import tryUrlencode +from couchpotato.core.helpers.variable import splitString from couchpotato.core.logger import CPLog from couchpotato.core.notifications.base import Notification import base64 @@ -13,7 +14,7 @@ class XBMC(Notification): def notify(self, message = '', data = {}, listener = None): if self.isDisabled(): return - hosts = [x.strip() for x in self.conf('host').split(",")] + hosts = splitString(self.conf('host')) successful = 0 for host in hosts: if self.send({'command': 'ExecBuiltIn', 'parameter': 'Notification(CouchPotato, %s)' % message}, host): diff --git a/couchpotato/core/plugins/movie/main.py b/couchpotato/core/plugins/movie/main.py index cee17f40..821eea18 100644 --- a/couchpotato/core/plugins/movie/main.py +++ b/couchpotato/core/plugins/movie/main.py @@ -3,7 +3,7 @@ from couchpotato.api import addApiView from couchpotato.core.event import fireEvent, fireEventAsync, addEvent from couchpotato.core.helpers.encoding import toUnicode, simplifyString from couchpotato.core.helpers.request import getParams, jsonified, getParam -from couchpotato.core.helpers.variable import getImdb +from couchpotato.core.helpers.variable import getImdb, splitString from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin from couchpotato.core.settings.model import Library, LibraryTitle, Movie @@ -166,7 +166,7 @@ class MoviePlugin(Plugin): .options(joinedload_all('files')) if limit_offset: - splt = [x.strip() for x in limit_offset.split(',')] + splt = splitString(limit_offset) limit = splt[0] offset = 0 if len(splt) is 1 else splt[1] q2 = q2.limit(limit).offset(offset) @@ -244,7 +244,7 @@ class MoviePlugin(Plugin): db = get_session() - for id in getParam('id').split(','): + for id in splitString(getParam('id')): movie = db.query(Movie).filter_by(id = id).first() if movie: @@ -386,7 +386,7 @@ class MoviePlugin(Plugin): available_status = fireEvent('status.get', 'available', single = True) - ids = [x.strip() for x in params.get('id').split(',')] + ids = splitString(params.get('id')) for movie_id in ids: m = db.query(Movie).filter_by(id = movie_id).first() @@ -422,7 +422,7 @@ class MoviePlugin(Plugin): params = getParams() - ids = [x.strip() for x in params.get('id').split(',')] + ids = splitString(params.get('id')) for movie_id in ids: self.delete(movie_id, delete_from = params.get('delete_from', 'all')) diff --git a/couchpotato/core/plugins/subtitle/main.py b/couchpotato/core/plugins/subtitle/main.py index 3a66a8bc..fc0a3904 100644 --- a/couchpotato/core/plugins/subtitle/main.py +++ b/couchpotato/core/plugins/subtitle/main.py @@ -1,6 +1,7 @@ from couchpotato import get_session from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.helpers.encoding import toUnicode +from couchpotato.core.helpers.variable import splitString from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin from couchpotato.core.settings.model import Library, FileType @@ -67,4 +68,4 @@ class Subtitle(Plugin): return False def getLanguages(self): - return [x.strip() for x in self.conf('languages').split(',')] + return splitString(self.conf('languages')) diff --git a/couchpotato/core/providers/movie/imdbapi/main.py b/couchpotato/core/providers/movie/imdbapi/main.py index 0fd91bf0..5b421c9c 100644 --- a/couchpotato/core/providers/movie/imdbapi/main.py +++ b/couchpotato/core/providers/movie/imdbapi/main.py @@ -1,6 +1,6 @@ from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.helpers.encoding import tryUrlencode -from couchpotato.core.helpers.variable import tryInt, tryFloat +from couchpotato.core.helpers.variable import tryInt, tryFloat, splitString from couchpotato.core.logger import CPLog from couchpotato.core.providers.movie.base import MovieProvider import json @@ -97,10 +97,10 @@ class IMDBAPI(MovieProvider): 'released': movie.get('Released', ''), 'year': year if isinstance(year, (int)) else None, 'plot': movie.get('Plot', ''), - 'genres': movie.get('Genre', '').split(','), - 'directors': movie.get('Director', '').split(','), - 'writers': movie.get('Writer', '').split(','), - 'actors': movie.get('Actors', '').split(','), + 'genres': splitString(movie.get('Genre', '')), + 'directors': splitString(movie.get('Director', '')), + 'writers': splitString(movie.get('Writer', '')), + 'actors': splitString(movie.get('Actors', '')), } except: log.error('Failed parsing IMDB API json: %s', traceback.format_exc()) diff --git a/couchpotato/core/providers/nzb/newznab/main.py b/couchpotato/core/providers/nzb/newznab/main.py index 5485c63b..e86c79b2 100644 --- a/couchpotato/core/providers/nzb/newznab/main.py +++ b/couchpotato/core/providers/nzb/newznab/main.py @@ -1,7 +1,7 @@ from couchpotato.core.event import fireEvent from couchpotato.core.helpers.encoding import tryUrlencode from couchpotato.core.helpers.rss import RSS -from couchpotato.core.helpers.variable import cleanHost +from couchpotato.core.helpers.variable import cleanHost, splitString from couchpotato.core.logger import CPLog from couchpotato.core.providers.nzb.base import NZBProvider from couchpotato.environment import Env @@ -161,9 +161,9 @@ class Newznab(NZBProvider, RSS): def getHosts(self): - uses = [x.strip() for x in str(self.conf('use')).split(',')] - hosts = [x.strip() for x in self.conf('host').split(',')] - api_keys = [x.strip() for x in self.conf('api_key').split(',')] + uses = splitString(str(self.conf('use'))) + hosts = splitString(self.conf('host')) + api_keys = splitString(self.conf('api_key')) list = [] for nr in range(len(hosts)): From 4dfd8b4cd5d444f82b32e30abd267bbbfdfa1e50 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 14 Oct 2012 17:32:45 +0200 Subject: [PATCH 67/92] Don't show trailer 404 errors --- couchpotato/core/plugins/base.py | 3 ++- .../core/providers/trailer/hdtrailers/main.py | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index 8a1e0767..5f3a9a44 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -239,7 +239,8 @@ class Plugin(object): self.setCache(cache_key, data, timeout = cache_timeout) return data except: - pass + if not kwargs.get('show_error'): + raise def setCache(self, cache_key, value, timeout = 300): log.debug('Setting cache %s', cache_key) diff --git a/couchpotato/core/providers/trailer/hdtrailers/main.py b/couchpotato/core/providers/trailer/hdtrailers/main.py index 09e24036..320a5835 100644 --- a/couchpotato/core/providers/trailer/hdtrailers/main.py +++ b/couchpotato/core/providers/trailer/hdtrailers/main.py @@ -4,6 +4,7 @@ from couchpotato.core.helpers.variable import mergeDicts, getTitle from couchpotato.core.logger import CPLog from couchpotato.core.providers.trailer.base import TrailerProvider from string import digits, ascii_letters +from urllib2 import HTTPError import re log = CPLog(__name__) @@ -22,7 +23,12 @@ class HDTrailers(TrailerProvider): movie_name = getTitle(group['library']) url = self.urls['api'] % self.movieUrlName(movie_name) - data = self.getCache('hdtrailers.%s' % group['library']['identifier'], url) + try: + data = self.getCache('hdtrailers.%s' % group['library']['identifier'], url, show_error = False) + except HTTPError: + log.debug('No page found for: %s', movie_name) + data = None + result_data = {'480p':[], '720p':[], '1080p':[]} if not data: @@ -47,7 +53,14 @@ class HDTrailers(TrailerProvider): movie_name = getTitle(group['library']) url = "%s?%s" % (self.urls['backup'], tryUrlencode({'s':movie_name})) - data = self.getCache('hdtrailers.alt.%s' % group['library']['identifier'], url) + try: + data = self.getCache('hdtrailers.alt.%s' % group['library']['identifier'], url, show_error = False) + except HTTPError: + log.debug('No alternative page found for: %s', movie_name) + data = None + + if not data: + return results try: tables = SoupStrainer('div') From 67c87444debf561595bcb37a6dacca51f556f2d5 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 14 Oct 2012 17:58:09 +0200 Subject: [PATCH 68/92] Subliminal update --- libs/guessit/__init__.py | 74 +- libs/guessit/country.py | 19 +- libs/guessit/date.py | 5 +- libs/guessit/fileutils.py | 10 +- libs/guessit/guess.py | 42 +- libs/guessit/hash_ed2k.py | 6 +- libs/guessit/hash_mpc.py | 1 + libs/guessit/language.py | 39 +- libs/guessit/matcher.py | 40 +- libs/guessit/matchtree.py | 13 +- libs/guessit/patterns.py | 29 +- libs/guessit/slogging.py | 1 + libs/guessit/textutils.py | 63 +- libs/guessit/transfo/__init__.py | 7 +- libs/guessit/transfo/guess_bonus_features.py | 1 + libs/guessit/transfo/guess_country.py | 42 + libs/guessit/transfo/guess_date.py | 1 + .../guess_episode_info_from_position.py | 1 + libs/guessit/transfo/guess_episodes_rexps.py | 28 +- libs/guessit/transfo/guess_filetype.py | 106 +- libs/guessit/transfo/guess_language.py | 1 + .../guess_movie_title_from_position.py | 1 + libs/guessit/transfo/guess_properties.py | 1 + libs/guessit/transfo/guess_release_group.py | 33 +- libs/guessit/transfo/guess_video_rexps.py | 1 + .../transfo/guess_weak_episodes_rexps.py | 10 +- libs/guessit/transfo/guess_website.py | 1 + libs/guessit/transfo/guess_year.py | 1 + libs/guessit/transfo/post_process.py | 1 + libs/guessit/transfo/split_explicit_groups.py | 6 +- libs/guessit/transfo/split_on_dash.py | 1 + libs/guessit/transfo/split_path_components.py | 1 + libs/requests/__init__.py | 35 +- libs/requests/_oauth.py | 24 + libs/requests/api.py | 15 +- libs/requests/auth.py | 357 +- libs/requests/cacert.pem | 3338 +++++++++++++++++ libs/requests/certs.py | 27 + libs/requests/compat.py | 16 +- libs/requests/cookies.py | 36 +- libs/requests/defaults.py | 11 +- libs/requests/exceptions.py | 10 + libs/requests/hooks.py | 12 +- libs/requests/models.py | 207 +- libs/requests/packages/chardet/__init__.py | 26 + libs/requests/packages/chardet/big5freq.py | 923 +++++ libs/requests/packages/chardet/big5prober.py | 41 + .../packages/chardet/chardistribution.py | 200 + .../packages/chardet/charsetgroupprober.py | 96 + .../packages/chardet/charsetprober.py | 60 + .../packages/chardet/codingstatemachine.py | 56 + libs/requests/packages/chardet/constants.py | 47 + libs/requests/packages/chardet/escprober.py | 79 + libs/requests/packages/chardet/escsm.py | 240 ++ libs/requests/packages/chardet/eucjpprober.py | 85 + libs/requests/packages/chardet/euckrfreq.py | 594 +++ libs/requests/packages/chardet/euckrprober.py | 41 + libs/requests/packages/chardet/euctwfreq.py | 426 +++ libs/requests/packages/chardet/euctwprober.py | 41 + libs/requests/packages/chardet/gb2312freq.py | 471 +++ .../requests/packages/chardet/gb2312prober.py | 41 + .../requests/packages/chardet/hebrewprober.py | 269 ++ libs/requests/packages/chardet/jisfreq.py | 567 +++ libs/requests/packages/chardet/jpcntx.py | 210 ++ .../packages/chardet/langbulgarianmodel.py | 228 ++ .../packages/chardet/langcyrillicmodel.py | 329 ++ .../packages/chardet/langgreekmodel.py | 225 ++ .../packages/chardet/langhebrewmodel.py | 201 + .../packages/chardet/langhungarianmodel.py | 225 ++ .../packages/chardet/langthaimodel.py | 200 + .../requests/packages/chardet/latin1prober.py | 136 + .../packages/chardet/mbcharsetprober.py | 82 + .../packages/chardet/mbcsgroupprober.py | 50 + libs/requests/packages/chardet/mbcssm.py | 514 +++ .../packages/chardet/sbcharsetprober.py | 106 + .../packages/chardet/sbcsgroupprober.py | 64 + libs/requests/packages/chardet/sjisprober.py | 85 + .../packages/chardet/universaldetector.py | 154 + libs/requests/packages/chardet/utf8prober.py | 76 + libs/requests/packages/chardet2/__init__.py | 26 + libs/requests/packages/chardet2/big5freq.py | 923 +++++ libs/requests/packages/chardet2/big5prober.py | 41 + .../packages/chardet2/chardistribution.py | 200 + .../packages/chardet2/charsetgroupprober.py | 97 + .../packages/chardet2/charsetprober.py | 61 + .../packages/chardet2/codingstatemachine.py | 57 + libs/requests/packages/chardet2/constants.py | 39 + libs/requests/packages/chardet2/escprober.py | 81 + libs/requests/packages/chardet2/escsm.py | 240 ++ .../requests/packages/chardet2/eucjpprober.py | 87 + libs/requests/packages/chardet2/euckrfreq.py | 594 +++ .../requests/packages/chardet2/euckrprober.py | 41 + libs/requests/packages/chardet2/euctwfreq.py | 426 +++ .../requests/packages/chardet2/euctwprober.py | 41 + libs/requests/packages/chardet2/gb2312freq.py | 471 +++ .../packages/chardet2/gb2312prober.py | 41 + .../packages/chardet2/hebrewprober.py | 269 ++ libs/requests/packages/chardet2/jisfreq.py | 567 +++ libs/requests/packages/chardet2/jpcntx.py | 210 ++ .../packages/chardet2/langbulgarianmodel.py | 228 ++ .../packages/chardet2/langcyrillicmodel.py | 329 ++ .../packages/chardet2/langgreekmodel.py | 225 ++ .../packages/chardet2/langhebrewmodel.py | 201 + .../packages/chardet2/langhungarianmodel.py | 225 ++ .../packages/chardet2/langthaimodel.py | 200 + .../packages/chardet2/latin1prober.py | 135 + .../packages/chardet2/mbcharsetprober.py | 83 + .../packages/chardet2/mbcsgroupprober.py | 50 + libs/requests/packages/chardet2/mbcssm.py | 514 +++ .../packages/chardet2/sbcharsetprober.py | 107 + .../packages/chardet2/sbcsgroupprober.py | 65 + libs/requests/packages/chardet2/sjisprober.py | 86 + libs/requests/packages/chardet2/test.py | 21 + .../packages/chardet2/universaldetector.py | 155 + libs/requests/packages/chardet2/utf8prober.py | 77 + libs/requests/packages/oauthlib/__init__.py | 0 libs/requests/packages/oauthlib/common.py | 229 ++ .../packages/oauthlib/oauth1/__init__.py | 13 + .../oauthlib/oauth1/rfc5849/__init__.py | 889 +++++ .../oauthlib/oauth1/rfc5849/parameters.py | 134 + .../oauthlib/oauth1/rfc5849/signature.py | 551 +++ .../packages/oauthlib/oauth1/rfc5849/utils.py | 99 + .../packages/oauthlib/oauth2/__init__.py | 13 + .../oauthlib/oauth2/draft25/__init__.py | 497 +++ .../oauthlib/oauth2/draft25/parameters.py | 256 ++ .../oauthlib/oauth2/draft25/tokens.py | 132 + .../packages/oauthlib/oauth2/draft25/utils.py | 39 + libs/requests/packages/urllib3/__init__.py | 20 +- .../requests/packages/urllib3/_collections.py | 171 +- .../packages/urllib3/connectionpool.py | 92 +- libs/requests/packages/urllib3/exceptions.py | 10 + libs/requests/packages/urllib3/filepost.py | 13 +- .../mimetools_choose_boundary/__init__.py | 47 - .../packages/urllib3/packages/ordered_dict.py | 260 ++ libs/requests/packages/urllib3/poolmanager.py | 64 +- libs/requests/packages/urllib3/response.py | 8 +- libs/requests/packages/urllib3/util.py | 194 +- libs/requests/safe_mode.py | 12 +- libs/requests/sessions.py | 60 +- libs/requests/status_codes.py | 2 +- libs/requests/structures.py | 1 + libs/requests/utils.py | 140 +- libs/subliminal/__init__.py | 0 libs/subliminal/api.py | 0 libs/subliminal/async.py | 0 libs/subliminal/cache.py | 0 libs/subliminal/core.py | 0 libs/subliminal/exceptions.py | 0 libs/subliminal/infos.py | 2 +- libs/subliminal/language.py | 0 libs/subliminal/services/__init__.py | 0 libs/subliminal/services/addic7ed.py | 133 +- libs/subliminal/services/bierdopje.py | 1 + libs/subliminal/services/opensubtitles.py | 0 libs/subliminal/services/podnapisi.py | 0 libs/subliminal/services/subswiki.py | 16 +- libs/subliminal/services/subtitulos.py | 2 +- libs/subliminal/services/thesubdb.py | 0 libs/subliminal/services/tvsubtitles.py | 0 libs/subliminal/subtitles.py | 2 +- libs/subliminal/tasks.py | 0 libs/subliminal/utils.py | 0 libs/subliminal/videos.py | 4 +- 163 files changed, 22377 insertions(+), 804 deletions(-) create mode 100644 libs/guessit/transfo/guess_country.py create mode 100644 libs/requests/_oauth.py create mode 100644 libs/requests/cacert.pem create mode 100644 libs/requests/certs.py create mode 100755 libs/requests/packages/chardet/__init__.py create mode 100755 libs/requests/packages/chardet/big5freq.py create mode 100755 libs/requests/packages/chardet/big5prober.py create mode 100755 libs/requests/packages/chardet/chardistribution.py create mode 100755 libs/requests/packages/chardet/charsetgroupprober.py create mode 100755 libs/requests/packages/chardet/charsetprober.py create mode 100755 libs/requests/packages/chardet/codingstatemachine.py create mode 100755 libs/requests/packages/chardet/constants.py create mode 100755 libs/requests/packages/chardet/escprober.py create mode 100755 libs/requests/packages/chardet/escsm.py create mode 100755 libs/requests/packages/chardet/eucjpprober.py create mode 100755 libs/requests/packages/chardet/euckrfreq.py create mode 100755 libs/requests/packages/chardet/euckrprober.py create mode 100755 libs/requests/packages/chardet/euctwfreq.py create mode 100755 libs/requests/packages/chardet/euctwprober.py create mode 100755 libs/requests/packages/chardet/gb2312freq.py create mode 100755 libs/requests/packages/chardet/gb2312prober.py create mode 100755 libs/requests/packages/chardet/hebrewprober.py create mode 100755 libs/requests/packages/chardet/jisfreq.py create mode 100755 libs/requests/packages/chardet/jpcntx.py create mode 100755 libs/requests/packages/chardet/langbulgarianmodel.py create mode 100755 libs/requests/packages/chardet/langcyrillicmodel.py create mode 100755 libs/requests/packages/chardet/langgreekmodel.py create mode 100755 libs/requests/packages/chardet/langhebrewmodel.py create mode 100755 libs/requests/packages/chardet/langhungarianmodel.py create mode 100755 libs/requests/packages/chardet/langthaimodel.py create mode 100755 libs/requests/packages/chardet/latin1prober.py create mode 100755 libs/requests/packages/chardet/mbcharsetprober.py create mode 100755 libs/requests/packages/chardet/mbcsgroupprober.py create mode 100755 libs/requests/packages/chardet/mbcssm.py create mode 100755 libs/requests/packages/chardet/sbcharsetprober.py create mode 100755 libs/requests/packages/chardet/sbcsgroupprober.py create mode 100755 libs/requests/packages/chardet/sjisprober.py create mode 100755 libs/requests/packages/chardet/universaldetector.py create mode 100755 libs/requests/packages/chardet/utf8prober.py create mode 100644 libs/requests/packages/chardet2/__init__.py create mode 100644 libs/requests/packages/chardet2/big5freq.py create mode 100644 libs/requests/packages/chardet2/big5prober.py create mode 100644 libs/requests/packages/chardet2/chardistribution.py create mode 100644 libs/requests/packages/chardet2/charsetgroupprober.py create mode 100644 libs/requests/packages/chardet2/charsetprober.py create mode 100644 libs/requests/packages/chardet2/codingstatemachine.py create mode 100644 libs/requests/packages/chardet2/constants.py create mode 100644 libs/requests/packages/chardet2/escprober.py create mode 100644 libs/requests/packages/chardet2/escsm.py create mode 100644 libs/requests/packages/chardet2/eucjpprober.py create mode 100644 libs/requests/packages/chardet2/euckrfreq.py create mode 100644 libs/requests/packages/chardet2/euckrprober.py create mode 100644 libs/requests/packages/chardet2/euctwfreq.py create mode 100644 libs/requests/packages/chardet2/euctwprober.py create mode 100644 libs/requests/packages/chardet2/gb2312freq.py create mode 100644 libs/requests/packages/chardet2/gb2312prober.py create mode 100644 libs/requests/packages/chardet2/hebrewprober.py create mode 100644 libs/requests/packages/chardet2/jisfreq.py create mode 100644 libs/requests/packages/chardet2/jpcntx.py create mode 100644 libs/requests/packages/chardet2/langbulgarianmodel.py create mode 100644 libs/requests/packages/chardet2/langcyrillicmodel.py create mode 100644 libs/requests/packages/chardet2/langgreekmodel.py create mode 100644 libs/requests/packages/chardet2/langhebrewmodel.py create mode 100644 libs/requests/packages/chardet2/langhungarianmodel.py create mode 100644 libs/requests/packages/chardet2/langthaimodel.py create mode 100644 libs/requests/packages/chardet2/latin1prober.py create mode 100644 libs/requests/packages/chardet2/mbcharsetprober.py create mode 100644 libs/requests/packages/chardet2/mbcsgroupprober.py create mode 100644 libs/requests/packages/chardet2/mbcssm.py create mode 100644 libs/requests/packages/chardet2/sbcharsetprober.py create mode 100644 libs/requests/packages/chardet2/sbcsgroupprober.py create mode 100644 libs/requests/packages/chardet2/sjisprober.py create mode 100644 libs/requests/packages/chardet2/test.py create mode 100644 libs/requests/packages/chardet2/universaldetector.py create mode 100644 libs/requests/packages/chardet2/utf8prober.py create mode 100644 libs/requests/packages/oauthlib/__init__.py create mode 100644 libs/requests/packages/oauthlib/common.py create mode 100644 libs/requests/packages/oauthlib/oauth1/__init__.py create mode 100644 libs/requests/packages/oauthlib/oauth1/rfc5849/__init__.py create mode 100644 libs/requests/packages/oauthlib/oauth1/rfc5849/parameters.py create mode 100644 libs/requests/packages/oauthlib/oauth1/rfc5849/signature.py create mode 100644 libs/requests/packages/oauthlib/oauth1/rfc5849/utils.py create mode 100644 libs/requests/packages/oauthlib/oauth2/__init__.py create mode 100644 libs/requests/packages/oauthlib/oauth2/draft25/__init__.py create mode 100644 libs/requests/packages/oauthlib/oauth2/draft25/parameters.py create mode 100644 libs/requests/packages/oauthlib/oauth2/draft25/tokens.py create mode 100644 libs/requests/packages/oauthlib/oauth2/draft25/utils.py delete mode 100644 libs/requests/packages/urllib3/packages/mimetools_choose_boundary/__init__.py create mode 100644 libs/requests/packages/urllib3/packages/ordered_dict.py mode change 100644 => 100755 libs/subliminal/__init__.py mode change 100644 => 100755 libs/subliminal/api.py mode change 100644 => 100755 libs/subliminal/async.py mode change 100644 => 100755 libs/subliminal/cache.py mode change 100644 => 100755 libs/subliminal/core.py mode change 100644 => 100755 libs/subliminal/exceptions.py mode change 100644 => 100755 libs/subliminal/infos.py mode change 100644 => 100755 libs/subliminal/language.py mode change 100644 => 100755 libs/subliminal/services/__init__.py mode change 100644 => 100755 libs/subliminal/services/addic7ed.py mode change 100644 => 100755 libs/subliminal/services/bierdopje.py mode change 100644 => 100755 libs/subliminal/services/opensubtitles.py mode change 100644 => 100755 libs/subliminal/services/podnapisi.py mode change 100644 => 100755 libs/subliminal/services/subswiki.py mode change 100644 => 100755 libs/subliminal/services/subtitulos.py mode change 100644 => 100755 libs/subliminal/services/thesubdb.py mode change 100644 => 100755 libs/subliminal/services/tvsubtitles.py mode change 100644 => 100755 libs/subliminal/subtitles.py mode change 100644 => 100755 libs/subliminal/tasks.py mode change 100644 => 100755 libs/subliminal/utils.py mode change 100644 => 100755 libs/subliminal/videos.py diff --git a/libs/guessit/__init__.py b/libs/guessit/__init__.py index e4f028f0..e19da095 100644 --- a/libs/guessit/__init__.py +++ b/libs/guessit/__init__.py @@ -18,12 +18,58 @@ # along with this program. If not, see . # -__version__ = '0.4.2' + +__version__ = '0.5.2' __all__ = ['Guess', 'Language', 'guess_file_info', 'guess_video_info', 'guess_movie_info', 'guess_episode_info'] +# Do python3 detection before importing any other module, to be sure that +# it will then always be available +# with code from http://lucumr.pocoo.org/2011/1/22/forwards-compatible-python/ +import sys +if sys.version_info[0] >= 3: + PY3 = True + unicode_text_type = str + native_text_type = str + base_text_type = str + def u(x): + return str(x) + def s(x): + return x + class UnicodeMixin(object): + __str__ = lambda x: x.__unicode__() + import binascii + def to_hex(x): + return binascii.hexlify(x).decode('utf-8') + +else: + PY3 = False + __all__ = [ str(s) for s in __all__ ] # fix imports for python2 + unicode_text_type = unicode + native_text_type = str + base_text_type = basestring + def u(x): + if isinstance(x, str): + return x.decode('utf-8') + return unicode(x) + def s(x): + if isinstance(x, unicode): + return x.encode('utf-8') + if isinstance(x, list): + return [ s(y) for y in x ] + if isinstance(x, tuple): + return tuple(s(y) for y in x) + if isinstance(x, dict): + return dict((s(key), s(value)) for key, value in x.items()) + return x + class UnicodeMixin(object): + __str__ = lambda x: unicode(x).encode('utf-8') + def to_hex(x): + return x.encode('hex') + + from guessit.guess import Guess, merge_all from guessit.language import Language from guessit.matcher import IterativeMatcher @@ -32,6 +78,7 @@ import logging log = logging.getLogger(__name__) + class NullHandler(logging.Handler): def emit(self, record): pass @@ -45,7 +92,7 @@ def guess_file_info(filename, filetype, info=None): """info can contain the names of the various plugins, such as 'filename' to detect filename info, or 'hash_md5' to get the md5 hash of the file. - >>> guess_file_info('test/dummy.srt', 'autodetect', info = ['hash_md5', 'hash_sha1']) + >>> guess_file_info('tests/dummy.srt', 'autodetect', info = ['hash_md5', 'hash_sha1']) {'hash_md5': 'e781de9b94ba2753a8e2945b2c0a123d', 'hash_sha1': 'bfd18e2f4e5d59775c2bc14d80f56971891ed620'} """ result = [] @@ -54,7 +101,7 @@ def guess_file_info(filename, filetype, info=None): if info is None: info = ['filename'] - if isinstance(info, basestring): + if isinstance(info, base_text_type): info = [info] for infotype in info: @@ -67,7 +114,7 @@ def guess_file_info(filename, filetype, info=None): try: result.append(Guess({'hash_mpc': hash_file(filename)}, confidence=1.0)) - except Exception, e: + except Exception as e: log.warning('Could not compute MPC-style hash because: %s' % e) elif infotype == 'hash_ed2k': @@ -75,7 +122,7 @@ def guess_file_info(filename, filetype, info=None): try: result.append(Guess({'hash_ed2k': hash_file(filename)}, confidence=1.0)) - except Exception, e: + except Exception as e: log.warning('Could not compute ed2k hash because: %s' % e) elif infotype.startswith('hash_'): @@ -97,17 +144,28 @@ def guess_file_info(filename, filetype, info=None): hasherobjs = dict(hashers).values() with open(filename, 'rb') as f: - for chunk in iter(lambda: f.read(blocksize), ''): + chunk = f.read(blocksize) + while chunk: for hasher in hasherobjs: hasher.update(chunk) + chunk = f.read(blocksize) for infotype, hasher in hashers: result.append(Guess({infotype: hasher.hexdigest()}, confidence=1.0)) - except Exception, e: + except Exception as e: log.warning('Could not compute hash because: %s' % e) - return merge_all(result) + result = merge_all(result) + + # last minute adjustments + + # if country is in the guessed properties, make it part of the filename + if 'country' in result: + result['series'] += ' (%s)' % result['country'].alpha2.upper() + + + return result def guess_video_info(filename, info=None): diff --git a/libs/guessit/country.py b/libs/guessit/country.py index b5f6d6e2..944b7df6 100644 --- a/libs/guessit/country.py +++ b/libs/guessit/country.py @@ -19,10 +19,12 @@ # from __future__ import unicode_literals -from guessit import fileutils -from guessit.textutils import to_unicode +from guessit import UnicodeMixin, base_text_type, u +from guessit.fileutils import load_file_in_same_dir import logging +__all__ = [ 'Country' ] + log = logging.getLogger(__name__) @@ -32,8 +34,7 @@ log = logging.getLogger(__name__) # "An English name, an alpha-2 code (when given), # an alpha-3 code (when given), a numeric code, and an ISO 31666-2 code # are all separated by pipe (|) characters." -_iso3166_contents = fileutils.load_file_in_same_dir(__file__, - 'ISO-3166-1_utf8.txt').decode('utf-8') +_iso3166_contents = load_file_in_same_dir(__file__, 'ISO-3166-1_utf8.txt') country_matrix = [ l.strip().split('|') for l in _iso3166_contents.strip().split('\n') ] @@ -59,7 +60,7 @@ country_alpha3_to_alpha2 = dict((c[2].lower(), c[1].lower()) for c in country_ma -class Country(object): +class Country(UnicodeMixin): """This class represents a country. You can initialize it with pretty much anything, as it knows conversion @@ -67,7 +68,7 @@ class Country(object): """ def __init__(self, country, strict=False): - country = to_unicode(country.strip().lower()) + country = u(country.strip().lower()) self.alpha3 = country_to_alpha3.get(country) if self.alpha3 is None and strict: @@ -93,7 +94,7 @@ class Country(object): if isinstance(other, Country): return self.alpha3 == other.alpha3 - if isinstance(other, basestring): + if isinstance(other, base_text_type): try: return self == Country(other) except ValueError: @@ -107,9 +108,5 @@ class Country(object): def __unicode__(self): return self.english_name - def __str__(self): - return unicode(self).encode('utf-8') - def __repr__(self): return 'Country(%s)' % self.english_name - diff --git a/libs/guessit/date.py b/libs/guessit/date.py index 4d0b510e..bd84c65d 100644 --- a/libs/guessit/date.py +++ b/libs/guessit/date.py @@ -18,9 +18,12 @@ # along with this program. If not, see . # +from __future__ import unicode_literals import datetime import re +def valid_year(year): + return 1920 < year < datetime.date.today().year + 5 def search_year(string): """Looks for year patterns, and if found return the year and group span. @@ -40,7 +43,7 @@ def search_year(string): match = re.search(r'[^0-9]([0-9]{4})[^0-9]', string) if match: year = int(match.group(1)) - if 1920 < year < datetime.date.today().year + 5: + if valid_year(year): return (year, match.span(1)) return (None, None) diff --git a/libs/guessit/fileutils.py b/libs/guessit/fileutils.py index 16e7348d..2fca6b7b 100644 --- a/libs/guessit/fileutils.py +++ b/libs/guessit/fileutils.py @@ -18,6 +18,8 @@ # along with this program. If not, see . # +from __future__ import unicode_literals +from guessit import s, u import os.path import zipfile @@ -31,10 +33,10 @@ def split_path(path): - the drive letter on Windows systems (eg: r'C:\') - the mount point '\\' on Windows systems (eg: r'\\host\share') - >>> split_path('/usr/bin/smewt') + >>> s(split_path('/usr/bin/smewt')) ['/', 'usr', 'bin', 'smewt'] - >>> split_path('relative_path/to/my_folder/') + >>> s(split_path('relative_path/to/my_folder/')) ['relative_path', 'to', 'my_folder'] """ @@ -65,7 +67,7 @@ def split_path(path): def file_in_same_dir(ref_file, desired_file): """Return the path for a file in the same dir as a given reference file. - >>> file_in_same_dir('~/smewt/smewt.db', 'smewt.settings') + >>> s(file_in_same_dir('~/smewt/smewt.db', 'smewt.settings')) '~/smewt/smewt.settings' """ @@ -82,4 +84,4 @@ def load_file_in_same_dir(ref_file, filename): zfile = zipfile.ZipFile(zfilename) return zfile.read('/'.join(path[i + 1:])) - return open(os.path.join(*path)).read() + return u(open(os.path.join(*path)).read()) diff --git a/libs/guessit/guess.py b/libs/guessit/guess.py index e25ca1f7..801af553 100644 --- a/libs/guessit/guess.py +++ b/libs/guessit/guess.py @@ -18,6 +18,10 @@ # along with this program. If not, see . # +from __future__ import unicode_literals +from guessit import UnicodeMixin, s, u, base_text_type +from guessit.language import Language +from guessit.country import Country import json import datetime import logging @@ -25,7 +29,7 @@ import logging log = logging.getLogger(__name__) -class Guess(dict): +class Guess(UnicodeMixin, dict): """A Guess is a dictionary which has an associated confidence for each of its values. @@ -44,23 +48,21 @@ class Guess(dict): for prop in self: self._confidence[prop] = confidence - def to_utf8_dict(self): - from guessit.language import Language + + def to_dict(self): data = dict(self) for prop, value in data.items(): if isinstance(value, datetime.date): data[prop] = value.isoformat() - elif isinstance(value, Language): - data[prop] = str(value) - elif isinstance(value, unicode): - data[prop] = value.encode('utf-8') + elif isinstance(value, (Language, Country, base_text_type)): + data[prop] = u(value) elif isinstance(value, list): - data[prop] = [str(x) for x in value] + data[prop] = [u(x) for x in value] return data def nice_string(self): - data = self.to_utf8_dict() + data = self.to_dict() parts = json.dumps(data, indent=4).split('\n') for i, p in enumerate(parts): @@ -72,8 +74,8 @@ class Guess(dict): return '\n'.join(parts) - def __str__(self): - return str(self.to_utf8_dict()) + def __unicode__(self): + return u(self.to_dict()) def confidence(self, prop): return self._confidence.get(prop, -1) @@ -138,16 +140,16 @@ def choose_string(g1, g2): differ very little, such as one string being the other one with the 'the' word prepended to it. - >>> choose_string(('Hello', 0.75), ('World', 0.5)) + >>> s(choose_string(('Hello', 0.75), ('World', 0.5))) ('Hello', 0.25) - >>> choose_string(('Hello', 0.5), ('hello', 0.5)) + >>> s(choose_string(('Hello', 0.5), ('hello', 0.5))) ('Hello', 0.75) - >>> choose_string(('Hello', 0.4), ('Hello World', 0.4)) + >>> s(choose_string(('Hello', 0.4), ('Hello World', 0.4))) ('Hello', 0.64) - >>> choose_string(('simpsons', 0.5), ('The Simpsons', 0.5)) + >>> s(choose_string(('simpsons', 0.5), ('The Simpsons', 0.5))) ('The Simpsons', 0.75) """ @@ -285,12 +287,12 @@ def merge_all(guesses, append=None): You can specify a list of properties that should be appended into a list instead of being merged. - >>> merge_all([ Guess({ 'season': 2 }, confidence = 0.6), - ... Guess({ 'episodeNumber': 13 }, confidence = 0.8) ]) + >>> s(merge_all([ Guess({ 'season': 2 }, confidence = 0.6), + ... Guess({ 'episodeNumber': 13 }, confidence = 0.8) ])) {'season': 2, 'episodeNumber': 13} - >>> merge_all([ Guess({ 'episodeNumber': 27 }, confidence = 0.02), - ... Guess({ 'season': 1 }, confidence = 0.2) ]) + >>> s(merge_all([ Guess({ 'episodeNumber': 27 }, confidence = 0.02), + ... Guess({ 'season': 1 }, confidence = 0.2) ])) {'season': 1} """ @@ -320,7 +322,7 @@ def merge_all(guesses, append=None): result.update_highest_confidence(g) # delete very unlikely values - for p in result.keys(): + for p in list(result.keys()): if result.confidence(p) < 0.05: del result[p] diff --git a/libs/guessit/hash_ed2k.py b/libs/guessit/hash_ed2k.py index 43303c58..7422d4e9 100644 --- a/libs/guessit/hash_ed2k.py +++ b/libs/guessit/hash_ed2k.py @@ -18,6 +18,8 @@ # along with this program. If not, see . # +from __future__ import unicode_literals +from guessit import s, to_hex import hashlib import os.path @@ -25,7 +27,7 @@ import os.path def hash_file(filename): """Returns the ed2k hash of a given file. - >>> hash_file('test/dummy.srt') + >>> s(hash_file('tests/dummy.srt')) 'ed2k://|file|dummy.srt|44|1CA0B9DED3473B926AA93A0A546138BB|/' """ return 'ed2k://|file|%s|%d|%s|/' % (os.path.basename(filename), @@ -58,6 +60,6 @@ def hash_filehash(filename): a = gen(f) hashes = [md4_hash(data).digest() for data in a] if len(hashes) == 1: - return hashes[0].encode("hex") + return to_hex(hashes[0]) else: return md4_hash(reduce(lambda a, d: a + d, hashes, "")).hexd diff --git a/libs/guessit/hash_mpc.py b/libs/guessit/hash_mpc.py index 7475940a..c9dd4292 100644 --- a/libs/guessit/hash_mpc.py +++ b/libs/guessit/hash_mpc.py @@ -18,6 +18,7 @@ # along with this program. If not, see . # +from __future__ import unicode_literals import struct import os diff --git a/libs/guessit/language.py b/libs/guessit/language.py index 344f9e2a..ccdd9cad 100644 --- a/libs/guessit/language.py +++ b/libs/guessit/language.py @@ -19,9 +19,9 @@ # from __future__ import unicode_literals -from guessit import fileutils +from guessit import UnicodeMixin, base_text_type, u, s +from guessit.fileutils import load_file_in_same_dir from guessit.country import Country -from guessit.textutils import to_unicode import re import logging @@ -39,8 +39,7 @@ log = logging.getLogger(__name__) # "An alpha-3 (bibliographic) code, an alpha-3 (terminologic) code (when given), # an alpha-2 code (when given), an English name, and a French name of a language # are all separated by pipe (|) characters." -_iso639_contents = fileutils.load_file_in_same_dir(__file__, - 'ISO-639-2_utf-8.txt').decode('utf-8') +_iso639_contents = load_file_in_same_dir(__file__, 'ISO-639-2_utf-8.txt') # drop the BOM from the beginning of the file _iso639_contents = _iso639_contents[1:] @@ -116,7 +115,6 @@ lng_exceptions = { 'unknown': ('und', None), 'cn': ('chi', None), 'chs': ('chi', None), 'jp': ('jpn', None), - 'scc': ('srp', None), 'scr': ('hrv', None) } @@ -137,7 +135,7 @@ def lang_set(languages, strict=False): return set(Language(l, strict=strict) for l in languages) -class Language(object): +class Language(UnicodeMixin): """This class represents a human language. You can initialize it with pretty much anything, as it knows conversion @@ -154,30 +152,30 @@ class Language(object): >>> Language('fr') Language(French) - >>> Language('eng').french_name - u'anglais' + >>> s(Language('eng').french_name) + 'anglais' - >>> Language('pt(br)').country.english_name - u'Brazil' + >>> s(Language('pt(br)').country.english_name) + 'Brazil' - >>> Language('Español (Latinoamérica)').country.english_name - u'Latin America' + >>> s(Language('Español (Latinoamérica)').country.english_name) + 'Latin America' >>> Language('Spanish (Latin America)') == Language('Español (Latinoamérica)') True - >>> Language('zz', strict=False).english_name - u'Undetermined' + >>> s(Language('zz', strict=False).english_name) + 'Undetermined' - >>> Language('pt(br)').opensubtitles - u'pob' + >>> s(Language('pt(br)').opensubtitles) + 'pob' """ _with_country_regexp = re.compile('(.*)\((.*)\)') _with_country_regexp2 = re.compile('(.*)-(.*)') def __init__(self, language, country=None, strict=False, scheme=None): - language = to_unicode(language.strip().lower()) + language = u(language.strip().lower()) with_country = (Language._with_country_regexp.match(language) or Language._with_country_regexp2.match(language)) if with_country: @@ -249,7 +247,7 @@ class Language(object): def opensubtitles(self): if self.lang == 'por' and self.country and self.country.alpha2 == 'br': return 'pob' - elif self.lang in ['gre', 'eus', 'ice', 'srp']: + elif self.lang in ['gre', 'srp']: return self.alpha3term return self.alpha3 @@ -266,7 +264,7 @@ class Language(object): if isinstance(other, Language): return self.lang == other.lang - if isinstance(other, basestring): + if isinstance(other, base_text_type): try: return self == Language(other) except ValueError: @@ -286,9 +284,6 @@ class Language(object): else: return self.english_name - def __str__(self): - return unicode(self).encode('utf-8') - def __repr__(self): if self.country: return 'Language(%s, country=%s)' % (self.english_name, self.country) diff --git a/libs/guessit/matcher.py b/libs/guessit/matcher.py index b0a5040c..d3392f68 100644 --- a/libs/guessit/matcher.py +++ b/libs/guessit/matcher.py @@ -18,8 +18,9 @@ # along with this program. If not, see . # +from __future__ import unicode_literals +from guessit import PY3, u from guessit.matchtree import MatchTree -from guessit.textutils import to_utf8 from guessit.guess import (merge_similar_guesses, merge_all, choose_int, choose_string) import copy @@ -69,12 +70,12 @@ class IterativeMatcher(object): """ valid_filetypes = ('autodetect', 'subtitle', 'video', - 'movie', 'moviesubtitle', - 'episode', 'episodesubtitle') + 'movie', 'moviesubtitle', + 'episode', 'episodesubtitle') if filetype not in valid_filetypes: raise ValueError("filetype needs to be one of %s" % valid_filetypes) - if not isinstance(filename, unicode): - log.debug('WARNING: given filename to matcher is not unicode...') + if not PY3 and not isinstance(filename, unicode): + log.warning('Given filename to matcher is not unicode...') self.match_tree = MatchTree(filename) mtree = self.match_tree @@ -99,21 +100,26 @@ class IterativeMatcher(object): apply_transfo('split_explicit_groups') # 4- try to match information for specific patterns + # NOTE: order needs to comply to the following: + # - website before language (eg: tvu.org.ru vs russian) + # - language before episodes_rexps + # - properties before language (eg: he-aac vs hebrew) + # - release_group before properties (eg: XviD-?? vs xvid) if mtree.guess['type'] in ('episode', 'episodesubtitle'): - strategy = ['guess_date', 'guess_video_rexps', - 'guess_episodes_rexps', 'guess_website', - 'guess_release_group', 'guess_properties', - 'guess_weak_episodes_rexps', 'guess_language'] + strategy = [ 'guess_date', 'guess_website', 'guess_release_group', + 'guess_properties', 'guess_language', + 'guess_video_rexps', + 'guess_episodes_rexps', 'guess_weak_episodes_rexps' ] else: - strategy = ['guess_date', 'guess_video_rexps', - 'guess_website', 'guess_release_group', - 'guess_properties', 'guess_language'] + strategy = [ 'guess_date', 'guess_website', 'guess_release_group', + 'guess_properties', 'guess_language', + 'guess_video_rexps' ] for name in strategy: apply_transfo(name) # more guessers for both movies and episodes - for name in ['guess_bonus_features']: + for name in ['guess_bonus_features', 'guess_year', 'guess_country']: apply_transfo(name) # split into '-' separated subgroups (with required separator chars @@ -125,13 +131,12 @@ class IterativeMatcher(object): if mtree.guess['type'] in ('episode', 'episodesubtitle'): apply_transfo('guess_episode_info_from_position') else: - apply_transfo('guess_year') apply_transfo('guess_movie_title_from_position') # 6- perform some post-processing steps apply_transfo('post_process') - log.debug('Found match tree:\n%s' % (to_utf8(unicode(mtree)))) + log.debug('Found match tree:\n%s' % u(mtree)) def matched(self): # we need to make a copy here, as the merge functions work in place and @@ -147,9 +152,12 @@ class IterativeMatcher(object): for string_part in ('title', 'series', 'container', 'format', 'releaseGroup', 'website', 'audioCodec', - 'videoCodec', 'screenSize', 'episodeFormat'): + 'videoCodec', 'screenSize', 'episodeFormat', + 'audioChannels'): merge_similar_guesses(parts, string_part, choose_string) + # 2- merge the rest, potentially discarding information not properly + # merged before result = merge_all(parts, append=['language', 'subtitleLanguage', 'other']) diff --git a/libs/guessit/matchtree.py b/libs/guessit/matchtree.py index 466e0bb9..28c8efa2 100644 --- a/libs/guessit/matchtree.py +++ b/libs/guessit/matchtree.py @@ -18,15 +18,16 @@ # along with this program. If not, see . # -from guessit import Guess -from guessit.textutils import clean_string, str_fill, to_utf8 +from __future__ import unicode_literals +from guessit import UnicodeMixin, base_text_type, Guess +from guessit.textutils import clean_string, str_fill from guessit.patterns import group_delimiters import logging log = logging.getLogger(__name__) -class BaseMatchTree(object): +class BaseMatchTree(UnicodeMixin): """A MatchTree represents the hierarchical split of a string into its constituent semantic groups.""" @@ -154,6 +155,7 @@ class BaseMatchTree(object): 'extension': 'e', 'format': 'f', 'language': 'l', + 'country': 'C', 'videoCodec': 'v', 'audioCodec': 'a', 'website': 'w', @@ -198,9 +200,6 @@ class BaseMatchTree(object): def __unicode__(self): return self.to_string() - def __str__(self): - return to_utf8(unicode(self)) - class MatchTree(BaseMatchTree): """The MatchTree contains a few "utility" methods which are not necessary @@ -218,7 +217,7 @@ class MatchTree(BaseMatchTree): return list(self._unidentified_leaves(valid)) def _leaves_containing(self, property_name): - if isinstance(property_name, basestring): + if isinstance(property_name, base_text_type): property_name = [ property_name ] for leaf in self._leaves(): diff --git a/libs/guessit/patterns.py b/libs/guessit/patterns.py index 5fa540ce..b75ca89b 100755 --- a/libs/guessit/patterns.py +++ b/libs/guessit/patterns.py @@ -19,6 +19,8 @@ # along with this program. If not, see . # +from __future__ import unicode_literals + subtitle_exts = [ 'srt', 'idx', 'sub', 'ssa', 'txt' ] @@ -40,7 +42,10 @@ episode_rexps = [ # ... Season 2 ... (r'saison (?P[0-9]+)', 1.0, (0, 0)), # ... s02e13 ... - (r'[Ss](?P[0-9]{1,2}).{,3}(?P(?:[EeXx][0-9]{1,2})+)[^0-9]', 1.0, (0, -1)), + (r'[Ss](?P[0-9]{1,2}).{,3}(?P(?:[Ee][0-9]{1,2})+)[^0-9]', 1.0, (0, -1)), + + # ... s03-x02 ... + (r'[Ss](?P[0-9]{1,2}).{,3}(?P(?:[Xx][0-9]{1,2})+)[^0-9]', 1.0, (0, -1)), # ... 2x13 ... (r'[^0-9](?P[0-9]{1,2})(?P(?:[xX][0-9]{1,2})+)[^0-9]', 0.8, (1, -1)), @@ -53,18 +58,16 @@ episode_rexps = [ # ... Season 2 ... (r'(?P[0-9]{1,3})v[23]' + sep, 0.6, (0, 0)), # ... ep 23 ... - ('ep' + sep + r'(?P[0-9]{1,2})[^0-9]', 0.7, (0, -1)) + ('ep' + sep + r'(?P[0-9]{1,2})[^0-9]', 0.7, (0, -1)), + + # ... e13 ... for a mini-series without a season number + (r'e(?P[0-9]{1,2})[^0-9]', 0.6, (0, -1)) + ] weak_episode_rexps = [ # ... 213 or 0106 ... - (sep + r'(?P[0-9]{1,4})' + sep, (1, -1)), - - # ... 2x13 ... - (sep + r'[^0-9](?P[0-9]{1,2})\.(?P[0-9]{1,2})[^0-9]' + sep, (1, -1)), - - # ... e13 ... for a mini-series without a season number - (r'e(?P[0-9]{1,4})[^0-9]', (0, -1)), + (sep + r'(?P[0-9]{2,4})' + sep, (1, -1)) ] non_episode_title = [ 'extras', 'rip' ] @@ -102,7 +105,7 @@ unlikely_series = ['series'] properties = { 'format': [ 'DVDRip', 'HD-DVD', 'HDDVD', 'HDDVDRip', 'BluRay', 'Blu-ray', 'BDRip', 'BRRip', 'HDRip', 'DVD', 'DVDivX', 'HDTV', 'DVB', 'DVBRip', 'PDTV', 'WEBRip', - 'DVDSCR', 'Screener', 'VHS', 'VIDEO_TS' ], + 'DVDSCR', 'Screener', 'VHS', 'VIDEO_TS', 'WEB-DL', 'WEBDL' ], 'screenSize': [ '720p', '720', '1080p', '1080' ], @@ -116,7 +119,10 @@ properties = { 'format': [ 'DVDRip', 'HD-DVD', 'HDDVD', 'HDDVDRip', 'BluRay', 'B 'CHD', 'ViTE', 'TLF', 'DEiTY', 'FLAiTE', 'MDX', 'GM4F', 'DVL', 'SVD', 'iLUMiNADOS', ' FiNaLe', 'UnSeeN', 'aXXo', 'KLAXXON', 'NoTV', 'ZeaL', 'LOL', - 'HDBRiSe' ], + 'SiNNERS', 'DiRTY', 'REWARD', 'ECI', 'KiNGS', 'CLUE', + 'CtrlHD', 'POD', 'WiKi', 'DIMENSION', 'IMMERSE', 'FQM', + '2HD', 'REPTiLE', 'CTU', 'HALCYON', 'EbP', 'SiTV', 'SAiNTS', + 'HDBRiSe', 'AlFleNi-TeaM', 'EVOLVE', '0TV' ], 'episodeFormat': [ 'Minisode', 'Minisodes' ], @@ -149,6 +155,7 @@ def find_properties(filename): property_synonyms = { 'DVD': [ 'DVDRip', 'VIDEO_TS' ], 'HD-DVD': [ 'HDDVD', 'HDDVDRip' ], 'BluRay': [ 'BDRip', 'BRRip', 'Blu-ray' ], + 'WEB-DL': [ 'WEBDL' ], 'DVB': [ 'DVBRip', 'PDTV' ], 'Screener': [ 'DVDSCR' ], 'DivX': [ 'DVDivX' ], diff --git a/libs/guessit/slogging.py b/libs/guessit/slogging.py index 34d9af79..f75773c0 100644 --- a/libs/guessit/slogging.py +++ b/libs/guessit/slogging.py @@ -18,6 +18,7 @@ # along with this program. If not, see . # +from __future__ import unicode_literals import logging import sys diff --git a/libs/guessit/textutils.py b/libs/guessit/textutils.py index 82c82b97..12043e59 100644 --- a/libs/guessit/textutils.py +++ b/libs/guessit/textutils.py @@ -18,7 +18,10 @@ # along with this program. If not, see . # +from __future__ import unicode_literals +from guessit import s from guessit.patterns import sep +import functools import unicodedata import copy @@ -61,45 +64,6 @@ def str_fill(string, region, c): return string[:start] + c * (end - start) + string[end:] -def to_utf8(o): - """Convert all unicode strings found in the given object to utf-8 - strings.""" - - if isinstance(o, unicode): - return o.encode('utf-8') - elif isinstance(o, list): - return [ to_utf8(i) for i in o ] - elif isinstance(o, dict): - # need to do it like that to handle Guess instances correctly - # FIXME: why is that necessary? - result = copy.deepcopy(o) - for key, value in o.items(): - result[to_utf8(key)] = to_utf8(value) - return result - - else: - return o - -def to_unicode(o): - """Convert all strings found in the given object to normalized - unicode strings, using the UTF-8 codec if needed.""" - - if isinstance(o, unicode): - return unicodedata.normalize('NFC', o) - if isinstance(o, str): - return unicodedata.normalize('NFC', o.decode('utf-8')) - elif isinstance(o, list): - return [ to_unicode(i) for i in o ] - elif isinstance(o, dict): - # need to do it like that to handle Guess instances correctly - #result = copy.deepcopy(o) - for key, value in o.items(): - result[to_unicode(key)] = to_unicode(value) - return result - - else: - return o - def levenshtein(a, b): if not a: @@ -176,21 +140,20 @@ def find_first_level_groups_span(string, enclosing): def split_on_groups(string, groups): """Split the given string using the different known groups for boundaries. - - >>> split_on_groups('0123456789', [ (2, 4) ]) + >>> s(split_on_groups('0123456789', [ (2, 4) ])) ['01', '23', '456789'] - >>> split_on_groups('0123456789', [ (2, 4), (4, 6) ]) + >>> s(split_on_groups('0123456789', [ (2, 4), (4, 6) ])) ['01', '23', '45', '6789'] - >>> split_on_groups('0123456789', [ (5, 7), (2, 4) ]) + >>> s(split_on_groups('0123456789', [ (5, 7), (2, 4) ])) ['01', '23', '4', '56', '789'] """ if not groups: return [ string ] - boundaries = sorted(set(reduce(lambda l, x: l + list(x), groups, []))) + boundaries = sorted(set(functools.reduce(lambda l, x: l + list(x), groups, []))) if boundaries[0] != 0: boundaries.insert(0, 0) if boundaries[-1] != len(string): @@ -212,22 +175,22 @@ def find_first_level_groups(string, enclosing, blank_sep=None): This does not return nested groups, ie: '(ab(c)(d))' will return a single group containing the whole string. - >>> find_first_level_groups('', '()') + >>> s(find_first_level_groups('', '()')) [''] - >>> find_first_level_groups('abcd', '()') + >>> s(find_first_level_groups('abcd', '()')) ['abcd'] - >>> find_first_level_groups('abc(de)fgh', '()') + >>> s(find_first_level_groups('abc(de)fgh', '()')) ['abc', '(de)', 'fgh'] - >>> find_first_level_groups('(ab(c)(d))', '()', blank_sep = '_') + >>> s(find_first_level_groups('(ab(c)(d))', '()', blank_sep = '_')) ['_ab(c)(d)_'] - >>> find_first_level_groups('ab[c]de[f]gh(i)', '[]') + >>> s(find_first_level_groups('ab[c]de[f]gh(i)', '[]')) ['ab', '[c]', 'de', '[f]', 'gh(i)'] - >>> find_first_level_groups('()[]()', '()', blank_sep = '-') + >>> s(find_first_level_groups('()[]()', '()', blank_sep = '-')) ['--', '[]', '--'] """ diff --git a/libs/guessit/transfo/__init__.py b/libs/guessit/transfo/__init__.py index 1bdd09be..67875dc6 100644 --- a/libs/guessit/transfo/__init__.py +++ b/libs/guessit/transfo/__init__.py @@ -18,7 +18,8 @@ # along with this program. If not, see . # -from guessit import Guess +from __future__ import unicode_literals +from guessit import base_text_type, Guess from guessit.patterns import canonical_form from guessit.textutils import clean_string import logging @@ -41,7 +42,7 @@ def format_guess(guess): if prop in ('season', 'episodeNumber', 'year', 'cdNumber', 'cdNumberTotal', 'bonusNumber', 'filmNumber'): guess[prop] = int(guess[prop]) - elif isinstance(value, basestring): + elif isinstance(value, base_text_type): if prop in ('edition',): value = clean_string(value) guess[prop] = canonical_form(value) @@ -63,7 +64,7 @@ def find_and_split_node(node, strategy, logger): if isinstance(result, Guess): if confidence is None: - confidence = result.confidence(result.keys()[0]) + confidence = result.confidence(list(result.keys())[0]) else: if confidence is None: confidence = 1.0 diff --git a/libs/guessit/transfo/guess_bonus_features.py b/libs/guessit/transfo/guess_bonus_features.py index 73fc7b41..8c7ac013 100644 --- a/libs/guessit/transfo/guess_bonus_features.py +++ b/libs/guessit/transfo/guess_bonus_features.py @@ -18,6 +18,7 @@ # along with this program. If not, see . # +from __future__ import unicode_literals from guessit.transfo import found_property import logging diff --git a/libs/guessit/transfo/guess_country.py b/libs/guessit/transfo/guess_country.py new file mode 100644 index 00000000..f95b62cf --- /dev/null +++ b/libs/guessit/transfo/guess_country.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# GuessIt - A library for guessing information from filenames +# Copyright (c) 2012 Nicolas Wack +# +# GuessIt is free software; you can redistribute it and/or modify it under +# the terms of the Lesser GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# GuessIt 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 +# Lesser GNU General Public License for more details. +# +# You should have received a copy of the Lesser GNU General Public License +# along with this program. If not, see . +# + +from __future__ import unicode_literals +#from guessit.transfo import SingleNodeGuesser +#from guessit.date import search_year +from guessit.country import Country +from guessit import Guess +import logging + +log = logging.getLogger(__name__) + + +def process(mtree): + for node in mtree.unidentified_leaves(): + # only keep explicit groups (enclosed in parentheses/brackets) + if len(node.node_idx) == 2: + try: + country = Country(node.value[1:-1], strict=True) + if node.value[0] + node.value[-1] not in ['()', '[]', '{}']: + continue + node.guess = Guess(country=country, confidence=1.0) + + except ValueError: + pass diff --git a/libs/guessit/transfo/guess_date.py b/libs/guessit/transfo/guess_date.py index ded80947..34a85989 100644 --- a/libs/guessit/transfo/guess_date.py +++ b/libs/guessit/transfo/guess_date.py @@ -18,6 +18,7 @@ # along with this program. If not, see . # +from __future__ import unicode_literals from guessit.transfo import SingleNodeGuesser from guessit.date import search_date import logging diff --git a/libs/guessit/transfo/guess_episode_info_from_position.py b/libs/guessit/transfo/guess_episode_info_from_position.py index 7b4f43f4..967c3341 100644 --- a/libs/guessit/transfo/guess_episode_info_from_position.py +++ b/libs/guessit/transfo/guess_episode_info_from_position.py @@ -18,6 +18,7 @@ # along with this program. If not, see . # +from __future__ import unicode_literals from guessit.transfo import found_property from guessit.patterns import non_episode_title, unlikely_series import logging diff --git a/libs/guessit/transfo/guess_episodes_rexps.py b/libs/guessit/transfo/guess_episodes_rexps.py index 690c3ed8..4ebfb547 100644 --- a/libs/guessit/transfo/guess_episodes_rexps.py +++ b/libs/guessit/transfo/guess_episodes_rexps.py @@ -18,6 +18,7 @@ # along with this program. If not, see . # +from __future__ import unicode_literals from guessit import Guess from guessit.transfo import SingleNodeGuesser from guessit.patterns import episode_rexps @@ -27,30 +28,35 @@ import logging log = logging.getLogger(__name__) def number_list(s): - return re.sub('[^0-9]+', ' ', s).split() + return list(re.sub('[^0-9]+', ' ', s).split()) def guess_episodes_rexps(string): for rexp, confidence, span_adjust in episode_rexps: match = re.search(rexp, string, re.IGNORECASE) if match: - result = (Guess(match.groupdict(), confidence=confidence), - (match.start() + span_adjust[0], - match.end() + span_adjust[1])) + guess = Guess(match.groupdict(), confidence=confidence) + span = (match.start() + span_adjust[0], + match.end() + span_adjust[1]) + # episodes which have a season > 25 are most likely errors - # (Simpsons is at 23!) - if int(result[0].get('season', 0)) > 25: + # (Simpsons is at 24!) + if int(guess.get('season', 0)) > 25: continue # decide whether we have only a single episode number or an # episode list - if result[0].get('episodeNumber'): - eplist = number_list(result[0]['episodeNumber']) - result[0].set('episodeNumber', int(eplist[0]), confidence=confidence) + if guess.get('episodeNumber'): + eplist = number_list(guess['episodeNumber']) + guess.set('episodeNumber', int(eplist[0]), confidence=confidence) if len(eplist) > 1: - result[0].set('episodeList', map(int, eplist), confidence=confidence) + guess.set('episodeList', list(map(int, eplist)), confidence=confidence) - return result + if guess.get('bonusNumber'): + eplist = number_list(guess['bonusNumber']) + guess.set('bonusNumber', int(eplist[0]), confidence=confidence) + + return guess, span return None, None diff --git a/libs/guessit/transfo/guess_filetype.py b/libs/guessit/transfo/guess_filetype.py index 56fb3fe9..cdaf1142 100644 --- a/libs/guessit/transfo/guess_filetype.py +++ b/libs/guessit/transfo/guess_filetype.py @@ -18,9 +18,12 @@ # along with this program. If not, see . # +from __future__ import unicode_literals from guessit import Guess from guessit.patterns import (subtitle_exts, video_exts, episode_rexps, find_properties, canonical_form) +from guessit.date import valid_year +from guessit.textutils import clean_string import os.path import re import mimetypes @@ -28,34 +31,22 @@ import logging log = logging.getLogger(__name__) +# List of well known movies and series, hardcoded because they cannot be +# guessed appropriately otherwise +MOVIES = [ 'OSS 117' ] +SERIES = [ 'Band of Brothers' ] -def guess_filetype(filename, filetype): - other = {} - - # look at the extension first - fileext = os.path.splitext(filename)[1][1:].lower() - if fileext in subtitle_exts: - if 'movie' in filetype: - filetype = 'moviesubtitle' - elif 'episode' in filetype: - filetype = 'episodesubtitle' - else: - filetype = 'subtitle' - other = { 'container': fileext } - elif fileext in video_exts: - if filetype == 'autodetect': - filetype = 'video' - other = { 'container': fileext } - else: - if filetype == 'autodetect': - filetype = 'unknown' - other = { 'extension': fileext } +MOVIES = [ m.lower() for m in MOVIES ] +SERIES = [ s.lower() for s in SERIES ] +def guess_filetype(mtree, filetype): # put the filetype inside a dummy container to be able to have the # following functions work correctly as closures # this is a workaround for python 2 which doesn't have the # 'nonlocal' keyword (python 3 does have it) filetype_container = [filetype] + other = {} + filename = mtree.string def upgrade_episode(): if filetype_container[0] == 'video': @@ -69,14 +60,82 @@ def guess_filetype(filename, filetype): elif filetype_container[0] == 'subtitle': filetype_container[0] = 'moviesubtitle' + def upgrade_subtitle(): + if 'movie' in filetype_container[0]: + filetype_container[0] = 'moviesubtitle' + elif 'episode' in filetype_container[0]: + filetype_container[0] = 'episodesubtitle' + else: + filetype_container[0] = 'subtitle' + + def upgrade(type='unknown'): + if filetype_container[0] == 'autodetect': + filetype_container[0] = type + + + # look at the extension first + fileext = os.path.splitext(filename)[1][1:].lower() + if fileext in subtitle_exts: + upgrade_subtitle() + other = { 'container': fileext } + elif fileext in video_exts: + upgrade(type='video') + other = { 'container': fileext } + else: + upgrade(type='unknown') + other = { 'extension': fileext } + + + + # check whether we are in a 'Movies', 'Tv Shows', ... folder + folder_rexps = [ (r'Movies?', upgrade_movie), + (r'Tv ?Shows?', upgrade_episode), + (r'Series', upgrade_episode) + ] + for frexp, upgrade_func in folder_rexps: + frexp = re.compile(frexp, re.IGNORECASE) + for pathgroup in mtree.children: + if frexp.match(pathgroup.value): + upgrade_func() + + # check for a few specific cases which will unintentionally make the + # following heuristics confused (eg: OSS 117 will look like an episode, + # season 1, epnum 17, when it is in fact a movie) + fname = clean_string(filename).lower() + for m in MOVIES: + if m in fname: + upgrade_movie() + for s in SERIES: + if s in fname: + upgrade_episode() + # now look whether there are some specific hints for episode vs movie - if filetype in ('video', 'subtitle'): + if filetype_container[0] in ('video', 'subtitle'): + # if we have an episode_rexp (eg: s02e13), it is an episode for rexp, _, _ in episode_rexps: match = re.search(rexp, filename, re.IGNORECASE) if match: upgrade_episode() break + # if we have a 3-4 digit number that's not a year, maybe an episode + match = re.search(r'[^0-9]([0-9]{3,4})[^0-9]', filename) + if match: + fullnumber = int(match.group()[1:-1]) + #season = fullnumber // 100 + epnumber = fullnumber % 100 + possible = True + + # check for validity + if epnumber > 40: + possible = False + if valid_year(fullnumber): + possible = False + + if possible: + upgrade_episode() + + # if we have certain properties characteristic of episodes, it is an ep for prop, value, _, _ in find_properties(filename): log.debug('prop: %s = %s' % (prop, value)) if prop == 'episodeFormat': @@ -87,6 +146,7 @@ def guess_filetype(filename, filetype): upgrade_episode() break + # origin-specific type if 'tvu.org.ru' in filename: upgrade_episode() @@ -98,7 +158,7 @@ def guess_filetype(filename, filetype): def process(mtree, filetype='autodetect'): - filetype, other = guess_filetype(mtree.string, filetype) + filetype, other = guess_filetype(mtree, filetype) mtree.guess.set('type', filetype, confidence=1.0) log.debug('Found with confidence %.2f: %s' % (1.0, mtree.guess)) diff --git a/libs/guessit/transfo/guess_language.py b/libs/guessit/transfo/guess_language.py index aa1431b5..fe547e61 100644 --- a/libs/guessit/transfo/guess_language.py +++ b/libs/guessit/transfo/guess_language.py @@ -18,6 +18,7 @@ # along with this program. If not, see . # +from __future__ import unicode_literals from guessit import Guess from guessit.transfo import SingleNodeGuesser from guessit.language import search_language diff --git a/libs/guessit/transfo/guess_movie_title_from_position.py b/libs/guessit/transfo/guess_movie_title_from_position.py index 55289c8f..8b6f5d0a 100644 --- a/libs/guessit/transfo/guess_movie_title_from_position.py +++ b/libs/guessit/transfo/guess_movie_title_from_position.py @@ -18,6 +18,7 @@ # along with this program. If not, see . # +from __future__ import unicode_literals from guessit import Guess import logging diff --git a/libs/guessit/transfo/guess_properties.py b/libs/guessit/transfo/guess_properties.py index 02d0cade..6c72dfd5 100644 --- a/libs/guessit/transfo/guess_properties.py +++ b/libs/guessit/transfo/guess_properties.py @@ -18,6 +18,7 @@ # along with this program. If not, see . # +from __future__ import unicode_literals from guessit.transfo import SingleNodeGuesser from guessit.patterns import find_properties import logging diff --git a/libs/guessit/transfo/guess_release_group.py b/libs/guessit/transfo/guess_release_group.py index 54a7148a..2cee4b07 100644 --- a/libs/guessit/transfo/guess_release_group.py +++ b/libs/guessit/transfo/guess_release_group.py @@ -18,24 +18,53 @@ # along with this program. If not, see . # +from __future__ import unicode_literals from guessit.transfo import SingleNodeGuesser +from guessit.patterns import properties, canonical_form import re import logging log = logging.getLogger(__name__) +CODECS = properties['videoCodec'] +FORMATS = properties['format'] + +def adjust_metadata(md): + codec = canonical_form(md['videoCodec']) + if codec in FORMATS: + md['format'] = codec + del md['videoCodec'] + return md + + def guess_release_group(string): group_names = [ r'\.(Xvid)-(?P.*?)[ \.]', r'\.(DivX)-(?P.*?)[\. ]', r'\.(DVDivX)-(?P.*?)[\. ]', ] + + # first try to see whether we have both a known codec and a known release group + group_names = [ r'\.(?P' + codec + r')-(?P.*?)[ \.]' + for codec in (CODECS + FORMATS) ] + for rexp in group_names: match = re.search(rexp, string, re.IGNORECASE) if match: metadata = match.groupdict() - metadata.update({ 'videoCodec': match.group(1) }) - return metadata, (match.start() + 1, match.end() - 1) + if canonical_form(metadata['releaseGroup']) in properties['releaseGroup']: + return adjust_metadata(metadata), (match.start(1), match.end(2)) + + # pick anything as releaseGroup as long as we have a codec in front + # this doesn't include a potential dash ('-') ending the release group + # eg: [...].X264-HiS@SiLUHD-English.[...] + group_names = [ r'\.(?P' + codec + r')-(?P.*?)(-(.*?))?[ \.]' + for codec in (CODECS + FORMATS) ] + + for rexp in group_names: + match = re.search(rexp, string, re.IGNORECASE) + if match: + return adjust_metadata(match.groupdict()), (match.start(1), match.end(2)) return None, None diff --git a/libs/guessit/transfo/guess_video_rexps.py b/libs/guessit/transfo/guess_video_rexps.py index 697a6af2..8ae9e6c6 100644 --- a/libs/guessit/transfo/guess_video_rexps.py +++ b/libs/guessit/transfo/guess_video_rexps.py @@ -18,6 +18,7 @@ # along with this program. If not, see . # +from __future__ import unicode_literals from guessit import Guess from guessit.transfo import SingleNodeGuesser from guessit.patterns import video_rexps, sep diff --git a/libs/guessit/transfo/guess_weak_episodes_rexps.py b/libs/guessit/transfo/guess_weak_episodes_rexps.py index 57c9f44f..8436ade8 100644 --- a/libs/guessit/transfo/guess_weak_episodes_rexps.py +++ b/libs/guessit/transfo/guess_weak_episodes_rexps.py @@ -18,6 +18,7 @@ # along with this program. If not, see . # +from __future__ import unicode_literals from guessit import Guess from guessit.transfo import SingleNodeGuesser from guessit.patterns import weak_episode_rexps @@ -40,8 +41,13 @@ def guess_weak_episodes_rexps(string, node): epnum = int(metadata['episodeNumber']) if epnum > 100: - return Guess({ 'season': epnum // 100, - 'episodeNumber': epnum % 100 }, + season, epnum = epnum // 100, epnum % 100 + # episodes which have a season > 25 are most likely errors + # (Simpsons is at 23!) + if season > 25: + continue + return Guess({ 'season': season, + 'episodeNumber': epnum }, confidence=0.6), span else: return Guess(metadata, confidence=0.3), span diff --git a/libs/guessit/transfo/guess_website.py b/libs/guessit/transfo/guess_website.py index 638f7d27..acfd8e11 100644 --- a/libs/guessit/transfo/guess_website.py +++ b/libs/guessit/transfo/guess_website.py @@ -18,6 +18,7 @@ # along with this program. If not, see . # +from __future__ import unicode_literals from guessit.transfo import SingleNodeGuesser from guessit.patterns import websites import logging diff --git a/libs/guessit/transfo/guess_year.py b/libs/guessit/transfo/guess_year.py index 7a90111f..4bc9b867 100644 --- a/libs/guessit/transfo/guess_year.py +++ b/libs/guessit/transfo/guess_year.py @@ -18,6 +18,7 @@ # along with this program. If not, see . # +from __future__ import unicode_literals from guessit.transfo import SingleNodeGuesser from guessit.date import search_year import logging diff --git a/libs/guessit/transfo/post_process.py b/libs/guessit/transfo/post_process.py index f08bbb2e..a2a7a336 100644 --- a/libs/guessit/transfo/post_process.py +++ b/libs/guessit/transfo/post_process.py @@ -18,6 +18,7 @@ # along with this program. If not, see . # +from __future__ import unicode_literals from guessit.patterns import subtitle_exts import logging diff --git a/libs/guessit/transfo/split_explicit_groups.py b/libs/guessit/transfo/split_explicit_groups.py index f99ff194..7ae5787d 100644 --- a/libs/guessit/transfo/split_explicit_groups.py +++ b/libs/guessit/transfo/split_explicit_groups.py @@ -18,8 +18,10 @@ # along with this program. If not, see . # +from __future__ import unicode_literals from guessit.textutils import find_first_level_groups from guessit.patterns import group_delimiters +import functools import logging log = logging.getLogger(__name__) @@ -33,10 +35,10 @@ def process(mtree): groups = find_first_level_groups(c.value, group_delimiters[0]) for delimiters in group_delimiters: flatten = lambda l, x: l + find_first_level_groups(x, delimiters) - groups = reduce(flatten, groups, []) + groups = functools.reduce(flatten, groups, []) # do not do this at this moment, it is not strong enough and can break other # patterns, such as dates, etc... - #groups = reduce(lambda l, x: l + x.split('-'), groups, []) + #groups = functools.reduce(lambda l, x: l + x.split('-'), groups, []) c.split_on_components(groups) diff --git a/libs/guessit/transfo/split_on_dash.py b/libs/guessit/transfo/split_on_dash.py index 0f2c34bd..b4454dcd 100644 --- a/libs/guessit/transfo/split_on_dash.py +++ b/libs/guessit/transfo/split_on_dash.py @@ -18,6 +18,7 @@ # along with this program. If not, see . # +from __future__ import unicode_literals from guessit.patterns import sep import re import logging diff --git a/libs/guessit/transfo/split_path_components.py b/libs/guessit/transfo/split_path_components.py index 9f7ec9b0..35fab405 100644 --- a/libs/guessit/transfo/split_path_components.py +++ b/libs/guessit/transfo/split_path_components.py @@ -18,6 +18,7 @@ # along with this program. If not, see . # +from __future__ import unicode_literals from guessit import fileutils import os.path import logging diff --git a/libs/requests/__init__.py b/libs/requests/__init__.py index 10c9e7ac..2e33412b 100644 --- a/libs/requests/__init__.py +++ b/libs/requests/__init__.py @@ -6,8 +6,35 @@ # / """ -requests -~~~~~~~~ +requests HTTP library +~~~~~~~~~~~~~~~~~~~~~ + +Requests is an HTTP library, written in Python, for human beings. Basic GET +usage: + + >>> import requests + >>> r = requests.get('http://python.org') + >>> r.status_code + 200 + >>> 'Python is a programming language' in r.content + True + +... or POST: + + >>> payload = dict(key1='value1', key2='value2') + >>> r = requests.post("http://httpbin.org/post", data=payload) + >>> print r.text + { + ... + "form": { + "key2": "value2", + "key1": "value1" + }, + ... + } + +The other HTTP methods are supported - see `requests.api`. Full documentation +is at . :copyright: (c) 2012 by Kenneth Reitz. :license: ISC, see LICENSE for more details. @@ -15,8 +42,8 @@ requests """ __title__ = 'requests' -__version__ = '0.13.1' -__build__ = 0x001301 +__version__ = '0.14.1' +__build__ = 0x001401 __author__ = 'Kenneth Reitz' __license__ = 'ISC' __copyright__ = 'Copyright 2012 Kenneth Reitz' diff --git a/libs/requests/_oauth.py b/libs/requests/_oauth.py new file mode 100644 index 00000000..165e937e --- /dev/null +++ b/libs/requests/_oauth.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +""" +requests._oauth +~~~~~~~~~~~~~~~ + +This module contains the path hack necessary for oauthlib to be vendored into +requests while allowing upstream changes. +""" + +import os +import sys + +try: + from oauthlib.oauth1 import rfc5849 + from oauthlib.common import extract_params + from oauthlib.oauth1.rfc5849 import (Client, SIGNATURE_HMAC, SIGNATURE_TYPE_AUTH_HEADER) +except ImportError: + directory = os.path.dirname(__file__) + path = os.path.join(directory, 'packages') + sys.path.insert(0, path) + from oauthlib.oauth1 import rfc5849 + from oauthlib.common import extract_params + from oauthlib.oauth1.rfc5849 import (Client, SIGNATURE_HMAC, SIGNATURE_TYPE_AUTH_HEADER) diff --git a/libs/requests/api.py b/libs/requests/api.py index 9cea79af..ded79352 100644 --- a/libs/requests/api.py +++ b/libs/requests/api.py @@ -14,6 +14,7 @@ This module implements the Requests API. from . import sessions from .safe_mode import catch_exceptions_if_in_safe_mode + @catch_exceptions_if_in_safe_mode def request(method, url, **kwargs): """Constructs and sends a :class:`Request `. @@ -38,9 +39,19 @@ def request(method, url, **kwargs): :param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair. """ - s = kwargs.pop('session') if 'session' in kwargs else sessions.session() - return s.request(method=method, url=url, **kwargs) + # if this session was passed in, leave it open (and retain pooled connections); + # if we're making it just for this call, then close it when we're done. + adhoc_session = False + session = kwargs.pop('session', None) + if session is None: + session = sessions.session() + adhoc_session = True + try: + return session.request(method=method, url=url, **kwargs) + finally: + if adhoc_session: + session.close() def get(url, **kwargs): diff --git a/libs/requests/auth.py b/libs/requests/auth.py index cb851d2c..6c5264e4 100644 --- a/libs/requests/auth.py +++ b/libs/requests/auth.py @@ -8,8 +8,10 @@ This module contains the authentication handlers for Requests. """ import os +import re import time import hashlib +import logging from base64 import b64encode @@ -17,15 +19,22 @@ from .compat import urlparse, str from .utils import parse_dict_header try: - from oauthlib.oauth1.rfc5849 import (Client, SIGNATURE_HMAC, SIGNATURE_TYPE_AUTH_HEADER) - from oauthlib.common import extract_params - # hush pyflakes: - SIGNATURE_HMAC; SIGNATURE_TYPE_AUTH_HEADER + from ._oauth import (Client, SIGNATURE_HMAC, SIGNATURE_TYPE_AUTH_HEADER, extract_params) + except (ImportError, SyntaxError): SIGNATURE_HMAC = None SIGNATURE_TYPE_AUTH_HEADER = None +try: + import kerberos as k +except ImportError as exc: + k = None + +log = logging.getLogger(__name__) + CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded' +CONTENT_TYPE_MULTI_PART = 'multipart/form-data' + def _basic_auth_str(username, password): """Returns a Basic Auth string.""" @@ -66,29 +75,37 @@ class OAuth1(AuthBase): Parameters may be included from the body if the content-type is urlencoded, if no content type is set an educated guess is made. """ - contenttype = r.headers.get('Content-Type', None) + # split(";") because Content-Type may be "multipart/form-data; boundary=xxxxx" + contenttype = r.headers.get('Content-Type', '').split(";")[0].lower() # extract_params will not give params unless the body is a properly # formatted string, a dictionary or a list of 2-tuples. - decoded_body = extract_params(r.data) - if contenttype == None and decoded_body != None: - # extract_params can only check the present r.data and does not know - # of r.files, thus an extra check is performed. We know that - # if files are present the request will not have - # Content-type: x-www-form-urlencoded. We guess it will have - # a mimetype of multipart/form-encoded and if this is not the case - # we assume the correct header will be set later. - if r.files: - # Omit body data in the signing and since it will always - # be empty (cant add paras to body if multipart) and we wish - # to preserve body. - r.headers['Content-Type'] = 'multipart/form-encoded' - r.url, r.headers, _ = self.client.sign( - unicode(r.url), unicode(r.method), None, r.headers) - else: - # Normal signing - r.headers['Content-Type'] = 'application/x-www-form-urlencoded' - r.url, r.headers, r.data = self.client.sign( - unicode(r.url), unicode(r.method), r.data, r.headers) + decoded_body = extract_params(r.data) + + # extract_params can only check the present r.data and does not know + # of r.files, thus an extra check is performed. We know that + # if files are present the request will not have + # Content-type: x-www-form-urlencoded. We guess it will have + # a mimetype of multipart/form-data and if this is not the case + # we assume the correct header will be set later. + _oauth_signed = True + if r.files and contenttype == CONTENT_TYPE_MULTI_PART: + # Omit body data in the signing and since it will always + # be empty (cant add paras to body if multipart) and we wish + # to preserve body. + r.url, r.headers, _ = self.client.sign( + unicode(r.full_url), unicode(r.method), None, r.headers) + elif decoded_body != None and contenttype in (CONTENT_TYPE_FORM_URLENCODED, ''): + # Normal signing + if not contenttype: + r.headers['Content-Type'] = CONTENT_TYPE_FORM_URLENCODED + r.url, r.headers, r.data = self.client.sign( + unicode(r.full_url), unicode(r.method), r.data, r.headers) + else: + _oauth_signed = False + if _oauth_signed: + # Both flows add params to the URL by using r.full_url, + # so this prevents adding it again later + r.params = {} # Having the authorization header, key or value, in unicode will # result in UnicodeDecodeErrors when the request is concatenated @@ -100,12 +117,12 @@ class OAuth1(AuthBase): # >>> d # { u'a' : 'foo' } u_header = unicode('Authorization') - if u_header in r.headers: + if u_header in r.headers: auth_header = r.headers[u_header].encode('utf-8') del r.headers[u_header] r.headers['Authorization'] = auth_header - return r + return r class HTTPBasicAuth(AuthBase): @@ -131,91 +148,101 @@ class HTTPDigestAuth(AuthBase): def __init__(self, username, password): self.username = username self.password = password + self.last_nonce = '' + self.nonce_count = 0 + self.chal = {} + + def build_digest_header(self, method, url): + + realm = self.chal['realm'] + nonce = self.chal['nonce'] + qop = self.chal.get('qop') + algorithm = self.chal.get('algorithm', 'MD5') + opaque = self.chal.get('opaque', None) + + algorithm = algorithm.upper() + # lambdas assume digest modules are imported at the top level + if algorithm == 'MD5': + def md5_utf8(x): + if isinstance(x, str): + x = x.encode('utf-8') + return hashlib.md5(x).hexdigest() + hash_utf8 = md5_utf8 + elif algorithm == 'SHA': + def sha_utf8(x): + if isinstance(x, str): + x = x.encode('utf-8') + return hashlib.sha1(x).hexdigest() + hash_utf8 = sha_utf8 + # XXX MD5-sess + KD = lambda s, d: hash_utf8("%s:%s" % (s, d)) + + if hash_utf8 is None: + return None + + # XXX not implemented yet + entdig = None + p_parsed = urlparse(url) + path = p_parsed.path + if p_parsed.query: + path += '?' + p_parsed.query + + A1 = '%s:%s:%s' % (self.username, realm, self.password) + A2 = '%s:%s' % (method, path) + + if qop == 'auth': + if nonce == self.last_nonce: + self.nonce_count += 1 + else: + self.nonce_count = 1 + + ncvalue = '%08x' % self.nonce_count + s = str(self.nonce_count).encode('utf-8') + s += nonce.encode('utf-8') + s += time.ctime().encode('utf-8') + s += os.urandom(8) + + cnonce = (hashlib.sha1(s).hexdigest()[:16]) + noncebit = "%s:%s:%s:%s:%s" % (nonce, ncvalue, cnonce, qop, hash_utf8(A2)) + respdig = KD(hash_utf8(A1), noncebit) + elif qop is None: + respdig = KD(hash_utf8(A1), "%s:%s" % (nonce, hash_utf8(A2))) + else: + # XXX handle auth-int. + return None + + self.last_nonce = nonce + + # XXX should the partial digests be encoded too? + base = 'username="%s", realm="%s", nonce="%s", uri="%s", ' \ + 'response="%s"' % (self.username, realm, nonce, path, respdig) + if opaque: + base += ', opaque="%s"' % opaque + if entdig: + base += ', digest="%s"' % entdig + base += ', algorithm="%s"' % algorithm + if qop: + base += ', qop=auth, nc=%s, cnonce="%s"' % (ncvalue, cnonce) + + return 'Digest %s' % (base) def handle_401(self, r): """Takes the given response and tries digest-auth, if needed.""" - r.request.deregister_hook('response', self.handle_401) + num_401_calls = r.request.hooks['response'].count(self.handle_401) s_auth = r.headers.get('www-authenticate', '') - if 'digest' in s_auth.lower(): + if 'digest' in s_auth.lower() and num_401_calls < 2: - last_nonce = '' - nonce_count = 0 + self.chal = parse_dict_header(s_auth.replace('Digest ', '')) - chal = parse_dict_header(s_auth.replace('Digest ', '')) + # Consume content and release the original connection + # to allow our new request to reuse the same one. + r.content + r.raw.release_conn() - realm = chal['realm'] - nonce = chal['nonce'] - qop = chal.get('qop') - algorithm = chal.get('algorithm', 'MD5') - opaque = chal.get('opaque', None) - - algorithm = algorithm.upper() - # lambdas assume digest modules are imported at the top level - if algorithm == 'MD5': - def md5_utf8(x): - if isinstance(x, str): - x = x.encode('utf-8') - return hashlib.md5(x).hexdigest() - hash_utf8 = md5_utf8 - elif algorithm == 'SHA': - def sha_utf8(x): - if isinstance(x, str): - x = x.encode('utf-8') - return hashlib.sha1(x).hexdigest() - hash_utf8 = sha_utf8 - # XXX MD5-sess - KD = lambda s, d: hash_utf8("%s:%s" % (s, d)) - - if hash_utf8 is None: - return None - - # XXX not implemented yet - entdig = None - p_parsed = urlparse(r.request.url) - path = p_parsed.path - if p_parsed.query: - path += '?' + p_parsed.query - - A1 = '%s:%s:%s' % (self.username, realm, self.password) - A2 = '%s:%s' % (r.request.method, path) - - if qop == 'auth': - if nonce == last_nonce: - nonce_count += 1 - else: - nonce_count = 1 - last_nonce = nonce - - ncvalue = '%08x' % nonce_count - s = str(nonce_count).encode('utf-8') - s += nonce.encode('utf-8') - s += time.ctime().encode('utf-8') - s += os.urandom(8) - - cnonce = (hashlib.sha1(s).hexdigest()[:16]) - noncebit = "%s:%s:%s:%s:%s" % (nonce, ncvalue, cnonce, qop, hash_utf8(A2)) - respdig = KD(hash_utf8(A1), noncebit) - elif qop is None: - respdig = KD(hash_utf8(A1), "%s:%s" % (nonce, hash_utf8(A2))) - else: - # XXX handle auth-int. - return None - - # XXX should the partial digests be encoded too? - base = 'username="%s", realm="%s", nonce="%s", uri="%s", ' \ - 'response="%s"' % (self.username, realm, nonce, path, respdig) - if opaque: - base += ', opaque="%s"' % opaque - if entdig: - base += ', digest="%s"' % entdig - base += ', algorithm="%s"' % algorithm - if qop: - base += ', qop=auth, nc=%s, cnonce="%s"' % (ncvalue, cnonce) - - r.request.headers['Authorization'] = 'Digest %s' % (base) + r.request.headers['Authorization'] = self.build_digest_header(r.request.method, r.request.url) r.request.send(anyway=True) _r = r.request.response _r.history.append(r) @@ -225,5 +252,131 @@ class HTTPDigestAuth(AuthBase): return r def __call__(self, r): + # If we have a saved nonce, skip the 401 + if self.last_nonce: + r.headers['Authorization'] = self.build_digest_header(r.method, r.url) r.register_hook('response', self.handle_401) return r + + +def _negotiate_value(r): + """Extracts the gssapi authentication token from the appropriate header""" + + authreq = r.headers.get('www-authenticate', None) + + if authreq: + rx = re.compile('(?:.*,)*\s*Negotiate\s*([^,]*),?', re.I) + mo = rx.search(authreq) + if mo: + return mo.group(1) + + return None + + +class HTTPKerberosAuth(AuthBase): + """Attaches HTTP GSSAPI/Kerberos Authentication to the given Request object.""" + def __init__(self, require_mutual_auth=True): + if k is None: + raise Exception("Kerberos libraries unavailable") + self.context = None + self.require_mutual_auth = require_mutual_auth + + def generate_request_header(self, r): + """Generates the gssapi authentication token with kerberos""" + + host = urlparse(r.url).netloc + tail, _, head = host.rpartition(':') + domain = tail if tail else head + + result, self.context = k.authGSSClientInit("HTTP@%s" % domain) + + if result < 1: + raise Exception("authGSSClientInit failed") + + result = k.authGSSClientStep(self.context, _negotiate_value(r)) + + if result < 0: + raise Exception("authGSSClientStep failed") + + response = k.authGSSClientResponse(self.context) + + return "Negotiate %s" % response + + def authenticate_user(self, r): + """Handles user authentication with gssapi/kerberos""" + + auth_header = self.generate_request_header(r) + log.debug("authenticate_user(): Authorization header: %s" % auth_header) + r.request.headers['Authorization'] = auth_header + r.request.send(anyway=True) + _r = r.request.response + _r.history.append(r) + log.debug("authenticate_user(): returning %s" % _r) + return _r + + def handle_401(self, r): + """Handles 401's, attempts to use gssapi/kerberos authentication""" + + log.debug("handle_401(): Handling: 401") + if _negotiate_value(r) is not None: + _r = self.authenticate_user(r) + log.debug("handle_401(): returning %s" % _r) + return _r + else: + log.debug("handle_401(): Kerberos is not supported") + log.debug("handle_401(): returning %s" % r) + return r + + def handle_other(self, r): + """Handles all responses with the exception of 401s. + + This is necessary so that we can authenticate responses if requested""" + + log.debug("handle_other(): Handling: %d" % r.status_code) + self.deregister(r) + if self.require_mutual_auth: + if _negotiate_value(r) is not None: + log.debug("handle_other(): Authenticating the server") + _r = self.authenticate_server(r) + log.debug("handle_other(): returning %s" % _r) + return _r + else: + log.error("handle_other(): Mutual authentication failed") + raise Exception("Mutual authentication failed") + else: + log.debug("handle_other(): returning %s" % r) + return r + + def authenticate_server(self, r): + """Uses GSSAPI to authenticate the server""" + + log.debug("authenticate_server(): Authenticate header: %s" % _negotiate_value(r)) + result = k.authGSSClientStep(self.context, _negotiate_value(r)) + if result < 1: + raise Exception("authGSSClientStep failed") + _r = r.request.response + log.debug("authenticate_server(): returning %s" % _r) + return _r + + def handle_response(self, r): + """Takes the given response and tries kerberos-auth, as needed.""" + + if r.status_code == 401: + _r = self.handle_401(r) + log.debug("handle_response returning %s" % _r) + return _r + else: + _r = self.handle_other(r) + log.debug("handle_response returning %s" % _r) + return _r + + log.debug("handle_response returning %s" % r) + return r + + def deregister(self, r): + """Deregisters the response handler""" + r.request.deregister_hook('response', self.handle_response) + + def __call__(self, r): + r.register_hook('response', self.handle_response) + return r diff --git a/libs/requests/cacert.pem b/libs/requests/cacert.pem new file mode 100644 index 00000000..7da84474 --- /dev/null +++ b/libs/requests/cacert.pem @@ -0,0 +1,3338 @@ +## +## ca-bundle.crt -- Bundle of CA Root Certificates +## +## Certificate data from Mozilla as of: Wed Jan 18 00:04:16 2012 +## +## This is a bundle of X.509 certificates of public Certificate Authorities +## (CA). These were automatically extracted from Mozilla's root certificates +## file (certdata.txt). This file can be found in the mozilla source tree: +## http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1 +## +## It contains the certificates in PEM format and therefore +## can be directly used with curl / libcurl / php_curl, or with +## an Apache+mod_ssl webserver for SSL client authentication. +## Just configure this file as the SSLCACertificateFile. +## + +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape security libraries. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1994-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +# @(#) $RCSfile: certdata.txt,v $ $Revision: 1.81 $ $Date: 2012/01/17 22:02:37 $ + +GTE CyberTrust Global Root +========================== +-----BEGIN CERTIFICATE----- +MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg +Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEG +A1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEz +MjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQL +Ex5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0 +IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4u +sJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcql +HHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQID +AQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMW +M4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OF +NMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ +-----END CERTIFICATE----- + +Thawte Server CA +================ +-----BEGIN CERTIFICATE----- +MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT +DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs +dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UE +AxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5j +b20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNV +BAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29u +c3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcG +A1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 +ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl +/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg7 +1CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzAR +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9J +GubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZ +GCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc= +-----END CERTIFICATE----- + +Thawte Premium Server CA +======================== +-----BEGIN CERTIFICATE----- +MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT +DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs +dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE +AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl +ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT +AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU +VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2 +aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ +cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2 +aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh +Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/ +qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm +SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf +8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t +UCemDaYj+bvLpgcUQg== +-----END CERTIFICATE----- + +Equifax Secure CA +================= +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE +ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT +B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR +fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW +8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG +A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE +CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG +A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS +spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB +Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961 +zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB +BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95 +70+sB3c4 +-----END CERTIFICATE----- + +Digital Signature Trust Co. Global CA 1 +======================================= +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE +ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMTAeFw05ODEy +MTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs +IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUA +A4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJE +NySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2i +o74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo +BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0 +dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw +IoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQY +MBaAFGp5fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAM +BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB +ACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lNQseSJqBcNJo4cvj9axY+IO6CizEq +kzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4 +RbyhkwS7hp86W0N6w4pl +-----END CERTIFICATE----- + +Digital Signature Trust Co. Global CA 3 +======================================= +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE +ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMjAeFw05ODEy +MDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs +IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUA +A4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGOD +VvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JS +xhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo +BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0 +dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw +IoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQY +MBaAFB6CTShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAM +BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB +AEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHRxdf0CiUPPXiBng+xZ8SQTGPdXqfi +up/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1 +mPnHfxsb1gYgAlihw6ID +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority +======================================================= +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVow +XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 +f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol +hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtMEivPLCYA +TxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59Ah +WM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2Omuf +Tqj/ZA1k +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority - G2 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO +FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71 +lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB +MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT +1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD +Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9 +-----END CERTIFICATE----- + +GlobalSign Root CA +================== +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx +GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds +b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD +VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa +DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc +THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb +Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP +c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX +gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF +AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj +Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG +j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH +hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC +X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +GlobalSign Root CA - R2 +======================= +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6 +ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp +s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN +S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL +TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C +ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i +YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN +BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp +9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu +01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7 +9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- + +ValiCert Class 1 VA +=================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIy +MjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIi +GQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCm +DuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwG +lN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8sogTLDAHkY7FkX +icnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPwnXS3qT6gpf+2SQMT2iLM7XGCK5nP +Orf1LXLI +-----END CERTIFICATE----- + +ValiCert Class 2 VA +=================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw +MTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVC +CSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7Rf +ZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZ +SWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbV +UjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8 +W9ViH0Pd +-----END CERTIFICATE----- + +RSA Root Certificate 1 +====================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw +MjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td +3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89H +BFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs +3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0WuPIqpsHEzXcjF +V9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5r +on+jjBXu +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1 +EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc +cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw +EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj +055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f +j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC +/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0 +xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa +t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----END CERTIFICATE----- + +Verisign Class 4 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS +tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM +8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW +Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX +Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt +mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm +fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd +RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG +UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== +-----END CERTIFICATE----- + +Entrust.net Secure Server CA +============================ +-----BEGIN CERTIFICATE----- +MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDASBgNV +BAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkg +cmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRl +ZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIG +A1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBi +eSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1p +dGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQ +aO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5 +gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcw +ggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHYpIHVMIHSMQsw +CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5l +dC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF +bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu +dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkw +NTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0Bow +HQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA +BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyN +Ewr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9 +n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= +-----END CERTIFICATE----- + +Entrust.net Premium 2048 Secure Server CA +========================================= +-----BEGIN CERTIFICATE----- +MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u +ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp +bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV +BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx +NzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 +d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl +MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u +ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL +Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr +hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW +nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi +VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo3QwcjARBglghkgBhvhC +AQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdER +gL7YibkIozH5oSQJFrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B +AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo +oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQh7A6tcOdBTcS +o8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z +2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjX +OP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ== +-----END CERTIFICATE----- + +Baltimore CyberTrust Root +========================= +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE +ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li +ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC +SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs +dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME +uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB +UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C +G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 +XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr +l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI +VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB +BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh +cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 +hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa +Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H +RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +Equifax Secure Global eBusiness CA +================================== +-----BEGIN CERTIFICATE----- +MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp +bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx +HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds +b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV +PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN +qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn +hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j +BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs +MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN +I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY +NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV +-----END CERTIFICATE----- + +Equifax Secure eBusiness CA 1 +============================= +-----BEGIN CERTIFICATE----- +MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +RXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENB +LTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UE +ChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNz +IENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ +1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4a +IZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBk +MBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kW +Nl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQF +AAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5 +lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+ +KpYrtWKmpj29f5JZzVoqgrI3eQ== +-----END CERTIFICATE----- + +Equifax Secure eBusiness CA 2 +============================= +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEXMBUGA1UE +ChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y +MB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoT +DkVxdWlmYXggU2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn +2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5 +BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAG +A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUx +JjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoG +A1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9e +uSBIplBqy/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMB +Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAAyGgq3oThr1 +jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia +78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUm +V+GRMOrN +-----END CERTIFICATE----- + +AddTrust Low-Value Services Root +================================ +-----BEGIN CERTIFICATE----- +MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU +cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw +CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO +ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6 +54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr +oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1 +Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui +GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w +HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT +RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw +HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt +ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph +iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY +eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr +mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj +ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= +-----END CERTIFICATE----- + +AddTrust External Root +====================== +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD +VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw +NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU +cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg +Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821 ++iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw +Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo +aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy +2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7 +7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL +VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk +VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB +IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl +j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355 +e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u +G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +-----END CERTIFICATE----- + +AddTrust Public Services Root +============================= +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU +cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ +BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l +dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu +nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i +d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG +Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw +HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G +A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux +FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G +A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4 +JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL ++YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao +GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9 +Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H +EufOX1362KqxMy3ZdvJOOjMMK7MtkAY= +-----END CERTIFICATE----- + +AddTrust Qualified Certificates Root +==================================== +-----BEGIN CERTIFICATE----- +MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU +cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx +CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ +IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx +64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3 +KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o +L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR +wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU +MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE +BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y +azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG +GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X +dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze +RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB +iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE= +-----END CERTIFICATE----- + +Entrust Root Certification Authority +==================================== +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw +b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG +A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 +MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu +MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu +Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v +dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz +A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww +Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 +j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN +rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 +MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH +hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM +Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa +v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS +W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 +tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +RSA Security 2048 v3 +==================== +-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK +ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy +MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb +BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7 +Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb +WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH +KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP ++Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/ +MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E +FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY +v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj +0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj +VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395 +nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA +pKnXwiJPZ9d37CAFYd4= +-----END CERTIFICATE----- + +GeoTrust Global CA +================== +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw +MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j +LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo +BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet +8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc +T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU +vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk +DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q +zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4 +d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2 +mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p +XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm +Mw== +-----END CERTIFICATE----- + +GeoTrust Global CA 2 +==================== +-----BEGIN CERTIFICATE----- +MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw +MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j +LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/ +NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k +LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA +Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b +HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH +K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7 +srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh +ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL +OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC +x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF +H4z1Ir+rzoPz4iIprn2DQKi6bA== +-----END CERTIFICATE----- + +GeoTrust Universal CA +===================== +-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1 +MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu +Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t +JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e +RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs +7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d +8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V +qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga +Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB +Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu +KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08 +ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0 +XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB +hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2 +qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL +oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK +xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF +KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2 +DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK +xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU +p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI +P/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE----- + +GeoTrust Universal CA 2 +======================= +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0 +MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg +SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0 +DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17 +j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q +JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a +QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2 +WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP +20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn +ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC +SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG +8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2 ++/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E +BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ +4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+ +mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq +A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg +Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP +pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d +FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp +gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm +X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE----- + +America Online Root Certification Authority 1 +============================================= +-----BEGIN CERTIFICATE----- +MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkG +A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg +T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CG +v2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44z +DyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145LcxVR5lu9Rh +sCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP +8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Z +o/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEf +GDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrF +VL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft +3OJvx8Fi8eNy1gTIdGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g +Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds +sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 +-----END CERTIFICATE----- + +America Online Root Certification Authority 2 +============================================= +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkG +A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg +T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC206B89en +fHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8 +f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE18aO6lhO +qKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JN +RvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0 +gBe4lL8BPeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn +6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9W6Wa6897Gqid +FEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZo2C7HK2JNDJiuEMhBnIMoVxtRsX6 +Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnj +B453cMor9H124HhnAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op +aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmnxPBUlgtk87FY +T15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p ++DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXg +JXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//Zoy +zH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgO +ZtMADjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh +1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZZLF0Kjhf +GEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y3WRayhgoPmMEEf0cjQAPuDff +Z4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuP +cX/9XhmgD0uRuMRUvAawRY8mkaKO/qk= +-----END CERTIFICATE----- + +Visa eCommerce Root +=================== +-----BEGIN CERTIFICATE----- +MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG +EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug +QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2 +WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm +VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv +bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL +F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b +RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0 +TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI +/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs +GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG +MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc +CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW +YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz +zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu +YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt +398znM/jra6O1I7mT1GvFpLgXPYHDw== +-----END CERTIFICATE----- + +Certum Root CA +============== +-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK +ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla +Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u +by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x +wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL +kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ +89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K +Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P +NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+ +GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg +GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/ +0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS +qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw== +-----END CERTIFICATE----- + +Comodo AAA Services root +======================== +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw +MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl +c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV +BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG +C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs +i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW +Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH +Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK +Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f +BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl +cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz +LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm +7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z +8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C +12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +Comodo Secure Services root +=========================== +-----BEGIN CERTIFICATE----- +MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw +MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu +Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi +BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP +9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc +rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC +oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V +p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E +FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w +gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj +YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm +aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm +4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj +Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL +DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw +pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H +RR3B7Hzs/Sk= +-----END CERTIFICATE----- + +Comodo Trusted Services root +============================ +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw +MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h +bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw +IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7 +3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y +/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6 +juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS +ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud +DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp +ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl +cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw +uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 +pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA +BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l +R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O +9y5Xt5hwXsjEeLBi +-----END CERTIFICATE----- + +QuoVadis Root CA +================ +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE +ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz +MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp +cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD +EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk +J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL +F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL +YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen +AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w +PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y +ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7 +MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj +YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs +ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW +Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu +BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw +FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6 +tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo +fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul +LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x +gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi +5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi +5nrQNiOKSnQ2+Q== +-----END CERTIFICATE----- + +QuoVadis Root CA 2 +================== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +QuoVadis Root CA 3 +================== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +Security Communication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw +8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM +DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX +5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd +DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 +JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g +0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a +mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ +s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ +6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi +FL39vmwLAw== +-----END CERTIFICATE----- + +Sonera Class 2 Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG +U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw +NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh +IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3 +/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT +dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG +f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P +tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH +nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT +XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt +0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI +cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph +Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx +EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH +llpwrN9M +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA +============================= +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE +ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g +Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w +HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh +bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt +vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P +jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca +C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth +vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6 +22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV +HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v +dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN +BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR +EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw +MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y +nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR +iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== +-----END CERTIFICATE----- + +UTN DATACorp SGC Root CA +======================== +-----BEGIN CERTIFICATE----- +MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ +BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa +MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w +HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy +dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys +raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo +wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA +9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv +33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud +DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9 +BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD +LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3 +DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft +Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0 +I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx +EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP +DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI +-----END CERTIFICATE----- + +UTN USERFirst Hardware Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd +BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx +OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0 +eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz +ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI +wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd +tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8 +i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf +Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw +gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF +lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF +UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF +BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM +//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW +XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2 +lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn +iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67 +nfhmqA== +-----END CERTIFICATE----- + +Camerfirma Chambers of Commerce Root +==================================== +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe +QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i +ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx +NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp +cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn +MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC +AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU +xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH +NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW +DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV +d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud +EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v +cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P +AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh +bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD +VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz +aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi +fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD +L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN +UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n +ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1 +erfutGWaIZDgqtCYvDi1czyL+Nw= +-----END CERTIFICATE----- + +Camerfirma Global Chambersign Root +================================== +-----BEGIN CERTIFICATE----- +MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe +QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i +ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx +NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt +YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg +MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw +ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J +1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O +by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl +6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c +8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/ +BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j +aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B +Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj +aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y +ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh +bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA +PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y +gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ +PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4 +IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes +t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== +-----END CERTIFICATE----- + +NetLock Notary (Class A) Root +============================= +-----BEGIN CERTIFICATE----- +MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI +EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 +dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j +ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX +DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH +EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD +VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz +cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM +D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ +z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC +/tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7 +tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6 +4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG +A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC +Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv +bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu +IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn +LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0 +ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz +IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh +IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu +b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh +bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg +Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp +bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5 +ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP +ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB +CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr +KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM +8CgHrTwXZoi1/baI +-----END CERTIFICATE----- + +NetLock Business (Class B) Root +=============================== +-----BEGIN CERTIFICATE----- +MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUxETAPBgNVBAcT +CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV +BAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikg +VGFudXNpdHZhbnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYD +VQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRv +bnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5ldExvY2sg +VXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2S +o/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr +1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV +HQ8BAf8EBAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZ +RUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRh +dGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0 +ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRv +c2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUg +YXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh +c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBz +Oi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNA +bmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhl +IHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2 +YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBj +cHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06sPgzTEdM +43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXan3BukxowOR0w2y7jfLKR +stE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgBazMpUIaD8QFI +-----END CERTIFICATE----- + +NetLock Express (Class C) Root +============================== +-----BEGIN CERTIFICATE----- +MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUxETAPBgNVBAcT +CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV +BAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBD +KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJ +BgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 +dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMrTmV0TG9j +ayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzANBgkqhkiG9w0BAQEFAAOB +jQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNAOoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3Z +W3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63 +euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQw +DgYDVR0PAQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJN +RklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxhbm9zIFN6b2xn +YWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBB +IGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1i +aXp0b3NpdGFzYSB2ZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0 +ZWxlIGF6IGVsb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs +ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25sYXBqYW4gYSBo +dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9y +emVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5k +IHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQ +UyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwg +YXQgY3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmYta3UzbM2 +xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2gpO0u9f38vf5NNwgMvOOW +gyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeAyNDYpQcCNJgEjTME1A== +-----END CERTIFICATE----- + +XRamp Global CA Root +==================== +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE +BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj +dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx +HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg +U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu +IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx +foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE +zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs +AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry +xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap +oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC +AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc +/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n +nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz +8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +Go Daddy Class 2 CA +=================== +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY +VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG +A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g +RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD +ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv +2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 +qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j +YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY +vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O +BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o +atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu +MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim +PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt +I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI +Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b +vZ8= +-----END CERTIFICATE----- + +Starfield Class 2 CA +==================== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc +U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo +MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG +A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG +SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY +bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ +JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm +epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN +F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF +MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f +hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo +bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs +afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM +PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD +KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 +QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +StartCom Certification Authority +================================ +-----BEGIN CERTIFICATE----- +MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu +ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 +NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk +LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg +U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y +o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ +Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d +eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt +2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z +6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ +osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ +untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc +UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT +37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE +FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0 +Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj +YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH +AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw +Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg +U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5 +LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh +cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT +dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC +AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh +3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm +vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk +fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3 +fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ +EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq +yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl +1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/ +lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro +g14= +-----END CERTIFICATE----- + +Taiwan GRCA +=========== +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG +EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X +DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv +dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN +w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5 +BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O +1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO +htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov +J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7 +Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t +B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB +O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8 +lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV +HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2 +09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ +TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj +Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2 +Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU +D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz +DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk +Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk +7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ +CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy ++fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS +-----END CERTIFICATE----- + +Firmaprofesional Root CA +======================== +-----BEGIN CERTIFICATE----- +MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMxIjAgBgNVBAcT +GUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1dG9yaWRhZCBkZSBDZXJ0aWZp +Y2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FA +ZmlybWFwcm9mZXNpb25hbC5jb20wHhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTEL +MAkGA1UEBhMCRVMxIjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMT +OUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2 +ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20wggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5uCp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5V +j1H5WuretXDE7aTt/6MNbg9kUDGvASdYrv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJH +lShbz++AbOCQl4oBPB3zhxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf +3H5idPayBQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcLiam8 +NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcbAgMBAAGjgZ8wgZww +KgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lvbmFsLmNvbTASBgNVHRMBAf8ECDAG +AQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQAD +ggEBAEdz/o0nVPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq +u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36mhoEyIwOdyPdf +wUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzflZKG+TQyTmAyX9odtsz/ny4Cm +7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBpQWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YG +VM+h4k0460tQtcsm9MracEpqoeJ5quGnM/b9Sh/22WA= +-----END CERTIFICATE----- + +Wells Fargo Root CA +=================== +-----BEGIN CERTIFICATE----- +MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMCVVMxFDASBgNV +BAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN +MDAxMDExMTY0MTI4WhcNMjEwMTE0MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dl +bGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEv +MC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n135zHCLielTWi5MbqNQ1mX +x3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHESxP9cMIlrCL1dQu3U+SlK93OvRw6esP3 +E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4OJgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5 +OEL8pahbSCOz6+MlsoCultQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4j +sNtlAHCEAQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMBAAGj +YTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcBCzAyMDAGCCsGAQUF +BwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRwb2xpY3kwDQYJKoZIhvcNAQEFBQAD +ggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrv +m+0fazbuSCUlFLZWohDo7qd/0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0R +OhPs7fpvcmR7nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx +x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ33ZwmVxwQ023 +tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s= +-----END CERTIFICATE----- + +Swisscom Root CA 1 +================== +-----BEGIN CERTIFICATE----- +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 +NY6E0F/6MBr1mmz0DlP5OlvRHA== +-----END CERTIFICATE----- + +DigiCert Assured ID Root CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx +MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO +9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy +UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW +/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy +oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf +GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF +66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq +hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc +EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn +SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i +8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +DigiCert Global Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw +MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn +TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 +BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H +4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y +7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB +o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm +8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF +BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr +EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt +tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 +UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +DigiCert High Assurance EV Root CA +================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw +KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw +MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ +MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu +Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t +Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS +OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 +MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ +NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe +h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY +JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ +V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp +myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK +mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K +-----END CERTIFICATE----- + +Certplus Class 2 Primary CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE +BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN +OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy +dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR +5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ +Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO +YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e +e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME +CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ +YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t +L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD +P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R +TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+ +7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW +//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 +l7+ijrRU +-----END CERTIFICATE----- + +DST Root CA X3 +============== +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK +ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X +DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1 +cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT +rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9 +UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy +xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d +utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ +MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug +dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE +GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw +RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS +fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- + +DST ACES CA X6 +============== +-----BEGIN CERTIFICATE----- +MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT +MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha +MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE +CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI +DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa +pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow +GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy +MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu +Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy +dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU +CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2 +5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t +Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq +nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs +vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3 +oKfN5XozNmr6mis= +-----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 1 +============================================== +-----BEGIN CERTIFICATE----- +MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEP +MA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0 +acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMx +MDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsg +U2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZB +TktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBC +aWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GX +yGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8i +Si9BB35JYbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ +8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4 +W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRME +BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46 +sWrv7/hg0Uw2ZkUd82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE +q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy +B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgY +nNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H +-----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 2 +============================================== +-----BEGIN CERTIFICATE----- +MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP +MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg +QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN +MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr +dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G +A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls +acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe +LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI +x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g +QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr +5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB +AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt +Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 +Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+ +hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P +9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5 +UrbnBEI= +-----END CERTIFICATE----- + +SwissSign Gold CA - G2 +====================== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +SwissSign Silver CA - G2 +======================== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority +======================================== +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx +CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ +cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN +b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9 +nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge +RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt +tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI +hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K +Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN +NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa +Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG +1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- + +thawte Primary Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE +BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 +aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3 +MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg +SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv +KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT +FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs +oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ +1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc +q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K +aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p +afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF +AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE +uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89 +jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH +z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G5 +============================================================ +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO +ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk +IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln +biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh +dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz +j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD +Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ +Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r +fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/ +BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv +Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG +SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+ +X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE +KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC +Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE +ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- + +SecureTrust CA +============== +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy +dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe +BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX +OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t +DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH +GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b +01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH +ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj +aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu +SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf +mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ +nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +Secure Global CA +================ +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH +bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg +MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg +Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx +YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ +bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g +8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV +HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi +0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn +oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA +MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ +OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn +CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 +3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +COMODO Certification Authority +============================== +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb +MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD +T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH ++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww +xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV +4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA +1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI +rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k +b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC +AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP +OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc +IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN ++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== +-----END CERTIFICATE----- + +Network Solutions Certificate Authority +======================================= +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG +EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr +IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx +MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx +jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT +aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT +crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc +/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB +AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv +bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA +A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q +4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/ +GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD +ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- + +WellsSecure Public Root Certificate Authority +============================================= +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM +F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw +NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN +MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl +bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD +VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1 +iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13 +i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8 +bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB +K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB +AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu +cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm +lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB +i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww +GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI +K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0 +bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj +qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es +E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ +tylv2G0xffX8oRAHh84vWdw+WNs= +-----END CERTIFICATE----- + +COMODO ECC Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix +GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X +4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni +wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG +FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA +U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +IGC/A +===== +-----BEGIN CERTIFICATE----- +MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD +VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE +Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy +MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI +EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT +STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2 +TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW +So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy +HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd +frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ +tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB +egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC +iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK +q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q +MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg +Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI +lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF +0mBWWg== +-----END CERTIFICATE----- + +Security Communication EV RootCA1 +================================= +-----BEGIN CERTIFICATE----- +MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE +BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl +Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO +/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX +WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z +ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4 +bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK +9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG +SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm +iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG +Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW +mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW +T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GA CA +=============================== +-----BEGIN CERTIFICATE----- +MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE +BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG +A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH +bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD +VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw +IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5 +IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9 +Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg +Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD +d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ +/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R +LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm +MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4 ++vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa +hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY +okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0= +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA +========================= +-----BEGIN CERTIFICATE----- +MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE +BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL +EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0 +MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz +dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT +GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG +d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N +oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc +QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ +PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb +MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG +IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD +VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3 +LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A +dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn +AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA +4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg +AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA +egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6 +Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO +PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv +c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h +cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw +IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT +WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV +MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER +MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp +Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal +HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT +nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE +aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a +86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK +yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB +S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU= +-----END CERTIFICATE----- + +Certigna +======== +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw +EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 +MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI +Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q +XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH +GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p +ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg +DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf +Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ +tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ +BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J +SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA +hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ +ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu +PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY +1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +AC Ra\xC3\xADz Certic\xC3\xA1mara S.A. +====================================== +-----BEGIN CERTIFICATE----- +MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNVBAYT +AkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRpZmljYWNpw7NuIERpZ2l0YWwg +LSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwaQUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4w +HhcNMDYxMTI3MjA0NjI5WhcNMzAwNDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+ +U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJh +IFMuQS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeGqentLhM0R7LQcNzJPNCN +yu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzLfDe3fezTf3MZsGqy2IiKLUV0qPezuMDU +2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQY5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU3 +4ojC2I+GdV75LaeHM/J4Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP +2yYe68yQ54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+bMMCm +8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48jilSH5L887uvDdUhf +HjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++EjYfDIJss2yKHzMI+ko6Kh3VOz3vCa +Mh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/ztA/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK +5lw1omdMEWux+IBkAC1vImHFrEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1b +czwmPS9KvqfJpxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE +AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCBlTCBkgYEVR0g +ADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFyYS5jb20vZHBjLzBaBggrBgEF +BQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2Ug +cHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEf +AygPU3zmpFmps4p6xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuX +EpBcunvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/Jre7Ir5v +/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dpezy4ydV/NgIlqmjCMRW3 +MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42gzmRkBDI8ck1fj+404HGIGQatlDCIaR4 +3NAvO2STdPCWkPHv+wlaNECW8DYSwaN0jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wk +eZBWN7PGKX6jD/EpOe9+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f +/RWmnkJDW2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/RL5h +RqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35rMDOhYil/SrnhLecU +Iw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxkBYn8eNZcLCZDqQ== +-----END CERTIFICATE----- + +TC TrustCenter Class 2 CA II +============================ +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy +IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw +MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 +c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE +AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw +IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2 +xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ +Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u +SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB +7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 +Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU +cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i +SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G +dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ +KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj +TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP +JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk +vQ== +-----END CERTIFICATE----- + +TC TrustCenter Class 3 CA II +============================ +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy +IENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYw +MTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 +c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UE +AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJWHt4bNwcwIi9v8Qbxq63W +yKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+QVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo +6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZ +uV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk +2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB +7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 +Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU +cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i +SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzE +O2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8 +yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9 +IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal +092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc +5A== +-----END CERTIFICATE----- + +TC TrustCenter Universal CA I +============================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy +IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN +MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg +VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw +JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC +qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv +xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw +ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O +gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j +BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG +1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy +vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3 +ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT +ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a +7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY +-----END CERTIFICATE----- + +Deutsche Telekom Root CA 2 +========================== +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT +RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG +A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5 +MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G +A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS +b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5 +bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI +KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY +AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK +Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV +jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV +HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr +E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy +zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8 +rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G +dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU +Cm26OWMohpLzGITY+9HPBVZkVw== +-----END CERTIFICATE----- + +ComSign Secured CA +================== +-----BEGIN CERTIFICATE----- +MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkGA1UE +AxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0w +NDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBD +QTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs +49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sWv+bznkqH +7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ueMv5WJDmyVIRD9YTC2LxB +kMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d1 +9guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUw +AwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29t +U2lnblNlY3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsA +j8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOC +AQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3a +BijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtp +FhpFfTMDZflScZAmlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP +51qJThRv4zdLhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz +OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== +-----END CERTIFICATE----- + +Cybertrust Global Root +====================== +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li +ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4 +MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD +ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA ++Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW +0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL +AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin +89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT +8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2 +MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G +A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO +lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi +5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2 +hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T +X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW +WL1WMRJOEcgh4LMRkWXbtKaIOM5V +-----END CERTIFICATE----- + +ePKI Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG +EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx +MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq +MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs +IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi +lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv +qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX +12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O +WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ +ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao +lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ +vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi +Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi +MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 +1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq +KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV +xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP +NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r +GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE +xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx +gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy +sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD +BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3 +============================================================================================================================= +-----BEGIN CERTIFICATE----- +MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH +DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q +aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry +b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV +BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg +S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4 +MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl +IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF +n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl +IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft +dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl +cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO +Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1 +xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR +6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL +hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd +BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4 +N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT +y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh +LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M +dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI= +-----END CERTIFICATE----- + +Buypass Class 2 CA 1 +==================== +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2 +MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh +c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M +cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83 +0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4 +0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R +uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P +AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV +1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt +7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2 +fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w +wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho +-----END CERTIFICATE----- + +Buypass Class 3 CA 1 +==================== +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAxMB4XDTA1 +MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh +c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKx +ifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//zNIqeKNc0 +n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI+MkcVyzwPX6UvCWThOia +AJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2RhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c +1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0P +AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7 +pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bA +EllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5 +htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQj +el/wroQk5PMr+4okoyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 +-----END CERTIFICATE----- + +EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 +========================================================================== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +certSIGN ROOT CA +================ +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD +VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa +Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE +CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I +JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH +rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 +ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD +0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 +AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B +Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB +AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 +SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 +x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt +vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz +TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +CNNIC ROOT +========== +-----BEGIN CERTIFICATE----- +MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE +ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw +OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD +o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz +VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT +VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or +czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK +y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC +wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S +lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5 +Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM +O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8 +BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2 +G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m +mxE= +-----END CERTIFICATE----- + +ApplicationCA - Japanese Government +=================================== +-----BEGIN CERTIFICATE----- +MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT +SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw +MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl +cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4 +fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN +wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE +jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu +nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU +WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV +BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD +vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs +o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g +/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD +io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW +dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL +rosot4LKGAfmt1t06SAZf7IbiVQ= +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G3 +============================================= +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0 +IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz +NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo +YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT +LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j +K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE +c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C +IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu +dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr +2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9 +cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE +Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s +t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- + +thawte Primary Root CA - G2 +=========================== +-----BEGIN CERTIFICATE----- +MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC +VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu +IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg +Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV +MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG +b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt +IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS +LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5 +8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU +mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN +G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K +rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== +-----END CERTIFICATE----- + +thawte Primary Root CA - G3 +=========================== +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE +BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 +aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w +ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh +d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD +VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG +A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At +P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC ++BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY +7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW +vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ +KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK +A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu +t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC +8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm +er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A= +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G2 +============================================= +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu +Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1 +OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl +b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG +BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc +KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+ +EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m +ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2 +npaqBA+K +-----END CERTIFICATE----- + +VeriSign Universal Root Certification Authority +=============================================== +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO +ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk +IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj +1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP +MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72 +9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I +AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR +tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G +CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O +a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3 +Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx +Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx +P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P +wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4 +mJO37M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G4 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC +VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3 +b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz +ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU +cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo +b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8 +Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz +rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw +HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u +Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD +A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx +AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----END CERTIFICATE----- + +NetLock Arany (Class Gold) FÅ‘tanúsítvány +============================================ +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G +A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 +dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB +cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx +MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO +ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 +c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu +0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw +/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk +H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw +fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 +neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW +qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta +YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna +NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu +dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA - G2 +================================== +-----BEGIN CERTIFICATE----- +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 +66+KAQ== +-----END CERTIFICATE----- + +CA Disig +======== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK +QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw +MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz +bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm +GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD +Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo +hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt +ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w +gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P +AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz +aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff +ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa +BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t +WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3 +mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ +CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K +ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA +4Z7CRneC9VkGjCFMhwnN5ag= +-----END CERTIFICATE----- + +Juur-SK +======= +-----BEGIN CERTIFICATE----- +MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA +c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw +DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG +SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy +aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf +TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC ++Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw +UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa +Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF +MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD +HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh +AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA +cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr +AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw +cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE +FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G +A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo +ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL +abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678 +IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh +Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2 +yyqcjg== +-----END CERTIFICATE----- + +Hongkong Post Root CA 1 +======================= +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT +DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx +NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n +IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1 +ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr +auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh +qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY +V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV +HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i +h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio +l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei +IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps +T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT +c4afU9hDDl3WY4JxHYB0yvbiAmvZWg== +-----END CERTIFICATE----- + +SecureSign RootCA11 +=================== +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi +SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS +b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw +KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 +cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL +TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO +wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq +g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP +O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA +bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX +t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh +OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r +bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ +Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 +y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 +lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +ACEDICOM Root +============= +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority +======================================================= +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow +XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 +f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol +hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABByUqkFFBky +CEHwxWsKzH4PIRnN5GfcX6kb5sroc50i2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWX +bj9T/UWZYB2oK0z5XqcJ2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/ +D/xwzoiQ +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER +MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv +c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE +BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt +U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA +fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG +0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA +pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm +1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC +AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf +QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE +FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o +lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX +I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 +yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi +LXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi +=================================================== +-----BEGIN CERTIFICATE----- +MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG +EwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoGA1UEAxMz +ZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3 +MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0 +cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9u +aWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdUMZTe1RK6UxYC6lhj71vY +8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlTL/jDj/6z/P2douNffb7tC+Bg62nsM+3Y +jfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAI +JjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk +9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqG +SIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5d +F4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwq +D2fK/A+JYZ1lpTzlvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4 +Vwpm+Vganf2XKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq +fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX +-----END CERTIFICATE----- + +GlobalSign Root CA - R3 +======================= +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt +iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ +0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 +rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl +OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 +xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 +lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 +EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E +bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 +YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r +kpeDMdmztcpHWD9f +-----END CERTIFICATE----- + +TC TrustCenter Universal CA III +=============================== +-----BEGIN CERTIFICATE----- +MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy +IFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAe +Fw0wOTA5MDkwODE1MjdaFw0yOTEyMzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNU +QyBUcnVzdENlbnRlciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0Ex +KDAmBgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF5+cvAqBNLaT6hdqbJYUt +QCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYvDIRlzg9uwliT6CwLOunBjvvya8o84pxO +juT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8vzArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+Eut +CHnNaYlAJ/Uqwa1D7KRTyGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1 +M4BDj5yjdipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBhMB8G +A1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI4jANBgkqhkiG9w0BAQUFAAOCAQEA +g8ev6n9NCjw5sWi+e22JLumzCecYV42FmhfzdkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+ +KGwWaODIl0YgoGhnYIg5IFHYaAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhK +BgePxLcHsU0GDeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV +CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPHLQNjO9Po5KIq +woIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg== +-----END CERTIFICATE----- + +Autoridad de Certificacion Firmaprofesional CIF A62634068 +========================================================= +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA +BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 +MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw +QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB +NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD +Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P +B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY +7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH +ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI +plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX +MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX +LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK +bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU +vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud +EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH +DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA +bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx +ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx +51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk +R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP +T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f +Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl +osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR +crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR +saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD +KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi +6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- + +Izenpe.com +========== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +Chambers of Commerce Root - 2008 +================================ +-----BEGIN CERTIFICATE----- +MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD +MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv +bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu +QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy +Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl +ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF +EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl +cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA +XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj +h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/ +ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk +NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g +D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331 +lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ +0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj +ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2 +EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI +G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ +BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh +bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh +bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC +CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH +AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1 +wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH +3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU +RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6 +M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1 +YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF +9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK +zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG +nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg +OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ +-----END CERTIFICATE----- + +Global Chambersign Root - 2008 +============================== +-----BEGIN CERTIFICATE----- +MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD +MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv +bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu +QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx +NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg +Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ +QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD +aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf +VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf +XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0 +ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB +/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA +TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M +H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe +Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF +HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh +wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB +AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT +BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE +BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm +aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm +aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp +1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 +dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG +/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6 +ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s +dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg +9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH +foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du +qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr +P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq +c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z +09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B +-----END CERTIFICATE----- + +Go Daddy Root Certificate Authority - G2 +======================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu +MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G +A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq +9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD ++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd +fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl +NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 +BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac +vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r +5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV +N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 +-----END CERTIFICATE----- + +Starfield Root Certificate Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 +eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw +DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg +VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB +dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv +W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs +bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk +N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf +ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU +JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol +TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx +4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw +F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ +c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +Starfield Services Root Certificate Authority - G2 +================================================== +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl +IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT +dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 +h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa +hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP +LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB +rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG +SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP +E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy +xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza +YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 +-----END CERTIFICATE----- + +AffirmTrust Commercial +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw +MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb +DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV +C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 +BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww +MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV +HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG +hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi +qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv +0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh +sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +AffirmTrust Networking +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw +MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE +Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI +dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 +/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb +h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV +HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu +UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 +12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 +WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 +/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +AffirmTrust Premium +=================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy +OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy +dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn +BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV +5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs ++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd +GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R +p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI +S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 +6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 +/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo ++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv +MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC +6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S +L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK ++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV +BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg +IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 +g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb +zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== +-----END CERTIFICATE----- + +AffirmTrust Premium ECC +======================= +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV +BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx +MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U +cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ +N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW +BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK +BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X +57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM +eQ== +-----END CERTIFICATE----- + +Certum Trusted Network CA +========================= +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK +ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy +MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU +ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC +l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J +J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 +fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 +cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB +Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw +DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj +jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 +mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj +Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +Certinomis - Autorité Racine +============================= +-----BEGIN CERTIFICATE----- +MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK +Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg +LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG +A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw +JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa +wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly +Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw +2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N +jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q +c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC +lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb +xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g +530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna +4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ +KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x +WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva +R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40 +nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B +CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv +JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE +qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b +WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE +wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/ +vgt2Fl43N+bYdJeimUV5 +-----END CERTIFICATE----- + +Root CA Generalitat Valenciana +============================== +-----BEGIN CERTIFICATE----- +MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE +ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290 +IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3 +WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE +CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2 +F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B +ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ +D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte +JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB +AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n +dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB +ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl +AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA +YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy +AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA +aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt +AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA +YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu +AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA +OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0 +dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV +BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G +A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S +b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh +TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz +Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63 +NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH +iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt ++GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM= +-----END CERTIFICATE----- + +A-Trust-nQual-03 +================ +-----BEGIN CERTIFICATE----- +MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE +Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy +a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R +dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw +RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0 +ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1 +c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA +zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n +yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE +SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4 +iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V +cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV +eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40 +ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr +sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd +JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS +mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6 +ahq97BvIxYSazQ== +-----END CERTIFICATE----- + +TWCA Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ +VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG +EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB +IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx +QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC +oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP +4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r +y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG +9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC +mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW +QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY +T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny +Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +Security Communication RootCA2 +============================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC +SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy +aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ ++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R +3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV +spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K +EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 +QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB +CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj +u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk +3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q +tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 +mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +EC-ACC +====== +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE +BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w +ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD +VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE +CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT +BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7 +MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt +SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl +Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh +cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK +w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT +ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4 +HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a +E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw +0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD +VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0 +Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l +dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ +lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa +Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe +l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2 +E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D +5EI= +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2011 +======================================================= +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT +O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y +aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT +AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo +IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI +1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa +71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u +8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH +3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/ +MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8 +MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu +b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt +XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD +/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N +7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- diff --git a/libs/requests/certs.py b/libs/requests/certs.py new file mode 100644 index 00000000..42df2f89 --- /dev/null +++ b/libs/requests/certs.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +ceritfi.py +~~~~~~~~~~ + +This module returns the installation location of cacert.pem. +""" + +import os +try: + import certifi +except ImportError: + certifi = None + + +def where(): + + if certifi: + return certifi.where() + else: + f = os.path.split(__file__)[0] + return os.path.join(f, 'cacert.pem') + +if __name__ == '__main__': + print(where()) diff --git a/libs/requests/compat.py b/libs/requests/compat.py index 37063f58..351b7c6e 100644 --- a/libs/requests/compat.py +++ b/libs/requests/compat.py @@ -72,6 +72,10 @@ is_osx = ('darwin' in str(sys.platform).lower()) is_hpux = ('hpux' in str(sys.platform).lower()) # Complete guess. is_solaris = ('solar==' in str(sys.platform).lower()) # Complete guess. +try: + import simplejson as json +except ImportError: + import json # --------- # Specifics @@ -85,10 +89,17 @@ if is_py2: import cookielib from Cookie import Morsel from StringIO import StringIO + try: + import cchardet as chardet + except ImportError: + from .packages import chardet + from .packages.urllib3.packages.ordered_dict import OrderedDict + builtin_str = str bytes = str str = unicode basestring = basestring + numeric_types = (int, long, float) @@ -98,8 +109,11 @@ elif is_py3: from http import cookiejar as cookielib from http.cookies import Morsel from io import StringIO + from .packages import chardet2 as chardet + from collections import OrderedDict + builtin_str = str str = str bytes = bytes basestring = (str,bytes) - + numeric_types = (int, float) diff --git a/libs/requests/cookies.py b/libs/requests/cookies.py index 85726b06..101e617d 100644 --- a/libs/requests/cookies.py +++ b/libs/requests/cookies.py @@ -14,6 +14,7 @@ try: except ImportError: import dummy_threading as threading + class MockRequest(object): """Wraps a `requests.Request` to mimic a `urllib2.Request`. @@ -39,7 +40,7 @@ class MockRequest(object): def get_origin_req_host(self): if self._r.response.history: r = self._r.response.history[0] - return urlparse(r).netloc + return urlparse(r.url).netloc else: return self.get_host() @@ -66,6 +67,11 @@ class MockRequest(object): def get_new_headers(self): return self._new_headers + @property + def unverifiable(self): + return self.is_unverifiable() + + class MockResponse(object): """Wraps a `httplib.HTTPMessage` to mimic a `urllib.addinfourl`. @@ -86,6 +92,7 @@ class MockResponse(object): def getheaders(self, name): self._headers.getheaders(name) + def extract_cookies_to_jar(jar, request, response): """Extract the cookies from the response into a CookieJar. @@ -99,12 +106,14 @@ def extract_cookies_to_jar(jar, request, response): res = MockResponse(response._original_response.msg) jar.extract_cookies(res, req) + def get_cookie_header(jar, request): """Produce an appropriate Cookie header string to be sent with `request`, or None.""" r = MockRequest(request) jar.add_cookie_header(r) return r.get_new_headers().get('Cookie') + def remove_cookie_by_name(cookiejar, name, domain=None, path=None): """Unsets a cookie by name, by default over all domains and paths. @@ -120,10 +129,12 @@ def remove_cookie_by_name(cookiejar, name, domain=None, path=None): for domain, path, name in clearables: cookiejar.clear(domain, path, name) + class CookieConflictError(RuntimeError): - """There are two cookies that meet the criteria specified in the cookie jar. + """There are two cookies that meet the criteria specified in the cookie jar. Use .get and .set and include domain and path args in order to be more specific.""" + class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping): """Compatibility class; is a cookielib.CookieJar, but exposes a dict interface. @@ -181,7 +192,7 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping): for cookie in iter(self): values.append(cookie.value) return values - + def items(self): """Dict-like items() that returns a list of name-value tuples from the jar. See keys() and values(). Allows client-code to call "dict(RequestsCookieJar) @@ -215,14 +226,14 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping): if cookie.domain is not None and cookie.domain in domains: return True domains.append(cookie.domain) - return False # there is only one domain in jar + return False # there is only one domain in jar def get_dict(self, domain=None, path=None): """Takes as an argument an optional domain and path and returns a plain old Python dict of name-value pairs of cookies that meet the requirements.""" dictionary = {} for cookie in iter(self): - if (domain == None or cookie.domain == domain) and (path == None + if (domain == None or cookie.domain == domain) and (path == None or cookie.path == path): dictionary[cookie.name] = cookie.value return dictionary @@ -244,7 +255,7 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping): remove_cookie_by_name(self, name) def _find(self, name, domain=None, path=None): - """Requests uses this method internally to get cookie values. Takes as args name + """Requests uses this method internally to get cookie values. Takes as args name and optional domain and path. Returns a cookie.value. If there are conflicting cookies, _find arbitrarily chooses one. See _find_no_duplicates if you want an exception thrown if there are conflicting cookies.""" @@ -257,18 +268,18 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping): raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path)) def _find_no_duplicates(self, name, domain=None, path=None): - """__get_item__ and get call _find_no_duplicates -- never used in Requests internally. - Takes as args name and optional domain and path. Returns a cookie.value. - Throws KeyError if cookie is not found and CookieConflictError if there are + """__get_item__ and get call _find_no_duplicates -- never used in Requests internally. + Takes as args name and optional domain and path. Returns a cookie.value. + Throws KeyError if cookie is not found and CookieConflictError if there are multiple cookies that match name and optionally domain and path.""" toReturn = None for cookie in iter(self): if cookie.name == name: if domain is None or cookie.domain == domain: if path is None or cookie.path == path: - if toReturn != None: # if there are multiple cookies that meet passed in criteria + if toReturn != None: # if there are multiple cookies that meet passed in criteria raise CookieConflictError('There are multiple cookies with name, %r' % (name)) - toReturn = cookie.value # we will eventually return this as long as no cookie conflict + toReturn = cookie.value # we will eventually return this as long as no cookie conflict if toReturn: return toReturn @@ -291,6 +302,7 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping): """This is not implemented. Calling this will throw an exception.""" raise NotImplementedError + def create_cookie(name, value, **kwargs): """Make a cookie from underspecified parameters. @@ -326,6 +338,7 @@ def create_cookie(name, value, **kwargs): return cookielib.Cookie(**result) + def morsel_to_cookie(morsel): """Convert a Morsel object into a Cookie containing the one k/v pair.""" c = create_cookie( @@ -349,6 +362,7 @@ def morsel_to_cookie(morsel): ) return c + def cookiejar_from_dict(cookie_dict, cookiejar=None): """Returns a CookieJar from a key/value dictionary. diff --git a/libs/requests/defaults.py b/libs/requests/defaults.py index 41e279df..91d038bc 100644 --- a/libs/requests/defaults.py +++ b/libs/requests/defaults.py @@ -20,20 +20,19 @@ Configurations: :pool_connections: The number of active HTTP connection pools to use. :encode_uri: If true, URIs will automatically be percent-encoded. :trust_env: If true, the surrouding environment will be trusted (environ, netrc). -:param store_cookies: If false, the received cookies as part of the HTTP response would be ignored. +:store_cookies: If false, the received cookies as part of the HTTP response would be ignored. """ SCHEMAS = ['http', 'https'] -from . import __version__ +from .utils import default_user_agent defaults = dict() - defaults['base_headers'] = { - 'User-Agent': 'python-requests/%s' % __version__, - 'Accept-Encoding': ', '.join(('identity', 'deflate', 'compress', 'gzip')), + 'User-Agent': default_user_agent(), + 'Accept-Encoding': ', '.join(('gzip', 'deflate', 'compress')), 'Accept': '*/*' } @@ -49,5 +48,3 @@ defaults['keep_alive'] = True defaults['encode_uri'] = True defaults['trust_env'] = True defaults['store_cookies'] = True - - diff --git a/libs/requests/exceptions.py b/libs/requests/exceptions.py index 57f7b82d..6759af56 100644 --- a/libs/requests/exceptions.py +++ b/libs/requests/exceptions.py @@ -8,34 +8,44 @@ This module contains the set of Requests' exceptions. """ + class RequestException(RuntimeError): """There was an ambiguous exception that occurred while handling your request.""" + class HTTPError(RequestException): """An HTTP error occurred.""" response = None + class ConnectionError(RequestException): """A Connection error occurred.""" + class SSLError(ConnectionError): """An SSL error occurred.""" + class Timeout(RequestException): """The request timed out.""" + class URLRequired(RequestException): """A valid URL is required to make a request.""" + class TooManyRedirects(RequestException): """Too many redirects.""" + class MissingSchema(RequestException, ValueError): """The URL schema (e.g. http or https) is missing.""" + class InvalidSchema(RequestException, ValueError): """See defaults.py for valid schemas.""" + class InvalidURL(RequestException, ValueError): """ The URL provided was somehow invalid. """ diff --git a/libs/requests/hooks.py b/libs/requests/hooks.py index 272abb73..9e0ce346 100644 --- a/libs/requests/hooks.py +++ b/libs/requests/hooks.py @@ -25,11 +25,10 @@ Available hooks: """ -import traceback - HOOKS = ('args', 'pre_request', 'pre_send', 'post_request', 'response') + def dispatch_hook(key, hooks, hook_data): """Dispatches a hook dictionary on a given piece of data.""" @@ -42,12 +41,9 @@ def dispatch_hook(key, hooks, hook_data): hooks = [hooks] for hook in hooks: - try: - _hook_data = hook(hook_data) - if _hook_data is not None: - hook_data = _hook_data + _hook_data = hook(hook_data) + if _hook_data is not None: + hook_data = _hook_data - except Exception: - traceback.print_exc() return hook_data diff --git a/libs/requests/models.py b/libs/requests/models.py index fbf7fc6e..2193c6e5 100644 --- a/libs/requests/models.py +++ b/libs/requests/models.py @@ -7,9 +7,10 @@ requests.models This module contains the primary objects that power Requests. """ -import json import os +import socket from datetime import datetime +from io import BytesIO from .hooks import dispatch_hook, HOOKS from .structures import CaseInsensitiveDict @@ -18,6 +19,7 @@ from .status_codes import codes from .auth import HTTPBasicAuth, HTTPProxyAuth from .cookies import cookiejar_from_dict, extract_cookies_to_jar, get_cookie_header from .packages.urllib3.exceptions import MaxRetryError, LocationParseError +from .packages.urllib3.exceptions import TimeoutError from .packages.urllib3.exceptions import SSLError as _SSLError from .packages.urllib3.exceptions import HTTPError as _HTTPError from .packages.urllib3 import connectionpool, poolmanager @@ -29,25 +31,18 @@ from .exceptions import ( from .utils import ( get_encoding_from_headers, stream_untransfer, guess_filename, requote_uri, stream_decode_response_unicode, get_netrc_auth, get_environ_proxies, - DEFAULT_CA_BUNDLE_PATH) + to_key_val_list, DEFAULT_CA_BUNDLE_PATH, parse_header_links, iter_slices) from .compat import ( cookielib, urlparse, urlunparse, urljoin, urlsplit, urlencode, str, bytes, - StringIO, is_py2) - -# Import chardet if it is available. -try: - import chardet - # hush pyflakes - chardet -except ImportError: - chardet = None + StringIO, is_py2, chardet, json, builtin_str) REDIRECT_STATI = (codes.moved, codes.found, codes.other, codes.temporary_moved) CONTENT_CHUNK_SIZE = 10 * 1024 + class Request(object): - """The :class:`Request ` object. It carries out all functionality of - Requests. Recommended interface is with the Requests functions. + """The :class:`Request ` object. It carries out all functionality + of Requests. Recommended interface is with the Requests functions. """ def __init__(self, @@ -65,7 +60,7 @@ class Request(object): proxies=None, hooks=None, config=None, - prefetch=False, + prefetch=True, _poolmanager=None, verify=None, session=None, @@ -79,7 +74,14 @@ class Request(object): self.timeout = timeout #: Request URL. - self.url = url + #: Accept objects that have string representations. + try: + self.url = unicode(url) + except NameError: + # We're on Python 3. + self.url = str(url) + except UnicodeDecodeError: + self.url = url #: Dictionary of HTTP Headers to attach to the :class:`Request `. self.headers = dict(headers or []) @@ -109,6 +111,10 @@ class Request(object): # Dictionary mapping protocol to the URL of the proxy (e.g. {'http': 'foo.bar:3128'}) self.proxies = dict(proxies or []) + for proxy_type,uri_ref in list(self.proxies.items()): + if not uri_ref: + del self.proxies[proxy_type] + # If no proxies are given, allow configuration by environment variables # HTTP_PROXY and HTTPS_PROXY. if not self.proxies and self.config.get('trust_env'): @@ -191,7 +197,7 @@ class Request(object): response.status_code = getattr(resp, 'status', None) # Make headers case-insensitive. - response.headers = CaseInsensitiveDict(getattr(resp, 'headers', None)) + response.headers = CaseInsensitiveDict(getattr(resp, 'headers', {})) # Set encoding. response.encoding = get_encoding_from_headers(response.headers) @@ -299,7 +305,8 @@ class Request(object): proxies=self.proxies, verify=self.verify, session=self.session, - cert=self.cert + cert=self.cert, + prefetch=self.prefetch, ) request.send() @@ -319,53 +326,60 @@ class Request(object): if parameters are supplied as a dict. """ - if isinstance(data, bytes): - return data - if isinstance(data, str): + if isinstance(data, (str, bytes)): return data elif hasattr(data, 'read'): return data elif hasattr(data, '__iter__'): - try: - dict(data) - except ValueError: - raise ValueError('Unable to encode lists with elements that are not 2-tuples.') - - params = list(data.items() if isinstance(data, dict) else data) result = [] - for k, vs in params: + for k, vs in to_key_val_list(data): for v in isinstance(vs, list) and vs or [vs]: - result.append( - (k.encode('utf-8') if isinstance(k, str) else k, - v.encode('utf-8') if isinstance(v, str) else v)) + if v is not None: + result.append( + (k.encode('utf-8') if isinstance(k, str) else k, + v.encode('utf-8') if isinstance(v, str) else v)) return urlencode(result, doseq=True) else: return data def _encode_files(self, files): + """Build the body for a multipart/form-data request. + Will successfully encode files when passed as a dict or a list of + 2-tuples. Order is retained if data is a list of 2-tuples but abritrary + if parameters are supplied as a dict. + + """ if (not files) or isinstance(self.data, str): return None - try: - fields = self.data.copy() - except AttributeError: - fields = dict(self.data) + new_fields = [] + fields = to_key_val_list(self.data) + files = to_key_val_list(files) - for (k, v) in list(files.items()): + for field, val in fields: + if isinstance(val, list): + for v in val: + new_fields.append((field, str(v))) + else: + new_fields.append((field, str(val))) + + for (k, v) in files: # support for explicit filename if isinstance(v, (tuple, list)): fn, fp = v else: fn = guess_filename(v) or k fp = v - if isinstance(fp, (bytes, str)): + if isinstance(fp, str): fp = StringIO(fp) - fields.update({k: (fn, fp.read())}) + if isinstance(fp, bytes): + fp = BytesIO(fp) + new_fields.append((k, (fn, fp.read()))) - (body, content_type) = encode_multipart_formdata(fields) + body, content_type = encode_multipart_formdata(new_fields) - return (body, content_type) + return body, content_type @property def full_url(self): @@ -385,7 +399,10 @@ class Request(object): if not scheme in SCHEMAS: raise InvalidSchema("Invalid scheme %r" % scheme) - netloc = netloc.encode('idna').decode('utf-8') + try: + netloc = netloc.encode('idna').decode('utf-8') + except UnicodeError: + raise InvalidURL('URL has an invalid label.') if not path: path = '/' @@ -404,14 +421,14 @@ class Request(object): if isinstance(fragment, str): fragment = fragment.encode('utf-8') - url = (urlunparse([scheme, netloc, path, params, query, fragment])) - enc_params = self._encode_params(self.params) if enc_params: - if urlparse(url).query: - url = '%s&%s' % (url, enc_params) + if query: + query = '%s&%s' % (query, enc_params) else: - url = '%s?%s' % (url, enc_params) + query = enc_params + + url = (urlunparse([scheme, netloc, path, params, query, fragment])) if self.config.get('encode_uri', True): url = requote_uri(url) @@ -445,8 +462,10 @@ class Request(object): def register_hook(self, event, hook): """Properly register a hook.""" - - self.hooks[event].append(hook) + if isinstance(hook, (list, tuple, set)): + self.hooks[event].extend(hook) + else: + self.hooks[event].append(hook) def deregister_hook(self, event, hook): """Deregister a previously registered hook. @@ -459,7 +478,7 @@ class Request(object): except ValueError: return False - def send(self, anyway=False, prefetch=False): + def send(self, anyway=False, prefetch=None): """Sends the request. Returns True if successful, False if not. If there was an HTTPError during transmission, self.response.status_code will contain the HTTPError code. @@ -468,6 +487,9 @@ class Request(object): :param anyway: If True, request will be sent, even if it has already been sent. + + :param prefetch: If not None, will override the request's own setting + for prefetch. """ # Build the URL @@ -483,10 +505,6 @@ class Request(object): datetime.now().isoformat(), self.method, url )) - # Nottin' on you. - body = None - content_type = None - # Use .netrc auth if none was provided. if not self.auth and self.config.get('trust_env'): self.auth = get_netrc_auth(url) @@ -502,6 +520,10 @@ class Request(object): # Update self to reflect the auth changes. self.__dict__.update(r.__dict__) + # Nottin' on you. + body = None + content_type = None + # Multi-part file uploads. if self.files: (body, content_type) = self._encode_files(self.files) @@ -509,7 +531,7 @@ class Request(object): if self.data: body = self._encode_params(self.data) - if isinstance(self.data, str) or hasattr(self.data, 'read'): + if isinstance(self.data, str) or isinstance(self.data, builtin_str) or hasattr(self.data, 'read'): content_type = None else: content_type = 'application/x-www-form-urlencoded' @@ -519,10 +541,10 @@ class Request(object): self.headers['Content-Type'] = content_type _p = urlparse(url) - no_proxy = filter(lambda x:x.strip(), self.proxies.get('no', '').split(',')) + no_proxy = filter(lambda x: x.strip(), self.proxies.get('no', '').split(',')) proxy = self.proxies.get(_p.scheme) - if proxy and not any(map(_p.netloc.endswith, no_proxy)): + if proxy and not any(map(_p.hostname.endswith, no_proxy)): conn = poolmanager.proxy_from_url(proxy) _proxy = urlparse(proxy) if '@' in _proxy.netloc: @@ -569,7 +591,7 @@ class Request(object): conn.cert_reqs = 'CERT_NONE' conn.ca_certs = None - if self.cert and self.verify: + if self.cert: if len(self.cert) == 2: conn.cert_file = self.cert[0] conn.key_file = self.cert[1] @@ -605,14 +627,19 @@ class Request(object): ) self.sent = True + except socket.error as sockerr: + raise ConnectionError(sockerr) + except MaxRetryError as e: raise ConnectionError(e) except (_SSLError, _HTTPError) as e: - if self.verify and isinstance(e, _SSLError): + if isinstance(e, _SSLError): raise SSLError(e) - - raise Timeout('Request timed out.') + elif isinstance(e, TimeoutError): + raise Timeout(e) + else: + raise Timeout('Request timed out.') # build_response can throw TooManyRedirects self._build_response(r) @@ -625,7 +652,9 @@ class Request(object): self.__dict__.update(r.__dict__) # If prefetch is True, mark content as consumed. - if prefetch or self.prefetch: + if prefetch is None: + prefetch = self.prefetch + if prefetch: # Save the response. self.response.content @@ -669,7 +698,7 @@ class Response(object): #: A list of :class:`Response ` objects from #: the history of the Request. Any redirect responses will end - #: up here. + #: up here. The list is sorted from the oldest to the most recent request. self.history = [] #: The :class:`Request ` that created the Response. @@ -707,9 +736,8 @@ class Response(object): length of each item returned as decoding can take place. """ if self._content_consumed: - raise RuntimeError( - 'The content for this response was already consumed' - ) + # simulate reading small chunks of the content + return iter_slices(self._content, chunk_size) def generate(): while 1: @@ -773,6 +801,8 @@ class Response(object): self._content = None self._content_consumed = True + # don't need to release the connection; that's been handled by urllib3 + # since we exhausted the data. return self._content @property @@ -798,10 +828,12 @@ class Response(object): # Decode unicode from given encoding. try: content = str(self.content, encoding, errors='replace') - except LookupError: + except (LookupError, TypeError): # A LookupError is raised if the encoding was not found which could # indicate a misspelling or similar mistake. # + # A TypeError can be raised if encoding is None + # # So we try blindly encoding. content = str(self.content, errors='replace') @@ -809,29 +841,52 @@ class Response(object): @property def json(self): - """Returns the json-encoded content of a request, if any.""" + """Returns the json-encoded content of a response, if any.""" try: return json.loads(self.text or self.content) except ValueError: return None + @property + def links(self): + """Returns the parsed header links of the response, if any.""" + + header = self.headers['link'] + + # l = MultiDict() + l = {} + + if header: + links = parse_header_links(header) + + for link in links: + key = link.get('rel') or link.get('url') + l[key] = link + + return l + + @property + def reason(self): + """The HTTP Reason for the response.""" + return self.raw.reason + def raise_for_status(self, allow_redirects=True): """Raises stored :class:`HTTPError` or :class:`URLError`, if one occurred.""" if self.error: raise self.error - if (self.status_code >= 300) and (self.status_code < 400) and not allow_redirects: - http_error = HTTPError('%s Redirection' % self.status_code) - http_error.response = self - raise http_error + http_error_msg = '' + if 300 <= self.status_code < 400 and not allow_redirects: + http_error_msg = '%s Redirection: %s' % (self.status_code, self.reason) - elif (self.status_code >= 400) and (self.status_code < 500): - http_error = HTTPError('%s Client Error' % self.status_code) - http_error.response = self - raise http_error + elif 400 <= self.status_code < 500: + http_error_msg = '%s Client Error: %s' % (self.status_code, self.reason) - elif (self.status_code >= 500) and (self.status_code < 600): - http_error = HTTPError('%s Server Error' % self.status_code) + elif 500 <= self.status_code < 600: + http_error_msg = '%s Server Error: %s' % (self.status_code, self.reason) + + if http_error_msg: + http_error = HTTPError(http_error_msg) http_error.response = self raise http_error diff --git a/libs/requests/packages/chardet/__init__.py b/libs/requests/packages/chardet/__init__.py new file mode 100755 index 00000000..b1872fe8 --- /dev/null +++ b/libs/requests/packages/chardet/__init__.py @@ -0,0 +1,26 @@ +######################## BEGIN LICENSE BLOCK ######################## +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +__version__ = "1.0.1" + +def detect(aBuf): + import universaldetector + u = universaldetector.UniversalDetector() + u.reset() + u.feed(aBuf) + u.close() + return u.result diff --git a/libs/requests/packages/chardet/big5freq.py b/libs/requests/packages/chardet/big5freq.py new file mode 100755 index 00000000..c1b0f3ce --- /dev/null +++ b/libs/requests/packages/chardet/big5freq.py @@ -0,0 +1,923 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Big5 frequency table +# by Taiwan's Mandarin Promotion Council +# +# +# 128 --> 0.42261 +# 256 --> 0.57851 +# 512 --> 0.74851 +# 1024 --> 0.89384 +# 2048 --> 0.97583 +# +# Ideal Distribution Ratio = 0.74851/(1-0.74851) =2.98 +# Random Distribution Ration = 512/(5401-512)=0.105 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR + +BIG5_TYPICAL_DISTRIBUTION_RATIO = 0.75 + +#Char to FreqOrder table +BIG5_TABLE_SIZE = 5376 + +Big5CharToFreqOrder = ( \ + 1,1801,1506, 255,1431, 198, 9, 82, 6,5008, 177, 202,3681,1256,2821, 110, # 16 +3814, 33,3274, 261, 76, 44,2114, 16,2946,2187,1176, 659,3971, 26,3451,2653, # 32 +1198,3972,3350,4202, 410,2215, 302, 590, 361,1964, 8, 204, 58,4510,5009,1932, # 48 + 63,5010,5011, 317,1614, 75, 222, 159,4203,2417,1480,5012,3555,3091, 224,2822, # 64 +3682, 3, 10,3973,1471, 29,2787,1135,2866,1940, 873, 130,3275,1123, 312,5013, # 80 +4511,2052, 507, 252, 682,5014, 142,1915, 124, 206,2947, 34,3556,3204, 64, 604, # 96 +5015,2501,1977,1978, 155,1991, 645, 641,1606,5016,3452, 337, 72, 406,5017, 80, # 112 + 630, 238,3205,1509, 263, 939,1092,2654, 756,1440,1094,3453, 449, 69,2987, 591, # 128 + 179,2096, 471, 115,2035,1844, 60, 50,2988, 134, 806,1869, 734,2036,3454, 180, # 144 + 995,1607, 156, 537,2907, 688,5018, 319,1305, 779,2145, 514,2379, 298,4512, 359, # 160 +2502, 90,2716,1338, 663, 11, 906,1099,2553, 20,2441, 182, 532,1716,5019, 732, # 176 +1376,4204,1311,1420,3206, 25,2317,1056, 113, 399, 382,1950, 242,3455,2474, 529, # 192 +3276, 475,1447,3683,5020, 117, 21, 656, 810,1297,2300,2334,3557,5021, 126,4205, # 208 + 706, 456, 150, 613,4513, 71,1118,2037,4206, 145,3092, 85, 835, 486,2115,1246, # 224 +1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,5022,2128,2359, 347,3815, 221, # 240 +3558,3135,5023,1956,1153,4207, 83, 296,1199,3093, 192, 624, 93,5024, 822,1898, # 256 +2823,3136, 795,2065, 991,1554,1542,1592, 27, 43,2867, 859, 139,1456, 860,4514, # 272 + 437, 712,3974, 164,2397,3137, 695, 211,3037,2097, 195,3975,1608,3559,3560,3684, # 288 +3976, 234, 811,2989,2098,3977,2233,1441,3561,1615,2380, 668,2077,1638, 305, 228, # 304 +1664,4515, 467, 415,5025, 262,2099,1593, 239, 108, 300, 200,1033, 512,1247,2078, # 320 +5026,5027,2176,3207,3685,2682, 593, 845,1062,3277, 88,1723,2038,3978,1951, 212, # 336 + 266, 152, 149, 468,1899,4208,4516, 77, 187,5028,3038, 37, 5,2990,5029,3979, # 352 +5030,5031, 39,2524,4517,2908,3208,2079, 55, 148, 74,4518, 545, 483,1474,1029, # 368 +1665, 217,1870,1531,3138,1104,2655,4209, 24, 172,3562, 900,3980,3563,3564,4519, # 384 + 32,1408,2824,1312, 329, 487,2360,2251,2717, 784,2683, 4,3039,3351,1427,1789, # 400 + 188, 109, 499,5032,3686,1717,1790, 888,1217,3040,4520,5033,3565,5034,3352,1520, # 416 +3687,3981, 196,1034, 775,5035,5036, 929,1816, 249, 439, 38,5037,1063,5038, 794, # 432 +3982,1435,2301, 46, 178,3278,2066,5039,2381,5040, 214,1709,4521, 804, 35, 707, # 448 + 324,3688,1601,2554, 140, 459,4210,5041,5042,1365, 839, 272, 978,2262,2580,3456, # 464 +2129,1363,3689,1423, 697, 100,3094, 48, 70,1231, 495,3139,2196,5043,1294,5044, # 480 +2080, 462, 586,1042,3279, 853, 256, 988, 185,2382,3457,1698, 434,1084,5045,3458, # 496 + 314,2625,2788,4522,2335,2336, 569,2285, 637,1817,2525, 757,1162,1879,1616,3459, # 512 + 287,1577,2116, 768,4523,1671,2868,3566,2526,1321,3816, 909,2418,5046,4211, 933, # 528 +3817,4212,2053,2361,1222,4524, 765,2419,1322, 786,4525,5047,1920,1462,1677,2909, # 544 +1699,5048,4526,1424,2442,3140,3690,2600,3353,1775,1941,3460,3983,4213, 309,1369, # 560 +1130,2825, 364,2234,1653,1299,3984,3567,3985,3986,2656, 525,1085,3041, 902,2001, # 576 +1475, 964,4527, 421,1845,1415,1057,2286, 940,1364,3141, 376,4528,4529,1381, 7, # 592 +2527, 983,2383, 336,1710,2684,1846, 321,3461, 559,1131,3042,2752,1809,1132,1313, # 608 + 265,1481,1858,5049, 352,1203,2826,3280, 167,1089, 420,2827, 776, 792,1724,3568, # 624 +4214,2443,3281,5050,4215,5051, 446, 229, 333,2753, 901,3818,1200,1557,4530,2657, # 640 +1921, 395,2754,2685,3819,4216,1836, 125, 916,3209,2626,4531,5052,5053,3820,5054, # 656 +5055,5056,4532,3142,3691,1133,2555,1757,3462,1510,2318,1409,3569,5057,2146, 438, # 672 +2601,2910,2384,3354,1068, 958,3043, 461, 311,2869,2686,4217,1916,3210,4218,1979, # 688 + 383, 750,2755,2627,4219, 274, 539, 385,1278,1442,5058,1154,1965, 384, 561, 210, # 704 + 98,1295,2556,3570,5059,1711,2420,1482,3463,3987,2911,1257, 129,5060,3821, 642, # 720 + 523,2789,2790,2658,5061, 141,2235,1333, 68, 176, 441, 876, 907,4220, 603,2602, # 736 + 710, 171,3464, 404, 549, 18,3143,2398,1410,3692,1666,5062,3571,4533,2912,4534, # 752 +5063,2991, 368,5064, 146, 366, 99, 871,3693,1543, 748, 807,1586,1185, 22,2263, # 768 + 379,3822,3211,5065,3212, 505,1942,2628,1992,1382,2319,5066, 380,2362, 218, 702, # 784 +1818,1248,3465,3044,3572,3355,3282,5067,2992,3694, 930,3283,3823,5068, 59,5069, # 800 + 585, 601,4221, 497,3466,1112,1314,4535,1802,5070,1223,1472,2177,5071, 749,1837, # 816 + 690,1900,3824,1773,3988,1476, 429,1043,1791,2236,2117, 917,4222, 447,1086,1629, # 832 +5072, 556,5073,5074,2021,1654, 844,1090, 105, 550, 966,1758,2828,1008,1783, 686, # 848 +1095,5075,2287, 793,1602,5076,3573,2603,4536,4223,2948,2302,4537,3825, 980,2503, # 864 + 544, 353, 527,4538, 908,2687,2913,5077, 381,2629,1943,1348,5078,1341,1252, 560, # 880 +3095,5079,3467,2870,5080,2054, 973, 886,2081, 143,4539,5081,5082, 157,3989, 496, # 896 +4224, 57, 840, 540,2039,4540,4541,3468,2118,1445, 970,2264,1748,1966,2082,4225, # 912 +3144,1234,1776,3284,2829,3695, 773,1206,2130,1066,2040,1326,3990,1738,1725,4226, # 928 + 279,3145, 51,1544,2604, 423,1578,2131,2067, 173,4542,1880,5083,5084,1583, 264, # 944 + 610,3696,4543,2444, 280, 154,5085,5086,5087,1739, 338,1282,3096, 693,2871,1411, # 960 +1074,3826,2445,5088,4544,5089,5090,1240, 952,2399,5091,2914,1538,2688, 685,1483, # 976 +4227,2475,1436, 953,4228,2055,4545, 671,2400, 79,4229,2446,3285, 608, 567,2689, # 992 +3469,4230,4231,1691, 393,1261,1792,2401,5092,4546,5093,5094,5095,5096,1383,1672, # 1008 +3827,3213,1464, 522,1119, 661,1150, 216, 675,4547,3991,1432,3574, 609,4548,2690, # 1024 +2402,5097,5098,5099,4232,3045, 0,5100,2476, 315, 231,2447, 301,3356,4549,2385, # 1040 +5101, 233,4233,3697,1819,4550,4551,5102, 96,1777,1315,2083,5103, 257,5104,1810, # 1056 +3698,2718,1139,1820,4234,2022,1124,2164,2791,1778,2659,5105,3097, 363,1655,3214, # 1072 +5106,2993,5107,5108,5109,3992,1567,3993, 718, 103,3215, 849,1443, 341,3357,2949, # 1088 +1484,5110,1712, 127, 67, 339,4235,2403, 679,1412, 821,5111,5112, 834, 738, 351, # 1104 +2994,2147, 846, 235,1497,1881, 418,1993,3828,2719, 186,1100,2148,2756,3575,1545, # 1120 +1355,2950,2872,1377, 583,3994,4236,2581,2995,5113,1298,3699,1078,2557,3700,2363, # 1136 + 78,3829,3830, 267,1289,2100,2002,1594,4237, 348, 369,1274,2197,2178,1838,4552, # 1152 +1821,2830,3701,2757,2288,2003,4553,2951,2758, 144,3358, 882,4554,3995,2759,3470, # 1168 +4555,2915,5114,4238,1726, 320,5115,3996,3046, 788,2996,5116,2831,1774,1327,2873, # 1184 +3997,2832,5117,1306,4556,2004,1700,3831,3576,2364,2660, 787,2023, 506, 824,3702, # 1200 + 534, 323,4557,1044,3359,2024,1901, 946,3471,5118,1779,1500,1678,5119,1882,4558, # 1216 + 165, 243,4559,3703,2528, 123, 683,4239, 764,4560, 36,3998,1793, 589,2916, 816, # 1232 + 626,1667,3047,2237,1639,1555,1622,3832,3999,5120,4000,2874,1370,1228,1933, 891, # 1248 +2084,2917, 304,4240,5121, 292,2997,2720,3577, 691,2101,4241,1115,4561, 118, 662, # 1264 +5122, 611,1156, 854,2386,1316,2875, 2, 386, 515,2918,5123,5124,3286, 868,2238, # 1280 +1486, 855,2661, 785,2216,3048,5125,1040,3216,3578,5126,3146, 448,5127,1525,5128, # 1296 +2165,4562,5129,3833,5130,4242,2833,3579,3147, 503, 818,4001,3148,1568, 814, 676, # 1312 +1444, 306,1749,5131,3834,1416,1030, 197,1428, 805,2834,1501,4563,5132,5133,5134, # 1328 +1994,5135,4564,5136,5137,2198, 13,2792,3704,2998,3149,1229,1917,5138,3835,2132, # 1344 +5139,4243,4565,2404,3580,5140,2217,1511,1727,1120,5141,5142, 646,3836,2448, 307, # 1360 +5143,5144,1595,3217,5145,5146,5147,3705,1113,1356,4002,1465,2529,2530,5148, 519, # 1376 +5149, 128,2133, 92,2289,1980,5150,4003,1512, 342,3150,2199,5151,2793,2218,1981, # 1392 +3360,4244, 290,1656,1317, 789, 827,2365,5152,3837,4566, 562, 581,4004,5153, 401, # 1408 +4567,2252, 94,4568,5154,1399,2794,5155,1463,2025,4569,3218,1944,5156, 828,1105, # 1424 +4245,1262,1394,5157,4246, 605,4570,5158,1784,2876,5159,2835, 819,2102, 578,2200, # 1440 +2952,5160,1502, 436,3287,4247,3288,2836,4005,2919,3472,3473,5161,2721,2320,5162, # 1456 +5163,2337,2068, 23,4571, 193, 826,3838,2103, 699,1630,4248,3098, 390,1794,1064, # 1472 +3581,5164,1579,3099,3100,1400,5165,4249,1839,1640,2877,5166,4572,4573, 137,4250, # 1488 + 598,3101,1967, 780, 104, 974,2953,5167, 278, 899, 253, 402, 572, 504, 493,1339, # 1504 +5168,4006,1275,4574,2582,2558,5169,3706,3049,3102,2253, 565,1334,2722, 863, 41, # 1520 +5170,5171,4575,5172,1657,2338, 19, 463,2760,4251, 606,5173,2999,3289,1087,2085, # 1536 +1323,2662,3000,5174,1631,1623,1750,4252,2691,5175,2878, 791,2723,2663,2339, 232, # 1552 +2421,5176,3001,1498,5177,2664,2630, 755,1366,3707,3290,3151,2026,1609, 119,1918, # 1568 +3474, 862,1026,4253,5178,4007,3839,4576,4008,4577,2265,1952,2477,5179,1125, 817, # 1584 +4254,4255,4009,1513,1766,2041,1487,4256,3050,3291,2837,3840,3152,5180,5181,1507, # 1600 +5182,2692, 733, 40,1632,1106,2879, 345,4257, 841,2531, 230,4578,3002,1847,3292, # 1616 +3475,5183,1263, 986,3476,5184, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562, # 1632 +4010,4011,2954, 967,2761,2665,1349, 592,2134,1692,3361,3003,1995,4258,1679,4012, # 1648 +1902,2188,5185, 739,3708,2724,1296,1290,5186,4259,2201,2202,1922,1563,2605,2559, # 1664 +1871,2762,3004,5187, 435,5188, 343,1108, 596, 17,1751,4579,2239,3477,3709,5189, # 1680 +4580, 294,3582,2955,1693, 477, 979, 281,2042,3583, 643,2043,3710,2631,2795,2266, # 1696 +1031,2340,2135,2303,3584,4581, 367,1249,2560,5190,3585,5191,4582,1283,3362,2005, # 1712 + 240,1762,3363,4583,4584, 836,1069,3153, 474,5192,2149,2532, 268,3586,5193,3219, # 1728 +1521,1284,5194,1658,1546,4260,5195,3587,3588,5196,4261,3364,2693,1685,4262, 961, # 1744 +1673,2632, 190,2006,2203,3841,4585,4586,5197, 570,2504,3711,1490,5198,4587,2633, # 1760 +3293,1957,4588, 584,1514, 396,1045,1945,5199,4589,1968,2449,5200,5201,4590,4013, # 1776 + 619,5202,3154,3294, 215,2007,2796,2561,3220,4591,3221,4592, 763,4263,3842,4593, # 1792 +5203,5204,1958,1767,2956,3365,3712,1174, 452,1477,4594,3366,3155,5205,2838,1253, # 1808 +2387,2189,1091,2290,4264, 492,5206, 638,1169,1825,2136,1752,4014, 648, 926,1021, # 1824 +1324,4595, 520,4596, 997, 847,1007, 892,4597,3843,2267,1872,3713,2405,1785,4598, # 1840 +1953,2957,3103,3222,1728,4265,2044,3714,4599,2008,1701,3156,1551, 30,2268,4266, # 1856 +5207,2027,4600,3589,5208, 501,5209,4267, 594,3478,2166,1822,3590,3479,3591,3223, # 1872 + 829,2839,4268,5210,1680,3157,1225,4269,5211,3295,4601,4270,3158,2341,5212,4602, # 1888 +4271,5213,4015,4016,5214,1848,2388,2606,3367,5215,4603, 374,4017, 652,4272,4273, # 1904 + 375,1140, 798,5216,5217,5218,2366,4604,2269, 546,1659, 138,3051,2450,4605,5219, # 1920 +2254, 612,1849, 910, 796,3844,1740,1371, 825,3845,3846,5220,2920,2562,5221, 692, # 1936 + 444,3052,2634, 801,4606,4274,5222,1491, 244,1053,3053,4275,4276, 340,5223,4018, # 1952 +1041,3005, 293,1168, 87,1357,5224,1539, 959,5225,2240, 721, 694,4277,3847, 219, # 1968 +1478, 644,1417,3368,2666,1413,1401,1335,1389,4019,5226,5227,3006,2367,3159,1826, # 1984 + 730,1515, 184,2840, 66,4607,5228,1660,2958, 246,3369, 378,1457, 226,3480, 975, # 2000 +4020,2959,1264,3592, 674, 696,5229, 163,5230,1141,2422,2167, 713,3593,3370,4608, # 2016 +4021,5231,5232,1186, 15,5233,1079,1070,5234,1522,3224,3594, 276,1050,2725, 758, # 2032 +1126, 653,2960,3296,5235,2342, 889,3595,4022,3104,3007, 903,1250,4609,4023,3481, # 2048 +3596,1342,1681,1718, 766,3297, 286, 89,2961,3715,5236,1713,5237,2607,3371,3008, # 2064 +5238,2962,2219,3225,2880,5239,4610,2505,2533, 181, 387,1075,4024, 731,2190,3372, # 2080 +5240,3298, 310, 313,3482,2304, 770,4278, 54,3054, 189,4611,3105,3848,4025,5241, # 2096 +1230,1617,1850, 355,3597,4279,4612,3373, 111,4280,3716,1350,3160,3483,3055,4281, # 2112 +2150,3299,3598,5242,2797,4026,4027,3009, 722,2009,5243,1071, 247,1207,2343,2478, # 2128 +1378,4613,2010, 864,1437,1214,4614, 373,3849,1142,2220, 667,4615, 442,2763,2563, # 2144 +3850,4028,1969,4282,3300,1840, 837, 170,1107, 934,1336,1883,5244,5245,2119,4283, # 2160 +2841, 743,1569,5246,4616,4284, 582,2389,1418,3484,5247,1803,5248, 357,1395,1729, # 2176 +3717,3301,2423,1564,2241,5249,3106,3851,1633,4617,1114,2086,4285,1532,5250, 482, # 2192 +2451,4618,5251,5252,1492, 833,1466,5253,2726,3599,1641,2842,5254,1526,1272,3718, # 2208 +4286,1686,1795, 416,2564,1903,1954,1804,5255,3852,2798,3853,1159,2321,5256,2881, # 2224 +4619,1610,1584,3056,2424,2764, 443,3302,1163,3161,5257,5258,4029,5259,4287,2506, # 2240 +3057,4620,4030,3162,2104,1647,3600,2011,1873,4288,5260,4289, 431,3485,5261, 250, # 2256 + 97, 81,4290,5262,1648,1851,1558, 160, 848,5263, 866, 740,1694,5264,2204,2843, # 2272 +3226,4291,4621,3719,1687, 950,2479, 426, 469,3227,3720,3721,4031,5265,5266,1188, # 2288 + 424,1996, 861,3601,4292,3854,2205,2694, 168,1235,3602,4293,5267,2087,1674,4622, # 2304 +3374,3303, 220,2565,1009,5268,3855, 670,3010, 332,1208, 717,5269,5270,3603,2452, # 2320 +4032,3375,5271, 513,5272,1209,2882,3376,3163,4623,1080,5273,5274,5275,5276,2534, # 2336 +3722,3604, 815,1587,4033,4034,5277,3605,3486,3856,1254,4624,1328,3058,1390,4035, # 2352 +1741,4036,3857,4037,5278, 236,3858,2453,3304,5279,5280,3723,3859,1273,3860,4625, # 2368 +5281, 308,5282,4626, 245,4627,1852,2480,1307,2583, 430, 715,2137,2454,5283, 270, # 2384 + 199,2883,4038,5284,3606,2727,1753, 761,1754, 725,1661,1841,4628,3487,3724,5285, # 2400 +5286, 587, 14,3305, 227,2608, 326, 480,2270, 943,2765,3607, 291, 650,1884,5287, # 2416 +1702,1226, 102,1547, 62,3488, 904,4629,3489,1164,4294,5288,5289,1224,1548,2766, # 2432 + 391, 498,1493,5290,1386,1419,5291,2056,1177,4630, 813, 880,1081,2368, 566,1145, # 2448 +4631,2291,1001,1035,2566,2609,2242, 394,1286,5292,5293,2069,5294, 86,1494,1730, # 2464 +4039, 491,1588, 745, 897,2963, 843,3377,4040,2767,2884,3306,1768, 998,2221,2070, # 2480 + 397,1827,1195,1970,3725,3011,3378, 284,5295,3861,2507,2138,2120,1904,5296,4041, # 2496 +2151,4042,4295,1036,3490,1905, 114,2567,4296, 209,1527,5297,5298,2964,2844,2635, # 2512 +2390,2728,3164, 812,2568,5299,3307,5300,1559, 737,1885,3726,1210, 885, 28,2695, # 2528 +3608,3862,5301,4297,1004,1780,4632,5302, 346,1982,2222,2696,4633,3863,1742, 797, # 2544 +1642,4043,1934,1072,1384,2152, 896,4044,3308,3727,3228,2885,3609,5303,2569,1959, # 2560 +4634,2455,1786,5304,5305,5306,4045,4298,1005,1308,3728,4299,2729,4635,4636,1528, # 2576 +2610, 161,1178,4300,1983, 987,4637,1101,4301, 631,4046,1157,3229,2425,1343,1241, # 2592 +1016,2243,2570, 372, 877,2344,2508,1160, 555,1935, 911,4047,5307, 466,1170, 169, # 2608 +1051,2921,2697,3729,2481,3012,1182,2012,2571,1251,2636,5308, 992,2345,3491,1540, # 2624 +2730,1201,2071,2406,1997,2482,5309,4638, 528,1923,2191,1503,1874,1570,2369,3379, # 2640 +3309,5310, 557,1073,5311,1828,3492,2088,2271,3165,3059,3107, 767,3108,2799,4639, # 2656 +1006,4302,4640,2346,1267,2179,3730,3230, 778,4048,3231,2731,1597,2667,5312,4641, # 2672 +5313,3493,5314,5315,5316,3310,2698,1433,3311, 131, 95,1504,4049, 723,4303,3166, # 2688 +1842,3610,2768,2192,4050,2028,2105,3731,5317,3013,4051,1218,5318,3380,3232,4052, # 2704 +4304,2584, 248,1634,3864, 912,5319,2845,3732,3060,3865, 654, 53,5320,3014,5321, # 2720 +1688,4642, 777,3494,1032,4053,1425,5322, 191, 820,2121,2846, 971,4643, 931,3233, # 2736 + 135, 664, 783,3866,1998, 772,2922,1936,4054,3867,4644,2923,3234, 282,2732, 640, # 2752 +1372,3495,1127, 922, 325,3381,5323,5324, 711,2045,5325,5326,4055,2223,2800,1937, # 2768 +4056,3382,2224,2255,3868,2305,5327,4645,3869,1258,3312,4057,3235,2139,2965,4058, # 2784 +4059,5328,2225, 258,3236,4646, 101,1227,5329,3313,1755,5330,1391,3314,5331,2924, # 2800 +2057, 893,5332,5333,5334,1402,4305,2347,5335,5336,3237,3611,5337,5338, 878,1325, # 2816 +1781,2801,4647, 259,1385,2585, 744,1183,2272,4648,5339,4060,2509,5340, 684,1024, # 2832 +4306,5341, 472,3612,3496,1165,3315,4061,4062, 322,2153, 881, 455,1695,1152,1340, # 2848 + 660, 554,2154,4649,1058,4650,4307, 830,1065,3383,4063,4651,1924,5342,1703,1919, # 2864 +5343, 932,2273, 122,5344,4652, 947, 677,5345,3870,2637, 297,1906,1925,2274,4653, # 2880 +2322,3316,5346,5347,4308,5348,4309, 84,4310, 112, 989,5349, 547,1059,4064, 701, # 2896 +3613,1019,5350,4311,5351,3497, 942, 639, 457,2306,2456, 993,2966, 407, 851, 494, # 2912 +4654,3384, 927,5352,1237,5353,2426,3385, 573,4312, 680, 921,2925,1279,1875, 285, # 2928 + 790,1448,1984, 719,2168,5354,5355,4655,4065,4066,1649,5356,1541, 563,5357,1077, # 2944 +5358,3386,3061,3498, 511,3015,4067,4068,3733,4069,1268,2572,3387,3238,4656,4657, # 2960 +5359, 535,1048,1276,1189,2926,2029,3167,1438,1373,2847,2967,1134,2013,5360,4313, # 2976 +1238,2586,3109,1259,5361, 700,5362,2968,3168,3734,4314,5363,4315,1146,1876,1907, # 2992 +4658,2611,4070, 781,2427, 132,1589, 203, 147, 273,2802,2407, 898,1787,2155,4071, # 3008 +4072,5364,3871,2803,5365,5366,4659,4660,5367,3239,5368,1635,3872, 965,5369,1805, # 3024 +2699,1516,3614,1121,1082,1329,3317,4073,1449,3873, 65,1128,2848,2927,2769,1590, # 3040 +3874,5370,5371, 12,2668, 45, 976,2587,3169,4661, 517,2535,1013,1037,3240,5372, # 3056 +3875,2849,5373,3876,5374,3499,5375,2612, 614,1999,2323,3877,3110,2733,2638,5376, # 3072 +2588,4316, 599,1269,5377,1811,3735,5378,2700,3111, 759,1060, 489,1806,3388,3318, # 3088 +1358,5379,5380,2391,1387,1215,2639,2256, 490,5381,5382,4317,1759,2392,2348,5383, # 3104 +4662,3878,1908,4074,2640,1807,3241,4663,3500,3319,2770,2349, 874,5384,5385,3501, # 3120 +3736,1859, 91,2928,3737,3062,3879,4664,5386,3170,4075,2669,5387,3502,1202,1403, # 3136 +3880,2969,2536,1517,2510,4665,3503,2511,5388,4666,5389,2701,1886,1495,1731,4076, # 3152 +2370,4667,5390,2030,5391,5392,4077,2702,1216, 237,2589,4318,2324,4078,3881,4668, # 3168 +4669,2703,3615,3504, 445,4670,5393,5394,5395,5396,2771, 61,4079,3738,1823,4080, # 3184 +5397, 687,2046, 935, 925, 405,2670, 703,1096,1860,2734,4671,4081,1877,1367,2704, # 3200 +3389, 918,2106,1782,2483, 334,3320,1611,1093,4672, 564,3171,3505,3739,3390, 945, # 3216 +2641,2058,4673,5398,1926, 872,4319,5399,3506,2705,3112, 349,4320,3740,4082,4674, # 3232 +3882,4321,3741,2156,4083,4675,4676,4322,4677,2408,2047, 782,4084, 400, 251,4323, # 3248 +1624,5400,5401, 277,3742, 299,1265, 476,1191,3883,2122,4324,4325,1109, 205,5402, # 3264 +2590,1000,2157,3616,1861,5403,5404,5405,4678,5406,4679,2573, 107,2484,2158,4085, # 3280 +3507,3172,5407,1533, 541,1301, 158, 753,4326,2886,3617,5408,1696, 370,1088,4327, # 3296 +4680,3618, 579, 327, 440, 162,2244, 269,1938,1374,3508, 968,3063, 56,1396,3113, # 3312 +2107,3321,3391,5409,1927,2159,4681,3016,5410,3619,5411,5412,3743,4682,2485,5413, # 3328 +2804,5414,1650,4683,5415,2613,5416,5417,4086,2671,3392,1149,3393,4087,3884,4088, # 3344 +5418,1076, 49,5419, 951,3242,3322,3323, 450,2850, 920,5420,1812,2805,2371,4328, # 3360 +1909,1138,2372,3885,3509,5421,3243,4684,1910,1147,1518,2428,4685,3886,5422,4686, # 3376 +2393,2614, 260,1796,3244,5423,5424,3887,3324, 708,5425,3620,1704,5426,3621,1351, # 3392 +1618,3394,3017,1887, 944,4329,3395,4330,3064,3396,4331,5427,3744, 422, 413,1714, # 3408 +3325, 500,2059,2350,4332,2486,5428,1344,1911, 954,5429,1668,5430,5431,4089,2409, # 3424 +4333,3622,3888,4334,5432,2307,1318,2512,3114, 133,3115,2887,4687, 629, 31,2851, # 3440 +2706,3889,4688, 850, 949,4689,4090,2970,1732,2089,4335,1496,1853,5433,4091, 620, # 3456 +3245, 981,1242,3745,3397,1619,3746,1643,3326,2140,2457,1971,1719,3510,2169,5434, # 3472 +3246,5435,5436,3398,1829,5437,1277,4690,1565,2048,5438,1636,3623,3116,5439, 869, # 3488 +2852, 655,3890,3891,3117,4092,3018,3892,1310,3624,4691,5440,5441,5442,1733, 558, # 3504 +4692,3747, 335,1549,3065,1756,4336,3748,1946,3511,1830,1291,1192, 470,2735,2108, # 3520 +2806, 913,1054,4093,5443,1027,5444,3066,4094,4693, 982,2672,3399,3173,3512,3247, # 3536 +3248,1947,2807,5445, 571,4694,5446,1831,5447,3625,2591,1523,2429,5448,2090, 984, # 3552 +4695,3749,1960,5449,3750, 852, 923,2808,3513,3751, 969,1519, 999,2049,2325,1705, # 3568 +5450,3118, 615,1662, 151, 597,4095,2410,2326,1049, 275,4696,3752,4337, 568,3753, # 3584 +3626,2487,4338,3754,5451,2430,2275, 409,3249,5452,1566,2888,3514,1002, 769,2853, # 3600 + 194,2091,3174,3755,2226,3327,4339, 628,1505,5453,5454,1763,2180,3019,4096, 521, # 3616 +1161,2592,1788,2206,2411,4697,4097,1625,4340,4341, 412, 42,3119, 464,5455,2642, # 3632 +4698,3400,1760,1571,2889,3515,2537,1219,2207,3893,2643,2141,2373,4699,4700,3328, # 3648 +1651,3401,3627,5456,5457,3628,2488,3516,5458,3756,5459,5460,2276,2092, 460,5461, # 3664 +4701,5462,3020, 962, 588,3629, 289,3250,2644,1116, 52,5463,3067,1797,5464,5465, # 3680 +5466,1467,5467,1598,1143,3757,4342,1985,1734,1067,4702,1280,3402, 465,4703,1572, # 3696 + 510,5468,1928,2245,1813,1644,3630,5469,4704,3758,5470,5471,2673,1573,1534,5472, # 3712 +5473, 536,1808,1761,3517,3894,3175,2645,5474,5475,5476,4705,3518,2929,1912,2809, # 3728 +5477,3329,1122, 377,3251,5478, 360,5479,5480,4343,1529, 551,5481,2060,3759,1769, # 3744 +2431,5482,2930,4344,3330,3120,2327,2109,2031,4706,1404, 136,1468,1479, 672,1171, # 3760 +3252,2308, 271,3176,5483,2772,5484,2050, 678,2736, 865,1948,4707,5485,2014,4098, # 3776 +2971,5486,2737,2227,1397,3068,3760,4708,4709,1735,2931,3403,3631,5487,3895, 509, # 3792 +2854,2458,2890,3896,5488,5489,3177,3178,4710,4345,2538,4711,2309,1166,1010, 552, # 3808 + 681,1888,5490,5491,2972,2973,4099,1287,1596,1862,3179, 358, 453, 736, 175, 478, # 3824 +1117, 905,1167,1097,5492,1854,1530,5493,1706,5494,2181,3519,2292,3761,3520,3632, # 3840 +4346,2093,4347,5495,3404,1193,2489,4348,1458,2193,2208,1863,1889,1421,3331,2932, # 3856 +3069,2182,3521, 595,2123,5496,4100,5497,5498,4349,1707,2646, 223,3762,1359, 751, # 3872 +3121, 183,3522,5499,2810,3021, 419,2374, 633, 704,3897,2394, 241,5500,5501,5502, # 3888 + 838,3022,3763,2277,2773,2459,3898,1939,2051,4101,1309,3122,2246,1181,5503,1136, # 3904 +2209,3899,2375,1446,4350,2310,4712,5504,5505,4351,1055,2615, 484,3764,5506,4102, # 3920 + 625,4352,2278,3405,1499,4353,4103,5507,4104,4354,3253,2279,2280,3523,5508,5509, # 3936 +2774, 808,2616,3765,3406,4105,4355,3123,2539, 526,3407,3900,4356, 955,5510,1620, # 3952 +4357,2647,2432,5511,1429,3766,1669,1832, 994, 928,5512,3633,1260,5513,5514,5515, # 3968 +1949,2293, 741,2933,1626,4358,2738,2460, 867,1184, 362,3408,1392,5516,5517,4106, # 3984 +4359,1770,1736,3254,2934,4713,4714,1929,2707,1459,1158,5518,3070,3409,2891,1292, # 4000 +1930,2513,2855,3767,1986,1187,2072,2015,2617,4360,5519,2574,2514,2170,3768,2490, # 4016 +3332,5520,3769,4715,5521,5522, 666,1003,3023,1022,3634,4361,5523,4716,1814,2257, # 4032 + 574,3901,1603, 295,1535, 705,3902,4362, 283, 858, 417,5524,5525,3255,4717,4718, # 4048 +3071,1220,1890,1046,2281,2461,4107,1393,1599, 689,2575, 388,4363,5526,2491, 802, # 4064 +5527,2811,3903,2061,1405,2258,5528,4719,3904,2110,1052,1345,3256,1585,5529, 809, # 4080 +5530,5531,5532, 575,2739,3524, 956,1552,1469,1144,2328,5533,2329,1560,2462,3635, # 4096 +3257,4108, 616,2210,4364,3180,2183,2294,5534,1833,5535,3525,4720,5536,1319,3770, # 4112 +3771,1211,3636,1023,3258,1293,2812,5537,5538,5539,3905, 607,2311,3906, 762,2892, # 4128 +1439,4365,1360,4721,1485,3072,5540,4722,1038,4366,1450,2062,2648,4367,1379,4723, # 4144 +2593,5541,5542,4368,1352,1414,2330,2935,1172,5543,5544,3907,3908,4724,1798,1451, # 4160 +5545,5546,5547,5548,2936,4109,4110,2492,2351, 411,4111,4112,3637,3333,3124,4725, # 4176 +1561,2674,1452,4113,1375,5549,5550, 47,2974, 316,5551,1406,1591,2937,3181,5552, # 4192 +1025,2142,3125,3182, 354,2740, 884,2228,4369,2412, 508,3772, 726,3638, 996,2433, # 4208 +3639, 729,5553, 392,2194,1453,4114,4726,3773,5554,5555,2463,3640,2618,1675,2813, # 4224 + 919,2352,2975,2353,1270,4727,4115, 73,5556,5557, 647,5558,3259,2856,2259,1550, # 4240 +1346,3024,5559,1332, 883,3526,5560,5561,5562,5563,3334,2775,5564,1212, 831,1347, # 4256 +4370,4728,2331,3909,1864,3073, 720,3910,4729,4730,3911,5565,4371,5566,5567,4731, # 4272 +5568,5569,1799,4732,3774,2619,4733,3641,1645,2376,4734,5570,2938, 669,2211,2675, # 4288 +2434,5571,2893,5572,5573,1028,3260,5574,4372,2413,5575,2260,1353,5576,5577,4735, # 4304 +3183, 518,5578,4116,5579,4373,1961,5580,2143,4374,5581,5582,3025,2354,2355,3912, # 4320 + 516,1834,1454,4117,2708,4375,4736,2229,2620,1972,1129,3642,5583,2776,5584,2976, # 4336 +1422, 577,1470,3026,1524,3410,5585,5586, 432,4376,3074,3527,5587,2594,1455,2515, # 4352 +2230,1973,1175,5588,1020,2741,4118,3528,4737,5589,2742,5590,1743,1361,3075,3529, # 4368 +2649,4119,4377,4738,2295, 895, 924,4378,2171, 331,2247,3076, 166,1627,3077,1098, # 4384 +5591,1232,2894,2231,3411,4739, 657, 403,1196,2377, 542,3775,3412,1600,4379,3530, # 4400 +5592,4740,2777,3261, 576, 530,1362,4741,4742,2540,2676,3776,4120,5593, 842,3913, # 4416 +5594,2814,2032,1014,4121, 213,2709,3413, 665, 621,4380,5595,3777,2939,2435,5596, # 4432 +2436,3335,3643,3414,4743,4381,2541,4382,4744,3644,1682,4383,3531,1380,5597, 724, # 4448 +2282, 600,1670,5598,1337,1233,4745,3126,2248,5599,1621,4746,5600, 651,4384,5601, # 4464 +1612,4385,2621,5602,2857,5603,2743,2312,3078,5604, 716,2464,3079, 174,1255,2710, # 4480 +4122,3645, 548,1320,1398, 728,4123,1574,5605,1891,1197,3080,4124,5606,3081,3082, # 4496 +3778,3646,3779, 747,5607, 635,4386,4747,5608,5609,5610,4387,5611,5612,4748,5613, # 4512 +3415,4749,2437, 451,5614,3780,2542,2073,4388,2744,4389,4125,5615,1764,4750,5616, # 4528 +4390, 350,4751,2283,2395,2493,5617,4391,4126,2249,1434,4127, 488,4752, 458,4392, # 4544 +4128,3781, 771,1330,2396,3914,2576,3184,2160,2414,1553,2677,3185,4393,5618,2494, # 4560 +2895,2622,1720,2711,4394,3416,4753,5619,2543,4395,5620,3262,4396,2778,5621,2016, # 4576 +2745,5622,1155,1017,3782,3915,5623,3336,2313, 201,1865,4397,1430,5624,4129,5625, # 4592 +5626,5627,5628,5629,4398,1604,5630, 414,1866, 371,2595,4754,4755,3532,2017,3127, # 4608 +4756,1708, 960,4399, 887, 389,2172,1536,1663,1721,5631,2232,4130,2356,2940,1580, # 4624 +5632,5633,1744,4757,2544,4758,4759,5634,4760,5635,2074,5636,4761,3647,3417,2896, # 4640 +4400,5637,4401,2650,3418,2815, 673,2712,2465, 709,3533,4131,3648,4402,5638,1148, # 4656 + 502, 634,5639,5640,1204,4762,3649,1575,4763,2623,3783,5641,3784,3128, 948,3263, # 4672 + 121,1745,3916,1110,5642,4403,3083,2516,3027,4132,3785,1151,1771,3917,1488,4133, # 4688 +1987,5643,2438,3534,5644,5645,2094,5646,4404,3918,1213,1407,2816, 531,2746,2545, # 4704 +3264,1011,1537,4764,2779,4405,3129,1061,5647,3786,3787,1867,2897,5648,2018, 120, # 4720 +4406,4407,2063,3650,3265,2314,3919,2678,3419,1955,4765,4134,5649,3535,1047,2713, # 4736 +1266,5650,1368,4766,2858, 649,3420,3920,2546,2747,1102,2859,2679,5651,5652,2000, # 4752 +5653,1111,3651,2977,5654,2495,3921,3652,2817,1855,3421,3788,5655,5656,3422,2415, # 4768 +2898,3337,3266,3653,5657,2577,5658,3654,2818,4135,1460, 856,5659,3655,5660,2899, # 4784 +2978,5661,2900,3922,5662,4408, 632,2517, 875,3923,1697,3924,2296,5663,5664,4767, # 4800 +3028,1239, 580,4768,4409,5665, 914, 936,2075,1190,4136,1039,2124,5666,5667,5668, # 4816 +5669,3423,1473,5670,1354,4410,3925,4769,2173,3084,4137, 915,3338,4411,4412,3339, # 4832 +1605,1835,5671,2748, 398,3656,4413,3926,4138, 328,1913,2860,4139,3927,1331,4414, # 4848 +3029, 937,4415,5672,3657,4140,4141,3424,2161,4770,3425, 524, 742, 538,3085,1012, # 4864 +5673,5674,3928,2466,5675, 658,1103, 225,3929,5676,5677,4771,5678,4772,5679,3267, # 4880 +1243,5680,4142, 963,2250,4773,5681,2714,3658,3186,5682,5683,2596,2332,5684,4774, # 4896 +5685,5686,5687,3536, 957,3426,2547,2033,1931,2941,2467, 870,2019,3659,1746,2780, # 4912 +2781,2439,2468,5688,3930,5689,3789,3130,3790,3537,3427,3791,5690,1179,3086,5691, # 4928 +3187,2378,4416,3792,2548,3188,3131,2749,4143,5692,3428,1556,2549,2297, 977,2901, # 4944 +2034,4144,1205,3429,5693,1765,3430,3189,2125,1271, 714,1689,4775,3538,5694,2333, # 4960 +3931, 533,4417,3660,2184, 617,5695,2469,3340,3539,2315,5696,5697,3190,5698,5699, # 4976 +3932,1988, 618, 427,2651,3540,3431,5700,5701,1244,1690,5702,2819,4418,4776,5703, # 4992 +3541,4777,5704,2284,1576, 473,3661,4419,3432, 972,5705,3662,5706,3087,5707,5708, # 5008 +4778,4779,5709,3793,4145,4146,5710, 153,4780, 356,5711,1892,2902,4420,2144, 408, # 5024 + 803,2357,5712,3933,5713,4421,1646,2578,2518,4781,4782,3934,5714,3935,4422,5715, # 5040 +2416,3433, 752,5716,5717,1962,3341,2979,5718, 746,3030,2470,4783,4423,3794, 698, # 5056 +4784,1893,4424,3663,2550,4785,3664,3936,5719,3191,3434,5720,1824,1302,4147,2715, # 5072 +3937,1974,4425,5721,4426,3192, 823,1303,1288,1236,2861,3542,4148,3435, 774,3938, # 5088 +5722,1581,4786,1304,2862,3939,4787,5723,2440,2162,1083,3268,4427,4149,4428, 344, # 5104 +1173, 288,2316, 454,1683,5724,5725,1461,4788,4150,2597,5726,5727,4789, 985, 894, # 5120 +5728,3436,3193,5729,1914,2942,3795,1989,5730,2111,1975,5731,4151,5732,2579,1194, # 5136 + 425,5733,4790,3194,1245,3796,4429,5734,5735,2863,5736, 636,4791,1856,3940, 760, # 5152 +1800,5737,4430,2212,1508,4792,4152,1894,1684,2298,5738,5739,4793,4431,4432,2213, # 5168 + 479,5740,5741, 832,5742,4153,2496,5743,2980,2497,3797, 990,3132, 627,1815,2652, # 5184 +4433,1582,4434,2126,2112,3543,4794,5744, 799,4435,3195,5745,4795,2113,1737,3031, # 5200 +1018, 543, 754,4436,3342,1676,4796,4797,4154,4798,1489,5746,3544,5747,2624,2903, # 5216 +4155,5748,5749,2981,5750,5751,5752,5753,3196,4799,4800,2185,1722,5754,3269,3270, # 5232 +1843,3665,1715, 481, 365,1976,1857,5755,5756,1963,2498,4801,5757,2127,3666,3271, # 5248 + 433,1895,2064,2076,5758, 602,2750,5759,5760,5761,5762,5763,3032,1628,3437,5764, # 5264 +3197,4802,4156,2904,4803,2519,5765,2551,2782,5766,5767,5768,3343,4804,2905,5769, # 5280 +4805,5770,2864,4806,4807,1221,2982,4157,2520,5771,5772,5773,1868,1990,5774,5775, # 5296 +5776,1896,5777,5778,4808,1897,4158, 318,5779,2095,4159,4437,5780,5781, 485,5782, # 5312 + 938,3941, 553,2680, 116,5783,3942,3667,5784,3545,2681,2783,3438,3344,2820,5785, # 5328 +3668,2943,4160,1747,2944,2983,5786,5787, 207,5788,4809,5789,4810,2521,5790,3033, # 5344 + 890,3669,3943,5791,1878,3798,3439,5792,2186,2358,3440,1652,5793,5794,5795, 941, # 5360 +2299, 208,3546,4161,2020, 330,4438,3944,2906,2499,3799,4439,4811,5796,5797,5798, # 5376 #last 512 +#Everything below is of no interest for detection purpose +2522,1613,4812,5799,3345,3945,2523,5800,4162,5801,1637,4163,2471,4813,3946,5802, # 5392 +2500,3034,3800,5803,5804,2195,4814,5805,2163,5806,5807,5808,5809,5810,5811,5812, # 5408 +5813,5814,5815,5816,5817,5818,5819,5820,5821,5822,5823,5824,5825,5826,5827,5828, # 5424 +5829,5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840,5841,5842,5843,5844, # 5440 +5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856,5857,5858,5859,5860, # 5456 +5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872,5873,5874,5875,5876, # 5472 +5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888,5889,5890,5891,5892, # 5488 +5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904,5905,5906,5907,5908, # 5504 +5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920,5921,5922,5923,5924, # 5520 +5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936,5937,5938,5939,5940, # 5536 +5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951,5952,5953,5954,5955,5956, # 5552 +5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968,5969,5970,5971,5972, # 5568 +5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,5984,5985,5986,5987,5988, # 5584 +5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,5999,6000,6001,6002,6003,6004, # 5600 +6005,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,6016,6017,6018,6019,6020, # 5616 +6021,6022,6023,6024,6025,6026,6027,6028,6029,6030,6031,6032,6033,6034,6035,6036, # 5632 +6037,6038,6039,6040,6041,6042,6043,6044,6045,6046,6047,6048,6049,6050,6051,6052, # 5648 +6053,6054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064,6065,6066,6067,6068, # 5664 +6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084, # 5680 +6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,6100, # 5696 +6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112,6113,6114,6115,6116, # 5712 +6117,6118,6119,6120,6121,6122,6123,6124,6125,6126,6127,6128,6129,6130,6131,6132, # 5728 +6133,6134,6135,6136,6137,6138,6139,6140,6141,6142,6143,6144,6145,6146,6147,6148, # 5744 +6149,6150,6151,6152,6153,6154,6155,6156,6157,6158,6159,6160,6161,6162,6163,6164, # 5760 +6165,6166,6167,6168,6169,6170,6171,6172,6173,6174,6175,6176,6177,6178,6179,6180, # 5776 +6181,6182,6183,6184,6185,6186,6187,6188,6189,6190,6191,6192,6193,6194,6195,6196, # 5792 +6197,6198,6199,6200,6201,6202,6203,6204,6205,6206,6207,6208,6209,6210,6211,6212, # 5808 +6213,6214,6215,6216,6217,6218,6219,6220,6221,6222,6223,3670,6224,6225,6226,6227, # 5824 +6228,6229,6230,6231,6232,6233,6234,6235,6236,6237,6238,6239,6240,6241,6242,6243, # 5840 +6244,6245,6246,6247,6248,6249,6250,6251,6252,6253,6254,6255,6256,6257,6258,6259, # 5856 +6260,6261,6262,6263,6264,6265,6266,6267,6268,6269,6270,6271,6272,6273,6274,6275, # 5872 +6276,6277,6278,6279,6280,6281,6282,6283,6284,6285,4815,6286,6287,6288,6289,6290, # 5888 +6291,6292,4816,6293,6294,6295,6296,6297,6298,6299,6300,6301,6302,6303,6304,6305, # 5904 +6306,6307,6308,6309,6310,6311,4817,4818,6312,6313,6314,6315,6316,6317,6318,4819, # 5920 +6319,6320,6321,6322,6323,6324,6325,6326,6327,6328,6329,6330,6331,6332,6333,6334, # 5936 +6335,6336,6337,4820,6338,6339,6340,6341,6342,6343,6344,6345,6346,6347,6348,6349, # 5952 +6350,6351,6352,6353,6354,6355,6356,6357,6358,6359,6360,6361,6362,6363,6364,6365, # 5968 +6366,6367,6368,6369,6370,6371,6372,6373,6374,6375,6376,6377,6378,6379,6380,6381, # 5984 +6382,6383,6384,6385,6386,6387,6388,6389,6390,6391,6392,6393,6394,6395,6396,6397, # 6000 +6398,6399,6400,6401,6402,6403,6404,6405,6406,6407,6408,6409,6410,3441,6411,6412, # 6016 +6413,6414,6415,6416,6417,6418,6419,6420,6421,6422,6423,6424,6425,4440,6426,6427, # 6032 +6428,6429,6430,6431,6432,6433,6434,6435,6436,6437,6438,6439,6440,6441,6442,6443, # 6048 +6444,6445,6446,6447,6448,6449,6450,6451,6452,6453,6454,4821,6455,6456,6457,6458, # 6064 +6459,6460,6461,6462,6463,6464,6465,6466,6467,6468,6469,6470,6471,6472,6473,6474, # 6080 +6475,6476,6477,3947,3948,6478,6479,6480,6481,3272,4441,6482,6483,6484,6485,4442, # 6096 +6486,6487,6488,6489,6490,6491,6492,6493,6494,6495,6496,4822,6497,6498,6499,6500, # 6112 +6501,6502,6503,6504,6505,6506,6507,6508,6509,6510,6511,6512,6513,6514,6515,6516, # 6128 +6517,6518,6519,6520,6521,6522,6523,6524,6525,6526,6527,6528,6529,6530,6531,6532, # 6144 +6533,6534,6535,6536,6537,6538,6539,6540,6541,6542,6543,6544,6545,6546,6547,6548, # 6160 +6549,6550,6551,6552,6553,6554,6555,6556,2784,6557,4823,6558,6559,6560,6561,6562, # 6176 +6563,6564,6565,6566,6567,6568,6569,3949,6570,6571,6572,4824,6573,6574,6575,6576, # 6192 +6577,6578,6579,6580,6581,6582,6583,4825,6584,6585,6586,3950,2785,6587,6588,6589, # 6208 +6590,6591,6592,6593,6594,6595,6596,6597,6598,6599,6600,6601,6602,6603,6604,6605, # 6224 +6606,6607,6608,6609,6610,6611,6612,4826,6613,6614,6615,4827,6616,6617,6618,6619, # 6240 +6620,6621,6622,6623,6624,6625,4164,6626,6627,6628,6629,6630,6631,6632,6633,6634, # 6256 +3547,6635,4828,6636,6637,6638,6639,6640,6641,6642,3951,2984,6643,6644,6645,6646, # 6272 +6647,6648,6649,4165,6650,4829,6651,6652,4830,6653,6654,6655,6656,6657,6658,6659, # 6288 +6660,6661,6662,4831,6663,6664,6665,6666,6667,6668,6669,6670,6671,4166,6672,4832, # 6304 +3952,6673,6674,6675,6676,4833,6677,6678,6679,4167,6680,6681,6682,3198,6683,6684, # 6320 +6685,6686,6687,6688,6689,6690,6691,6692,6693,6694,6695,6696,6697,4834,6698,6699, # 6336 +6700,6701,6702,6703,6704,6705,6706,6707,6708,6709,6710,6711,6712,6713,6714,6715, # 6352 +6716,6717,6718,6719,6720,6721,6722,6723,6724,6725,6726,6727,6728,6729,6730,6731, # 6368 +6732,6733,6734,4443,6735,6736,6737,6738,6739,6740,6741,6742,6743,6744,6745,4444, # 6384 +6746,6747,6748,6749,6750,6751,6752,6753,6754,6755,6756,6757,6758,6759,6760,6761, # 6400 +6762,6763,6764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,6775,6776,6777, # 6416 +6778,6779,6780,6781,4168,6782,6783,3442,6784,6785,6786,6787,6788,6789,6790,6791, # 6432 +4169,6792,6793,6794,6795,6796,6797,6798,6799,6800,6801,6802,6803,6804,6805,6806, # 6448 +6807,6808,6809,6810,6811,4835,6812,6813,6814,4445,6815,6816,4446,6817,6818,6819, # 6464 +6820,6821,6822,6823,6824,6825,6826,6827,6828,6829,6830,6831,6832,6833,6834,6835, # 6480 +3548,6836,6837,6838,6839,6840,6841,6842,6843,6844,6845,6846,4836,6847,6848,6849, # 6496 +6850,6851,6852,6853,6854,3953,6855,6856,6857,6858,6859,6860,6861,6862,6863,6864, # 6512 +6865,6866,6867,6868,6869,6870,6871,6872,6873,6874,6875,6876,6877,3199,6878,6879, # 6528 +6880,6881,6882,4447,6883,6884,6885,6886,6887,6888,6889,6890,6891,6892,6893,6894, # 6544 +6895,6896,6897,6898,6899,6900,6901,6902,6903,6904,4170,6905,6906,6907,6908,6909, # 6560 +6910,6911,6912,6913,6914,6915,6916,6917,6918,6919,6920,6921,6922,6923,6924,6925, # 6576 +6926,6927,4837,6928,6929,6930,6931,6932,6933,6934,6935,6936,3346,6937,6938,4838, # 6592 +6939,6940,6941,4448,6942,6943,6944,6945,6946,4449,6947,6948,6949,6950,6951,6952, # 6608 +6953,6954,6955,6956,6957,6958,6959,6960,6961,6962,6963,6964,6965,6966,6967,6968, # 6624 +6969,6970,6971,6972,6973,6974,6975,6976,6977,6978,6979,6980,6981,6982,6983,6984, # 6640 +6985,6986,6987,6988,6989,6990,6991,6992,6993,6994,3671,6995,6996,6997,6998,4839, # 6656 +6999,7000,7001,7002,3549,7003,7004,7005,7006,7007,7008,7009,7010,7011,7012,7013, # 6672 +7014,7015,7016,7017,7018,7019,7020,7021,7022,7023,7024,7025,7026,7027,7028,7029, # 6688 +7030,4840,7031,7032,7033,7034,7035,7036,7037,7038,4841,7039,7040,7041,7042,7043, # 6704 +7044,7045,7046,7047,7048,7049,7050,7051,7052,7053,7054,7055,7056,7057,7058,7059, # 6720 +7060,7061,7062,7063,7064,7065,7066,7067,7068,7069,7070,2985,7071,7072,7073,7074, # 6736 +7075,7076,7077,7078,7079,7080,4842,7081,7082,7083,7084,7085,7086,7087,7088,7089, # 6752 +7090,7091,7092,7093,7094,7095,7096,7097,7098,7099,7100,7101,7102,7103,7104,7105, # 6768 +7106,7107,7108,7109,7110,7111,7112,7113,7114,7115,7116,7117,7118,4450,7119,7120, # 6784 +7121,7122,7123,7124,7125,7126,7127,7128,7129,7130,7131,7132,7133,7134,7135,7136, # 6800 +7137,7138,7139,7140,7141,7142,7143,4843,7144,7145,7146,7147,7148,7149,7150,7151, # 6816 +7152,7153,7154,7155,7156,7157,7158,7159,7160,7161,7162,7163,7164,7165,7166,7167, # 6832 +7168,7169,7170,7171,7172,7173,7174,7175,7176,7177,7178,7179,7180,7181,7182,7183, # 6848 +7184,7185,7186,7187,7188,4171,4172,7189,7190,7191,7192,7193,7194,7195,7196,7197, # 6864 +7198,7199,7200,7201,7202,7203,7204,7205,7206,7207,7208,7209,7210,7211,7212,7213, # 6880 +7214,7215,7216,7217,7218,7219,7220,7221,7222,7223,7224,7225,7226,7227,7228,7229, # 6896 +7230,7231,7232,7233,7234,7235,7236,7237,7238,7239,7240,7241,7242,7243,7244,7245, # 6912 +7246,7247,7248,7249,7250,7251,7252,7253,7254,7255,7256,7257,7258,7259,7260,7261, # 6928 +7262,7263,7264,7265,7266,7267,7268,7269,7270,7271,7272,7273,7274,7275,7276,7277, # 6944 +7278,7279,7280,7281,7282,7283,7284,7285,7286,7287,7288,7289,7290,7291,7292,7293, # 6960 +7294,7295,7296,4844,7297,7298,7299,7300,7301,7302,7303,7304,7305,7306,7307,7308, # 6976 +7309,7310,7311,7312,7313,7314,7315,7316,4451,7317,7318,7319,7320,7321,7322,7323, # 6992 +7324,7325,7326,7327,7328,7329,7330,7331,7332,7333,7334,7335,7336,7337,7338,7339, # 7008 +7340,7341,7342,7343,7344,7345,7346,7347,7348,7349,7350,7351,7352,7353,4173,7354, # 7024 +7355,4845,7356,7357,7358,7359,7360,7361,7362,7363,7364,7365,7366,7367,7368,7369, # 7040 +7370,7371,7372,7373,7374,7375,7376,7377,7378,7379,7380,7381,7382,7383,7384,7385, # 7056 +7386,7387,7388,4846,7389,7390,7391,7392,7393,7394,7395,7396,7397,7398,7399,7400, # 7072 +7401,7402,7403,7404,7405,3672,7406,7407,7408,7409,7410,7411,7412,7413,7414,7415, # 7088 +7416,7417,7418,7419,7420,7421,7422,7423,7424,7425,7426,7427,7428,7429,7430,7431, # 7104 +7432,7433,7434,7435,7436,7437,7438,7439,7440,7441,7442,7443,7444,7445,7446,7447, # 7120 +7448,7449,7450,7451,7452,7453,4452,7454,3200,7455,7456,7457,7458,7459,7460,7461, # 7136 +7462,7463,7464,7465,7466,7467,7468,7469,7470,7471,7472,7473,7474,4847,7475,7476, # 7152 +7477,3133,7478,7479,7480,7481,7482,7483,7484,7485,7486,7487,7488,7489,7490,7491, # 7168 +7492,7493,7494,7495,7496,7497,7498,7499,7500,7501,7502,3347,7503,7504,7505,7506, # 7184 +7507,7508,7509,7510,7511,7512,7513,7514,7515,7516,7517,7518,7519,7520,7521,4848, # 7200 +7522,7523,7524,7525,7526,7527,7528,7529,7530,7531,7532,7533,7534,7535,7536,7537, # 7216 +7538,7539,7540,7541,7542,7543,7544,7545,7546,7547,7548,7549,3801,4849,7550,7551, # 7232 +7552,7553,7554,7555,7556,7557,7558,7559,7560,7561,7562,7563,7564,7565,7566,7567, # 7248 +7568,7569,3035,7570,7571,7572,7573,7574,7575,7576,7577,7578,7579,7580,7581,7582, # 7264 +7583,7584,7585,7586,7587,7588,7589,7590,7591,7592,7593,7594,7595,7596,7597,7598, # 7280 +7599,7600,7601,7602,7603,7604,7605,7606,7607,7608,7609,7610,7611,7612,7613,7614, # 7296 +7615,7616,4850,7617,7618,3802,7619,7620,7621,7622,7623,7624,7625,7626,7627,7628, # 7312 +7629,7630,7631,7632,4851,7633,7634,7635,7636,7637,7638,7639,7640,7641,7642,7643, # 7328 +7644,7645,7646,7647,7648,7649,7650,7651,7652,7653,7654,7655,7656,7657,7658,7659, # 7344 +7660,7661,7662,7663,7664,7665,7666,7667,7668,7669,7670,4453,7671,7672,7673,7674, # 7360 +7675,7676,7677,7678,7679,7680,7681,7682,7683,7684,7685,7686,7687,7688,7689,7690, # 7376 +7691,7692,7693,7694,7695,7696,7697,3443,7698,7699,7700,7701,7702,4454,7703,7704, # 7392 +7705,7706,7707,7708,7709,7710,7711,7712,7713,2472,7714,7715,7716,7717,7718,7719, # 7408 +7720,7721,7722,7723,7724,7725,7726,7727,7728,7729,7730,7731,3954,7732,7733,7734, # 7424 +7735,7736,7737,7738,7739,7740,7741,7742,7743,7744,7745,7746,7747,7748,7749,7750, # 7440 +3134,7751,7752,4852,7753,7754,7755,4853,7756,7757,7758,7759,7760,4174,7761,7762, # 7456 +7763,7764,7765,7766,7767,7768,7769,7770,7771,7772,7773,7774,7775,7776,7777,7778, # 7472 +7779,7780,7781,7782,7783,7784,7785,7786,7787,7788,7789,7790,7791,7792,7793,7794, # 7488 +7795,7796,7797,7798,7799,7800,7801,7802,7803,7804,7805,4854,7806,7807,7808,7809, # 7504 +7810,7811,7812,7813,7814,7815,7816,7817,7818,7819,7820,7821,7822,7823,7824,7825, # 7520 +4855,7826,7827,7828,7829,7830,7831,7832,7833,7834,7835,7836,7837,7838,7839,7840, # 7536 +7841,7842,7843,7844,7845,7846,7847,3955,7848,7849,7850,7851,7852,7853,7854,7855, # 7552 +7856,7857,7858,7859,7860,3444,7861,7862,7863,7864,7865,7866,7867,7868,7869,7870, # 7568 +7871,7872,7873,7874,7875,7876,7877,7878,7879,7880,7881,7882,7883,7884,7885,7886, # 7584 +7887,7888,7889,7890,7891,4175,7892,7893,7894,7895,7896,4856,4857,7897,7898,7899, # 7600 +7900,2598,7901,7902,7903,7904,7905,7906,7907,7908,4455,7909,7910,7911,7912,7913, # 7616 +7914,3201,7915,7916,7917,7918,7919,7920,7921,4858,7922,7923,7924,7925,7926,7927, # 7632 +7928,7929,7930,7931,7932,7933,7934,7935,7936,7937,7938,7939,7940,7941,7942,7943, # 7648 +7944,7945,7946,7947,7948,7949,7950,7951,7952,7953,7954,7955,7956,7957,7958,7959, # 7664 +7960,7961,7962,7963,7964,7965,7966,7967,7968,7969,7970,7971,7972,7973,7974,7975, # 7680 +7976,7977,7978,7979,7980,7981,4859,7982,7983,7984,7985,7986,7987,7988,7989,7990, # 7696 +7991,7992,7993,7994,7995,7996,4860,7997,7998,7999,8000,8001,8002,8003,8004,8005, # 7712 +8006,8007,8008,8009,8010,8011,8012,8013,8014,8015,8016,4176,8017,8018,8019,8020, # 7728 +8021,8022,8023,4861,8024,8025,8026,8027,8028,8029,8030,8031,8032,8033,8034,8035, # 7744 +8036,4862,4456,8037,8038,8039,8040,4863,8041,8042,8043,8044,8045,8046,8047,8048, # 7760 +8049,8050,8051,8052,8053,8054,8055,8056,8057,8058,8059,8060,8061,8062,8063,8064, # 7776 +8065,8066,8067,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079,8080, # 7792 +8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095,8096, # 7808 +8097,8098,8099,4864,4177,8100,8101,8102,8103,8104,8105,8106,8107,8108,8109,8110, # 7824 +8111,8112,8113,8114,8115,8116,8117,8118,8119,8120,4178,8121,8122,8123,8124,8125, # 7840 +8126,8127,8128,8129,8130,8131,8132,8133,8134,8135,8136,8137,8138,8139,8140,8141, # 7856 +8142,8143,8144,8145,4865,4866,8146,8147,8148,8149,8150,8151,8152,8153,8154,8155, # 7872 +8156,8157,8158,8159,8160,8161,8162,8163,8164,8165,4179,8166,8167,8168,8169,8170, # 7888 +8171,8172,8173,8174,8175,8176,8177,8178,8179,8180,8181,4457,8182,8183,8184,8185, # 7904 +8186,8187,8188,8189,8190,8191,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201, # 7920 +8202,8203,8204,8205,8206,8207,8208,8209,8210,8211,8212,8213,8214,8215,8216,8217, # 7936 +8218,8219,8220,8221,8222,8223,8224,8225,8226,8227,8228,8229,8230,8231,8232,8233, # 7952 +8234,8235,8236,8237,8238,8239,8240,8241,8242,8243,8244,8245,8246,8247,8248,8249, # 7968 +8250,8251,8252,8253,8254,8255,8256,3445,8257,8258,8259,8260,8261,8262,4458,8263, # 7984 +8264,8265,8266,8267,8268,8269,8270,8271,8272,4459,8273,8274,8275,8276,3550,8277, # 8000 +8278,8279,8280,8281,8282,8283,8284,8285,8286,8287,8288,8289,4460,8290,8291,8292, # 8016 +8293,8294,8295,8296,8297,8298,8299,8300,8301,8302,8303,8304,8305,8306,8307,4867, # 8032 +8308,8309,8310,8311,8312,3551,8313,8314,8315,8316,8317,8318,8319,8320,8321,8322, # 8048 +8323,8324,8325,8326,4868,8327,8328,8329,8330,8331,8332,8333,8334,8335,8336,8337, # 8064 +8338,8339,8340,8341,8342,8343,8344,8345,8346,8347,8348,8349,8350,8351,8352,8353, # 8080 +8354,8355,8356,8357,8358,8359,8360,8361,8362,8363,4869,4461,8364,8365,8366,8367, # 8096 +8368,8369,8370,4870,8371,8372,8373,8374,8375,8376,8377,8378,8379,8380,8381,8382, # 8112 +8383,8384,8385,8386,8387,8388,8389,8390,8391,8392,8393,8394,8395,8396,8397,8398, # 8128 +8399,8400,8401,8402,8403,8404,8405,8406,8407,8408,8409,8410,4871,8411,8412,8413, # 8144 +8414,8415,8416,8417,8418,8419,8420,8421,8422,4462,8423,8424,8425,8426,8427,8428, # 8160 +8429,8430,8431,8432,8433,2986,8434,8435,8436,8437,8438,8439,8440,8441,8442,8443, # 8176 +8444,8445,8446,8447,8448,8449,8450,8451,8452,8453,8454,8455,8456,8457,8458,8459, # 8192 +8460,8461,8462,8463,8464,8465,8466,8467,8468,8469,8470,8471,8472,8473,8474,8475, # 8208 +8476,8477,8478,4180,8479,8480,8481,8482,8483,8484,8485,8486,8487,8488,8489,8490, # 8224 +8491,8492,8493,8494,8495,8496,8497,8498,8499,8500,8501,8502,8503,8504,8505,8506, # 8240 +8507,8508,8509,8510,8511,8512,8513,8514,8515,8516,8517,8518,8519,8520,8521,8522, # 8256 +8523,8524,8525,8526,8527,8528,8529,8530,8531,8532,8533,8534,8535,8536,8537,8538, # 8272 +8539,8540,8541,8542,8543,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554, # 8288 +8555,8556,8557,8558,8559,8560,8561,8562,8563,8564,4872,8565,8566,8567,8568,8569, # 8304 +8570,8571,8572,8573,4873,8574,8575,8576,8577,8578,8579,8580,8581,8582,8583,8584, # 8320 +8585,8586,8587,8588,8589,8590,8591,8592,8593,8594,8595,8596,8597,8598,8599,8600, # 8336 +8601,8602,8603,8604,8605,3803,8606,8607,8608,8609,8610,8611,8612,8613,4874,3804, # 8352 +8614,8615,8616,8617,8618,8619,8620,8621,3956,8622,8623,8624,8625,8626,8627,8628, # 8368 +8629,8630,8631,8632,8633,8634,8635,8636,8637,8638,2865,8639,8640,8641,8642,8643, # 8384 +8644,8645,8646,8647,8648,8649,8650,8651,8652,8653,8654,8655,8656,4463,8657,8658, # 8400 +8659,4875,4876,8660,8661,8662,8663,8664,8665,8666,8667,8668,8669,8670,8671,8672, # 8416 +8673,8674,8675,8676,8677,8678,8679,8680,8681,4464,8682,8683,8684,8685,8686,8687, # 8432 +8688,8689,8690,8691,8692,8693,8694,8695,8696,8697,8698,8699,8700,8701,8702,8703, # 8448 +8704,8705,8706,8707,8708,8709,2261,8710,8711,8712,8713,8714,8715,8716,8717,8718, # 8464 +8719,8720,8721,8722,8723,8724,8725,8726,8727,8728,8729,8730,8731,8732,8733,4181, # 8480 +8734,8735,8736,8737,8738,8739,8740,8741,8742,8743,8744,8745,8746,8747,8748,8749, # 8496 +8750,8751,8752,8753,8754,8755,8756,8757,8758,8759,8760,8761,8762,8763,4877,8764, # 8512 +8765,8766,8767,8768,8769,8770,8771,8772,8773,8774,8775,8776,8777,8778,8779,8780, # 8528 +8781,8782,8783,8784,8785,8786,8787,8788,4878,8789,4879,8790,8791,8792,4880,8793, # 8544 +8794,8795,8796,8797,8798,8799,8800,8801,4881,8802,8803,8804,8805,8806,8807,8808, # 8560 +8809,8810,8811,8812,8813,8814,8815,3957,8816,8817,8818,8819,8820,8821,8822,8823, # 8576 +8824,8825,8826,8827,8828,8829,8830,8831,8832,8833,8834,8835,8836,8837,8838,8839, # 8592 +8840,8841,8842,8843,8844,8845,8846,8847,4882,8848,8849,8850,8851,8852,8853,8854, # 8608 +8855,8856,8857,8858,8859,8860,8861,8862,8863,8864,8865,8866,8867,8868,8869,8870, # 8624 +8871,8872,8873,8874,8875,8876,8877,8878,8879,8880,8881,8882,8883,8884,3202,8885, # 8640 +8886,8887,8888,8889,8890,8891,8892,8893,8894,8895,8896,8897,8898,8899,8900,8901, # 8656 +8902,8903,8904,8905,8906,8907,8908,8909,8910,8911,8912,8913,8914,8915,8916,8917, # 8672 +8918,8919,8920,8921,8922,8923,8924,4465,8925,8926,8927,8928,8929,8930,8931,8932, # 8688 +4883,8933,8934,8935,8936,8937,8938,8939,8940,8941,8942,8943,2214,8944,8945,8946, # 8704 +8947,8948,8949,8950,8951,8952,8953,8954,8955,8956,8957,8958,8959,8960,8961,8962, # 8720 +8963,8964,8965,4884,8966,8967,8968,8969,8970,8971,8972,8973,8974,8975,8976,8977, # 8736 +8978,8979,8980,8981,8982,8983,8984,8985,8986,8987,8988,8989,8990,8991,8992,4885, # 8752 +8993,8994,8995,8996,8997,8998,8999,9000,9001,9002,9003,9004,9005,9006,9007,9008, # 8768 +9009,9010,9011,9012,9013,9014,9015,9016,9017,9018,9019,9020,9021,4182,9022,9023, # 8784 +9024,9025,9026,9027,9028,9029,9030,9031,9032,9033,9034,9035,9036,9037,9038,9039, # 8800 +9040,9041,9042,9043,9044,9045,9046,9047,9048,9049,9050,9051,9052,9053,9054,9055, # 8816 +9056,9057,9058,9059,9060,9061,9062,9063,4886,9064,9065,9066,9067,9068,9069,4887, # 8832 +9070,9071,9072,9073,9074,9075,9076,9077,9078,9079,9080,9081,9082,9083,9084,9085, # 8848 +9086,9087,9088,9089,9090,9091,9092,9093,9094,9095,9096,9097,9098,9099,9100,9101, # 8864 +9102,9103,9104,9105,9106,9107,9108,9109,9110,9111,9112,9113,9114,9115,9116,9117, # 8880 +9118,9119,9120,9121,9122,9123,9124,9125,9126,9127,9128,9129,9130,9131,9132,9133, # 8896 +9134,9135,9136,9137,9138,9139,9140,9141,3958,9142,9143,9144,9145,9146,9147,9148, # 8912 +9149,9150,9151,4888,9152,9153,9154,9155,9156,9157,9158,9159,9160,9161,9162,9163, # 8928 +9164,9165,9166,9167,9168,9169,9170,9171,9172,9173,9174,9175,4889,9176,9177,9178, # 8944 +9179,9180,9181,9182,9183,9184,9185,9186,9187,9188,9189,9190,9191,9192,9193,9194, # 8960 +9195,9196,9197,9198,9199,9200,9201,9202,9203,4890,9204,9205,9206,9207,9208,9209, # 8976 +9210,9211,9212,9213,9214,9215,9216,9217,9218,9219,9220,9221,9222,4466,9223,9224, # 8992 +9225,9226,9227,9228,9229,9230,9231,9232,9233,9234,9235,9236,9237,9238,9239,9240, # 9008 +9241,9242,9243,9244,9245,4891,9246,9247,9248,9249,9250,9251,9252,9253,9254,9255, # 9024 +9256,9257,4892,9258,9259,9260,9261,4893,4894,9262,9263,9264,9265,9266,9267,9268, # 9040 +9269,9270,9271,9272,9273,4467,9274,9275,9276,9277,9278,9279,9280,9281,9282,9283, # 9056 +9284,9285,3673,9286,9287,9288,9289,9290,9291,9292,9293,9294,9295,9296,9297,9298, # 9072 +9299,9300,9301,9302,9303,9304,9305,9306,9307,9308,9309,9310,9311,9312,9313,9314, # 9088 +9315,9316,9317,9318,9319,9320,9321,9322,4895,9323,9324,9325,9326,9327,9328,9329, # 9104 +9330,9331,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,9343,9344,9345, # 9120 +9346,9347,4468,9348,9349,9350,9351,9352,9353,9354,9355,9356,9357,9358,9359,9360, # 9136 +9361,9362,9363,9364,9365,9366,9367,9368,9369,9370,9371,9372,9373,4896,9374,4469, # 9152 +9375,9376,9377,9378,9379,4897,9380,9381,9382,9383,9384,9385,9386,9387,9388,9389, # 9168 +9390,9391,9392,9393,9394,9395,9396,9397,9398,9399,9400,9401,9402,9403,9404,9405, # 9184 +9406,4470,9407,2751,9408,9409,3674,3552,9410,9411,9412,9413,9414,9415,9416,9417, # 9200 +9418,9419,9420,9421,4898,9422,9423,9424,9425,9426,9427,9428,9429,3959,9430,9431, # 9216 +9432,9433,9434,9435,9436,4471,9437,9438,9439,9440,9441,9442,9443,9444,9445,9446, # 9232 +9447,9448,9449,9450,3348,9451,9452,9453,9454,9455,9456,9457,9458,9459,9460,9461, # 9248 +9462,9463,9464,9465,9466,9467,9468,9469,9470,9471,9472,4899,9473,9474,9475,9476, # 9264 +9477,4900,9478,9479,9480,9481,9482,9483,9484,9485,9486,9487,9488,3349,9489,9490, # 9280 +9491,9492,9493,9494,9495,9496,9497,9498,9499,9500,9501,9502,9503,9504,9505,9506, # 9296 +9507,9508,9509,9510,9511,9512,9513,9514,9515,9516,9517,9518,9519,9520,4901,9521, # 9312 +9522,9523,9524,9525,9526,4902,9527,9528,9529,9530,9531,9532,9533,9534,9535,9536, # 9328 +9537,9538,9539,9540,9541,9542,9543,9544,9545,9546,9547,9548,9549,9550,9551,9552, # 9344 +9553,9554,9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567,9568, # 9360 +9569,9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,9581,9582,9583,9584, # 9376 +3805,9585,9586,9587,9588,9589,9590,9591,9592,9593,9594,9595,9596,9597,9598,9599, # 9392 +9600,9601,9602,4903,9603,9604,9605,9606,9607,4904,9608,9609,9610,9611,9612,9613, # 9408 +9614,4905,9615,9616,9617,9618,9619,9620,9621,9622,9623,9624,9625,9626,9627,9628, # 9424 +9629,9630,9631,9632,4906,9633,9634,9635,9636,9637,9638,9639,9640,9641,9642,9643, # 9440 +4907,9644,9645,9646,9647,9648,9649,9650,9651,9652,9653,9654,9655,9656,9657,9658, # 9456 +9659,9660,9661,9662,9663,9664,9665,9666,9667,9668,9669,9670,9671,9672,4183,9673, # 9472 +9674,9675,9676,9677,4908,9678,9679,9680,9681,4909,9682,9683,9684,9685,9686,9687, # 9488 +9688,9689,9690,4910,9691,9692,9693,3675,9694,9695,9696,2945,9697,9698,9699,9700, # 9504 +9701,9702,9703,9704,9705,4911,9706,9707,9708,9709,9710,9711,9712,9713,9714,9715, # 9520 +9716,9717,9718,9719,9720,9721,9722,9723,9724,9725,9726,9727,9728,9729,9730,9731, # 9536 +9732,9733,9734,9735,4912,9736,9737,9738,9739,9740,4913,9741,9742,9743,9744,9745, # 9552 +9746,9747,9748,9749,9750,9751,9752,9753,9754,9755,9756,9757,9758,4914,9759,9760, # 9568 +9761,9762,9763,9764,9765,9766,9767,9768,9769,9770,9771,9772,9773,9774,9775,9776, # 9584 +9777,9778,9779,9780,9781,9782,4915,9783,9784,9785,9786,9787,9788,9789,9790,9791, # 9600 +9792,9793,4916,9794,9795,9796,9797,9798,9799,9800,9801,9802,9803,9804,9805,9806, # 9616 +9807,9808,9809,9810,9811,9812,9813,9814,9815,9816,9817,9818,9819,9820,9821,9822, # 9632 +9823,9824,9825,9826,9827,9828,9829,9830,9831,9832,9833,9834,9835,9836,9837,9838, # 9648 +9839,9840,9841,9842,9843,9844,9845,9846,9847,9848,9849,9850,9851,9852,9853,9854, # 9664 +9855,9856,9857,9858,9859,9860,9861,9862,9863,9864,9865,9866,9867,9868,4917,9869, # 9680 +9870,9871,9872,9873,9874,9875,9876,9877,9878,9879,9880,9881,9882,9883,9884,9885, # 9696 +9886,9887,9888,9889,9890,9891,9892,4472,9893,9894,9895,9896,9897,3806,9898,9899, # 9712 +9900,9901,9902,9903,9904,9905,9906,9907,9908,9909,9910,9911,9912,9913,9914,4918, # 9728 +9915,9916,9917,4919,9918,9919,9920,9921,4184,9922,9923,9924,9925,9926,9927,9928, # 9744 +9929,9930,9931,9932,9933,9934,9935,9936,9937,9938,9939,9940,9941,9942,9943,9944, # 9760 +9945,9946,4920,9947,9948,9949,9950,9951,9952,9953,9954,9955,4185,9956,9957,9958, # 9776 +9959,9960,9961,9962,9963,9964,9965,4921,9966,9967,9968,4473,9969,9970,9971,9972, # 9792 +9973,9974,9975,9976,9977,4474,9978,9979,9980,9981,9982,9983,9984,9985,9986,9987, # 9808 +9988,9989,9990,9991,9992,9993,9994,9995,9996,9997,9998,9999,10000,10001,10002,10003, # 9824 +10004,10005,10006,10007,10008,10009,10010,10011,10012,10013,10014,10015,10016,10017,10018,10019, # 9840 +10020,10021,4922,10022,4923,10023,10024,10025,10026,10027,10028,10029,10030,10031,10032,10033, # 9856 +10034,10035,10036,10037,10038,10039,10040,10041,10042,10043,10044,10045,10046,10047,10048,4924, # 9872 +10049,10050,10051,10052,10053,10054,10055,10056,10057,10058,10059,10060,10061,10062,10063,10064, # 9888 +10065,10066,10067,10068,10069,10070,10071,10072,10073,10074,10075,10076,10077,10078,10079,10080, # 9904 +10081,10082,10083,10084,10085,10086,10087,4475,10088,10089,10090,10091,10092,10093,10094,10095, # 9920 +10096,10097,4476,10098,10099,10100,10101,10102,10103,10104,10105,10106,10107,10108,10109,10110, # 9936 +10111,2174,10112,10113,10114,10115,10116,10117,10118,10119,10120,10121,10122,10123,10124,10125, # 9952 +10126,10127,10128,10129,10130,10131,10132,10133,10134,10135,10136,10137,10138,10139,10140,3807, # 9968 +4186,4925,10141,10142,10143,10144,10145,10146,10147,4477,4187,10148,10149,10150,10151,10152, # 9984 +10153,4188,10154,10155,10156,10157,10158,10159,10160,10161,4926,10162,10163,10164,10165,10166, #10000 +10167,10168,10169,10170,10171,10172,10173,10174,10175,10176,10177,10178,10179,10180,10181,10182, #10016 +10183,10184,10185,10186,10187,10188,10189,10190,10191,10192,3203,10193,10194,10195,10196,10197, #10032 +10198,10199,10200,4478,10201,10202,10203,10204,4479,10205,10206,10207,10208,10209,10210,10211, #10048 +10212,10213,10214,10215,10216,10217,10218,10219,10220,10221,10222,10223,10224,10225,10226,10227, #10064 +10228,10229,10230,10231,10232,10233,10234,4927,10235,10236,10237,10238,10239,10240,10241,10242, #10080 +10243,10244,10245,10246,10247,10248,10249,10250,10251,10252,10253,10254,10255,10256,10257,10258, #10096 +10259,10260,10261,10262,10263,10264,10265,10266,10267,10268,10269,10270,10271,10272,10273,4480, #10112 +4928,4929,10274,10275,10276,10277,10278,10279,10280,10281,10282,10283,10284,10285,10286,10287, #10128 +10288,10289,10290,10291,10292,10293,10294,10295,10296,10297,10298,10299,10300,10301,10302,10303, #10144 +10304,10305,10306,10307,10308,10309,10310,10311,10312,10313,10314,10315,10316,10317,10318,10319, #10160 +10320,10321,10322,10323,10324,10325,10326,10327,10328,10329,10330,10331,10332,10333,10334,4930, #10176 +10335,10336,10337,10338,10339,10340,10341,10342,4931,10343,10344,10345,10346,10347,10348,10349, #10192 +10350,10351,10352,10353,10354,10355,3088,10356,2786,10357,10358,10359,10360,4189,10361,10362, #10208 +10363,10364,10365,10366,10367,10368,10369,10370,10371,10372,10373,10374,10375,4932,10376,10377, #10224 +10378,10379,10380,10381,10382,10383,10384,10385,10386,10387,10388,10389,10390,10391,10392,4933, #10240 +10393,10394,10395,4934,10396,10397,10398,10399,10400,10401,10402,10403,10404,10405,10406,10407, #10256 +10408,10409,10410,10411,10412,3446,10413,10414,10415,10416,10417,10418,10419,10420,10421,10422, #10272 +10423,4935,10424,10425,10426,10427,10428,10429,10430,4936,10431,10432,10433,10434,10435,10436, #10288 +10437,10438,10439,10440,10441,10442,10443,4937,10444,10445,10446,10447,4481,10448,10449,10450, #10304 +10451,10452,10453,10454,10455,10456,10457,10458,10459,10460,10461,10462,10463,10464,10465,10466, #10320 +10467,10468,10469,10470,10471,10472,10473,10474,10475,10476,10477,10478,10479,10480,10481,10482, #10336 +10483,10484,10485,10486,10487,10488,10489,10490,10491,10492,10493,10494,10495,10496,10497,10498, #10352 +10499,10500,10501,10502,10503,10504,10505,4938,10506,10507,10508,10509,10510,2552,10511,10512, #10368 +10513,10514,10515,10516,3447,10517,10518,10519,10520,10521,10522,10523,10524,10525,10526,10527, #10384 +10528,10529,10530,10531,10532,10533,10534,10535,10536,10537,10538,10539,10540,10541,10542,10543, #10400 +4482,10544,4939,10545,10546,10547,10548,10549,10550,10551,10552,10553,10554,10555,10556,10557, #10416 +10558,10559,10560,10561,10562,10563,10564,10565,10566,10567,3676,4483,10568,10569,10570,10571, #10432 +10572,3448,10573,10574,10575,10576,10577,10578,10579,10580,10581,10582,10583,10584,10585,10586, #10448 +10587,10588,10589,10590,10591,10592,10593,10594,10595,10596,10597,10598,10599,10600,10601,10602, #10464 +10603,10604,10605,10606,10607,10608,10609,10610,10611,10612,10613,10614,10615,10616,10617,10618, #10480 +10619,10620,10621,10622,10623,10624,10625,10626,10627,4484,10628,10629,10630,10631,10632,4940, #10496 +10633,10634,10635,10636,10637,10638,10639,10640,10641,10642,10643,10644,10645,10646,10647,10648, #10512 +10649,10650,10651,10652,10653,10654,10655,10656,4941,10657,10658,10659,2599,10660,10661,10662, #10528 +10663,10664,10665,10666,3089,10667,10668,10669,10670,10671,10672,10673,10674,10675,10676,10677, #10544 +10678,10679,10680,4942,10681,10682,10683,10684,10685,10686,10687,10688,10689,10690,10691,10692, #10560 +10693,10694,10695,10696,10697,4485,10698,10699,10700,10701,10702,10703,10704,4943,10705,3677, #10576 +10706,10707,10708,10709,10710,10711,10712,4944,10713,10714,10715,10716,10717,10718,10719,10720, #10592 +10721,10722,10723,10724,10725,10726,10727,10728,4945,10729,10730,10731,10732,10733,10734,10735, #10608 +10736,10737,10738,10739,10740,10741,10742,10743,10744,10745,10746,10747,10748,10749,10750,10751, #10624 +10752,10753,10754,10755,10756,10757,10758,10759,10760,10761,4946,10762,10763,10764,10765,10766, #10640 +10767,4947,4948,10768,10769,10770,10771,10772,10773,10774,10775,10776,10777,10778,10779,10780, #10656 +10781,10782,10783,10784,10785,10786,10787,10788,10789,10790,10791,10792,10793,10794,10795,10796, #10672 +10797,10798,10799,10800,10801,10802,10803,10804,10805,10806,10807,10808,10809,10810,10811,10812, #10688 +10813,10814,10815,10816,10817,10818,10819,10820,10821,10822,10823,10824,10825,10826,10827,10828, #10704 +10829,10830,10831,10832,10833,10834,10835,10836,10837,10838,10839,10840,10841,10842,10843,10844, #10720 +10845,10846,10847,10848,10849,10850,10851,10852,10853,10854,10855,10856,10857,10858,10859,10860, #10736 +10861,10862,10863,10864,10865,10866,10867,10868,10869,10870,10871,10872,10873,10874,10875,10876, #10752 +10877,10878,4486,10879,10880,10881,10882,10883,10884,10885,4949,10886,10887,10888,10889,10890, #10768 +10891,10892,10893,10894,10895,10896,10897,10898,10899,10900,10901,10902,10903,10904,10905,10906, #10784 +10907,10908,10909,10910,10911,10912,10913,10914,10915,10916,10917,10918,10919,4487,10920,10921, #10800 +10922,10923,10924,10925,10926,10927,10928,10929,10930,10931,10932,4950,10933,10934,10935,10936, #10816 +10937,10938,10939,10940,10941,10942,10943,10944,10945,10946,10947,10948,10949,4488,10950,10951, #10832 +10952,10953,10954,10955,10956,10957,10958,10959,4190,10960,10961,10962,10963,10964,10965,10966, #10848 +10967,10968,10969,10970,10971,10972,10973,10974,10975,10976,10977,10978,10979,10980,10981,10982, #10864 +10983,10984,10985,10986,10987,10988,10989,10990,10991,10992,10993,10994,10995,10996,10997,10998, #10880 +10999,11000,11001,11002,11003,11004,11005,11006,3960,11007,11008,11009,11010,11011,11012,11013, #10896 +11014,11015,11016,11017,11018,11019,11020,11021,11022,11023,11024,11025,11026,11027,11028,11029, #10912 +11030,11031,11032,4951,11033,11034,11035,11036,11037,11038,11039,11040,11041,11042,11043,11044, #10928 +11045,11046,11047,4489,11048,11049,11050,11051,4952,11052,11053,11054,11055,11056,11057,11058, #10944 +4953,11059,11060,11061,11062,11063,11064,11065,11066,11067,11068,11069,11070,11071,4954,11072, #10960 +11073,11074,11075,11076,11077,11078,11079,11080,11081,11082,11083,11084,11085,11086,11087,11088, #10976 +11089,11090,11091,11092,11093,11094,11095,11096,11097,11098,11099,11100,11101,11102,11103,11104, #10992 +11105,11106,11107,11108,11109,11110,11111,11112,11113,11114,11115,3808,11116,11117,11118,11119, #11008 +11120,11121,11122,11123,11124,11125,11126,11127,11128,11129,11130,11131,11132,11133,11134,4955, #11024 +11135,11136,11137,11138,11139,11140,11141,11142,11143,11144,11145,11146,11147,11148,11149,11150, #11040 +11151,11152,11153,11154,11155,11156,11157,11158,11159,11160,11161,4956,11162,11163,11164,11165, #11056 +11166,11167,11168,11169,11170,11171,11172,11173,11174,11175,11176,11177,11178,11179,11180,4957, #11072 +11181,11182,11183,11184,11185,11186,4958,11187,11188,11189,11190,11191,11192,11193,11194,11195, #11088 +11196,11197,11198,11199,11200,3678,11201,11202,11203,11204,11205,11206,4191,11207,11208,11209, #11104 +11210,11211,11212,11213,11214,11215,11216,11217,11218,11219,11220,11221,11222,11223,11224,11225, #11120 +11226,11227,11228,11229,11230,11231,11232,11233,11234,11235,11236,11237,11238,11239,11240,11241, #11136 +11242,11243,11244,11245,11246,11247,11248,11249,11250,11251,4959,11252,11253,11254,11255,11256, #11152 +11257,11258,11259,11260,11261,11262,11263,11264,11265,11266,11267,11268,11269,11270,11271,11272, #11168 +11273,11274,11275,11276,11277,11278,11279,11280,11281,11282,11283,11284,11285,11286,11287,11288, #11184 +11289,11290,11291,11292,11293,11294,11295,11296,11297,11298,11299,11300,11301,11302,11303,11304, #11200 +11305,11306,11307,11308,11309,11310,11311,11312,11313,11314,3679,11315,11316,11317,11318,4490, #11216 +11319,11320,11321,11322,11323,11324,11325,11326,11327,11328,11329,11330,11331,11332,11333,11334, #11232 +11335,11336,11337,11338,11339,11340,11341,11342,11343,11344,11345,11346,11347,4960,11348,11349, #11248 +11350,11351,11352,11353,11354,11355,11356,11357,11358,11359,11360,11361,11362,11363,11364,11365, #11264 +11366,11367,11368,11369,11370,11371,11372,11373,11374,11375,11376,11377,3961,4961,11378,11379, #11280 +11380,11381,11382,11383,11384,11385,11386,11387,11388,11389,11390,11391,11392,11393,11394,11395, #11296 +11396,11397,4192,11398,11399,11400,11401,11402,11403,11404,11405,11406,11407,11408,11409,11410, #11312 +11411,4962,11412,11413,11414,11415,11416,11417,11418,11419,11420,11421,11422,11423,11424,11425, #11328 +11426,11427,11428,11429,11430,11431,11432,11433,11434,11435,11436,11437,11438,11439,11440,11441, #11344 +11442,11443,11444,11445,11446,11447,11448,11449,11450,11451,11452,11453,11454,11455,11456,11457, #11360 +11458,11459,11460,11461,11462,11463,11464,11465,11466,11467,11468,11469,4963,11470,11471,4491, #11376 +11472,11473,11474,11475,4964,11476,11477,11478,11479,11480,11481,11482,11483,11484,11485,11486, #11392 +11487,11488,11489,11490,11491,11492,4965,11493,11494,11495,11496,11497,11498,11499,11500,11501, #11408 +11502,11503,11504,11505,11506,11507,11508,11509,11510,11511,11512,11513,11514,11515,11516,11517, #11424 +11518,11519,11520,11521,11522,11523,11524,11525,11526,11527,11528,11529,3962,11530,11531,11532, #11440 +11533,11534,11535,11536,11537,11538,11539,11540,11541,11542,11543,11544,11545,11546,11547,11548, #11456 +11549,11550,11551,11552,11553,11554,11555,11556,11557,11558,11559,11560,11561,11562,11563,11564, #11472 +4193,4194,11565,11566,11567,11568,11569,11570,11571,11572,11573,11574,11575,11576,11577,11578, #11488 +11579,11580,11581,11582,11583,11584,11585,11586,11587,11588,11589,11590,11591,4966,4195,11592, #11504 +11593,11594,11595,11596,11597,11598,11599,11600,11601,11602,11603,11604,3090,11605,11606,11607, #11520 +11608,11609,11610,4967,11611,11612,11613,11614,11615,11616,11617,11618,11619,11620,11621,11622, #11536 +11623,11624,11625,11626,11627,11628,11629,11630,11631,11632,11633,11634,11635,11636,11637,11638, #11552 +11639,11640,11641,11642,11643,11644,11645,11646,11647,11648,11649,11650,11651,11652,11653,11654, #11568 +11655,11656,11657,11658,11659,11660,11661,11662,11663,11664,11665,11666,11667,11668,11669,11670, #11584 +11671,11672,11673,11674,4968,11675,11676,11677,11678,11679,11680,11681,11682,11683,11684,11685, #11600 +11686,11687,11688,11689,11690,11691,11692,11693,3809,11694,11695,11696,11697,11698,11699,11700, #11616 +11701,11702,11703,11704,11705,11706,11707,11708,11709,11710,11711,11712,11713,11714,11715,11716, #11632 +11717,11718,3553,11719,11720,11721,11722,11723,11724,11725,11726,11727,11728,11729,11730,4969, #11648 +11731,11732,11733,11734,11735,11736,11737,11738,11739,11740,4492,11741,11742,11743,11744,11745, #11664 +11746,11747,11748,11749,11750,11751,11752,4970,11753,11754,11755,11756,11757,11758,11759,11760, #11680 +11761,11762,11763,11764,11765,11766,11767,11768,11769,11770,11771,11772,11773,11774,11775,11776, #11696 +11777,11778,11779,11780,11781,11782,11783,11784,11785,11786,11787,11788,11789,11790,4971,11791, #11712 +11792,11793,11794,11795,11796,11797,4972,11798,11799,11800,11801,11802,11803,11804,11805,11806, #11728 +11807,11808,11809,11810,4973,11811,11812,11813,11814,11815,11816,11817,11818,11819,11820,11821, #11744 +11822,11823,11824,11825,11826,11827,11828,11829,11830,11831,11832,11833,11834,3680,3810,11835, #11760 +11836,4974,11837,11838,11839,11840,11841,11842,11843,11844,11845,11846,11847,11848,11849,11850, #11776 +11851,11852,11853,11854,11855,11856,11857,11858,11859,11860,11861,11862,11863,11864,11865,11866, #11792 +11867,11868,11869,11870,11871,11872,11873,11874,11875,11876,11877,11878,11879,11880,11881,11882, #11808 +11883,11884,4493,11885,11886,11887,11888,11889,11890,11891,11892,11893,11894,11895,11896,11897, #11824 +11898,11899,11900,11901,11902,11903,11904,11905,11906,11907,11908,11909,11910,11911,11912,11913, #11840 +11914,11915,4975,11916,11917,11918,11919,11920,11921,11922,11923,11924,11925,11926,11927,11928, #11856 +11929,11930,11931,11932,11933,11934,11935,11936,11937,11938,11939,11940,11941,11942,11943,11944, #11872 +11945,11946,11947,11948,11949,4976,11950,11951,11952,11953,11954,11955,11956,11957,11958,11959, #11888 +11960,11961,11962,11963,11964,11965,11966,11967,11968,11969,11970,11971,11972,11973,11974,11975, #11904 +11976,11977,11978,11979,11980,11981,11982,11983,11984,11985,11986,11987,4196,11988,11989,11990, #11920 +11991,11992,4977,11993,11994,11995,11996,11997,11998,11999,12000,12001,12002,12003,12004,12005, #11936 +12006,12007,12008,12009,12010,12011,12012,12013,12014,12015,12016,12017,12018,12019,12020,12021, #11952 +12022,12023,12024,12025,12026,12027,12028,12029,12030,12031,12032,12033,12034,12035,12036,12037, #11968 +12038,12039,12040,12041,12042,12043,12044,12045,12046,12047,12048,12049,12050,12051,12052,12053, #11984 +12054,12055,12056,12057,12058,12059,12060,12061,4978,12062,12063,12064,12065,12066,12067,12068, #12000 +12069,12070,12071,12072,12073,12074,12075,12076,12077,12078,12079,12080,12081,12082,12083,12084, #12016 +12085,12086,12087,12088,12089,12090,12091,12092,12093,12094,12095,12096,12097,12098,12099,12100, #12032 +12101,12102,12103,12104,12105,12106,12107,12108,12109,12110,12111,12112,12113,12114,12115,12116, #12048 +12117,12118,12119,12120,12121,12122,12123,4979,12124,12125,12126,12127,12128,4197,12129,12130, #12064 +12131,12132,12133,12134,12135,12136,12137,12138,12139,12140,12141,12142,12143,12144,12145,12146, #12080 +12147,12148,12149,12150,12151,12152,12153,12154,4980,12155,12156,12157,12158,12159,12160,4494, #12096 +12161,12162,12163,12164,3811,12165,12166,12167,12168,12169,4495,12170,12171,4496,12172,12173, #12112 +12174,12175,12176,3812,12177,12178,12179,12180,12181,12182,12183,12184,12185,12186,12187,12188, #12128 +12189,12190,12191,12192,12193,12194,12195,12196,12197,12198,12199,12200,12201,12202,12203,12204, #12144 +12205,12206,12207,12208,12209,12210,12211,12212,12213,12214,12215,12216,12217,12218,12219,12220, #12160 +12221,4981,12222,12223,12224,12225,12226,12227,12228,12229,12230,12231,12232,12233,12234,12235, #12176 +4982,12236,12237,12238,12239,12240,12241,12242,12243,12244,12245,4983,12246,12247,12248,12249, #12192 +4984,12250,12251,12252,12253,12254,12255,12256,12257,12258,12259,12260,12261,12262,12263,12264, #12208 +4985,12265,4497,12266,12267,12268,12269,12270,12271,12272,12273,12274,12275,12276,12277,12278, #12224 +12279,12280,12281,12282,12283,12284,12285,12286,12287,4986,12288,12289,12290,12291,12292,12293, #12240 +12294,12295,12296,2473,12297,12298,12299,12300,12301,12302,12303,12304,12305,12306,12307,12308, #12256 +12309,12310,12311,12312,12313,12314,12315,12316,12317,12318,12319,3963,12320,12321,12322,12323, #12272 +12324,12325,12326,12327,12328,12329,12330,12331,12332,4987,12333,12334,12335,12336,12337,12338, #12288 +12339,12340,12341,12342,12343,12344,12345,12346,12347,12348,12349,12350,12351,12352,12353,12354, #12304 +12355,12356,12357,12358,12359,3964,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369, #12320 +12370,3965,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384, #12336 +12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400, #12352 +12401,12402,12403,12404,12405,12406,12407,12408,4988,12409,12410,12411,12412,12413,12414,12415, #12368 +12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431, #12384 +12432,12433,12434,12435,12436,12437,12438,3554,12439,12440,12441,12442,12443,12444,12445,12446, #12400 +12447,12448,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462, #12416 +12463,12464,4989,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477, #12432 +12478,12479,12480,4990,12481,12482,12483,12484,12485,12486,12487,12488,12489,4498,12490,12491, #12448 +12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507, #12464 +12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523, #12480 +12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,12535,12536,12537,12538,12539, #12496 +12540,12541,12542,12543,12544,12545,12546,12547,12548,12549,12550,12551,4991,12552,12553,12554, #12512 +12555,12556,12557,12558,12559,12560,12561,12562,12563,12564,12565,12566,12567,12568,12569,12570, #12528 +12571,12572,12573,12574,12575,12576,12577,12578,3036,12579,12580,12581,12582,12583,3966,12584, #12544 +12585,12586,12587,12588,12589,12590,12591,12592,12593,12594,12595,12596,12597,12598,12599,12600, #12560 +12601,12602,12603,12604,12605,12606,12607,12608,12609,12610,12611,12612,12613,12614,12615,12616, #12576 +12617,12618,12619,12620,12621,12622,12623,12624,12625,12626,12627,12628,12629,12630,12631,12632, #12592 +12633,12634,12635,12636,12637,12638,12639,12640,12641,12642,12643,12644,12645,12646,4499,12647, #12608 +12648,12649,12650,12651,12652,12653,12654,12655,12656,12657,12658,12659,12660,12661,12662,12663, #12624 +12664,12665,12666,12667,12668,12669,12670,12671,12672,12673,12674,12675,12676,12677,12678,12679, #12640 +12680,12681,12682,12683,12684,12685,12686,12687,12688,12689,12690,12691,12692,12693,12694,12695, #12656 +12696,12697,12698,4992,12699,12700,12701,12702,12703,12704,12705,12706,12707,12708,12709,12710, #12672 +12711,12712,12713,12714,12715,12716,12717,12718,12719,12720,12721,12722,12723,12724,12725,12726, #12688 +12727,12728,12729,12730,12731,12732,12733,12734,12735,12736,12737,12738,12739,12740,12741,12742, #12704 +12743,12744,12745,12746,12747,12748,12749,12750,12751,12752,12753,12754,12755,12756,12757,12758, #12720 +12759,12760,12761,12762,12763,12764,12765,12766,12767,12768,12769,12770,12771,12772,12773,12774, #12736 +12775,12776,12777,12778,4993,2175,12779,12780,12781,12782,12783,12784,12785,12786,4500,12787, #12752 +12788,12789,12790,12791,12792,12793,12794,12795,12796,12797,12798,12799,12800,12801,12802,12803, #12768 +12804,12805,12806,12807,12808,12809,12810,12811,12812,12813,12814,12815,12816,12817,12818,12819, #12784 +12820,12821,12822,12823,12824,12825,12826,4198,3967,12827,12828,12829,12830,12831,12832,12833, #12800 +12834,12835,12836,12837,12838,12839,12840,12841,12842,12843,12844,12845,12846,12847,12848,12849, #12816 +12850,12851,12852,12853,12854,12855,12856,12857,12858,12859,12860,12861,4199,12862,12863,12864, #12832 +12865,12866,12867,12868,12869,12870,12871,12872,12873,12874,12875,12876,12877,12878,12879,12880, #12848 +12881,12882,12883,12884,12885,12886,12887,4501,12888,12889,12890,12891,12892,12893,12894,12895, #12864 +12896,12897,12898,12899,12900,12901,12902,12903,12904,12905,12906,12907,12908,12909,12910,12911, #12880 +12912,4994,12913,12914,12915,12916,12917,12918,12919,12920,12921,12922,12923,12924,12925,12926, #12896 +12927,12928,12929,12930,12931,12932,12933,12934,12935,12936,12937,12938,12939,12940,12941,12942, #12912 +12943,12944,12945,12946,12947,12948,12949,12950,12951,12952,12953,12954,12955,12956,1772,12957, #12928 +12958,12959,12960,12961,12962,12963,12964,12965,12966,12967,12968,12969,12970,12971,12972,12973, #12944 +12974,12975,12976,12977,12978,12979,12980,12981,12982,12983,12984,12985,12986,12987,12988,12989, #12960 +12990,12991,12992,12993,12994,12995,12996,12997,4502,12998,4503,12999,13000,13001,13002,13003, #12976 +4504,13004,13005,13006,13007,13008,13009,13010,13011,13012,13013,13014,13015,13016,13017,13018, #12992 +13019,13020,13021,13022,13023,13024,13025,13026,13027,13028,13029,3449,13030,13031,13032,13033, #13008 +13034,13035,13036,13037,13038,13039,13040,13041,13042,13043,13044,13045,13046,13047,13048,13049, #13024 +13050,13051,13052,13053,13054,13055,13056,13057,13058,13059,13060,13061,13062,13063,13064,13065, #13040 +13066,13067,13068,13069,13070,13071,13072,13073,13074,13075,13076,13077,13078,13079,13080,13081, #13056 +13082,13083,13084,13085,13086,13087,13088,13089,13090,13091,13092,13093,13094,13095,13096,13097, #13072 +13098,13099,13100,13101,13102,13103,13104,13105,13106,13107,13108,13109,13110,13111,13112,13113, #13088 +13114,13115,13116,13117,13118,3968,13119,4995,13120,13121,13122,13123,13124,13125,13126,13127, #13104 +4505,13128,13129,13130,13131,13132,13133,13134,4996,4506,13135,13136,13137,13138,13139,4997, #13120 +13140,13141,13142,13143,13144,13145,13146,13147,13148,13149,13150,13151,13152,13153,13154,13155, #13136 +13156,13157,13158,13159,4998,13160,13161,13162,13163,13164,13165,13166,13167,13168,13169,13170, #13152 +13171,13172,13173,13174,13175,13176,4999,13177,13178,13179,13180,13181,13182,13183,13184,13185, #13168 +13186,13187,13188,13189,13190,13191,13192,13193,13194,13195,13196,13197,13198,13199,13200,13201, #13184 +13202,13203,13204,13205,13206,5000,13207,13208,13209,13210,13211,13212,13213,13214,13215,13216, #13200 +13217,13218,13219,13220,13221,13222,13223,13224,13225,13226,13227,4200,5001,13228,13229,13230, #13216 +13231,13232,13233,13234,13235,13236,13237,13238,13239,13240,3969,13241,13242,13243,13244,3970, #13232 +13245,13246,13247,13248,13249,13250,13251,13252,13253,13254,13255,13256,13257,13258,13259,13260, #13248 +13261,13262,13263,13264,13265,13266,13267,13268,3450,13269,13270,13271,13272,13273,13274,13275, #13264 +13276,5002,13277,13278,13279,13280,13281,13282,13283,13284,13285,13286,13287,13288,13289,13290, #13280 +13291,13292,13293,13294,13295,13296,13297,13298,13299,13300,13301,13302,3813,13303,13304,13305, #13296 +13306,13307,13308,13309,13310,13311,13312,13313,13314,13315,13316,13317,13318,13319,13320,13321, #13312 +13322,13323,13324,13325,13326,13327,13328,4507,13329,13330,13331,13332,13333,13334,13335,13336, #13328 +13337,13338,13339,13340,13341,5003,13342,13343,13344,13345,13346,13347,13348,13349,13350,13351, #13344 +13352,13353,13354,13355,13356,13357,13358,13359,13360,13361,13362,13363,13364,13365,13366,13367, #13360 +5004,13368,13369,13370,13371,13372,13373,13374,13375,13376,13377,13378,13379,13380,13381,13382, #13376 +13383,13384,13385,13386,13387,13388,13389,13390,13391,13392,13393,13394,13395,13396,13397,13398, #13392 +13399,13400,13401,13402,13403,13404,13405,13406,13407,13408,13409,13410,13411,13412,13413,13414, #13408 +13415,13416,13417,13418,13419,13420,13421,13422,13423,13424,13425,13426,13427,13428,13429,13430, #13424 +13431,13432,4508,13433,13434,13435,4201,13436,13437,13438,13439,13440,13441,13442,13443,13444, #13440 +13445,13446,13447,13448,13449,13450,13451,13452,13453,13454,13455,13456,13457,5005,13458,13459, #13456 +13460,13461,13462,13463,13464,13465,13466,13467,13468,13469,13470,4509,13471,13472,13473,13474, #13472 +13475,13476,13477,13478,13479,13480,13481,13482,13483,13484,13485,13486,13487,13488,13489,13490, #13488 +13491,13492,13493,13494,13495,13496,13497,13498,13499,13500,13501,13502,13503,13504,13505,13506, #13504 +13507,13508,13509,13510,13511,13512,13513,13514,13515,13516,13517,13518,13519,13520,13521,13522, #13520 +13523,13524,13525,13526,13527,13528,13529,13530,13531,13532,13533,13534,13535,13536,13537,13538, #13536 +13539,13540,13541,13542,13543,13544,13545,13546,13547,13548,13549,13550,13551,13552,13553,13554, #13552 +13555,13556,13557,13558,13559,13560,13561,13562,13563,13564,13565,13566,13567,13568,13569,13570, #13568 +13571,13572,13573,13574,13575,13576,13577,13578,13579,13580,13581,13582,13583,13584,13585,13586, #13584 +13587,13588,13589,13590,13591,13592,13593,13594,13595,13596,13597,13598,13599,13600,13601,13602, #13600 +13603,13604,13605,13606,13607,13608,13609,13610,13611,13612,13613,13614,13615,13616,13617,13618, #13616 +13619,13620,13621,13622,13623,13624,13625,13626,13627,13628,13629,13630,13631,13632,13633,13634, #13632 +13635,13636,13637,13638,13639,13640,13641,13642,5006,13643,13644,13645,13646,13647,13648,13649, #13648 +13650,13651,5007,13652,13653,13654,13655,13656,13657,13658,13659,13660,13661,13662,13663,13664, #13664 +13665,13666,13667,13668,13669,13670,13671,13672,13673,13674,13675,13676,13677,13678,13679,13680, #13680 +13681,13682,13683,13684,13685,13686,13687,13688,13689,13690,13691,13692,13693,13694,13695,13696, #13696 +13697,13698,13699,13700,13701,13702,13703,13704,13705,13706,13707,13708,13709,13710,13711,13712, #13712 +13713,13714,13715,13716,13717,13718,13719,13720,13721,13722,13723,13724,13725,13726,13727,13728, #13728 +13729,13730,13731,13732,13733,13734,13735,13736,13737,13738,13739,13740,13741,13742,13743,13744, #13744 +13745,13746,13747,13748,13749,13750,13751,13752,13753,13754,13755,13756,13757,13758,13759,13760, #13760 +13761,13762,13763,13764,13765,13766,13767,13768,13769,13770,13771,13772,13773,13774,3273,13775, #13776 +13776,13777,13778,13779,13780,13781,13782,13783,13784,13785,13786,13787,13788,13789,13790,13791, #13792 +13792,13793,13794,13795,13796,13797,13798,13799,13800,13801,13802,13803,13804,13805,13806,13807, #13808 +13808,13809,13810,13811,13812,13813,13814,13815,13816,13817,13818,13819,13820,13821,13822,13823, #13824 +13824,13825,13826,13827,13828,13829,13830,13831,13832,13833,13834,13835,13836,13837,13838,13839, #13840 +13840,13841,13842,13843,13844,13845,13846,13847,13848,13849,13850,13851,13852,13853,13854,13855, #13856 +13856,13857,13858,13859,13860,13861,13862,13863,13864,13865,13866,13867,13868,13869,13870,13871, #13872 +13872,13873,13874,13875,13876,13877,13878,13879,13880,13881,13882,13883,13884,13885,13886,13887, #13888 +13888,13889,13890,13891,13892,13893,13894,13895,13896,13897,13898,13899,13900,13901,13902,13903, #13904 +13904,13905,13906,13907,13908,13909,13910,13911,13912,13913,13914,13915,13916,13917,13918,13919, #13920 +13920,13921,13922,13923,13924,13925,13926,13927,13928,13929,13930,13931,13932,13933,13934,13935, #13936 +13936,13937,13938,13939,13940,13941,13942,13943,13944,13945,13946,13947,13948,13949,13950,13951, #13952 +13952,13953,13954,13955,13956,13957,13958,13959,13960,13961,13962,13963,13964,13965,13966,13967, #13968 +13968,13969,13970,13971,13972) #13973 diff --git a/libs/requests/packages/chardet/big5prober.py b/libs/requests/packages/chardet/big5prober.py new file mode 100755 index 00000000..e6b52aad --- /dev/null +++ b/libs/requests/packages/chardet/big5prober.py @@ -0,0 +1,41 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from mbcharsetprober import MultiByteCharSetProber +from codingstatemachine import CodingStateMachine +from chardistribution import Big5DistributionAnalysis +from mbcssm import Big5SMModel + +class Big5Prober(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(Big5SMModel) + self._mDistributionAnalyzer = Big5DistributionAnalysis() + self.reset() + + def get_charset_name(self): + return "Big5" diff --git a/libs/requests/packages/chardet/chardistribution.py b/libs/requests/packages/chardet/chardistribution.py new file mode 100755 index 00000000..b8933418 --- /dev/null +++ b/libs/requests/packages/chardet/chardistribution.py @@ -0,0 +1,200 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import constants +from euctwfreq import EUCTWCharToFreqOrder, EUCTW_TABLE_SIZE, EUCTW_TYPICAL_DISTRIBUTION_RATIO +from euckrfreq import EUCKRCharToFreqOrder, EUCKR_TABLE_SIZE, EUCKR_TYPICAL_DISTRIBUTION_RATIO +from gb2312freq import GB2312CharToFreqOrder, GB2312_TABLE_SIZE, GB2312_TYPICAL_DISTRIBUTION_RATIO +from big5freq import Big5CharToFreqOrder, BIG5_TABLE_SIZE, BIG5_TYPICAL_DISTRIBUTION_RATIO +from jisfreq import JISCharToFreqOrder, JIS_TABLE_SIZE, JIS_TYPICAL_DISTRIBUTION_RATIO + +ENOUGH_DATA_THRESHOLD = 1024 +SURE_YES = 0.99 +SURE_NO = 0.01 + +class CharDistributionAnalysis: + def __init__(self): + self._mCharToFreqOrder = None # Mapping table to get frequency order from char order (get from GetOrder()) + self._mTableSize = None # Size of above table + self._mTypicalDistributionRatio = None # This is a constant value which varies from language to language, used in calculating confidence. See http://www.mozilla.org/projects/intl/UniversalCharsetDetection.html for further detail. + self.reset() + + def reset(self): + """reset analyser, clear any state""" + self._mDone = constants.False # If this flag is set to constants.True, detection is done and conclusion has been made + self._mTotalChars = 0 # Total characters encountered + self._mFreqChars = 0 # The number of characters whose frequency order is less than 512 + + def feed(self, aStr, aCharLen): + """feed a character with known length""" + if aCharLen == 2: + # we only care about 2-bytes character in our distribution analysis + order = self.get_order(aStr) + else: + order = -1 + if order >= 0: + self._mTotalChars += 1 + # order is valid + if order < self._mTableSize: + if 512 > self._mCharToFreqOrder[order]: + self._mFreqChars += 1 + + def get_confidence(self): + """return confidence based on existing data""" + # if we didn't receive any character in our consideration range, return negative answer + if self._mTotalChars <= 0: + return SURE_NO + + if self._mTotalChars != self._mFreqChars: + r = self._mFreqChars / ((self._mTotalChars - self._mFreqChars) * self._mTypicalDistributionRatio) + if r < SURE_YES: + return r + + # normalize confidence (we don't want to be 100% sure) + return SURE_YES + + def got_enough_data(self): + # It is not necessary to receive all data to draw conclusion. For charset detection, + # certain amount of data is enough + return self._mTotalChars > ENOUGH_DATA_THRESHOLD + + def get_order(self, aStr): + # We do not handle characters based on the original encoding string, but + # convert this encoding string to a number, here called order. + # This allows multiple encodings of a language to share one frequency table. + return -1 + +class EUCTWDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = EUCTWCharToFreqOrder + self._mTableSize = EUCTW_TABLE_SIZE + self._mTypicalDistributionRatio = EUCTW_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aStr): + # for euc-TW encoding, we are interested + # first byte range: 0xc4 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + if aStr[0] >= '\xC4': + return 94 * (ord(aStr[0]) - 0xC4) + ord(aStr[1]) - 0xA1 + else: + return -1 + +class EUCKRDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = EUCKRCharToFreqOrder + self._mTableSize = EUCKR_TABLE_SIZE + self._mTypicalDistributionRatio = EUCKR_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aStr): + # for euc-KR encoding, we are interested + # first byte range: 0xb0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + if aStr[0] >= '\xB0': + return 94 * (ord(aStr[0]) - 0xB0) + ord(aStr[1]) - 0xA1 + else: + return -1; + +class GB2312DistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = GB2312CharToFreqOrder + self._mTableSize = GB2312_TABLE_SIZE + self._mTypicalDistributionRatio = GB2312_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aStr): + # for GB2312 encoding, we are interested + # first byte range: 0xb0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + if (aStr[0] >= '\xB0') and (aStr[1] >= '\xA1'): + return 94 * (ord(aStr[0]) - 0xB0) + ord(aStr[1]) - 0xA1 + else: + return -1; + +class Big5DistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = Big5CharToFreqOrder + self._mTableSize = BIG5_TABLE_SIZE + self._mTypicalDistributionRatio = BIG5_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aStr): + # for big5 encoding, we are interested + # first byte range: 0xa4 -- 0xfe + # second byte range: 0x40 -- 0x7e , 0xa1 -- 0xfe + # no validation needed here. State machine has done that + if aStr[0] >= '\xA4': + if aStr[1] >= '\xA1': + return 157 * (ord(aStr[0]) - 0xA4) + ord(aStr[1]) - 0xA1 + 63 + else: + return 157 * (ord(aStr[0]) - 0xA4) + ord(aStr[1]) - 0x40 + else: + return -1 + +class SJISDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = JISCharToFreqOrder + self._mTableSize = JIS_TABLE_SIZE + self._mTypicalDistributionRatio = JIS_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aStr): + # for sjis encoding, we are interested + # first byte range: 0x81 -- 0x9f , 0xe0 -- 0xfe + # second byte range: 0x40 -- 0x7e, 0x81 -- oxfe + # no validation needed here. State machine has done that + if (aStr[0] >= '\x81') and (aStr[0] <= '\x9F'): + order = 188 * (ord(aStr[0]) - 0x81) + elif (aStr[0] >= '\xE0') and (aStr[0] <= '\xEF'): + order = 188 * (ord(aStr[0]) - 0xE0 + 31) + else: + return -1; + order = order + ord(aStr[1]) - 0x40 + if aStr[1] > '\x7F': + order =- 1 + return order + +class EUCJPDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = JISCharToFreqOrder + self._mTableSize = JIS_TABLE_SIZE + self._mTypicalDistributionRatio = JIS_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aStr): + # for euc-JP encoding, we are interested + # first byte range: 0xa0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + if aStr[0] >= '\xA0': + return 94 * (ord(aStr[0]) - 0xA1) + ord(aStr[1]) - 0xa1 + else: + return -1 diff --git a/libs/requests/packages/chardet/charsetgroupprober.py b/libs/requests/packages/chardet/charsetgroupprober.py new file mode 100755 index 00000000..51880694 --- /dev/null +++ b/libs/requests/packages/chardet/charsetgroupprober.py @@ -0,0 +1,96 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import constants, sys +from charsetprober import CharSetProber + +class CharSetGroupProber(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self._mActiveNum = 0 + self._mProbers = [] + self._mBestGuessProber = None + + def reset(self): + CharSetProber.reset(self) + self._mActiveNum = 0 + for prober in self._mProbers: + if prober: + prober.reset() + prober.active = constants.True + self._mActiveNum += 1 + self._mBestGuessProber = None + + def get_charset_name(self): + if not self._mBestGuessProber: + self.get_confidence() + if not self._mBestGuessProber: return None +# self._mBestGuessProber = self._mProbers[0] + return self._mBestGuessProber.get_charset_name() + + def feed(self, aBuf): + for prober in self._mProbers: + if not prober: continue + if not prober.active: continue + st = prober.feed(aBuf) + if not st: continue + if st == constants.eFoundIt: + self._mBestGuessProber = prober + return self.get_state() + elif st == constants.eNotMe: + prober.active = constants.False + self._mActiveNum -= 1 + if self._mActiveNum <= 0: + self._mState = constants.eNotMe + return self.get_state() + return self.get_state() + + def get_confidence(self): + st = self.get_state() + if st == constants.eFoundIt: + return 0.99 + elif st == constants.eNotMe: + return 0.01 + bestConf = 0.0 + self._mBestGuessProber = None + for prober in self._mProbers: + if not prober: continue + if not prober.active: + if constants._debug: + sys.stderr.write(prober.get_charset_name() + ' not active\n') + continue + cf = prober.get_confidence() + if constants._debug: + sys.stderr.write('%s confidence = %s\n' % (prober.get_charset_name(), cf)) + if bestConf < cf: + bestConf = cf + self._mBestGuessProber = prober + if not self._mBestGuessProber: return 0.0 + return bestConf +# else: +# self._mBestGuessProber = self._mProbers[0] +# return self._mBestGuessProber.get_confidence() diff --git a/libs/requests/packages/chardet/charsetprober.py b/libs/requests/packages/chardet/charsetprober.py new file mode 100755 index 00000000..3ac1683c --- /dev/null +++ b/libs/requests/packages/chardet/charsetprober.py @@ -0,0 +1,60 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import constants, re + +class CharSetProber: + def __init__(self): + pass + + def reset(self): + self._mState = constants.eDetecting + + def get_charset_name(self): + return None + + def feed(self, aBuf): + pass + + def get_state(self): + return self._mState + + def get_confidence(self): + return 0.0 + + def filter_high_bit_only(self, aBuf): + aBuf = re.sub(r'([\x00-\x7F])+', ' ', aBuf) + return aBuf + + def filter_without_english_letters(self, aBuf): + aBuf = re.sub(r'([A-Za-z])+', ' ', aBuf) + return aBuf + + def filter_with_english_letters(self, aBuf): + # TODO + return aBuf diff --git a/libs/requests/packages/chardet/codingstatemachine.py b/libs/requests/packages/chardet/codingstatemachine.py new file mode 100755 index 00000000..452d3b0a --- /dev/null +++ b/libs/requests/packages/chardet/codingstatemachine.py @@ -0,0 +1,56 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from constants import eStart, eError, eItsMe + +class CodingStateMachine: + def __init__(self, sm): + self._mModel = sm + self._mCurrentBytePos = 0 + self._mCurrentCharLen = 0 + self.reset() + + def reset(self): + self._mCurrentState = eStart + + def next_state(self, c): + # for each byte we get its class + # if it is first byte, we also get byte length + byteCls = self._mModel['classTable'][ord(c)] + if self._mCurrentState == eStart: + self._mCurrentBytePos = 0 + self._mCurrentCharLen = self._mModel['charLenTable'][byteCls] + # from byte's class and stateTable, we get its next state + self._mCurrentState = self._mModel['stateTable'][self._mCurrentState * self._mModel['classFactor'] + byteCls] + self._mCurrentBytePos += 1 + return self._mCurrentState + + def get_current_charlen(self): + return self._mCurrentCharLen + + def get_coding_state_machine(self): + return self._mModel['name'] diff --git a/libs/requests/packages/chardet/constants.py b/libs/requests/packages/chardet/constants.py new file mode 100755 index 00000000..e94e226b --- /dev/null +++ b/libs/requests/packages/chardet/constants.py @@ -0,0 +1,47 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +_debug = 0 + +eDetecting = 0 +eFoundIt = 1 +eNotMe = 2 + +eStart = 0 +eError = 1 +eItsMe = 2 + +SHORTCUT_THRESHOLD = 0.95 + +import __builtin__ +if not hasattr(__builtin__, 'False'): + False = 0 + True = 1 +else: + False = __builtin__.False + True = __builtin__.True diff --git a/libs/requests/packages/chardet/escprober.py b/libs/requests/packages/chardet/escprober.py new file mode 100755 index 00000000..572ed7be --- /dev/null +++ b/libs/requests/packages/chardet/escprober.py @@ -0,0 +1,79 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import constants, sys +from escsm import HZSMModel, ISO2022CNSMModel, ISO2022JPSMModel, ISO2022KRSMModel +from charsetprober import CharSetProber +from codingstatemachine import CodingStateMachine + +class EscCharSetProber(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self._mCodingSM = [ \ + CodingStateMachine(HZSMModel), + CodingStateMachine(ISO2022CNSMModel), + CodingStateMachine(ISO2022JPSMModel), + CodingStateMachine(ISO2022KRSMModel) + ] + self.reset() + + def reset(self): + CharSetProber.reset(self) + for codingSM in self._mCodingSM: + if not codingSM: continue + codingSM.active = constants.True + codingSM.reset() + self._mActiveSM = len(self._mCodingSM) + self._mDetectedCharset = None + + def get_charset_name(self): + return self._mDetectedCharset + + def get_confidence(self): + if self._mDetectedCharset: + return 0.99 + else: + return 0.00 + + def feed(self, aBuf): + for c in aBuf: + for codingSM in self._mCodingSM: + if not codingSM: continue + if not codingSM.active: continue + codingState = codingSM.next_state(c) + if codingState == constants.eError: + codingSM.active = constants.False + self._mActiveSM -= 1 + if self._mActiveSM <= 0: + self._mState = constants.eNotMe + return self.get_state() + elif codingState == constants.eItsMe: + self._mState = constants.eFoundIt + self._mDetectedCharset = codingSM.get_coding_state_machine() + return self.get_state() + + return self.get_state() diff --git a/libs/requests/packages/chardet/escsm.py b/libs/requests/packages/chardet/escsm.py new file mode 100755 index 00000000..9fa22952 --- /dev/null +++ b/libs/requests/packages/chardet/escsm.py @@ -0,0 +1,240 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from constants import eStart, eError, eItsMe + +HZ_cls = ( \ +1,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,0,0,0,0, # 20 - 27 +0,0,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,0,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,4,0,5,2,0, # 78 - 7f +1,1,1,1,1,1,1,1, # 80 - 87 +1,1,1,1,1,1,1,1, # 88 - 8f +1,1,1,1,1,1,1,1, # 90 - 97 +1,1,1,1,1,1,1,1, # 98 - 9f +1,1,1,1,1,1,1,1, # a0 - a7 +1,1,1,1,1,1,1,1, # a8 - af +1,1,1,1,1,1,1,1, # b0 - b7 +1,1,1,1,1,1,1,1, # b8 - bf +1,1,1,1,1,1,1,1, # c0 - c7 +1,1,1,1,1,1,1,1, # c8 - cf +1,1,1,1,1,1,1,1, # d0 - d7 +1,1,1,1,1,1,1,1, # d8 - df +1,1,1,1,1,1,1,1, # e0 - e7 +1,1,1,1,1,1,1,1, # e8 - ef +1,1,1,1,1,1,1,1, # f0 - f7 +1,1,1,1,1,1,1,1, # f8 - ff +) + +HZ_st = ( \ +eStart,eError, 3,eStart,eStart,eStart,eError,eError,# 00-07 +eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,# 08-0f +eItsMe,eItsMe,eError,eError,eStart,eStart, 4,eError,# 10-17 + 5,eError, 6,eError, 5, 5, 4,eError,# 18-1f + 4,eError, 4, 4, 4,eError, 4,eError,# 20-27 + 4,eItsMe,eStart,eStart,eStart,eStart,eStart,eStart,# 28-2f +) + +HZCharLenTable = (0, 0, 0, 0, 0, 0) + +HZSMModel = {'classTable': HZ_cls, + 'classFactor': 6, + 'stateTable': HZ_st, + 'charLenTable': HZCharLenTable, + 'name': "HZ-GB-2312"} + +ISO2022CN_cls = ( \ +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,0,0,0,0, # 20 - 27 +0,3,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,4,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022CN_st = ( \ +eStart, 3,eError,eStart,eStart,eStart,eStart,eStart,# 00-07 +eStart,eError,eError,eError,eError,eError,eError,eError,# 08-0f +eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,# 10-17 +eItsMe,eItsMe,eItsMe,eError,eError,eError, 4,eError,# 18-1f +eError,eError,eError,eItsMe,eError,eError,eError,eError,# 20-27 + 5, 6,eError,eError,eError,eError,eError,eError,# 28-2f +eError,eError,eError,eItsMe,eError,eError,eError,eError,# 30-37 +eError,eError,eError,eError,eError,eItsMe,eError,eStart,# 38-3f +) + +ISO2022CNCharLenTable = (0, 0, 0, 0, 0, 0, 0, 0, 0) + +ISO2022CNSMModel = {'classTable': ISO2022CN_cls, + 'classFactor': 9, + 'stateTable': ISO2022CN_st, + 'charLenTable': ISO2022CNCharLenTable, + 'name': "ISO-2022-CN"} + +ISO2022JP_cls = ( \ +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,2,2, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,7,0,0,0, # 20 - 27 +3,0,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +6,0,4,0,8,0,0,0, # 40 - 47 +0,9,5,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022JP_st = ( \ +eStart, 3,eError,eStart,eStart,eStart,eStart,eStart,# 00-07 +eStart,eStart,eError,eError,eError,eError,eError,eError,# 08-0f +eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,# 10-17 +eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eError,eError,# 18-1f +eError, 5,eError,eError,eError, 4,eError,eError,# 20-27 +eError,eError,eError, 6,eItsMe,eError,eItsMe,eError,# 28-2f +eError,eError,eError,eError,eError,eError,eItsMe,eItsMe,# 30-37 +eError,eError,eError,eItsMe,eError,eError,eError,eError,# 38-3f +eError,eError,eError,eError,eItsMe,eError,eStart,eStart,# 40-47 +) + +ISO2022JPCharLenTable = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + +ISO2022JPSMModel = {'classTable': ISO2022JP_cls, + 'classFactor': 10, + 'stateTable': ISO2022JP_st, + 'charLenTable': ISO2022JPCharLenTable, + 'name': "ISO-2022-JP"} + +ISO2022KR_cls = ( \ +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,3,0,0,0, # 20 - 27 +0,4,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,5,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022KR_st = ( \ +eStart, 3,eError,eStart,eStart,eStart,eError,eError,# 00-07 +eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,# 08-0f +eItsMe,eItsMe,eError,eError,eError, 4,eError,eError,# 10-17 +eError,eError,eError,eError, 5,eError,eError,eError,# 18-1f +eError,eError,eError,eItsMe,eStart,eStart,eStart,eStart,# 20-27 +) + +ISO2022KRCharLenTable = (0, 0, 0, 0, 0, 0) + +ISO2022KRSMModel = {'classTable': ISO2022KR_cls, + 'classFactor': 6, + 'stateTable': ISO2022KR_st, + 'charLenTable': ISO2022KRCharLenTable, + 'name': "ISO-2022-KR"} diff --git a/libs/requests/packages/chardet/eucjpprober.py b/libs/requests/packages/chardet/eucjpprober.py new file mode 100755 index 00000000..46a8b38b --- /dev/null +++ b/libs/requests/packages/chardet/eucjpprober.py @@ -0,0 +1,85 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import constants, sys +from constants import eStart, eError, eItsMe +from mbcharsetprober import MultiByteCharSetProber +from codingstatemachine import CodingStateMachine +from chardistribution import EUCJPDistributionAnalysis +from jpcntx import EUCJPContextAnalysis +from mbcssm import EUCJPSMModel + +class EUCJPProber(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(EUCJPSMModel) + self._mDistributionAnalyzer = EUCJPDistributionAnalysis() + self._mContextAnalyzer = EUCJPContextAnalysis() + self.reset() + + def reset(self): + MultiByteCharSetProber.reset(self) + self._mContextAnalyzer.reset() + + def get_charset_name(self): + return "EUC-JP" + + def feed(self, aBuf): + aLen = len(aBuf) + for i in range(0, aLen): + codingState = self._mCodingSM.next_state(aBuf[i]) + if codingState == eError: + if constants._debug: + sys.stderr.write(self.get_charset_name() + ' prober hit error at byte ' + str(i) + '\n') + self._mState = constants.eNotMe + break + elif codingState == eItsMe: + self._mState = constants.eFoundIt + break + elif codingState == eStart: + charLen = self._mCodingSM.get_current_charlen() + if i == 0: + self._mLastChar[1] = aBuf[0] + self._mContextAnalyzer.feed(self._mLastChar, charLen) + self._mDistributionAnalyzer.feed(self._mLastChar, charLen) + else: + self._mContextAnalyzer.feed(aBuf[i-1:i+1], charLen) + self._mDistributionAnalyzer.feed(aBuf[i-1:i+1], charLen) + + self._mLastChar[0] = aBuf[aLen - 1] + + if self.get_state() == constants.eDetecting: + if self._mContextAnalyzer.got_enough_data() and \ + (self.get_confidence() > constants.SHORTCUT_THRESHOLD): + self._mState = constants.eFoundIt + + return self.get_state() + + def get_confidence(self): + contxtCf = self._mContextAnalyzer.get_confidence() + distribCf = self._mDistributionAnalyzer.get_confidence() + return max(contxtCf, distribCf) diff --git a/libs/requests/packages/chardet/euckrfreq.py b/libs/requests/packages/chardet/euckrfreq.py new file mode 100755 index 00000000..1463fa1d --- /dev/null +++ b/libs/requests/packages/chardet/euckrfreq.py @@ -0,0 +1,594 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Sampling from about 20M text materials include literature and computer technology + +# 128 --> 0.79 +# 256 --> 0.92 +# 512 --> 0.986 +# 1024 --> 0.99944 +# 2048 --> 0.99999 +# +# Idea Distribution Ratio = 0.98653 / (1-0.98653) = 73.24 +# Random Distribution Ration = 512 / (2350-512) = 0.279. +# +# Typical Distribution Ratio + +EUCKR_TYPICAL_DISTRIBUTION_RATIO = 6.0 + +EUCKR_TABLE_SIZE = 2352 + +# Char to FreqOrder table , +EUCKRCharToFreqOrder = ( \ + 13, 130, 120,1396, 481,1719,1720, 328, 609, 212,1721, 707, 400, 299,1722, 87, +1397,1723, 104, 536,1117,1203,1724,1267, 685,1268, 508,1725,1726,1727,1728,1398, +1399,1729,1730,1731, 141, 621, 326,1057, 368,1732, 267, 488, 20,1733,1269,1734, + 945,1400,1735, 47, 904,1270,1736,1737, 773, 248,1738, 409, 313, 786, 429,1739, + 116, 987, 813,1401, 683, 75,1204, 145,1740,1741,1742,1743, 16, 847, 667, 622, + 708,1744,1745,1746, 966, 787, 304, 129,1747, 60, 820, 123, 676,1748,1749,1750, +1751, 617,1752, 626,1753,1754,1755,1756, 653,1757,1758,1759,1760,1761,1762, 856, + 344,1763,1764,1765,1766, 89, 401, 418, 806, 905, 848,1767,1768,1769, 946,1205, + 709,1770,1118,1771, 241,1772,1773,1774,1271,1775, 569,1776, 999,1777,1778,1779, +1780, 337, 751,1058, 28, 628, 254,1781, 177, 906, 270, 349, 891,1079,1782, 19, +1783, 379,1784, 315,1785, 629, 754,1402, 559,1786, 636, 203,1206,1787, 710, 567, +1788, 935, 814,1789,1790,1207, 766, 528,1791,1792,1208,1793,1794,1795,1796,1797, +1403,1798,1799, 533,1059,1404,1405,1156,1406, 936, 884,1080,1800, 351,1801,1802, +1803,1804,1805, 801,1806,1807,1808,1119,1809,1157, 714, 474,1407,1810, 298, 899, + 885,1811,1120, 802,1158,1812, 892,1813,1814,1408, 659,1815,1816,1121,1817,1818, +1819,1820,1821,1822, 319,1823, 594, 545,1824, 815, 937,1209,1825,1826, 573,1409, +1022,1827,1210,1828,1829,1830,1831,1832,1833, 556, 722, 807,1122,1060,1834, 697, +1835, 900, 557, 715,1836,1410, 540,1411, 752,1159, 294, 597,1211, 976, 803, 770, +1412,1837,1838, 39, 794,1413, 358,1839, 371, 925,1840, 453, 661, 788, 531, 723, + 544,1023,1081, 869, 91,1841, 392, 430, 790, 602,1414, 677,1082, 457,1415,1416, +1842,1843, 475, 327,1024,1417, 795, 121,1844, 733, 403,1418,1845,1846,1847, 300, + 119, 711,1212, 627,1848,1272, 207,1849,1850, 796,1213, 382,1851, 519,1852,1083, + 893,1853,1854,1855, 367, 809, 487, 671,1856, 663,1857,1858, 956, 471, 306, 857, +1859,1860,1160,1084,1861,1862,1863,1864,1865,1061,1866,1867,1868,1869,1870,1871, + 282, 96, 574,1872, 502,1085,1873,1214,1874, 907,1875,1876, 827, 977,1419,1420, +1421, 268,1877,1422,1878,1879,1880, 308,1881, 2, 537,1882,1883,1215,1884,1885, + 127, 791,1886,1273,1423,1887, 34, 336, 404, 643,1888, 571, 654, 894, 840,1889, + 0, 886,1274, 122, 575, 260, 908, 938,1890,1275, 410, 316,1891,1892, 100,1893, +1894,1123, 48,1161,1124,1025,1895, 633, 901,1276,1896,1897, 115, 816,1898, 317, +1899, 694,1900, 909, 734,1424, 572, 866,1425, 691, 85, 524,1010, 543, 394, 841, +1901,1902,1903,1026,1904,1905,1906,1907,1908,1909, 30, 451, 651, 988, 310,1910, +1911,1426, 810,1216, 93,1912,1913,1277,1217,1914, 858, 759, 45, 58, 181, 610, + 269,1915,1916, 131,1062, 551, 443,1000, 821,1427, 957, 895,1086,1917,1918, 375, +1919, 359,1920, 687,1921, 822,1922, 293,1923,1924, 40, 662, 118, 692, 29, 939, + 887, 640, 482, 174,1925, 69,1162, 728,1428, 910,1926,1278,1218,1279, 386, 870, + 217, 854,1163, 823,1927,1928,1929,1930, 834,1931, 78,1932, 859,1933,1063,1934, +1935,1936,1937, 438,1164, 208, 595,1938,1939,1940,1941,1219,1125,1942, 280, 888, +1429,1430,1220,1431,1943,1944,1945,1946,1947,1280, 150, 510,1432,1948,1949,1950, +1951,1952,1953,1954,1011,1087,1955,1433,1043,1956, 881,1957, 614, 958,1064,1065, +1221,1958, 638,1001, 860, 967, 896,1434, 989, 492, 553,1281,1165,1959,1282,1002, +1283,1222,1960,1961,1962,1963, 36, 383, 228, 753, 247, 454,1964, 876, 678,1965, +1966,1284, 126, 464, 490, 835, 136, 672, 529, 940,1088,1435, 473,1967,1968, 467, + 50, 390, 227, 587, 279, 378, 598, 792, 968, 240, 151, 160, 849, 882,1126,1285, + 639,1044, 133, 140, 288, 360, 811, 563,1027, 561, 142, 523,1969,1970,1971, 7, + 103, 296, 439, 407, 506, 634, 990,1972,1973,1974,1975, 645,1976,1977,1978,1979, +1980,1981, 236,1982,1436,1983,1984,1089, 192, 828, 618, 518,1166, 333,1127,1985, + 818,1223,1986,1987,1988,1989,1990,1991,1992,1993, 342,1128,1286, 746, 842,1994, +1995, 560, 223,1287, 98, 8, 189, 650, 978,1288,1996,1437,1997, 17, 345, 250, + 423, 277, 234, 512, 226, 97, 289, 42, 167,1998, 201,1999,2000, 843, 836, 824, + 532, 338, 783,1090, 182, 576, 436,1438,1439, 527, 500,2001, 947, 889,2002,2003, +2004,2005, 262, 600, 314, 447,2006, 547,2007, 693, 738,1129,2008, 71,1440, 745, + 619, 688,2009, 829,2010,2011, 147,2012, 33, 948,2013,2014, 74, 224,2015, 61, + 191, 918, 399, 637,2016,1028,1130, 257, 902,2017,2018,2019,2020,2021,2022,2023, +2024,2025,2026, 837,2027,2028,2029,2030, 179, 874, 591, 52, 724, 246,2031,2032, +2033,2034,1167, 969,2035,1289, 630, 605, 911,1091,1168,2036,2037,2038,1441, 912, +2039, 623,2040,2041, 253,1169,1290,2042,1442, 146, 620, 611, 577, 433,2043,1224, + 719,1170, 959, 440, 437, 534, 84, 388, 480,1131, 159, 220, 198, 679,2044,1012, + 819,1066,1443, 113,1225, 194, 318,1003,1029,2045,2046,2047,2048,1067,2049,2050, +2051,2052,2053, 59, 913, 112,2054, 632,2055, 455, 144, 739,1291,2056, 273, 681, + 499,2057, 448,2058,2059, 760,2060,2061, 970, 384, 169, 245,1132,2062,2063, 414, +1444,2064,2065, 41, 235,2066, 157, 252, 877, 568, 919, 789, 580,2067, 725,2068, +2069,1292,2070,2071,1445,2072,1446,2073,2074, 55, 588, 66,1447, 271,1092,2075, +1226,2076, 960,1013, 372,2077,2078,2079,2080,2081,1293,2082,2083,2084,2085, 850, +2086,2087,2088,2089,2090, 186,2091,1068, 180,2092,2093,2094, 109,1227, 522, 606, +2095, 867,1448,1093, 991,1171, 926, 353,1133,2096, 581,2097,2098,2099,1294,1449, +1450,2100, 596,1172,1014,1228,2101,1451,1295,1173,1229,2102,2103,1296,1134,1452, + 949,1135,2104,2105,1094,1453,1454,1455,2106,1095,2107,2108,2109,2110,2111,2112, +2113,2114,2115,2116,2117, 804,2118,2119,1230,1231, 805,1456, 405,1136,2120,2121, +2122,2123,2124, 720, 701,1297, 992,1457, 927,1004,2125,2126,2127,2128,2129,2130, + 22, 417,2131, 303,2132, 385,2133, 971, 520, 513,2134,1174, 73,1096, 231, 274, + 962,1458, 673,2135,1459,2136, 152,1137,2137,2138,2139,2140,1005,1138,1460,1139, +2141,2142,2143,2144, 11, 374, 844,2145, 154,1232, 46,1461,2146, 838, 830, 721, +1233, 106,2147, 90, 428, 462, 578, 566,1175, 352,2148,2149, 538,1234, 124,1298, +2150,1462, 761, 565,2151, 686,2152, 649,2153, 72, 173,2154, 460, 415,2155,1463, +2156,1235, 305,2157,2158,2159,2160,2161,2162, 579,2163,2164,2165,2166,2167, 747, +2168,2169,2170,2171,1464, 669,2172,2173,2174,2175,2176,1465,2177, 23, 530, 285, +2178, 335, 729,2179, 397,2180,2181,2182,1030,2183,2184, 698,2185,2186, 325,2187, +2188, 369,2189, 799,1097,1015, 348,2190,1069, 680,2191, 851,1466,2192,2193, 10, +2194, 613, 424,2195, 979, 108, 449, 589, 27, 172, 81,1031, 80, 774, 281, 350, +1032, 525, 301, 582,1176,2196, 674,1045,2197,2198,1467, 730, 762,2199,2200,2201, +2202,1468,2203, 993,2204,2205, 266,1070, 963,1140,2206,2207,2208, 664,1098, 972, +2209,2210,2211,1177,1469,1470, 871,2212,2213,2214,2215,2216,1471,2217,2218,2219, +2220,2221,2222,2223,2224,2225,2226,2227,1472,1236,2228,2229,2230,2231,2232,2233, +2234,2235,1299,2236,2237, 200,2238, 477, 373,2239,2240, 731, 825, 777,2241,2242, +2243, 521, 486, 548,2244,2245,2246,1473,1300, 53, 549, 137, 875, 76, 158,2247, +1301,1474, 469, 396,1016, 278, 712,2248, 321, 442, 503, 767, 744, 941,1237,1178, +1475,2249, 82, 178,1141,1179, 973,2250,1302,2251, 297,2252,2253, 570,2254,2255, +2256, 18, 450, 206,2257, 290, 292,1142,2258, 511, 162, 99, 346, 164, 735,2259, +1476,1477, 4, 554, 343, 798,1099,2260,1100,2261, 43, 171,1303, 139, 215,2262, +2263, 717, 775,2264,1033, 322, 216,2265, 831,2266, 149,2267,1304,2268,2269, 702, +1238, 135, 845, 347, 309,2270, 484,2271, 878, 655, 238,1006,1478,2272, 67,2273, + 295,2274,2275, 461,2276, 478, 942, 412,2277,1034,2278,2279,2280, 265,2281, 541, +2282,2283,2284,2285,2286, 70, 852,1071,2287,2288,2289,2290, 21, 56, 509, 117, + 432,2291,2292, 331, 980, 552,1101, 148, 284, 105, 393,1180,1239, 755,2293, 187, +2294,1046,1479,2295, 340,2296, 63,1047, 230,2297,2298,1305, 763,1306, 101, 800, + 808, 494,2299,2300,2301, 903,2302, 37,1072, 14, 5,2303, 79, 675,2304, 312, +2305,2306,2307,2308,2309,1480, 6,1307,2310,2311,2312, 1, 470, 35, 24, 229, +2313, 695, 210, 86, 778, 15, 784, 592, 779, 32, 77, 855, 964,2314, 259,2315, + 501, 380,2316,2317, 83, 981, 153, 689,1308,1481,1482,1483,2318,2319, 716,1484, +2320,2321,2322,2323,2324,2325,1485,2326,2327, 128, 57, 68, 261,1048, 211, 170, +1240, 31,2328, 51, 435, 742,2329,2330,2331, 635,2332, 264, 456,2333,2334,2335, + 425,2336,1486, 143, 507, 263, 943,2337, 363, 920,1487, 256,1488,1102, 243, 601, +1489,2338,2339,2340,2341,2342,2343,2344, 861,2345,2346,2347,2348,2349,2350, 395, +2351,1490,1491, 62, 535, 166, 225,2352,2353, 668, 419,1241, 138, 604, 928,2354, +1181,2355,1492,1493,2356,2357,2358,1143,2359, 696,2360, 387, 307,1309, 682, 476, +2361,2362, 332, 12, 222, 156,2363, 232,2364, 641, 276, 656, 517,1494,1495,1035, + 416, 736,1496,2365,1017, 586,2366,2367,2368,1497,2369, 242,2370,2371,2372,1498, +2373, 965, 713,2374,2375,2376,2377, 740, 982,1499, 944,1500,1007,2378,2379,1310, +1501,2380,2381,2382, 785, 329,2383,2384,1502,2385,2386,2387, 932,2388,1503,2389, +2390,2391,2392,1242,2393,2394,2395,2396,2397, 994, 950,2398,2399,2400,2401,1504, +1311,2402,2403,2404,2405,1049, 749,2406,2407, 853, 718,1144,1312,2408,1182,1505, +2409,2410, 255, 516, 479, 564, 550, 214,1506,1507,1313, 413, 239, 444, 339,1145, +1036,1508,1509,1314,1037,1510,1315,2411,1511,2412,2413,2414, 176, 703, 497, 624, + 593, 921, 302,2415, 341, 165,1103,1512,2416,1513,2417,2418,2419, 376,2420, 700, +2421,2422,2423, 258, 768,1316,2424,1183,2425, 995, 608,2426,2427,2428,2429, 221, +2430,2431,2432,2433,2434,2435,2436,2437, 195, 323, 726, 188, 897, 983,1317, 377, + 644,1050, 879,2438, 452,2439,2440,2441,2442,2443,2444, 914,2445,2446,2447,2448, + 915, 489,2449,1514,1184,2450,2451, 515, 64, 427, 495,2452, 583,2453, 483, 485, +1038, 562, 213,1515, 748, 666,2454,2455,2456,2457, 334,2458, 780, 996,1008, 705, +1243,2459,2460,2461,2462,2463, 114,2464, 493,1146, 366, 163,1516, 961,1104,2465, + 291,2466,1318,1105,2467,1517, 365,2468, 355, 951,1244,2469,1319,2470, 631,2471, +2472, 218,1320, 364, 320, 756,1518,1519,1321,1520,1322,2473,2474,2475,2476, 997, +2477,2478,2479,2480, 665,1185,2481, 916,1521,2482,2483,2484, 584, 684,2485,2486, + 797,2487,1051,1186,2488,2489,2490,1522,2491,2492, 370,2493,1039,1187, 65,2494, + 434, 205, 463,1188,2495, 125, 812, 391, 402, 826, 699, 286, 398, 155, 781, 771, + 585,2496, 590, 505,1073,2497, 599, 244, 219, 917,1018, 952, 646,1523,2498,1323, +2499,2500, 49, 984, 354, 741,2501, 625,2502,1324,2503,1019, 190, 357, 757, 491, + 95, 782, 868,2504,2505,2506,2507,2508,2509, 134,1524,1074, 422,1525, 898,2510, + 161,2511,2512,2513,2514, 769,2515,1526,2516,2517, 411,1325,2518, 472,1527,2519, +2520,2521,2522,2523,2524, 985,2525,2526,2527,2528,2529,2530, 764,2531,1245,2532, +2533, 25, 204, 311,2534, 496,2535,1052,2536,2537,2538,2539,2540,2541,2542, 199, + 704, 504, 468, 758, 657,1528, 196, 44, 839,1246, 272, 750,2543, 765, 862,2544, +2545,1326,2546, 132, 615, 933,2547, 732,2548,2549,2550,1189,1529,2551, 283,1247, +1053, 607, 929,2552,2553,2554, 930, 183, 872, 616,1040,1147,2555,1148,1020, 441, + 249,1075,2556,2557,2558, 466, 743,2559,2560,2561, 92, 514, 426, 420, 526,2562, +2563,2564,2565,2566,2567,2568, 185,2569,2570,2571,2572, 776,1530, 658,2573, 362, +2574, 361, 922,1076, 793,2575,2576,2577,2578,2579,2580,1531, 251,2581,2582,2583, +2584,1532, 54, 612, 237,1327,2585,2586, 275, 408, 647, 111,2587,1533,1106, 465, + 3, 458, 9, 38,2588, 107, 110, 890, 209, 26, 737, 498,2589,1534,2590, 431, + 202, 88,1535, 356, 287,1107, 660,1149,2591, 381,1536, 986,1150, 445,1248,1151, + 974,2592,2593, 846,2594, 446, 953, 184,1249,1250, 727,2595, 923, 193, 883,2596, +2597,2598, 102, 324, 539, 817,2599, 421,1041,2600, 832,2601, 94, 175, 197, 406, +2602, 459,2603,2604,2605,2606,2607, 330, 555,2608,2609,2610, 706,1108, 389,2611, +2612,2613,2614, 233,2615, 833, 558, 931, 954,1251,2616,2617,1537, 546,2618,2619, +1009,2620,2621,2622,1538, 690,1328,2623, 955,2624,1539,2625,2626, 772,2627,2628, +2629,2630,2631, 924, 648, 863, 603,2632,2633, 934,1540, 864, 865,2634, 642,1042, + 670,1190,2635,2636,2637,2638, 168,2639, 652, 873, 542,1054,1541,2640,2641,2642, # 512, 256 +#Everything below is of no interest for detection purpose +2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,2654,2655,2656,2657,2658, +2659,2660,2661,2662,2663,2664,2665,2666,2667,2668,2669,2670,2671,2672,2673,2674, +2675,2676,2677,2678,2679,2680,2681,2682,2683,2684,2685,2686,2687,2688,2689,2690, +2691,2692,2693,2694,2695,2696,2697,2698,2699,1542, 880,2700,2701,2702,2703,2704, +2705,2706,2707,2708,2709,2710,2711,2712,2713,2714,2715,2716,2717,2718,2719,2720, +2721,2722,2723,2724,2725,1543,2726,2727,2728,2729,2730,2731,2732,1544,2733,2734, +2735,2736,2737,2738,2739,2740,2741,2742,2743,2744,2745,2746,2747,2748,2749,2750, +2751,2752,2753,2754,1545,2755,2756,2757,2758,2759,2760,2761,2762,2763,2764,2765, +2766,1546,2767,1547,2768,2769,2770,2771,2772,2773,2774,2775,2776,2777,2778,2779, +2780,2781,2782,2783,2784,2785,2786,1548,2787,2788,2789,1109,2790,2791,2792,2793, +2794,2795,2796,2797,2798,2799,2800,2801,2802,2803,2804,2805,2806,2807,2808,2809, +2810,2811,2812,1329,2813,2814,2815,2816,2817,2818,2819,2820,2821,2822,2823,2824, +2825,2826,2827,2828,2829,2830,2831,2832,2833,2834,2835,2836,2837,2838,2839,2840, +2841,2842,2843,2844,2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856, +1549,2857,2858,2859,2860,1550,2861,2862,1551,2863,2864,2865,2866,2867,2868,2869, +2870,2871,2872,2873,2874,1110,1330,2875,2876,2877,2878,2879,2880,2881,2882,2883, +2884,2885,2886,2887,2888,2889,2890,2891,2892,2893,2894,2895,2896,2897,2898,2899, +2900,2901,2902,2903,2904,2905,2906,2907,2908,2909,2910,2911,2912,2913,2914,2915, +2916,2917,2918,2919,2920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2930,1331, +2931,2932,2933,2934,2935,2936,2937,2938,2939,2940,2941,2942,2943,1552,2944,2945, +2946,2947,2948,2949,2950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961, +2962,2963,2964,1252,2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2976, +2977,2978,2979,2980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992, +2993,2994,2995,2996,2997,2998,2999,3000,3001,3002,3003,3004,3005,3006,3007,3008, +3009,3010,3011,3012,1553,3013,3014,3015,3016,3017,1554,3018,1332,3019,3020,3021, +3022,3023,3024,3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037, +3038,3039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,1555,3051,3052, +3053,1556,1557,3054,3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066, +3067,1558,3068,3069,3070,3071,3072,3073,3074,3075,3076,1559,3077,3078,3079,3080, +3081,3082,3083,1253,3084,3085,3086,3087,3088,3089,3090,3091,3092,3093,3094,3095, +3096,3097,3098,3099,3100,3101,3102,3103,3104,3105,3106,3107,3108,1152,3109,3110, +3111,3112,3113,1560,3114,3115,3116,3117,1111,3118,3119,3120,3121,3122,3123,3124, +3125,3126,3127,3128,3129,3130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140, +3141,3142,3143,3144,3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156, +3157,3158,3159,3160,3161,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172, +3173,3174,3175,3176,1333,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187, +3188,3189,1561,3190,3191,1334,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201, +3202,3203,3204,3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217, +3218,3219,3220,3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233, +3234,1562,3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248, +3249,3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264, +3265,3266,3267,3268,3269,3270,3271,3272,3273,3274,3275,3276,3277,1563,3278,3279, +3280,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,3295, +3296,3297,3298,3299,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309,3310,3311, +3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,3325,3326,3327, +3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,3340,3341,3342,3343, +3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,3359, +3360,3361,3362,3363,3364,1335,3365,3366,3367,3368,3369,3370,3371,3372,3373,3374, +3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387,1336,3388,3389, +3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,3400,3401,3402,3403,3404,3405, +3406,3407,3408,3409,3410,3411,3412,3413,3414,1337,3415,3416,3417,3418,3419,1338, +3420,3421,3422,1564,1565,3423,3424,3425,3426,3427,3428,3429,3430,3431,1254,3432, +3433,3434,1339,3435,3436,3437,3438,3439,1566,3440,3441,3442,3443,3444,3445,3446, +3447,3448,3449,3450,3451,3452,3453,3454,1255,3455,3456,3457,3458,3459,1567,1191, +3460,1568,1569,3461,3462,3463,1570,3464,3465,3466,3467,3468,1571,3469,3470,3471, +3472,3473,1572,3474,3475,3476,3477,3478,3479,3480,3481,3482,3483,3484,3485,3486, +1340,3487,3488,3489,3490,3491,3492,1021,3493,3494,3495,3496,3497,3498,1573,3499, +1341,3500,3501,3502,3503,3504,3505,3506,3507,3508,3509,3510,3511,1342,3512,3513, +3514,3515,3516,1574,1343,3517,3518,3519,1575,3520,1576,3521,3522,3523,3524,3525, +3526,3527,3528,3529,3530,3531,3532,3533,3534,3535,3536,3537,3538,3539,3540,3541, +3542,3543,3544,3545,3546,3547,3548,3549,3550,3551,3552,3553,3554,3555,3556,3557, +3558,3559,3560,3561,3562,3563,3564,3565,3566,3567,3568,3569,3570,3571,3572,3573, +3574,3575,3576,3577,3578,3579,3580,1577,3581,3582,1578,3583,3584,3585,3586,3587, +3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603, +3604,1579,3605,3606,3607,3608,3609,3610,3611,3612,3613,3614,3615,3616,3617,3618, +3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,3629,1580,3630,3631,1581,3632, +3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,3643,3644,3645,3646,3647,3648, +3649,3650,3651,3652,3653,3654,3655,3656,1582,3657,3658,3659,3660,3661,3662,3663, +3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3674,3675,3676,3677,3678,3679, +3680,3681,3682,3683,3684,3685,3686,3687,3688,3689,3690,3691,3692,3693,3694,3695, +3696,3697,3698,3699,3700,1192,3701,3702,3703,3704,1256,3705,3706,3707,3708,1583, +1257,3709,3710,3711,3712,3713,3714,3715,3716,1584,3717,3718,3719,3720,3721,3722, +3723,3724,3725,3726,3727,3728,3729,3730,3731,3732,3733,3734,3735,3736,3737,3738, +3739,3740,3741,3742,3743,3744,3745,1344,3746,3747,3748,3749,3750,3751,3752,3753, +3754,3755,3756,1585,3757,3758,3759,3760,3761,3762,3763,3764,3765,3766,1586,3767, +3768,3769,3770,3771,3772,3773,3774,3775,3776,3777,3778,1345,3779,3780,3781,3782, +3783,3784,3785,3786,3787,3788,3789,3790,3791,3792,3793,3794,3795,1346,1587,3796, +3797,1588,3798,3799,3800,3801,3802,3803,3804,3805,3806,1347,3807,3808,3809,3810, +3811,1589,3812,3813,3814,3815,3816,3817,3818,3819,3820,3821,1590,3822,3823,1591, +1348,3824,3825,3826,3827,3828,3829,3830,1592,3831,3832,1593,3833,3834,3835,3836, +3837,3838,3839,3840,3841,3842,3843,3844,1349,3845,3846,3847,3848,3849,3850,3851, +3852,3853,3854,3855,3856,3857,3858,1594,3859,3860,3861,3862,3863,3864,3865,3866, +3867,3868,3869,1595,3870,3871,3872,3873,1596,3874,3875,3876,3877,3878,3879,3880, +3881,3882,3883,3884,3885,3886,1597,3887,3888,3889,3890,3891,3892,3893,3894,3895, +1598,3896,3897,3898,1599,1600,3899,1350,3900,1351,3901,3902,1352,3903,3904,3905, +3906,3907,3908,3909,3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921, +3922,3923,3924,1258,3925,3926,3927,3928,3929,3930,3931,1193,3932,1601,3933,3934, +3935,3936,3937,3938,3939,3940,3941,3942,3943,1602,3944,3945,3946,3947,3948,1603, +3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964, +3965,1604,3966,3967,3968,3969,3970,3971,3972,3973,3974,3975,3976,3977,1353,3978, +3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990,3991,1354,3992,3993, +3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009, +4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,1355,4024, +4025,4026,4027,4028,4029,4030,4031,4032,4033,4034,4035,4036,4037,4038,4039,4040, +1605,4041,4042,4043,4044,4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055, +4056,4057,4058,4059,4060,1606,4061,4062,4063,4064,1607,4065,4066,4067,4068,4069, +4070,4071,4072,4073,4074,4075,4076,1194,4077,4078,1608,4079,4080,4081,4082,4083, +4084,4085,4086,4087,1609,4088,4089,4090,4091,4092,4093,4094,4095,4096,4097,4098, +4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,1259,4109,4110,4111,4112,4113, +4114,4115,4116,4117,4118,4119,4120,4121,4122,4123,4124,1195,4125,4126,4127,1610, +4128,4129,4130,4131,4132,4133,4134,4135,4136,4137,1356,4138,4139,4140,4141,4142, +4143,4144,1611,4145,4146,4147,4148,4149,4150,4151,4152,4153,4154,4155,4156,4157, +4158,4159,4160,4161,4162,4163,4164,4165,4166,4167,4168,4169,4170,4171,4172,4173, +4174,4175,4176,4177,4178,4179,4180,4181,4182,4183,4184,4185,4186,4187,4188,4189, +4190,4191,4192,4193,4194,4195,4196,4197,4198,4199,4200,4201,4202,4203,4204,4205, +4206,4207,4208,4209,4210,4211,4212,4213,4214,4215,4216,4217,4218,4219,1612,4220, +4221,4222,4223,4224,4225,4226,4227,1357,4228,1613,4229,4230,4231,4232,4233,4234, +4235,4236,4237,4238,4239,4240,4241,4242,4243,1614,4244,4245,4246,4247,4248,4249, +4250,4251,4252,4253,4254,4255,4256,4257,4258,4259,4260,4261,4262,4263,4264,4265, +4266,4267,4268,4269,4270,1196,1358,4271,4272,4273,4274,4275,4276,4277,4278,4279, +4280,4281,4282,4283,4284,4285,4286,4287,1615,4288,4289,4290,4291,4292,4293,4294, +4295,4296,4297,4298,4299,4300,4301,4302,4303,4304,4305,4306,4307,4308,4309,4310, +4311,4312,4313,4314,4315,4316,4317,4318,4319,4320,4321,4322,4323,4324,4325,4326, +4327,4328,4329,4330,4331,4332,4333,4334,1616,4335,4336,4337,4338,4339,4340,4341, +4342,4343,4344,4345,4346,4347,4348,4349,4350,4351,4352,4353,4354,4355,4356,4357, +4358,4359,4360,1617,4361,4362,4363,4364,4365,1618,4366,4367,4368,4369,4370,4371, +4372,4373,4374,4375,4376,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387, +4388,4389,4390,4391,4392,4393,4394,4395,4396,4397,4398,4399,4400,4401,4402,4403, +4404,4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,1619,4417,4418, +4419,4420,4421,4422,4423,4424,4425,1112,4426,4427,4428,4429,4430,1620,4431,4432, +4433,4434,4435,4436,4437,4438,4439,4440,4441,4442,1260,1261,4443,4444,4445,4446, +4447,4448,4449,4450,4451,4452,4453,4454,4455,1359,4456,4457,4458,4459,4460,4461, +4462,4463,4464,4465,1621,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476, +4477,4478,4479,4480,4481,4482,4483,4484,4485,4486,4487,4488,4489,1055,4490,4491, +4492,4493,4494,4495,4496,4497,4498,4499,4500,4501,4502,4503,4504,4505,4506,4507, +4508,4509,4510,4511,4512,4513,4514,4515,4516,4517,4518,1622,4519,4520,4521,1623, +4522,4523,4524,4525,4526,4527,4528,4529,4530,4531,4532,4533,4534,4535,1360,4536, +4537,4538,4539,4540,4541,4542,4543, 975,4544,4545,4546,4547,4548,4549,4550,4551, +4552,4553,4554,4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,4567, +4568,4569,4570,4571,1624,4572,4573,4574,4575,4576,1625,4577,4578,4579,4580,4581, +4582,4583,4584,1626,4585,4586,4587,4588,4589,4590,4591,4592,4593,4594,4595,1627, +4596,4597,4598,4599,4600,4601,4602,4603,4604,4605,4606,4607,4608,4609,4610,4611, +4612,4613,4614,4615,1628,4616,4617,4618,4619,4620,4621,4622,4623,4624,4625,4626, +4627,4628,4629,4630,4631,4632,4633,4634,4635,4636,4637,4638,4639,4640,4641,4642, +4643,4644,4645,4646,4647,4648,4649,1361,4650,4651,4652,4653,4654,4655,4656,4657, +4658,4659,4660,4661,1362,4662,4663,4664,4665,4666,4667,4668,4669,4670,4671,4672, +4673,4674,4675,4676,4677,4678,4679,4680,4681,4682,1629,4683,4684,4685,4686,4687, +1630,4688,4689,4690,4691,1153,4692,4693,4694,1113,4695,4696,4697,4698,4699,4700, +4701,4702,4703,4704,4705,4706,4707,4708,4709,4710,4711,1197,4712,4713,4714,4715, +4716,4717,4718,4719,4720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731, +4732,4733,4734,4735,1631,4736,1632,4737,4738,4739,4740,4741,4742,4743,4744,1633, +4745,4746,4747,4748,4749,1262,4750,4751,4752,4753,4754,1363,4755,4756,4757,4758, +4759,4760,4761,4762,4763,4764,4765,4766,4767,4768,1634,4769,4770,4771,4772,4773, +4774,4775,4776,4777,4778,1635,4779,4780,4781,4782,4783,4784,4785,4786,4787,4788, +4789,1636,4790,4791,4792,4793,4794,4795,4796,4797,4798,4799,4800,4801,4802,4803, +4804,4805,4806,1637,4807,4808,4809,1638,4810,4811,4812,4813,4814,4815,4816,4817, +4818,1639,4819,4820,4821,4822,4823,4824,4825,4826,4827,4828,4829,4830,4831,4832, +4833,1077,4834,4835,4836,4837,4838,4839,4840,4841,4842,4843,4844,4845,4846,4847, +4848,4849,4850,4851,4852,4853,4854,4855,4856,4857,4858,4859,4860,4861,4862,4863, +4864,4865,4866,4867,4868,4869,4870,4871,4872,4873,4874,4875,4876,4877,4878,4879, +4880,4881,4882,4883,1640,4884,4885,1641,4886,4887,4888,4889,4890,4891,4892,4893, +4894,4895,4896,4897,4898,4899,4900,4901,4902,4903,4904,4905,4906,4907,4908,4909, +4910,4911,1642,4912,4913,4914,1364,4915,4916,4917,4918,4919,4920,4921,4922,4923, +4924,4925,4926,4927,4928,4929,4930,4931,1643,4932,4933,4934,4935,4936,4937,4938, +4939,4940,4941,4942,4943,4944,4945,4946,4947,4948,4949,4950,4951,4952,4953,4954, +4955,4956,4957,4958,4959,4960,4961,4962,4963,4964,4965,4966,4967,4968,4969,4970, +4971,4972,4973,4974,4975,4976,4977,4978,4979,4980,1644,4981,4982,4983,4984,1645, +4985,4986,1646,4987,4988,4989,4990,4991,4992,4993,4994,4995,4996,4997,4998,4999, +5000,5001,5002,5003,5004,5005,1647,5006,1648,5007,5008,5009,5010,5011,5012,1078, +5013,5014,5015,5016,5017,5018,5019,5020,5021,5022,5023,5024,5025,5026,5027,5028, +1365,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039,1649,5040,5041,5042, +5043,5044,5045,1366,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,1650,5056, +5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072, +5073,5074,5075,5076,5077,1651,5078,5079,5080,5081,5082,5083,5084,5085,5086,5087, +5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102,5103, +5104,5105,5106,5107,5108,5109,5110,1652,5111,5112,5113,5114,5115,5116,5117,5118, +1367,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,1653,5130,5131,5132, +5133,5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,5144,5145,5146,5147,5148, +5149,1368,5150,1654,5151,1369,5152,5153,5154,5155,5156,5157,5158,5159,5160,5161, +5162,5163,5164,5165,5166,5167,5168,5169,5170,5171,5172,5173,5174,5175,5176,5177, +5178,1370,5179,5180,5181,5182,5183,5184,5185,5186,5187,5188,5189,5190,5191,5192, +5193,5194,5195,5196,5197,5198,1655,5199,5200,5201,5202,1656,5203,5204,5205,5206, +1371,5207,1372,5208,5209,5210,5211,1373,5212,5213,1374,5214,5215,5216,5217,5218, +5219,5220,5221,5222,5223,5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,5234, +5235,5236,5237,5238,5239,5240,5241,5242,5243,5244,5245,5246,5247,1657,5248,5249, +5250,5251,1658,1263,5252,5253,5254,5255,5256,1375,5257,5258,5259,5260,5261,5262, +5263,5264,5265,5266,5267,5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278, +5279,5280,5281,5282,5283,1659,5284,5285,5286,5287,5288,5289,5290,5291,5292,5293, +5294,5295,5296,5297,5298,5299,5300,1660,5301,5302,5303,5304,5305,5306,5307,5308, +5309,5310,5311,5312,5313,5314,5315,5316,5317,5318,5319,5320,5321,1376,5322,5323, +5324,5325,5326,5327,5328,5329,5330,5331,5332,5333,1198,5334,5335,5336,5337,5338, +5339,5340,5341,5342,5343,1661,5344,5345,5346,5347,5348,5349,5350,5351,5352,5353, +5354,5355,5356,5357,5358,5359,5360,5361,5362,5363,5364,5365,5366,5367,5368,5369, +5370,5371,5372,5373,5374,5375,5376,5377,5378,5379,5380,5381,5382,5383,5384,5385, +5386,5387,5388,5389,5390,5391,5392,5393,5394,5395,5396,5397,5398,1264,5399,5400, +5401,5402,5403,5404,5405,5406,5407,5408,5409,5410,5411,5412,1662,5413,5414,5415, +5416,1663,5417,5418,5419,5420,5421,5422,5423,5424,5425,5426,5427,5428,5429,5430, +5431,5432,5433,5434,5435,5436,5437,5438,1664,5439,5440,5441,5442,5443,5444,5445, +5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456,5457,5458,5459,5460,5461, +5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472,5473,5474,5475,5476,5477, +5478,1154,5479,5480,5481,5482,5483,5484,5485,1665,5486,5487,5488,5489,5490,5491, +5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,5504,5505,5506,5507, +5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,5519,5520,5521,5522,5523, +5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,5534,5535,5536,5537,5538,5539, +5540,5541,5542,5543,5544,5545,5546,5547,5548,1377,5549,5550,5551,5552,5553,5554, +5555,5556,5557,5558,5559,5560,5561,5562,5563,5564,5565,5566,5567,5568,5569,5570, +1114,5571,5572,5573,5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584,5585, +5586,5587,5588,5589,5590,5591,5592,1378,5593,5594,5595,5596,5597,5598,5599,5600, +5601,5602,5603,5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,1379,5615, +5616,5617,5618,5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631, +5632,5633,5634,1380,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646, +5647,5648,5649,1381,1056,5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660, +1666,5661,5662,5663,5664,5665,5666,5667,5668,1667,5669,1668,5670,5671,5672,5673, +5674,5675,5676,5677,5678,1155,5679,5680,5681,5682,5683,5684,5685,5686,5687,5688, +5689,5690,5691,5692,5693,5694,5695,5696,5697,5698,1669,5699,5700,5701,5702,5703, +5704,5705,1670,5706,5707,5708,5709,5710,1671,5711,5712,5713,5714,1382,5715,5716, +5717,5718,5719,5720,5721,5722,5723,5724,5725,1672,5726,5727,1673,1674,5728,5729, +5730,5731,5732,5733,5734,5735,5736,1675,5737,5738,5739,5740,5741,5742,5743,5744, +1676,5745,5746,5747,5748,5749,5750,5751,1383,5752,5753,5754,5755,5756,5757,5758, +5759,5760,5761,5762,5763,5764,5765,5766,5767,5768,1677,5769,5770,5771,5772,5773, +1678,5774,5775,5776, 998,5777,5778,5779,5780,5781,5782,5783,5784,5785,1384,5786, +5787,5788,5789,5790,5791,5792,5793,5794,5795,5796,5797,5798,5799,5800,1679,5801, +5802,5803,1115,1116,5804,5805,5806,5807,5808,5809,5810,5811,5812,5813,5814,5815, +5816,5817,5818,5819,5820,5821,5822,5823,5824,5825,5826,5827,5828,5829,5830,5831, +5832,5833,5834,5835,5836,5837,5838,5839,5840,5841,5842,5843,5844,5845,5846,5847, +5848,5849,5850,5851,5852,5853,5854,5855,1680,5856,5857,5858,5859,5860,5861,5862, +5863,5864,1681,5865,5866,5867,1682,5868,5869,5870,5871,5872,5873,5874,5875,5876, +5877,5878,5879,1683,5880,1684,5881,5882,5883,5884,1685,5885,5886,5887,5888,5889, +5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904,5905, +5906,5907,1686,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920, +5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,1687, +5936,5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951, +5952,1688,1689,5953,1199,5954,5955,5956,5957,5958,5959,5960,5961,1690,5962,5963, +5964,5965,5966,5967,5968,5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979, +5980,5981,1385,5982,1386,5983,5984,5985,5986,5987,5988,5989,5990,5991,5992,5993, +5994,5995,5996,5997,5998,5999,6000,6001,6002,6003,6004,6005,6006,6007,6008,6009, +6010,6011,6012,6013,6014,6015,6016,6017,6018,6019,6020,6021,6022,6023,6024,6025, +6026,6027,1265,6028,6029,1691,6030,6031,6032,6033,6034,6035,6036,6037,6038,6039, +6040,6041,6042,6043,6044,6045,6046,6047,6048,6049,6050,6051,6052,6053,6054,6055, +6056,6057,6058,6059,6060,6061,6062,6063,6064,6065,6066,6067,6068,6069,6070,6071, +6072,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084,1692,6085,6086, +6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,6100,6101,6102, +6103,6104,6105,6106,6107,6108,6109,6110,6111,6112,6113,6114,6115,6116,6117,6118, +6119,6120,6121,6122,6123,6124,6125,6126,6127,6128,6129,6130,6131,1693,6132,6133, +6134,6135,6136,1694,6137,6138,6139,6140,6141,1695,6142,6143,6144,6145,6146,6147, +6148,6149,6150,6151,6152,6153,6154,6155,6156,6157,6158,6159,6160,6161,6162,6163, +6164,6165,6166,6167,6168,6169,6170,6171,6172,6173,6174,6175,6176,6177,6178,6179, +6180,6181,6182,6183,6184,6185,1696,6186,6187,6188,6189,6190,6191,6192,6193,6194, +6195,6196,6197,6198,6199,6200,6201,6202,6203,6204,6205,6206,6207,6208,6209,6210, +6211,6212,6213,6214,6215,6216,6217,6218,6219,1697,6220,6221,6222,6223,6224,6225, +6226,6227,6228,6229,6230,6231,6232,6233,6234,6235,6236,6237,6238,6239,6240,6241, +6242,6243,6244,6245,6246,6247,6248,6249,6250,6251,6252,6253,1698,6254,6255,6256, +6257,6258,6259,6260,6261,6262,6263,1200,6264,6265,6266,6267,6268,6269,6270,6271, #1024 +6272,6273,6274,6275,6276,6277,6278,6279,6280,6281,6282,6283,6284,6285,6286,6287, +6288,6289,6290,6291,6292,6293,6294,6295,6296,6297,6298,6299,6300,6301,6302,1699, +6303,6304,1700,6305,6306,6307,6308,6309,6310,6311,6312,6313,6314,6315,6316,6317, +6318,6319,6320,6321,6322,6323,6324,6325,6326,6327,6328,6329,6330,6331,6332,6333, +6334,6335,6336,6337,6338,6339,1701,6340,6341,6342,6343,6344,1387,6345,6346,6347, +6348,6349,6350,6351,6352,6353,6354,6355,6356,6357,6358,6359,6360,6361,6362,6363, +6364,6365,6366,6367,6368,6369,6370,6371,6372,6373,6374,6375,6376,6377,6378,6379, +6380,6381,6382,6383,6384,6385,6386,6387,6388,6389,6390,6391,6392,6393,6394,6395, +6396,6397,6398,6399,6400,6401,6402,6403,6404,6405,6406,6407,6408,6409,6410,6411, +6412,6413,1702,6414,6415,6416,6417,6418,6419,6420,6421,6422,1703,6423,6424,6425, +6426,6427,6428,6429,6430,6431,6432,6433,6434,6435,6436,6437,6438,1704,6439,6440, +6441,6442,6443,6444,6445,6446,6447,6448,6449,6450,6451,6452,6453,6454,6455,6456, +6457,6458,6459,6460,6461,6462,6463,6464,6465,6466,6467,6468,6469,6470,6471,6472, +6473,6474,6475,6476,6477,6478,6479,6480,6481,6482,6483,6484,6485,6486,6487,6488, +6489,6490,6491,6492,6493,6494,6495,6496,6497,6498,6499,6500,6501,6502,6503,1266, +6504,6505,6506,6507,6508,6509,6510,6511,6512,6513,6514,6515,6516,6517,6518,6519, +6520,6521,6522,6523,6524,6525,6526,6527,6528,6529,6530,6531,6532,6533,6534,6535, +6536,6537,6538,6539,6540,6541,6542,6543,6544,6545,6546,6547,6548,6549,6550,6551, +1705,1706,6552,6553,6554,6555,6556,6557,6558,6559,6560,6561,6562,6563,6564,6565, +6566,6567,6568,6569,6570,6571,6572,6573,6574,6575,6576,6577,6578,6579,6580,6581, +6582,6583,6584,6585,6586,6587,6588,6589,6590,6591,6592,6593,6594,6595,6596,6597, +6598,6599,6600,6601,6602,6603,6604,6605,6606,6607,6608,6609,6610,6611,6612,6613, +6614,6615,6616,6617,6618,6619,6620,6621,6622,6623,6624,6625,6626,6627,6628,6629, +6630,6631,6632,6633,6634,6635,6636,6637,1388,6638,6639,6640,6641,6642,6643,6644, +1707,6645,6646,6647,6648,6649,6650,6651,6652,6653,6654,6655,6656,6657,6658,6659, +6660,6661,6662,6663,1708,6664,6665,6666,6667,6668,6669,6670,6671,6672,6673,6674, +1201,6675,6676,6677,6678,6679,6680,6681,6682,6683,6684,6685,6686,6687,6688,6689, +6690,6691,6692,6693,6694,6695,6696,6697,6698,6699,6700,6701,6702,6703,6704,6705, +6706,6707,6708,6709,6710,6711,6712,6713,6714,6715,6716,6717,6718,6719,6720,6721, +6722,6723,6724,6725,1389,6726,6727,6728,6729,6730,6731,6732,6733,6734,6735,6736, +1390,1709,6737,6738,6739,6740,6741,6742,1710,6743,6744,6745,6746,1391,6747,6748, +6749,6750,6751,6752,6753,6754,6755,6756,6757,1392,6758,6759,6760,6761,6762,6763, +6764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,6775,6776,6777,6778,6779, +6780,1202,6781,6782,6783,6784,6785,6786,6787,6788,6789,6790,6791,6792,6793,6794, +6795,6796,6797,6798,6799,6800,6801,6802,6803,6804,6805,6806,6807,6808,6809,1711, +6810,6811,6812,6813,6814,6815,6816,6817,6818,6819,6820,6821,6822,6823,6824,6825, +6826,6827,6828,6829,6830,6831,6832,6833,6834,6835,6836,1393,6837,6838,6839,6840, +6841,6842,6843,6844,6845,6846,6847,6848,6849,6850,6851,6852,6853,6854,6855,6856, +6857,6858,6859,6860,6861,6862,6863,6864,6865,6866,6867,6868,6869,6870,6871,6872, +6873,6874,6875,6876,6877,6878,6879,6880,6881,6882,6883,6884,6885,6886,6887,6888, +6889,6890,6891,6892,6893,6894,6895,6896,6897,6898,6899,6900,6901,6902,1712,6903, +6904,6905,6906,6907,6908,6909,6910,1713,6911,6912,6913,6914,6915,6916,6917,6918, +6919,6920,6921,6922,6923,6924,6925,6926,6927,6928,6929,6930,6931,6932,6933,6934, +6935,6936,6937,6938,6939,6940,6941,6942,6943,6944,6945,6946,6947,6948,6949,6950, +6951,6952,6953,6954,6955,6956,6957,6958,6959,6960,6961,6962,6963,6964,6965,6966, +6967,6968,6969,6970,6971,6972,6973,6974,1714,6975,6976,6977,6978,6979,6980,6981, +6982,6983,6984,6985,6986,6987,6988,1394,6989,6990,6991,6992,6993,6994,6995,6996, +6997,6998,6999,7000,1715,7001,7002,7003,7004,7005,7006,7007,7008,7009,7010,7011, +7012,7013,7014,7015,7016,7017,7018,7019,7020,7021,7022,7023,7024,7025,7026,7027, +7028,1716,7029,7030,7031,7032,7033,7034,7035,7036,7037,7038,7039,7040,7041,7042, +7043,7044,7045,7046,7047,7048,7049,7050,7051,7052,7053,7054,7055,7056,7057,7058, +7059,7060,7061,7062,7063,7064,7065,7066,7067,7068,7069,7070,7071,7072,7073,7074, +7075,7076,7077,7078,7079,7080,7081,7082,7083,7084,7085,7086,7087,7088,7089,7090, +7091,7092,7093,7094,7095,7096,7097,7098,7099,7100,7101,7102,7103,7104,7105,7106, +7107,7108,7109,7110,7111,7112,7113,7114,7115,7116,7117,7118,7119,7120,7121,7122, +7123,7124,7125,7126,7127,7128,7129,7130,7131,7132,7133,7134,7135,7136,7137,7138, +7139,7140,7141,7142,7143,7144,7145,7146,7147,7148,7149,7150,7151,7152,7153,7154, +7155,7156,7157,7158,7159,7160,7161,7162,7163,7164,7165,7166,7167,7168,7169,7170, +7171,7172,7173,7174,7175,7176,7177,7178,7179,7180,7181,7182,7183,7184,7185,7186, +7187,7188,7189,7190,7191,7192,7193,7194,7195,7196,7197,7198,7199,7200,7201,7202, +7203,7204,7205,7206,7207,1395,7208,7209,7210,7211,7212,7213,1717,7214,7215,7216, +7217,7218,7219,7220,7221,7222,7223,7224,7225,7226,7227,7228,7229,7230,7231,7232, +7233,7234,7235,7236,7237,7238,7239,7240,7241,7242,7243,7244,7245,7246,7247,7248, +7249,7250,7251,7252,7253,7254,7255,7256,7257,7258,7259,7260,7261,7262,7263,7264, +7265,7266,7267,7268,7269,7270,7271,7272,7273,7274,7275,7276,7277,7278,7279,7280, +7281,7282,7283,7284,7285,7286,7287,7288,7289,7290,7291,7292,7293,7294,7295,7296, +7297,7298,7299,7300,7301,7302,7303,7304,7305,7306,7307,7308,7309,7310,7311,7312, +7313,1718,7314,7315,7316,7317,7318,7319,7320,7321,7322,7323,7324,7325,7326,7327, +7328,7329,7330,7331,7332,7333,7334,7335,7336,7337,7338,7339,7340,7341,7342,7343, +7344,7345,7346,7347,7348,7349,7350,7351,7352,7353,7354,7355,7356,7357,7358,7359, +7360,7361,7362,7363,7364,7365,7366,7367,7368,7369,7370,7371,7372,7373,7374,7375, +7376,7377,7378,7379,7380,7381,7382,7383,7384,7385,7386,7387,7388,7389,7390,7391, +7392,7393,7394,7395,7396,7397,7398,7399,7400,7401,7402,7403,7404,7405,7406,7407, +7408,7409,7410,7411,7412,7413,7414,7415,7416,7417,7418,7419,7420,7421,7422,7423, +7424,7425,7426,7427,7428,7429,7430,7431,7432,7433,7434,7435,7436,7437,7438,7439, +7440,7441,7442,7443,7444,7445,7446,7447,7448,7449,7450,7451,7452,7453,7454,7455, +7456,7457,7458,7459,7460,7461,7462,7463,7464,7465,7466,7467,7468,7469,7470,7471, +7472,7473,7474,7475,7476,7477,7478,7479,7480,7481,7482,7483,7484,7485,7486,7487, +7488,7489,7490,7491,7492,7493,7494,7495,7496,7497,7498,7499,7500,7501,7502,7503, +7504,7505,7506,7507,7508,7509,7510,7511,7512,7513,7514,7515,7516,7517,7518,7519, +7520,7521,7522,7523,7524,7525,7526,7527,7528,7529,7530,7531,7532,7533,7534,7535, +7536,7537,7538,7539,7540,7541,7542,7543,7544,7545,7546,7547,7548,7549,7550,7551, +7552,7553,7554,7555,7556,7557,7558,7559,7560,7561,7562,7563,7564,7565,7566,7567, +7568,7569,7570,7571,7572,7573,7574,7575,7576,7577,7578,7579,7580,7581,7582,7583, +7584,7585,7586,7587,7588,7589,7590,7591,7592,7593,7594,7595,7596,7597,7598,7599, +7600,7601,7602,7603,7604,7605,7606,7607,7608,7609,7610,7611,7612,7613,7614,7615, +7616,7617,7618,7619,7620,7621,7622,7623,7624,7625,7626,7627,7628,7629,7630,7631, +7632,7633,7634,7635,7636,7637,7638,7639,7640,7641,7642,7643,7644,7645,7646,7647, +7648,7649,7650,7651,7652,7653,7654,7655,7656,7657,7658,7659,7660,7661,7662,7663, +7664,7665,7666,7667,7668,7669,7670,7671,7672,7673,7674,7675,7676,7677,7678,7679, +7680,7681,7682,7683,7684,7685,7686,7687,7688,7689,7690,7691,7692,7693,7694,7695, +7696,7697,7698,7699,7700,7701,7702,7703,7704,7705,7706,7707,7708,7709,7710,7711, +7712,7713,7714,7715,7716,7717,7718,7719,7720,7721,7722,7723,7724,7725,7726,7727, +7728,7729,7730,7731,7732,7733,7734,7735,7736,7737,7738,7739,7740,7741,7742,7743, +7744,7745,7746,7747,7748,7749,7750,7751,7752,7753,7754,7755,7756,7757,7758,7759, +7760,7761,7762,7763,7764,7765,7766,7767,7768,7769,7770,7771,7772,7773,7774,7775, +7776,7777,7778,7779,7780,7781,7782,7783,7784,7785,7786,7787,7788,7789,7790,7791, +7792,7793,7794,7795,7796,7797,7798,7799,7800,7801,7802,7803,7804,7805,7806,7807, +7808,7809,7810,7811,7812,7813,7814,7815,7816,7817,7818,7819,7820,7821,7822,7823, +7824,7825,7826,7827,7828,7829,7830,7831,7832,7833,7834,7835,7836,7837,7838,7839, +7840,7841,7842,7843,7844,7845,7846,7847,7848,7849,7850,7851,7852,7853,7854,7855, +7856,7857,7858,7859,7860,7861,7862,7863,7864,7865,7866,7867,7868,7869,7870,7871, +7872,7873,7874,7875,7876,7877,7878,7879,7880,7881,7882,7883,7884,7885,7886,7887, +7888,7889,7890,7891,7892,7893,7894,7895,7896,7897,7898,7899,7900,7901,7902,7903, +7904,7905,7906,7907,7908,7909,7910,7911,7912,7913,7914,7915,7916,7917,7918,7919, +7920,7921,7922,7923,7924,7925,7926,7927,7928,7929,7930,7931,7932,7933,7934,7935, +7936,7937,7938,7939,7940,7941,7942,7943,7944,7945,7946,7947,7948,7949,7950,7951, +7952,7953,7954,7955,7956,7957,7958,7959,7960,7961,7962,7963,7964,7965,7966,7967, +7968,7969,7970,7971,7972,7973,7974,7975,7976,7977,7978,7979,7980,7981,7982,7983, +7984,7985,7986,7987,7988,7989,7990,7991,7992,7993,7994,7995,7996,7997,7998,7999, +8000,8001,8002,8003,8004,8005,8006,8007,8008,8009,8010,8011,8012,8013,8014,8015, +8016,8017,8018,8019,8020,8021,8022,8023,8024,8025,8026,8027,8028,8029,8030,8031, +8032,8033,8034,8035,8036,8037,8038,8039,8040,8041,8042,8043,8044,8045,8046,8047, +8048,8049,8050,8051,8052,8053,8054,8055,8056,8057,8058,8059,8060,8061,8062,8063, +8064,8065,8066,8067,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079, +8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095, +8096,8097,8098,8099,8100,8101,8102,8103,8104,8105,8106,8107,8108,8109,8110,8111, +8112,8113,8114,8115,8116,8117,8118,8119,8120,8121,8122,8123,8124,8125,8126,8127, +8128,8129,8130,8131,8132,8133,8134,8135,8136,8137,8138,8139,8140,8141,8142,8143, +8144,8145,8146,8147,8148,8149,8150,8151,8152,8153,8154,8155,8156,8157,8158,8159, +8160,8161,8162,8163,8164,8165,8166,8167,8168,8169,8170,8171,8172,8173,8174,8175, +8176,8177,8178,8179,8180,8181,8182,8183,8184,8185,8186,8187,8188,8189,8190,8191, +8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8203,8204,8205,8206,8207, +8208,8209,8210,8211,8212,8213,8214,8215,8216,8217,8218,8219,8220,8221,8222,8223, +8224,8225,8226,8227,8228,8229,8230,8231,8232,8233,8234,8235,8236,8237,8238,8239, +8240,8241,8242,8243,8244,8245,8246,8247,8248,8249,8250,8251,8252,8253,8254,8255, +8256,8257,8258,8259,8260,8261,8262,8263,8264,8265,8266,8267,8268,8269,8270,8271, +8272,8273,8274,8275,8276,8277,8278,8279,8280,8281,8282,8283,8284,8285,8286,8287, +8288,8289,8290,8291,8292,8293,8294,8295,8296,8297,8298,8299,8300,8301,8302,8303, +8304,8305,8306,8307,8308,8309,8310,8311,8312,8313,8314,8315,8316,8317,8318,8319, +8320,8321,8322,8323,8324,8325,8326,8327,8328,8329,8330,8331,8332,8333,8334,8335, +8336,8337,8338,8339,8340,8341,8342,8343,8344,8345,8346,8347,8348,8349,8350,8351, +8352,8353,8354,8355,8356,8357,8358,8359,8360,8361,8362,8363,8364,8365,8366,8367, +8368,8369,8370,8371,8372,8373,8374,8375,8376,8377,8378,8379,8380,8381,8382,8383, +8384,8385,8386,8387,8388,8389,8390,8391,8392,8393,8394,8395,8396,8397,8398,8399, +8400,8401,8402,8403,8404,8405,8406,8407,8408,8409,8410,8411,8412,8413,8414,8415, +8416,8417,8418,8419,8420,8421,8422,8423,8424,8425,8426,8427,8428,8429,8430,8431, +8432,8433,8434,8435,8436,8437,8438,8439,8440,8441,8442,8443,8444,8445,8446,8447, +8448,8449,8450,8451,8452,8453,8454,8455,8456,8457,8458,8459,8460,8461,8462,8463, +8464,8465,8466,8467,8468,8469,8470,8471,8472,8473,8474,8475,8476,8477,8478,8479, +8480,8481,8482,8483,8484,8485,8486,8487,8488,8489,8490,8491,8492,8493,8494,8495, +8496,8497,8498,8499,8500,8501,8502,8503,8504,8505,8506,8507,8508,8509,8510,8511, +8512,8513,8514,8515,8516,8517,8518,8519,8520,8521,8522,8523,8524,8525,8526,8527, +8528,8529,8530,8531,8532,8533,8534,8535,8536,8537,8538,8539,8540,8541,8542,8543, +8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,8556,8557,8558,8559, +8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,8570,8571,8572,8573,8574,8575, +8576,8577,8578,8579,8580,8581,8582,8583,8584,8585,8586,8587,8588,8589,8590,8591, +8592,8593,8594,8595,8596,8597,8598,8599,8600,8601,8602,8603,8604,8605,8606,8607, +8608,8609,8610,8611,8612,8613,8614,8615,8616,8617,8618,8619,8620,8621,8622,8623, +8624,8625,8626,8627,8628,8629,8630,8631,8632,8633,8634,8635,8636,8637,8638,8639, +8640,8641,8642,8643,8644,8645,8646,8647,8648,8649,8650,8651,8652,8653,8654,8655, +8656,8657,8658,8659,8660,8661,8662,8663,8664,8665,8666,8667,8668,8669,8670,8671, +8672,8673,8674,8675,8676,8677,8678,8679,8680,8681,8682,8683,8684,8685,8686,8687, +8688,8689,8690,8691,8692,8693,8694,8695,8696,8697,8698,8699,8700,8701,8702,8703, +8704,8705,8706,8707,8708,8709,8710,8711,8712,8713,8714,8715,8716,8717,8718,8719, +8720,8721,8722,8723,8724,8725,8726,8727,8728,8729,8730,8731,8732,8733,8734,8735, +8736,8737,8738,8739,8740,8741) diff --git a/libs/requests/packages/chardet/euckrprober.py b/libs/requests/packages/chardet/euckrprober.py new file mode 100755 index 00000000..bd697ebf --- /dev/null +++ b/libs/requests/packages/chardet/euckrprober.py @@ -0,0 +1,41 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from mbcharsetprober import MultiByteCharSetProber +from codingstatemachine import CodingStateMachine +from chardistribution import EUCKRDistributionAnalysis +from mbcssm import EUCKRSMModel + +class EUCKRProber(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(EUCKRSMModel) + self._mDistributionAnalyzer = EUCKRDistributionAnalysis() + self.reset() + + def get_charset_name(self): + return "EUC-KR" diff --git a/libs/requests/packages/chardet/euctwfreq.py b/libs/requests/packages/chardet/euctwfreq.py new file mode 100755 index 00000000..c0572095 --- /dev/null +++ b/libs/requests/packages/chardet/euctwfreq.py @@ -0,0 +1,426 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# EUCTW frequency table +# Converted from big5 work +# by Taiwan's Mandarin Promotion Council +# + +# 128 --> 0.42261 +# 256 --> 0.57851 +# 512 --> 0.74851 +# 1024 --> 0.89384 +# 2048 --> 0.97583 +# +# Idea Distribution Ratio = 0.74851/(1-0.74851) =2.98 +# Random Distribution Ration = 512/(5401-512)=0.105 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR + +EUCTW_TYPICAL_DISTRIBUTION_RATIO = 0.75 + +# Char to FreqOrder table , +EUCTW_TABLE_SIZE = 8102 + +EUCTWCharToFreqOrder = ( \ + 1,1800,1506, 255,1431, 198, 9, 82, 6,7310, 177, 202,3615,1256,2808, 110, # 2742 +3735, 33,3241, 261, 76, 44,2113, 16,2931,2184,1176, 659,3868, 26,3404,2643, # 2758 +1198,3869,3313,4060, 410,2211, 302, 590, 361,1963, 8, 204, 58,4296,7311,1931, # 2774 + 63,7312,7313, 317,1614, 75, 222, 159,4061,2412,1480,7314,3500,3068, 224,2809, # 2790 +3616, 3, 10,3870,1471, 29,2774,1135,2852,1939, 873, 130,3242,1123, 312,7315, # 2806 +4297,2051, 507, 252, 682,7316, 142,1914, 124, 206,2932, 34,3501,3173, 64, 604, # 2822 +7317,2494,1976,1977, 155,1990, 645, 641,1606,7318,3405, 337, 72, 406,7319, 80, # 2838 + 630, 238,3174,1509, 263, 939,1092,2644, 756,1440,1094,3406, 449, 69,2969, 591, # 2854 + 179,2095, 471, 115,2034,1843, 60, 50,2970, 134, 806,1868, 734,2035,3407, 180, # 2870 + 995,1607, 156, 537,2893, 688,7320, 319,1305, 779,2144, 514,2374, 298,4298, 359, # 2886 +2495, 90,2707,1338, 663, 11, 906,1099,2545, 20,2436, 182, 532,1716,7321, 732, # 2902 +1376,4062,1311,1420,3175, 25,2312,1056, 113, 399, 382,1949, 242,3408,2467, 529, # 2918 +3243, 475,1447,3617,7322, 117, 21, 656, 810,1297,2295,2329,3502,7323, 126,4063, # 2934 + 706, 456, 150, 613,4299, 71,1118,2036,4064, 145,3069, 85, 835, 486,2114,1246, # 2950 +1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,7324,2127,2354, 347,3736, 221, # 2966 +3503,3110,7325,1955,1153,4065, 83, 296,1199,3070, 192, 624, 93,7326, 822,1897, # 2982 +2810,3111, 795,2064, 991,1554,1542,1592, 27, 43,2853, 859, 139,1456, 860,4300, # 2998 + 437, 712,3871, 164,2392,3112, 695, 211,3017,2096, 195,3872,1608,3504,3505,3618, # 3014 +3873, 234, 811,2971,2097,3874,2229,1441,3506,1615,2375, 668,2076,1638, 305, 228, # 3030 +1664,4301, 467, 415,7327, 262,2098,1593, 239, 108, 300, 200,1033, 512,1247,2077, # 3046 +7328,7329,2173,3176,3619,2673, 593, 845,1062,3244, 88,1723,2037,3875,1950, 212, # 3062 + 266, 152, 149, 468,1898,4066,4302, 77, 187,7330,3018, 37, 5,2972,7331,3876, # 3078 +7332,7333, 39,2517,4303,2894,3177,2078, 55, 148, 74,4304, 545, 483,1474,1029, # 3094 +1665, 217,1869,1531,3113,1104,2645,4067, 24, 172,3507, 900,3877,3508,3509,4305, # 3110 + 32,1408,2811,1312, 329, 487,2355,2247,2708, 784,2674, 4,3019,3314,1427,1788, # 3126 + 188, 109, 499,7334,3620,1717,1789, 888,1217,3020,4306,7335,3510,7336,3315,1520, # 3142 +3621,3878, 196,1034, 775,7337,7338, 929,1815, 249, 439, 38,7339,1063,7340, 794, # 3158 +3879,1435,2296, 46, 178,3245,2065,7341,2376,7342, 214,1709,4307, 804, 35, 707, # 3174 + 324,3622,1601,2546, 140, 459,4068,7343,7344,1365, 839, 272, 978,2257,2572,3409, # 3190 +2128,1363,3623,1423, 697, 100,3071, 48, 70,1231, 495,3114,2193,7345,1294,7346, # 3206 +2079, 462, 586,1042,3246, 853, 256, 988, 185,2377,3410,1698, 434,1084,7347,3411, # 3222 + 314,2615,2775,4308,2330,2331, 569,2280, 637,1816,2518, 757,1162,1878,1616,3412, # 3238 + 287,1577,2115, 768,4309,1671,2854,3511,2519,1321,3737, 909,2413,7348,4069, 933, # 3254 +3738,7349,2052,2356,1222,4310, 765,2414,1322, 786,4311,7350,1919,1462,1677,2895, # 3270 +1699,7351,4312,1424,2437,3115,3624,2590,3316,1774,1940,3413,3880,4070, 309,1369, # 3286 +1130,2812, 364,2230,1653,1299,3881,3512,3882,3883,2646, 525,1085,3021, 902,2000, # 3302 +1475, 964,4313, 421,1844,1415,1057,2281, 940,1364,3116, 376,4314,4315,1381, 7, # 3318 +2520, 983,2378, 336,1710,2675,1845, 321,3414, 559,1131,3022,2742,1808,1132,1313, # 3334 + 265,1481,1857,7352, 352,1203,2813,3247, 167,1089, 420,2814, 776, 792,1724,3513, # 3350 +4071,2438,3248,7353,4072,7354, 446, 229, 333,2743, 901,3739,1200,1557,4316,2647, # 3366 +1920, 395,2744,2676,3740,4073,1835, 125, 916,3178,2616,4317,7355,7356,3741,7357, # 3382 +7358,7359,4318,3117,3625,1133,2547,1757,3415,1510,2313,1409,3514,7360,2145, 438, # 3398 +2591,2896,2379,3317,1068, 958,3023, 461, 311,2855,2677,4074,1915,3179,4075,1978, # 3414 + 383, 750,2745,2617,4076, 274, 539, 385,1278,1442,7361,1154,1964, 384, 561, 210, # 3430 + 98,1295,2548,3515,7362,1711,2415,1482,3416,3884,2897,1257, 129,7363,3742, 642, # 3446 + 523,2776,2777,2648,7364, 141,2231,1333, 68, 176, 441, 876, 907,4077, 603,2592, # 3462 + 710, 171,3417, 404, 549, 18,3118,2393,1410,3626,1666,7365,3516,4319,2898,4320, # 3478 +7366,2973, 368,7367, 146, 366, 99, 871,3627,1543, 748, 807,1586,1185, 22,2258, # 3494 + 379,3743,3180,7368,3181, 505,1941,2618,1991,1382,2314,7369, 380,2357, 218, 702, # 3510 +1817,1248,3418,3024,3517,3318,3249,7370,2974,3628, 930,3250,3744,7371, 59,7372, # 3526 + 585, 601,4078, 497,3419,1112,1314,4321,1801,7373,1223,1472,2174,7374, 749,1836, # 3542 + 690,1899,3745,1772,3885,1476, 429,1043,1790,2232,2116, 917,4079, 447,1086,1629, # 3558 +7375, 556,7376,7377,2020,1654, 844,1090, 105, 550, 966,1758,2815,1008,1782, 686, # 3574 +1095,7378,2282, 793,1602,7379,3518,2593,4322,4080,2933,2297,4323,3746, 980,2496, # 3590 + 544, 353, 527,4324, 908,2678,2899,7380, 381,2619,1942,1348,7381,1341,1252, 560, # 3606 +3072,7382,3420,2856,7383,2053, 973, 886,2080, 143,4325,7384,7385, 157,3886, 496, # 3622 +4081, 57, 840, 540,2038,4326,4327,3421,2117,1445, 970,2259,1748,1965,2081,4082, # 3638 +3119,1234,1775,3251,2816,3629, 773,1206,2129,1066,2039,1326,3887,1738,1725,4083, # 3654 + 279,3120, 51,1544,2594, 423,1578,2130,2066, 173,4328,1879,7386,7387,1583, 264, # 3670 + 610,3630,4329,2439, 280, 154,7388,7389,7390,1739, 338,1282,3073, 693,2857,1411, # 3686 +1074,3747,2440,7391,4330,7392,7393,1240, 952,2394,7394,2900,1538,2679, 685,1483, # 3702 +4084,2468,1436, 953,4085,2054,4331, 671,2395, 79,4086,2441,3252, 608, 567,2680, # 3718 +3422,4087,4088,1691, 393,1261,1791,2396,7395,4332,7396,7397,7398,7399,1383,1672, # 3734 +3748,3182,1464, 522,1119, 661,1150, 216, 675,4333,3888,1432,3519, 609,4334,2681, # 3750 +2397,7400,7401,7402,4089,3025, 0,7403,2469, 315, 231,2442, 301,3319,4335,2380, # 3766 +7404, 233,4090,3631,1818,4336,4337,7405, 96,1776,1315,2082,7406, 257,7407,1809, # 3782 +3632,2709,1139,1819,4091,2021,1124,2163,2778,1777,2649,7408,3074, 363,1655,3183, # 3798 +7409,2975,7410,7411,7412,3889,1567,3890, 718, 103,3184, 849,1443, 341,3320,2934, # 3814 +1484,7413,1712, 127, 67, 339,4092,2398, 679,1412, 821,7414,7415, 834, 738, 351, # 3830 +2976,2146, 846, 235,1497,1880, 418,1992,3749,2710, 186,1100,2147,2746,3520,1545, # 3846 +1355,2935,2858,1377, 583,3891,4093,2573,2977,7416,1298,3633,1078,2549,3634,2358, # 3862 + 78,3750,3751, 267,1289,2099,2001,1594,4094, 348, 369,1274,2194,2175,1837,4338, # 3878 +1820,2817,3635,2747,2283,2002,4339,2936,2748, 144,3321, 882,4340,3892,2749,3423, # 3894 +4341,2901,7417,4095,1726, 320,7418,3893,3026, 788,2978,7419,2818,1773,1327,2859, # 3910 +3894,2819,7420,1306,4342,2003,1700,3752,3521,2359,2650, 787,2022, 506, 824,3636, # 3926 + 534, 323,4343,1044,3322,2023,1900, 946,3424,7421,1778,1500,1678,7422,1881,4344, # 3942 + 165, 243,4345,3637,2521, 123, 683,4096, 764,4346, 36,3895,1792, 589,2902, 816, # 3958 + 626,1667,3027,2233,1639,1555,1622,3753,3896,7423,3897,2860,1370,1228,1932, 891, # 3974 +2083,2903, 304,4097,7424, 292,2979,2711,3522, 691,2100,4098,1115,4347, 118, 662, # 3990 +7425, 611,1156, 854,2381,1316,2861, 2, 386, 515,2904,7426,7427,3253, 868,2234, # 4006 +1486, 855,2651, 785,2212,3028,7428,1040,3185,3523,7429,3121, 448,7430,1525,7431, # 4022 +2164,4348,7432,3754,7433,4099,2820,3524,3122, 503, 818,3898,3123,1568, 814, 676, # 4038 +1444, 306,1749,7434,3755,1416,1030, 197,1428, 805,2821,1501,4349,7435,7436,7437, # 4054 +1993,7438,4350,7439,7440,2195, 13,2779,3638,2980,3124,1229,1916,7441,3756,2131, # 4070 +7442,4100,4351,2399,3525,7443,2213,1511,1727,1120,7444,7445, 646,3757,2443, 307, # 4086 +7446,7447,1595,3186,7448,7449,7450,3639,1113,1356,3899,1465,2522,2523,7451, 519, # 4102 +7452, 128,2132, 92,2284,1979,7453,3900,1512, 342,3125,2196,7454,2780,2214,1980, # 4118 +3323,7455, 290,1656,1317, 789, 827,2360,7456,3758,4352, 562, 581,3901,7457, 401, # 4134 +4353,2248, 94,4354,1399,2781,7458,1463,2024,4355,3187,1943,7459, 828,1105,4101, # 4150 +1262,1394,7460,4102, 605,4356,7461,1783,2862,7462,2822, 819,2101, 578,2197,2937, # 4166 +7463,1502, 436,3254,4103,3255,2823,3902,2905,3425,3426,7464,2712,2315,7465,7466, # 4182 +2332,2067, 23,4357, 193, 826,3759,2102, 699,1630,4104,3075, 390,1793,1064,3526, # 4198 +7467,1579,3076,3077,1400,7468,4105,1838,1640,2863,7469,4358,4359, 137,4106, 598, # 4214 +3078,1966, 780, 104, 974,2938,7470, 278, 899, 253, 402, 572, 504, 493,1339,7471, # 4230 +3903,1275,4360,2574,2550,7472,3640,3029,3079,2249, 565,1334,2713, 863, 41,7473, # 4246 +7474,4361,7475,1657,2333, 19, 463,2750,4107, 606,7476,2981,3256,1087,2084,1323, # 4262 +2652,2982,7477,1631,1623,1750,4108,2682,7478,2864, 791,2714,2653,2334, 232,2416, # 4278 +7479,2983,1498,7480,2654,2620, 755,1366,3641,3257,3126,2025,1609, 119,1917,3427, # 4294 + 862,1026,4109,7481,3904,3760,4362,3905,4363,2260,1951,2470,7482,1125, 817,4110, # 4310 +4111,3906,1513,1766,2040,1487,4112,3030,3258,2824,3761,3127,7483,7484,1507,7485, # 4326 +2683, 733, 40,1632,1106,2865, 345,4113, 841,2524, 230,4364,2984,1846,3259,3428, # 4342 +7486,1263, 986,3429,7487, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562,3907, # 4358 +3908,2939, 967,2751,2655,1349, 592,2133,1692,3324,2985,1994,4114,1679,3909,1901, # 4374 +2185,7488, 739,3642,2715,1296,1290,7489,4115,2198,2199,1921,1563,2595,2551,1870, # 4390 +2752,2986,7490, 435,7491, 343,1108, 596, 17,1751,4365,2235,3430,3643,7492,4366, # 4406 + 294,3527,2940,1693, 477, 979, 281,2041,3528, 643,2042,3644,2621,2782,2261,1031, # 4422 +2335,2134,2298,3529,4367, 367,1249,2552,7493,3530,7494,4368,1283,3325,2004, 240, # 4438 +1762,3326,4369,4370, 836,1069,3128, 474,7495,2148,2525, 268,3531,7496,3188,1521, # 4454 +1284,7497,1658,1546,4116,7498,3532,3533,7499,4117,3327,2684,1685,4118, 961,1673, # 4470 +2622, 190,2005,2200,3762,4371,4372,7500, 570,2497,3645,1490,7501,4373,2623,3260, # 4486 +1956,4374, 584,1514, 396,1045,1944,7502,4375,1967,2444,7503,7504,4376,3910, 619, # 4502 +7505,3129,3261, 215,2006,2783,2553,3189,4377,3190,4378, 763,4119,3763,4379,7506, # 4518 +7507,1957,1767,2941,3328,3646,1174, 452,1477,4380,3329,3130,7508,2825,1253,2382, # 4534 +2186,1091,2285,4120, 492,7509, 638,1169,1824,2135,1752,3911, 648, 926,1021,1324, # 4550 +4381, 520,4382, 997, 847,1007, 892,4383,3764,2262,1871,3647,7510,2400,1784,4384, # 4566 +1952,2942,3080,3191,1728,4121,2043,3648,4385,2007,1701,3131,1551, 30,2263,4122, # 4582 +7511,2026,4386,3534,7512, 501,7513,4123, 594,3431,2165,1821,3535,3432,3536,3192, # 4598 + 829,2826,4124,7514,1680,3132,1225,4125,7515,3262,4387,4126,3133,2336,7516,4388, # 4614 +4127,7517,3912,3913,7518,1847,2383,2596,3330,7519,4389, 374,3914, 652,4128,4129, # 4630 + 375,1140, 798,7520,7521,7522,2361,4390,2264, 546,1659, 138,3031,2445,4391,7523, # 4646 +2250, 612,1848, 910, 796,3765,1740,1371, 825,3766,3767,7524,2906,2554,7525, 692, # 4662 + 444,3032,2624, 801,4392,4130,7526,1491, 244,1053,3033,4131,4132, 340,7527,3915, # 4678 +1041,2987, 293,1168, 87,1357,7528,1539, 959,7529,2236, 721, 694,4133,3768, 219, # 4694 +1478, 644,1417,3331,2656,1413,1401,1335,1389,3916,7530,7531,2988,2362,3134,1825, # 4710 + 730,1515, 184,2827, 66,4393,7532,1660,2943, 246,3332, 378,1457, 226,3433, 975, # 4726 +3917,2944,1264,3537, 674, 696,7533, 163,7534,1141,2417,2166, 713,3538,3333,4394, # 4742 +3918,7535,7536,1186, 15,7537,1079,1070,7538,1522,3193,3539, 276,1050,2716, 758, # 4758 +1126, 653,2945,3263,7539,2337, 889,3540,3919,3081,2989, 903,1250,4395,3920,3434, # 4774 +3541,1342,1681,1718, 766,3264, 286, 89,2946,3649,7540,1713,7541,2597,3334,2990, # 4790 +7542,2947,2215,3194,2866,7543,4396,2498,2526, 181, 387,1075,3921, 731,2187,3335, # 4806 +7544,3265, 310, 313,3435,2299, 770,4134, 54,3034, 189,4397,3082,3769,3922,7545, # 4822 +1230,1617,1849, 355,3542,4135,4398,3336, 111,4136,3650,1350,3135,3436,3035,4137, # 4838 +2149,3266,3543,7546,2784,3923,3924,2991, 722,2008,7547,1071, 247,1207,2338,2471, # 4854 +1378,4399,2009, 864,1437,1214,4400, 373,3770,1142,2216, 667,4401, 442,2753,2555, # 4870 +3771,3925,1968,4138,3267,1839, 837, 170,1107, 934,1336,1882,7548,7549,2118,4139, # 4886 +2828, 743,1569,7550,4402,4140, 582,2384,1418,3437,7551,1802,7552, 357,1395,1729, # 4902 +3651,3268,2418,1564,2237,7553,3083,3772,1633,4403,1114,2085,4141,1532,7554, 482, # 4918 +2446,4404,7555,7556,1492, 833,1466,7557,2717,3544,1641,2829,7558,1526,1272,3652, # 4934 +4142,1686,1794, 416,2556,1902,1953,1803,7559,3773,2785,3774,1159,2316,7560,2867, # 4950 +4405,1610,1584,3036,2419,2754, 443,3269,1163,3136,7561,7562,3926,7563,4143,2499, # 4966 +3037,4406,3927,3137,2103,1647,3545,2010,1872,4144,7564,4145, 431,3438,7565, 250, # 4982 + 97, 81,4146,7566,1648,1850,1558, 160, 848,7567, 866, 740,1694,7568,2201,2830, # 4998 +3195,4147,4407,3653,1687, 950,2472, 426, 469,3196,3654,3655,3928,7569,7570,1188, # 5014 + 424,1995, 861,3546,4148,3775,2202,2685, 168,1235,3547,4149,7571,2086,1674,4408, # 5030 +3337,3270, 220,2557,1009,7572,3776, 670,2992, 332,1208, 717,7573,7574,3548,2447, # 5046 +3929,3338,7575, 513,7576,1209,2868,3339,3138,4409,1080,7577,7578,7579,7580,2527, # 5062 +3656,3549, 815,1587,3930,3931,7581,3550,3439,3777,1254,4410,1328,3038,1390,3932, # 5078 +1741,3933,3778,3934,7582, 236,3779,2448,3271,7583,7584,3657,3780,1273,3781,4411, # 5094 +7585, 308,7586,4412, 245,4413,1851,2473,1307,2575, 430, 715,2136,2449,7587, 270, # 5110 + 199,2869,3935,7588,3551,2718,1753, 761,1754, 725,1661,1840,4414,3440,3658,7589, # 5126 +7590, 587, 14,3272, 227,2598, 326, 480,2265, 943,2755,3552, 291, 650,1883,7591, # 5142 +1702,1226, 102,1547, 62,3441, 904,4415,3442,1164,4150,7592,7593,1224,1548,2756, # 5158 + 391, 498,1493,7594,1386,1419,7595,2055,1177,4416, 813, 880,1081,2363, 566,1145, # 5174 +4417,2286,1001,1035,2558,2599,2238, 394,1286,7596,7597,2068,7598, 86,1494,1730, # 5190 +3936, 491,1588, 745, 897,2948, 843,3340,3937,2757,2870,3273,1768, 998,2217,2069, # 5206 + 397,1826,1195,1969,3659,2993,3341, 284,7599,3782,2500,2137,2119,1903,7600,3938, # 5222 +2150,3939,4151,1036,3443,1904, 114,2559,4152, 209,1527,7601,7602,2949,2831,2625, # 5238 +2385,2719,3139, 812,2560,7603,3274,7604,1559, 737,1884,3660,1210, 885, 28,2686, # 5254 +3553,3783,7605,4153,1004,1779,4418,7606, 346,1981,2218,2687,4419,3784,1742, 797, # 5270 +1642,3940,1933,1072,1384,2151, 896,3941,3275,3661,3197,2871,3554,7607,2561,1958, # 5286 +4420,2450,1785,7608,7609,7610,3942,4154,1005,1308,3662,4155,2720,4421,4422,1528, # 5302 +2600, 161,1178,4156,1982, 987,4423,1101,4157, 631,3943,1157,3198,2420,1343,1241, # 5318 +1016,2239,2562, 372, 877,2339,2501,1160, 555,1934, 911,3944,7611, 466,1170, 169, # 5334 +1051,2907,2688,3663,2474,2994,1182,2011,2563,1251,2626,7612, 992,2340,3444,1540, # 5350 +2721,1201,2070,2401,1996,2475,7613,4424, 528,1922,2188,1503,1873,1570,2364,3342, # 5366 +3276,7614, 557,1073,7615,1827,3445,2087,2266,3140,3039,3084, 767,3085,2786,4425, # 5382 +1006,4158,4426,2341,1267,2176,3664,3199, 778,3945,3200,2722,1597,2657,7616,4427, # 5398 +7617,3446,7618,7619,7620,3277,2689,1433,3278, 131, 95,1504,3946, 723,4159,3141, # 5414 +1841,3555,2758,2189,3947,2027,2104,3665,7621,2995,3948,1218,7622,3343,3201,3949, # 5430 +4160,2576, 248,1634,3785, 912,7623,2832,3666,3040,3786, 654, 53,7624,2996,7625, # 5446 +1688,4428, 777,3447,1032,3950,1425,7626, 191, 820,2120,2833, 971,4429, 931,3202, # 5462 + 135, 664, 783,3787,1997, 772,2908,1935,3951,3788,4430,2909,3203, 282,2723, 640, # 5478 +1372,3448,1127, 922, 325,3344,7627,7628, 711,2044,7629,7630,3952,2219,2787,1936, # 5494 +3953,3345,2220,2251,3789,2300,7631,4431,3790,1258,3279,3954,3204,2138,2950,3955, # 5510 +3956,7632,2221, 258,3205,4432, 101,1227,7633,3280,1755,7634,1391,3281,7635,2910, # 5526 +2056, 893,7636,7637,7638,1402,4161,2342,7639,7640,3206,3556,7641,7642, 878,1325, # 5542 +1780,2788,4433, 259,1385,2577, 744,1183,2267,4434,7643,3957,2502,7644, 684,1024, # 5558 +4162,7645, 472,3557,3449,1165,3282,3958,3959, 322,2152, 881, 455,1695,1152,1340, # 5574 + 660, 554,2153,4435,1058,4436,4163, 830,1065,3346,3960,4437,1923,7646,1703,1918, # 5590 +7647, 932,2268, 122,7648,4438, 947, 677,7649,3791,2627, 297,1905,1924,2269,4439, # 5606 +2317,3283,7650,7651,4164,7652,4165, 84,4166, 112, 989,7653, 547,1059,3961, 701, # 5622 +3558,1019,7654,4167,7655,3450, 942, 639, 457,2301,2451, 993,2951, 407, 851, 494, # 5638 +4440,3347, 927,7656,1237,7657,2421,3348, 573,4168, 680, 921,2911,1279,1874, 285, # 5654 + 790,1448,1983, 719,2167,7658,7659,4441,3962,3963,1649,7660,1541, 563,7661,1077, # 5670 +7662,3349,3041,3451, 511,2997,3964,3965,3667,3966,1268,2564,3350,3207,4442,4443, # 5686 +7663, 535,1048,1276,1189,2912,2028,3142,1438,1373,2834,2952,1134,2012,7664,4169, # 5702 +1238,2578,3086,1259,7665, 700,7666,2953,3143,3668,4170,7667,4171,1146,1875,1906, # 5718 +4444,2601,3967, 781,2422, 132,1589, 203, 147, 273,2789,2402, 898,1786,2154,3968, # 5734 +3969,7668,3792,2790,7669,7670,4445,4446,7671,3208,7672,1635,3793, 965,7673,1804, # 5750 +2690,1516,3559,1121,1082,1329,3284,3970,1449,3794, 65,1128,2835,2913,2759,1590, # 5766 +3795,7674,7675, 12,2658, 45, 976,2579,3144,4447, 517,2528,1013,1037,3209,7676, # 5782 +3796,2836,7677,3797,7678,3452,7679,2602, 614,1998,2318,3798,3087,2724,2628,7680, # 5798 +2580,4172, 599,1269,7681,1810,3669,7682,2691,3088, 759,1060, 489,1805,3351,3285, # 5814 +1358,7683,7684,2386,1387,1215,2629,2252, 490,7685,7686,4173,1759,2387,2343,7687, # 5830 +4448,3799,1907,3971,2630,1806,3210,4449,3453,3286,2760,2344, 874,7688,7689,3454, # 5846 +3670,1858, 91,2914,3671,3042,3800,4450,7690,3145,3972,2659,7691,3455,1202,1403, # 5862 +3801,2954,2529,1517,2503,4451,3456,2504,7692,4452,7693,2692,1885,1495,1731,3973, # 5878 +2365,4453,7694,2029,7695,7696,3974,2693,1216, 237,2581,4174,2319,3975,3802,4454, # 5894 +4455,2694,3560,3457, 445,4456,7697,7698,7699,7700,2761, 61,3976,3672,1822,3977, # 5910 +7701, 687,2045, 935, 925, 405,2660, 703,1096,1859,2725,4457,3978,1876,1367,2695, # 5926 +3352, 918,2105,1781,2476, 334,3287,1611,1093,4458, 564,3146,3458,3673,3353, 945, # 5942 +2631,2057,4459,7702,1925, 872,4175,7703,3459,2696,3089, 349,4176,3674,3979,4460, # 5958 +3803,4177,3675,2155,3980,4461,4462,4178,4463,2403,2046, 782,3981, 400, 251,4179, # 5974 +1624,7704,7705, 277,3676, 299,1265, 476,1191,3804,2121,4180,4181,1109, 205,7706, # 5990 +2582,1000,2156,3561,1860,7707,7708,7709,4464,7710,4465,2565, 107,2477,2157,3982, # 6006 +3460,3147,7711,1533, 541,1301, 158, 753,4182,2872,3562,7712,1696, 370,1088,4183, # 6022 +4466,3563, 579, 327, 440, 162,2240, 269,1937,1374,3461, 968,3043, 56,1396,3090, # 6038 +2106,3288,3354,7713,1926,2158,4467,2998,7714,3564,7715,7716,3677,4468,2478,7717, # 6054 +2791,7718,1650,4469,7719,2603,7720,7721,3983,2661,3355,1149,3356,3984,3805,3985, # 6070 +7722,1076, 49,7723, 951,3211,3289,3290, 450,2837, 920,7724,1811,2792,2366,4184, # 6086 +1908,1138,2367,3806,3462,7725,3212,4470,1909,1147,1518,2423,4471,3807,7726,4472, # 6102 +2388,2604, 260,1795,3213,7727,7728,3808,3291, 708,7729,3565,1704,7730,3566,1351, # 6118 +1618,3357,2999,1886, 944,4185,3358,4186,3044,3359,4187,7731,3678, 422, 413,1714, # 6134 +3292, 500,2058,2345,4188,2479,7732,1344,1910, 954,7733,1668,7734,7735,3986,2404, # 6150 +4189,3567,3809,4190,7736,2302,1318,2505,3091, 133,3092,2873,4473, 629, 31,2838, # 6166 +2697,3810,4474, 850, 949,4475,3987,2955,1732,2088,4191,1496,1852,7737,3988, 620, # 6182 +3214, 981,1242,3679,3360,1619,3680,1643,3293,2139,2452,1970,1719,3463,2168,7738, # 6198 +3215,7739,7740,3361,1828,7741,1277,4476,1565,2047,7742,1636,3568,3093,7743, 869, # 6214 +2839, 655,3811,3812,3094,3989,3000,3813,1310,3569,4477,7744,7745,7746,1733, 558, # 6230 +4478,3681, 335,1549,3045,1756,4192,3682,1945,3464,1829,1291,1192, 470,2726,2107, # 6246 +2793, 913,1054,3990,7747,1027,7748,3046,3991,4479, 982,2662,3362,3148,3465,3216, # 6262 +3217,1946,2794,7749, 571,4480,7750,1830,7751,3570,2583,1523,2424,7752,2089, 984, # 6278 +4481,3683,1959,7753,3684, 852, 923,2795,3466,3685, 969,1519, 999,2048,2320,1705, # 6294 +7754,3095, 615,1662, 151, 597,3992,2405,2321,1049, 275,4482,3686,4193, 568,3687, # 6310 +3571,2480,4194,3688,7755,2425,2270, 409,3218,7756,1566,2874,3467,1002, 769,2840, # 6326 + 194,2090,3149,3689,2222,3294,4195, 628,1505,7757,7758,1763,2177,3001,3993, 521, # 6342 +1161,2584,1787,2203,2406,4483,3994,1625,4196,4197, 412, 42,3096, 464,7759,2632, # 6358 +4484,3363,1760,1571,2875,3468,2530,1219,2204,3814,2633,2140,2368,4485,4486,3295, # 6374 +1651,3364,3572,7760,7761,3573,2481,3469,7762,3690,7763,7764,2271,2091, 460,7765, # 6390 +4487,7766,3002, 962, 588,3574, 289,3219,2634,1116, 52,7767,3047,1796,7768,7769, # 6406 +7770,1467,7771,1598,1143,3691,4198,1984,1734,1067,4488,1280,3365, 465,4489,1572, # 6422 + 510,7772,1927,2241,1812,1644,3575,7773,4490,3692,7774,7775,2663,1573,1534,7776, # 6438 +7777,4199, 536,1807,1761,3470,3815,3150,2635,7778,7779,7780,4491,3471,2915,1911, # 6454 +2796,7781,3296,1122, 377,3220,7782, 360,7783,7784,4200,1529, 551,7785,2059,3693, # 6470 +1769,2426,7786,2916,4201,3297,3097,2322,2108,2030,4492,1404, 136,1468,1479, 672, # 6486 +1171,3221,2303, 271,3151,7787,2762,7788,2049, 678,2727, 865,1947,4493,7789,2013, # 6502 +3995,2956,7790,2728,2223,1397,3048,3694,4494,4495,1735,2917,3366,3576,7791,3816, # 6518 + 509,2841,2453,2876,3817,7792,7793,3152,3153,4496,4202,2531,4497,2304,1166,1010, # 6534 + 552, 681,1887,7794,7795,2957,2958,3996,1287,1596,1861,3154, 358, 453, 736, 175, # 6550 + 478,1117, 905,1167,1097,7796,1853,1530,7797,1706,7798,2178,3472,2287,3695,3473, # 6566 +3577,4203,2092,4204,7799,3367,1193,2482,4205,1458,2190,2205,1862,1888,1421,3298, # 6582 +2918,3049,2179,3474, 595,2122,7800,3997,7801,7802,4206,1707,2636, 223,3696,1359, # 6598 + 751,3098, 183,3475,7803,2797,3003, 419,2369, 633, 704,3818,2389, 241,7804,7805, # 6614 +7806, 838,3004,3697,2272,2763,2454,3819,1938,2050,3998,1309,3099,2242,1181,7807, # 6630 +1136,2206,3820,2370,1446,4207,2305,4498,7808,7809,4208,1055,2605, 484,3698,7810, # 6646 +3999, 625,4209,2273,3368,1499,4210,4000,7811,4001,4211,3222,2274,2275,3476,7812, # 6662 +7813,2764, 808,2606,3699,3369,4002,4212,3100,2532, 526,3370,3821,4213, 955,7814, # 6678 +1620,4214,2637,2427,7815,1429,3700,1669,1831, 994, 928,7816,3578,1260,7817,7818, # 6694 +7819,1948,2288, 741,2919,1626,4215,2729,2455, 867,1184, 362,3371,1392,7820,7821, # 6710 +4003,4216,1770,1736,3223,2920,4499,4500,1928,2698,1459,1158,7822,3050,3372,2877, # 6726 +1292,1929,2506,2842,3701,1985,1187,2071,2014,2607,4217,7823,2566,2507,2169,3702, # 6742 +2483,3299,7824,3703,4501,7825,7826, 666,1003,3005,1022,3579,4218,7827,4502,1813, # 6758 +2253, 574,3822,1603, 295,1535, 705,3823,4219, 283, 858, 417,7828,7829,3224,4503, # 6774 +4504,3051,1220,1889,1046,2276,2456,4004,1393,1599, 689,2567, 388,4220,7830,2484, # 6790 + 802,7831,2798,3824,2060,1405,2254,7832,4505,3825,2109,1052,1345,3225,1585,7833, # 6806 + 809,7834,7835,7836, 575,2730,3477, 956,1552,1469,1144,2323,7837,2324,1560,2457, # 6822 +3580,3226,4005, 616,2207,3155,2180,2289,7838,1832,7839,3478,4506,7840,1319,3704, # 6838 +3705,1211,3581,1023,3227,1293,2799,7841,7842,7843,3826, 607,2306,3827, 762,2878, # 6854 +1439,4221,1360,7844,1485,3052,7845,4507,1038,4222,1450,2061,2638,4223,1379,4508, # 6870 +2585,7846,7847,4224,1352,1414,2325,2921,1172,7848,7849,3828,3829,7850,1797,1451, # 6886 +7851,7852,7853,7854,2922,4006,4007,2485,2346, 411,4008,4009,3582,3300,3101,4509, # 6902 +1561,2664,1452,4010,1375,7855,7856, 47,2959, 316,7857,1406,1591,2923,3156,7858, # 6918 +1025,2141,3102,3157, 354,2731, 884,2224,4225,2407, 508,3706, 726,3583, 996,2428, # 6934 +3584, 729,7859, 392,2191,1453,4011,4510,3707,7860,7861,2458,3585,2608,1675,2800, # 6950 + 919,2347,2960,2348,1270,4511,4012, 73,7862,7863, 647,7864,3228,2843,2255,1550, # 6966 +1346,3006,7865,1332, 883,3479,7866,7867,7868,7869,3301,2765,7870,1212, 831,1347, # 6982 +4226,4512,2326,3830,1863,3053, 720,3831,4513,4514,3832,7871,4227,7872,7873,4515, # 6998 +7874,7875,1798,4516,3708,2609,4517,3586,1645,2371,7876,7877,2924, 669,2208,2665, # 7014 +2429,7878,2879,7879,7880,1028,3229,7881,4228,2408,7882,2256,1353,7883,7884,4518, # 7030 +3158, 518,7885,4013,7886,4229,1960,7887,2142,4230,7888,7889,3007,2349,2350,3833, # 7046 + 516,1833,1454,4014,2699,4231,4519,2225,2610,1971,1129,3587,7890,2766,7891,2961, # 7062 +1422, 577,1470,3008,1524,3373,7892,7893, 432,4232,3054,3480,7894,2586,1455,2508, # 7078 +2226,1972,1175,7895,1020,2732,4015,3481,4520,7896,2733,7897,1743,1361,3055,3482, # 7094 +2639,4016,4233,4521,2290, 895, 924,4234,2170, 331,2243,3056, 166,1627,3057,1098, # 7110 +7898,1232,2880,2227,3374,4522, 657, 403,1196,2372, 542,3709,3375,1600,4235,3483, # 7126 +7899,4523,2767,3230, 576, 530,1362,7900,4524,2533,2666,3710,4017,7901, 842,3834, # 7142 +7902,2801,2031,1014,4018, 213,2700,3376, 665, 621,4236,7903,3711,2925,2430,7904, # 7158 +2431,3302,3588,3377,7905,4237,2534,4238,4525,3589,1682,4239,3484,1380,7906, 724, # 7174 +2277, 600,1670,7907,1337,1233,4526,3103,2244,7908,1621,4527,7909, 651,4240,7910, # 7190 +1612,4241,2611,7911,2844,7912,2734,2307,3058,7913, 716,2459,3059, 174,1255,2701, # 7206 +4019,3590, 548,1320,1398, 728,4020,1574,7914,1890,1197,3060,4021,7915,3061,3062, # 7222 +3712,3591,3713, 747,7916, 635,4242,4528,7917,7918,7919,4243,7920,7921,4529,7922, # 7238 +3378,4530,2432, 451,7923,3714,2535,2072,4244,2735,4245,4022,7924,1764,4531,7925, # 7254 +4246, 350,7926,2278,2390,2486,7927,4247,4023,2245,1434,4024, 488,4532, 458,4248, # 7270 +4025,3715, 771,1330,2391,3835,2568,3159,2159,2409,1553,2667,3160,4249,7928,2487, # 7286 +2881,2612,1720,2702,4250,3379,4533,7929,2536,4251,7930,3231,4252,2768,7931,2015, # 7302 +2736,7932,1155,1017,3716,3836,7933,3303,2308, 201,1864,4253,1430,7934,4026,7935, # 7318 +7936,7937,7938,7939,4254,1604,7940, 414,1865, 371,2587,4534,4535,3485,2016,3104, # 7334 +4536,1708, 960,4255, 887, 389,2171,1536,1663,1721,7941,2228,4027,2351,2926,1580, # 7350 +7942,7943,7944,1744,7945,2537,4537,4538,7946,4539,7947,2073,7948,7949,3592,3380, # 7366 +2882,4256,7950,4257,2640,3381,2802, 673,2703,2460, 709,3486,4028,3593,4258,7951, # 7382 +1148, 502, 634,7952,7953,1204,4540,3594,1575,4541,2613,3717,7954,3718,3105, 948, # 7398 +3232, 121,1745,3837,1110,7955,4259,3063,2509,3009,4029,3719,1151,1771,3838,1488, # 7414 +4030,1986,7956,2433,3487,7957,7958,2093,7959,4260,3839,1213,1407,2803, 531,2737, # 7430 +2538,3233,1011,1537,7960,2769,4261,3106,1061,7961,3720,3721,1866,2883,7962,2017, # 7446 + 120,4262,4263,2062,3595,3234,2309,3840,2668,3382,1954,4542,7963,7964,3488,1047, # 7462 +2704,1266,7965,1368,4543,2845, 649,3383,3841,2539,2738,1102,2846,2669,7966,7967, # 7478 +1999,7968,1111,3596,2962,7969,2488,3842,3597,2804,1854,3384,3722,7970,7971,3385, # 7494 +2410,2884,3304,3235,3598,7972,2569,7973,3599,2805,4031,1460, 856,7974,3600,7975, # 7510 +2885,2963,7976,2886,3843,7977,4264, 632,2510, 875,3844,1697,3845,2291,7978,7979, # 7526 +4544,3010,1239, 580,4545,4265,7980, 914, 936,2074,1190,4032,1039,2123,7981,7982, # 7542 +7983,3386,1473,7984,1354,4266,3846,7985,2172,3064,4033, 915,3305,4267,4268,3306, # 7558 +1605,1834,7986,2739, 398,3601,4269,3847,4034, 328,1912,2847,4035,3848,1331,4270, # 7574 +3011, 937,4271,7987,3602,4036,4037,3387,2160,4546,3388, 524, 742, 538,3065,1012, # 7590 +7988,7989,3849,2461,7990, 658,1103, 225,3850,7991,7992,4547,7993,4548,7994,3236, # 7606 +1243,7995,4038, 963,2246,4549,7996,2705,3603,3161,7997,7998,2588,2327,7999,4550, # 7622 +8000,8001,8002,3489,3307, 957,3389,2540,2032,1930,2927,2462, 870,2018,3604,1746, # 7638 +2770,2771,2434,2463,8003,3851,8004,3723,3107,3724,3490,3390,3725,8005,1179,3066, # 7654 +8006,3162,2373,4272,3726,2541,3163,3108,2740,4039,8007,3391,1556,2542,2292, 977, # 7670 +2887,2033,4040,1205,3392,8008,1765,3393,3164,2124,1271,1689, 714,4551,3491,8009, # 7686 +2328,3852, 533,4273,3605,2181, 617,8010,2464,3308,3492,2310,8011,8012,3165,8013, # 7702 +8014,3853,1987, 618, 427,2641,3493,3394,8015,8016,1244,1690,8017,2806,4274,4552, # 7718 +8018,3494,8019,8020,2279,1576, 473,3606,4275,3395, 972,8021,3607,8022,3067,8023, # 7734 +8024,4553,4554,8025,3727,4041,4042,8026, 153,4555, 356,8027,1891,2888,4276,2143, # 7750 + 408, 803,2352,8028,3854,8029,4277,1646,2570,2511,4556,4557,3855,8030,3856,4278, # 7766 +8031,2411,3396, 752,8032,8033,1961,2964,8034, 746,3012,2465,8035,4279,3728, 698, # 7782 +4558,1892,4280,3608,2543,4559,3609,3857,8036,3166,3397,8037,1823,1302,4043,2706, # 7798 +3858,1973,4281,8038,4282,3167, 823,1303,1288,1236,2848,3495,4044,3398, 774,3859, # 7814 +8039,1581,4560,1304,2849,3860,4561,8040,2435,2161,1083,3237,4283,4045,4284, 344, # 7830 +1173, 288,2311, 454,1683,8041,8042,1461,4562,4046,2589,8043,8044,4563, 985, 894, # 7846 +8045,3399,3168,8046,1913,2928,3729,1988,8047,2110,1974,8048,4047,8049,2571,1194, # 7862 + 425,8050,4564,3169,1245,3730,4285,8051,8052,2850,8053, 636,4565,1855,3861, 760, # 7878 +1799,8054,4286,2209,1508,4566,4048,1893,1684,2293,8055,8056,8057,4287,4288,2210, # 7894 + 479,8058,8059, 832,8060,4049,2489,8061,2965,2490,3731, 990,3109, 627,1814,2642, # 7910 +4289,1582,4290,2125,2111,3496,4567,8062, 799,4291,3170,8063,4568,2112,1737,3013, # 7926 +1018, 543, 754,4292,3309,1676,4569,4570,4050,8064,1489,8065,3497,8066,2614,2889, # 7942 +4051,8067,8068,2966,8069,8070,8071,8072,3171,4571,4572,2182,1722,8073,3238,3239, # 7958 +1842,3610,1715, 481, 365,1975,1856,8074,8075,1962,2491,4573,8076,2126,3611,3240, # 7974 + 433,1894,2063,2075,8077, 602,2741,8078,8079,8080,8081,8082,3014,1628,3400,8083, # 7990 +3172,4574,4052,2890,4575,2512,8084,2544,2772,8085,8086,8087,3310,4576,2891,8088, # 8006 +4577,8089,2851,4578,4579,1221,2967,4053,2513,8090,8091,8092,1867,1989,8093,8094, # 8022 +8095,1895,8096,8097,4580,1896,4054, 318,8098,2094,4055,4293,8099,8100, 485,8101, # 8038 + 938,3862, 553,2670, 116,8102,3863,3612,8103,3498,2671,2773,3401,3311,2807,8104, # 8054 +3613,2929,4056,1747,2930,2968,8105,8106, 207,8107,8108,2672,4581,2514,8109,3015, # 8070 + 890,3614,3864,8110,1877,3732,3402,8111,2183,2353,3403,1652,8112,8113,8114, 941, # 8086 +2294, 208,3499,4057,2019, 330,4294,3865,2892,2492,3733,4295,8115,8116,8117,8118, # 8102 +#Everything below is of no interest for detection purpose +2515,1613,4582,8119,3312,3866,2516,8120,4058,8121,1637,4059,2466,4583,3867,8122, # 8118 +2493,3016,3734,8123,8124,2192,8125,8126,2162,8127,8128,8129,8130,8131,8132,8133, # 8134 +8134,8135,8136,8137,8138,8139,8140,8141,8142,8143,8144,8145,8146,8147,8148,8149, # 8150 +8150,8151,8152,8153,8154,8155,8156,8157,8158,8159,8160,8161,8162,8163,8164,8165, # 8166 +8166,8167,8168,8169,8170,8171,8172,8173,8174,8175,8176,8177,8178,8179,8180,8181, # 8182 +8182,8183,8184,8185,8186,8187,8188,8189,8190,8191,8192,8193,8194,8195,8196,8197, # 8198 +8198,8199,8200,8201,8202,8203,8204,8205,8206,8207,8208,8209,8210,8211,8212,8213, # 8214 +8214,8215,8216,8217,8218,8219,8220,8221,8222,8223,8224,8225,8226,8227,8228,8229, # 8230 +8230,8231,8232,8233,8234,8235,8236,8237,8238,8239,8240,8241,8242,8243,8244,8245, # 8246 +8246,8247,8248,8249,8250,8251,8252,8253,8254,8255,8256,8257,8258,8259,8260,8261, # 8262 +8262,8263,8264,8265,8266,8267,8268,8269,8270,8271,8272,8273,8274,8275,8276,8277, # 8278 +8278,8279,8280,8281,8282,8283,8284,8285,8286,8287,8288,8289,8290,8291,8292,8293, # 8294 +8294,8295,8296,8297,8298,8299,8300,8301,8302,8303,8304,8305,8306,8307,8308,8309, # 8310 +8310,8311,8312,8313,8314,8315,8316,8317,8318,8319,8320,8321,8322,8323,8324,8325, # 8326 +8326,8327,8328,8329,8330,8331,8332,8333,8334,8335,8336,8337,8338,8339,8340,8341, # 8342 +8342,8343,8344,8345,8346,8347,8348,8349,8350,8351,8352,8353,8354,8355,8356,8357, # 8358 +8358,8359,8360,8361,8362,8363,8364,8365,8366,8367,8368,8369,8370,8371,8372,8373, # 8374 +8374,8375,8376,8377,8378,8379,8380,8381,8382,8383,8384,8385,8386,8387,8388,8389, # 8390 +8390,8391,8392,8393,8394,8395,8396,8397,8398,8399,8400,8401,8402,8403,8404,8405, # 8406 +8406,8407,8408,8409,8410,8411,8412,8413,8414,8415,8416,8417,8418,8419,8420,8421, # 8422 +8422,8423,8424,8425,8426,8427,8428,8429,8430,8431,8432,8433,8434,8435,8436,8437, # 8438 +8438,8439,8440,8441,8442,8443,8444,8445,8446,8447,8448,8449,8450,8451,8452,8453, # 8454 +8454,8455,8456,8457,8458,8459,8460,8461,8462,8463,8464,8465,8466,8467,8468,8469, # 8470 +8470,8471,8472,8473,8474,8475,8476,8477,8478,8479,8480,8481,8482,8483,8484,8485, # 8486 +8486,8487,8488,8489,8490,8491,8492,8493,8494,8495,8496,8497,8498,8499,8500,8501, # 8502 +8502,8503,8504,8505,8506,8507,8508,8509,8510,8511,8512,8513,8514,8515,8516,8517, # 8518 +8518,8519,8520,8521,8522,8523,8524,8525,8526,8527,8528,8529,8530,8531,8532,8533, # 8534 +8534,8535,8536,8537,8538,8539,8540,8541,8542,8543,8544,8545,8546,8547,8548,8549, # 8550 +8550,8551,8552,8553,8554,8555,8556,8557,8558,8559,8560,8561,8562,8563,8564,8565, # 8566 +8566,8567,8568,8569,8570,8571,8572,8573,8574,8575,8576,8577,8578,8579,8580,8581, # 8582 +8582,8583,8584,8585,8586,8587,8588,8589,8590,8591,8592,8593,8594,8595,8596,8597, # 8598 +8598,8599,8600,8601,8602,8603,8604,8605,8606,8607,8608,8609,8610,8611,8612,8613, # 8614 +8614,8615,8616,8617,8618,8619,8620,8621,8622,8623,8624,8625,8626,8627,8628,8629, # 8630 +8630,8631,8632,8633,8634,8635,8636,8637,8638,8639,8640,8641,8642,8643,8644,8645, # 8646 +8646,8647,8648,8649,8650,8651,8652,8653,8654,8655,8656,8657,8658,8659,8660,8661, # 8662 +8662,8663,8664,8665,8666,8667,8668,8669,8670,8671,8672,8673,8674,8675,8676,8677, # 8678 +8678,8679,8680,8681,8682,8683,8684,8685,8686,8687,8688,8689,8690,8691,8692,8693, # 8694 +8694,8695,8696,8697,8698,8699,8700,8701,8702,8703,8704,8705,8706,8707,8708,8709, # 8710 +8710,8711,8712,8713,8714,8715,8716,8717,8718,8719,8720,8721,8722,8723,8724,8725, # 8726 +8726,8727,8728,8729,8730,8731,8732,8733,8734,8735,8736,8737,8738,8739,8740,8741) # 8742 diff --git a/libs/requests/packages/chardet/euctwprober.py b/libs/requests/packages/chardet/euctwprober.py new file mode 100755 index 00000000..b073f134 --- /dev/null +++ b/libs/requests/packages/chardet/euctwprober.py @@ -0,0 +1,41 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from mbcharsetprober import MultiByteCharSetProber +from codingstatemachine import CodingStateMachine +from chardistribution import EUCTWDistributionAnalysis +from mbcssm import EUCTWSMModel + +class EUCTWProber(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(EUCTWSMModel) + self._mDistributionAnalyzer = EUCTWDistributionAnalysis() + self.reset() + + def get_charset_name(self): + return "EUC-TW" diff --git a/libs/requests/packages/chardet/gb2312freq.py b/libs/requests/packages/chardet/gb2312freq.py new file mode 100755 index 00000000..7a4d5a1b --- /dev/null +++ b/libs/requests/packages/chardet/gb2312freq.py @@ -0,0 +1,471 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# GB2312 most frequently used character table +# +# Char to FreqOrder table , from hz6763 + +# 512 --> 0.79 -- 0.79 +# 1024 --> 0.92 -- 0.13 +# 2048 --> 0.98 -- 0.06 +# 6768 --> 1.00 -- 0.02 +# +# Ideal Distribution Ratio = 0.79135/(1-0.79135) = 3.79 +# Random Distribution Ration = 512 / (3755 - 512) = 0.157 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher that RDR + +GB2312_TYPICAL_DISTRIBUTION_RATIO = 0.9 + +GB2312_TABLE_SIZE = 3760 + +GB2312CharToFreqOrder = ( \ +1671, 749,1443,2364,3924,3807,2330,3921,1704,3463,2691,1511,1515, 572,3191,2205, +2361, 224,2558, 479,1711, 963,3162, 440,4060,1905,2966,2947,3580,2647,3961,3842, +2204, 869,4207, 970,2678,5626,2944,2956,1479,4048, 514,3595, 588,1346,2820,3409, + 249,4088,1746,1873,2047,1774, 581,1813, 358,1174,3590,1014,1561,4844,2245, 670, +1636,3112, 889,1286, 953, 556,2327,3060,1290,3141, 613, 185,3477,1367, 850,3820, +1715,2428,2642,2303,2732,3041,2562,2648,3566,3946,1349, 388,3098,2091,1360,3585, + 152,1687,1539, 738,1559, 59,1232,2925,2267,1388,1249,1741,1679,2960, 151,1566, +1125,1352,4271, 924,4296, 385,3166,4459, 310,1245,2850, 70,3285,2729,3534,3575, +2398,3298,3466,1960,2265, 217,3647, 864,1909,2084,4401,2773,1010,3269,5152, 853, +3051,3121,1244,4251,1895, 364,1499,1540,2313,1180,3655,2268, 562, 715,2417,3061, + 544, 336,3768,2380,1752,4075, 950, 280,2425,4382, 183,2759,3272, 333,4297,2155, +1688,2356,1444,1039,4540, 736,1177,3349,2443,2368,2144,2225, 565, 196,1482,3406, + 927,1335,4147, 692, 878,1311,1653,3911,3622,1378,4200,1840,2969,3149,2126,1816, +2534,1546,2393,2760, 737,2494, 13, 447, 245,2747, 38,2765,2129,2589,1079, 606, + 360, 471,3755,2890, 404, 848, 699,1785,1236, 370,2221,1023,3746,2074,2026,2023, +2388,1581,2119, 812,1141,3091,2536,1519, 804,2053, 406,1596,1090, 784, 548,4414, +1806,2264,2936,1100, 343,4114,5096, 622,3358, 743,3668,1510,1626,5020,3567,2513, +3195,4115,5627,2489,2991, 24,2065,2697,1087,2719, 48,1634, 315, 68, 985,2052, + 198,2239,1347,1107,1439, 597,2366,2172, 871,3307, 919,2487,2790,1867, 236,2570, +1413,3794, 906,3365,3381,1701,1982,1818,1524,2924,1205, 616,2586,2072,2004, 575, + 253,3099, 32,1365,1182, 197,1714,2454,1201, 554,3388,3224,2748, 756,2587, 250, +2567,1507,1517,3529,1922,2761,2337,3416,1961,1677,2452,2238,3153, 615, 911,1506, +1474,2495,1265,1906,2749,3756,3280,2161, 898,2714,1759,3450,2243,2444, 563, 26, +3286,2266,3769,3344,2707,3677, 611,1402, 531,1028,2871,4548,1375, 261,2948, 835, +1190,4134, 353, 840,2684,1900,3082,1435,2109,1207,1674, 329,1872,2781,4055,2686, +2104, 608,3318,2423,2957,2768,1108,3739,3512,3271,3985,2203,1771,3520,1418,2054, +1681,1153, 225,1627,2929, 162,2050,2511,3687,1954, 124,1859,2431,1684,3032,2894, + 585,4805,3969,2869,2704,2088,2032,2095,3656,2635,4362,2209, 256, 518,2042,2105, +3777,3657, 643,2298,1148,1779, 190, 989,3544, 414, 11,2135,2063,2979,1471, 403, +3678, 126, 770,1563, 671,2499,3216,2877, 600,1179, 307,2805,4937,1268,1297,2694, + 252,4032,1448,1494,1331,1394, 127,2256, 222,1647,1035,1481,3056,1915,1048, 873, +3651, 210, 33,1608,2516, 200,1520, 415, 102, 0,3389,1287, 817, 91,3299,2940, + 836,1814, 549,2197,1396,1669,2987,3582,2297,2848,4528,1070, 687, 20,1819, 121, +1552,1364,1461,1968,2617,3540,2824,2083, 177, 948,4938,2291, 110,4549,2066, 648, +3359,1755,2110,2114,4642,4845,1693,3937,3308,1257,1869,2123, 208,1804,3159,2992, +2531,2549,3361,2418,1350,2347,2800,2568,1291,2036,2680, 72, 842,1990, 212,1233, +1154,1586, 75,2027,3410,4900,1823,1337,2710,2676, 728,2810,1522,3026,4995, 157, + 755,1050,4022, 710, 785,1936,2194,2085,1406,2777,2400, 150,1250,4049,1206, 807, +1910, 534, 529,3309,1721,1660, 274, 39,2827, 661,2670,1578, 925,3248,3815,1094, +4278,4901,4252, 41,1150,3747,2572,2227,4501,3658,4902,3813,3357,3617,2884,2258, + 887, 538,4187,3199,1294,2439,3042,2329,2343,2497,1255, 107, 543,1527, 521,3478, +3568, 194,5062, 15, 961,3870,1241,1192,2664, 66,5215,3260,2111,1295,1127,2152, +3805,4135, 901,1164,1976, 398,1278, 530,1460, 748, 904,1054,1966,1426, 53,2909, + 509, 523,2279,1534, 536,1019, 239,1685, 460,2353, 673,1065,2401,3600,4298,2272, +1272,2363, 284,1753,3679,4064,1695, 81, 815,2677,2757,2731,1386, 859, 500,4221, +2190,2566, 757,1006,2519,2068,1166,1455, 337,2654,3203,1863,1682,1914,3025,1252, +1409,1366, 847, 714,2834,2038,3209, 964,2970,1901, 885,2553,1078,1756,3049, 301, +1572,3326, 688,2130,1996,2429,1805,1648,2930,3421,2750,3652,3088, 262,1158,1254, + 389,1641,1812, 526,1719, 923,2073,1073,1902, 468, 489,4625,1140, 857,2375,3070, +3319,2863, 380, 116,1328,2693,1161,2244, 273,1212,1884,2769,3011,1775,1142, 461, +3066,1200,2147,2212, 790, 702,2695,4222,1601,1058, 434,2338,5153,3640, 67,2360, +4099,2502, 618,3472,1329, 416,1132, 830,2782,1807,2653,3211,3510,1662, 192,2124, + 296,3979,1739,1611,3684, 23, 118, 324, 446,1239,1225, 293,2520,3814,3795,2535, +3116, 17,1074, 467,2692,2201, 387,2922, 45,1326,3055,1645,3659,2817, 958, 243, +1903,2320,1339,2825,1784,3289, 356, 576, 865,2315,2381,3377,3916,1088,3122,1713, +1655, 935, 628,4689,1034,1327, 441, 800, 720, 894,1979,2183,1528,5289,2702,1071, +4046,3572,2399,1571,3281, 79, 761,1103, 327, 134, 758,1899,1371,1615, 879, 442, + 215,2605,2579, 173,2048,2485,1057,2975,3317,1097,2253,3801,4263,1403,1650,2946, + 814,4968,3487,1548,2644,1567,1285, 2, 295,2636, 97, 946,3576, 832, 141,4257, +3273, 760,3821,3521,3156,2607, 949,1024,1733,1516,1803,1920,2125,2283,2665,3180, +1501,2064,3560,2171,1592, 803,3518,1416, 732,3897,4258,1363,1362,2458, 119,1427, + 602,1525,2608,1605,1639,3175, 694,3064, 10, 465, 76,2000,4846,4208, 444,3781, +1619,3353,2206,1273,3796, 740,2483, 320,1723,2377,3660,2619,1359,1137,1762,1724, +2345,2842,1850,1862, 912, 821,1866, 612,2625,1735,2573,3369,1093, 844, 89, 937, + 930,1424,3564,2413,2972,1004,3046,3019,2011, 711,3171,1452,4178, 428, 801,1943, + 432, 445,2811, 206,4136,1472, 730, 349, 73, 397,2802,2547, 998,1637,1167, 789, + 396,3217, 154,1218, 716,1120,1780,2819,4826,1931,3334,3762,2139,1215,2627, 552, +3664,3628,3232,1405,2383,3111,1356,2652,3577,3320,3101,1703, 640,1045,1370,1246, +4996, 371,1575,2436,1621,2210, 984,4033,1734,2638, 16,4529, 663,2755,3255,1451, +3917,2257,1253,1955,2234,1263,2951, 214,1229, 617, 485, 359,1831,1969, 473,2310, + 750,2058, 165, 80,2864,2419, 361,4344,2416,2479,1134, 796,3726,1266,2943, 860, +2715, 938, 390,2734,1313,1384, 248, 202, 877,1064,2854, 522,3907, 279,1602, 297, +2357, 395,3740, 137,2075, 944,4089,2584,1267,3802, 62,1533,2285, 178, 176, 780, +2440, 201,3707, 590, 478,1560,4354,2117,1075, 30, 74,4643,4004,1635,1441,2745, + 776,2596, 238,1077,1692,1912,2844, 605, 499,1742,3947, 241,3053, 980,1749, 936, +2640,4511,2582, 515,1543,2162,5322,2892,2993, 890,2148,1924, 665,1827,3581,1032, + 968,3163, 339,1044,1896, 270, 583,1791,1720,4367,1194,3488,3669, 43,2523,1657, + 163,2167, 290,1209,1622,3378, 550, 634,2508,2510, 695,2634,2384,2512,1476,1414, + 220,1469,2341,2138,2852,3183,2900,4939,2865,3502,1211,3680, 854,3227,1299,2976, +3172, 186,2998,1459, 443,1067,3251,1495, 321,1932,3054, 909, 753,1410,1828, 436, +2441,1119,1587,3164,2186,1258, 227, 231,1425,1890,3200,3942, 247, 959, 725,5254, +2741, 577,2158,2079, 929, 120, 174, 838,2813, 591,1115, 417,2024, 40,3240,1536, +1037, 291,4151,2354, 632,1298,2406,2500,3535,1825,1846,3451, 205,1171, 345,4238, + 18,1163, 811, 685,2208,1217, 425,1312,1508,1175,4308,2552,1033, 587,1381,3059, +2984,3482, 340,1316,4023,3972, 792,3176, 519, 777,4690, 918, 933,4130,2981,3741, + 90,3360,2911,2200,5184,4550, 609,3079,2030, 272,3379,2736, 363,3881,1130,1447, + 286, 779, 357,1169,3350,3137,1630,1220,2687,2391, 747,1277,3688,2618,2682,2601, +1156,3196,5290,4034,3102,1689,3596,3128, 874, 219,2783, 798, 508,1843,2461, 269, +1658,1776,1392,1913,2983,3287,2866,2159,2372, 829,4076, 46,4253,2873,1889,1894, + 915,1834,1631,2181,2318, 298, 664,2818,3555,2735, 954,3228,3117, 527,3511,2173, + 681,2712,3033,2247,2346,3467,1652, 155,2164,3382, 113,1994, 450, 899, 494, 994, +1237,2958,1875,2336,1926,3727, 545,1577,1550, 633,3473, 204,1305,3072,2410,1956, +2471, 707,2134, 841,2195,2196,2663,3843,1026,4940, 990,3252,4997, 368,1092, 437, +3212,3258,1933,1829, 675,2977,2893, 412, 943,3723,4644,3294,3283,2230,2373,5154, +2389,2241,2661,2323,1404,2524, 593, 787, 677,3008,1275,2059, 438,2709,2609,2240, +2269,2246,1446, 36,1568,1373,3892,1574,2301,1456,3962, 693,2276,5216,2035,1143, +2720,1919,1797,1811,2763,4137,2597,1830,1699,1488,1198,2090, 424,1694, 312,3634, +3390,4179,3335,2252,1214, 561,1059,3243,2295,2561, 975,5155,2321,2751,3772, 472, +1537,3282,3398,1047,2077,2348,2878,1323,3340,3076, 690,2906, 51, 369, 170,3541, +1060,2187,2688,3670,2541,1083,1683, 928,3918, 459, 109,4427, 599,3744,4286, 143, +2101,2730,2490, 82,1588,3036,2121, 281,1860, 477,4035,1238,2812,3020,2716,3312, +1530,2188,2055,1317, 843, 636,1808,1173,3495, 649, 181,1002, 147,3641,1159,2414, +3750,2289,2795, 813,3123,2610,1136,4368, 5,3391,4541,2174, 420, 429,1728, 754, +1228,2115,2219, 347,2223,2733, 735,1518,3003,2355,3134,1764,3948,3329,1888,2424, +1001,1234,1972,3321,3363,1672,1021,1450,1584, 226, 765, 655,2526,3404,3244,2302, +3665, 731, 594,2184, 319,1576, 621, 658,2656,4299,2099,3864,1279,2071,2598,2739, + 795,3086,3699,3908,1707,2352,2402,1382,3136,2475,1465,4847,3496,3865,1085,3004, +2591,1084, 213,2287,1963,3565,2250, 822, 793,4574,3187,1772,1789,3050, 595,1484, +1959,2770,1080,2650, 456, 422,2996, 940,3322,4328,4345,3092,2742, 965,2784, 739, +4124, 952,1358,2498,2949,2565, 332,2698,2378, 660,2260,2473,4194,3856,2919, 535, +1260,2651,1208,1428,1300,1949,1303,2942, 433,2455,2450,1251,1946, 614,1269, 641, +1306,1810,2737,3078,2912, 564,2365,1419,1415,1497,4460,2367,2185,1379,3005,1307, +3218,2175,1897,3063, 682,1157,4040,4005,1712,1160,1941,1399, 394, 402,2952,1573, +1151,2986,2404, 862, 299,2033,1489,3006, 346, 171,2886,3401,1726,2932, 168,2533, + 47,2507,1030,3735,1145,3370,1395,1318,1579,3609,4560,2857,4116,1457,2529,1965, + 504,1036,2690,2988,2405, 745,5871, 849,2397,2056,3081, 863,2359,3857,2096, 99, +1397,1769,2300,4428,1643,3455,1978,1757,3718,1440, 35,4879,3742,1296,4228,2280, + 160,5063,1599,2013, 166, 520,3479,1646,3345,3012, 490,1937,1545,1264,2182,2505, +1096,1188,1369,1436,2421,1667,2792,2460,1270,2122, 727,3167,2143, 806,1706,1012, +1800,3037, 960,2218,1882, 805, 139,2456,1139,1521, 851,1052,3093,3089, 342,2039, + 744,5097,1468,1502,1585,2087, 223, 939, 326,2140,2577, 892,2481,1623,4077, 982, +3708, 135,2131, 87,2503,3114,2326,1106, 876,1616, 547,2997,2831,2093,3441,4530, +4314, 9,3256,4229,4148, 659,1462,1986,1710,2046,2913,2231,4090,4880,5255,3392, +3274,1368,3689,4645,1477, 705,3384,3635,1068,1529,2941,1458,3782,1509, 100,1656, +2548, 718,2339, 408,1590,2780,3548,1838,4117,3719,1345,3530, 717,3442,2778,3220, +2898,1892,4590,3614,3371,2043,1998,1224,3483, 891, 635, 584,2559,3355, 733,1766, +1729,1172,3789,1891,2307, 781,2982,2271,1957,1580,5773,2633,2005,4195,3097,1535, +3213,1189,1934,5693,3262, 586,3118,1324,1598, 517,1564,2217,1868,1893,4445,3728, +2703,3139,1526,1787,1992,3882,2875,1549,1199,1056,2224,1904,2711,5098,4287, 338, +1993,3129,3489,2689,1809,2815,1997, 957,1855,3898,2550,3275,3057,1105,1319, 627, +1505,1911,1883,3526, 698,3629,3456,1833,1431, 746, 77,1261,2017,2296,1977,1885, + 125,1334,1600, 525,1798,1109,2222,1470,1945, 559,2236,1186,3443,2476,1929,1411, +2411,3135,1777,3372,2621,1841,1613,3229, 668,1430,1839,2643,2916, 195,1989,2671, +2358,1387, 629,3205,2293,5256,4439, 123,1310, 888,1879,4300,3021,3605,1003,1162, +3192,2910,2010, 140,2395,2859, 55,1082,2012,2901, 662, 419,2081,1438, 680,2774, +4654,3912,1620,1731,1625,5035,4065,2328, 512,1344, 802,5443,2163,2311,2537, 524, +3399, 98,1155,2103,1918,2606,3925,2816,1393,2465,1504,3773,2177,3963,1478,4346, + 180,1113,4655,3461,2028,1698, 833,2696,1235,1322,1594,4408,3623,3013,3225,2040, +3022, 541,2881, 607,3632,2029,1665,1219, 639,1385,1686,1099,2803,3231,1938,3188, +2858, 427, 676,2772,1168,2025, 454,3253,2486,3556, 230,1950, 580, 791,1991,1280, +1086,1974,2034, 630, 257,3338,2788,4903,1017, 86,4790, 966,2789,1995,1696,1131, + 259,3095,4188,1308, 179,1463,5257, 289,4107,1248, 42,3413,1725,2288, 896,1947, + 774,4474,4254, 604,3430,4264, 392,2514,2588, 452, 237,1408,3018, 988,4531,1970, +3034,3310, 540,2370,1562,1288,2990, 502,4765,1147, 4,1853,2708, 207, 294,2814, +4078,2902,2509, 684, 34,3105,3532,2551, 644, 709,2801,2344, 573,1727,3573,3557, +2021,1081,3100,4315,2100,3681, 199,2263,1837,2385, 146,3484,1195,2776,3949, 997, +1939,3973,1008,1091,1202,1962,1847,1149,4209,5444,1076, 493, 117,5400,2521, 972, +1490,2934,1796,4542,2374,1512,2933,2657, 413,2888,1135,2762,2314,2156,1355,2369, + 766,2007,2527,2170,3124,2491,2593,2632,4757,2437, 234,3125,3591,1898,1750,1376, +1942,3468,3138, 570,2127,2145,3276,4131, 962, 132,1445,4196, 19, 941,3624,3480, +3366,1973,1374,4461,3431,2629, 283,2415,2275, 808,2887,3620,2112,2563,1353,3610, + 955,1089,3103,1053, 96, 88,4097, 823,3808,1583, 399, 292,4091,3313, 421,1128, + 642,4006, 903,2539,1877,2082, 596, 29,4066,1790, 722,2157, 130, 995,1569, 769, +1485, 464, 513,2213, 288,1923,1101,2453,4316, 133, 486,2445, 50, 625, 487,2207, + 57, 423, 481,2962, 159,3729,1558, 491, 303, 482, 501, 240,2837, 112,3648,2392, +1783, 362, 8,3433,3422, 610,2793,3277,1390,1284,1654, 21,3823, 734, 367, 623, + 193, 287, 374,1009,1483, 816, 476, 313,2255,2340,1262,2150,2899,1146,2581, 782, +2116,1659,2018,1880, 255,3586,3314,1110,2867,2137,2564, 986,2767,5185,2006, 650, + 158, 926, 762, 881,3157,2717,2362,3587, 306,3690,3245,1542,3077,2427,1691,2478, +2118,2985,3490,2438, 539,2305, 983, 129,1754, 355,4201,2386, 827,2923, 104,1773, +2838,2771, 411,2905,3919, 376, 767, 122,1114, 828,2422,1817,3506, 266,3460,1007, +1609,4998, 945,2612,4429,2274, 726,1247,1964,2914,2199,2070,4002,4108, 657,3323, +1422, 579, 455,2764,4737,1222,2895,1670, 824,1223,1487,2525, 558, 861,3080, 598, +2659,2515,1967, 752,2583,2376,2214,4180, 977, 704,2464,4999,2622,4109,1210,2961, + 819,1541, 142,2284, 44, 418, 457,1126,3730,4347,4626,1644,1876,3671,1864, 302, +1063,5694, 624, 723,1984,3745,1314,1676,2488,1610,1449,3558,3569,2166,2098, 409, +1011,2325,3704,2306, 818,1732,1383,1824,1844,3757, 999,2705,3497,1216,1423,2683, +2426,2954,2501,2726,2229,1475,2554,5064,1971,1794,1666,2014,1343, 783, 724, 191, +2434,1354,2220,5065,1763,2752,2472,4152, 131, 175,2885,3434, 92,1466,4920,2616, +3871,3872,3866, 128,1551,1632, 669,1854,3682,4691,4125,1230, 188,2973,3290,1302, +1213, 560,3266, 917, 763,3909,3249,1760, 868,1958, 764,1782,2097, 145,2277,3774, +4462, 64,1491,3062, 971,2132,3606,2442, 221,1226,1617, 218, 323,1185,3207,3147, + 571, 619,1473,1005,1744,2281, 449,1887,2396,3685, 275, 375,3816,1743,3844,3731, + 845,1983,2350,4210,1377, 773, 967,3499,3052,3743,2725,4007,1697,1022,3943,1464, +3264,2855,2722,1952,1029,2839,2467, 84,4383,2215, 820,1391,2015,2448,3672, 377, +1948,2168, 797,2545,3536,2578,2645, 94,2874,1678, 405,1259,3071, 771, 546,1315, + 470,1243,3083, 895,2468, 981, 969,2037, 846,4181, 653,1276,2928, 14,2594, 557, +3007,2474, 156, 902,1338,1740,2574, 537,2518, 973,2282,2216,2433,1928, 138,2903, +1293,2631,1612, 646,3457, 839,2935, 111, 496,2191,2847, 589,3186, 149,3994,2060, +4031,2641,4067,3145,1870, 37,3597,2136,1025,2051,3009,3383,3549,1121,1016,3261, +1301, 251,2446,2599,2153, 872,3246, 637, 334,3705, 831, 884, 921,3065,3140,4092, +2198,1944, 246,2964, 108,2045,1152,1921,2308,1031, 203,3173,4170,1907,3890, 810, +1401,2003,1690, 506, 647,1242,2828,1761,1649,3208,2249,1589,3709,2931,5156,1708, + 498, 666,2613, 834,3817,1231, 184,2851,1124, 883,3197,2261,3710,1765,1553,2658, +1178,2639,2351, 93,1193, 942,2538,2141,4402, 235,1821, 870,1591,2192,1709,1871, +3341,1618,4126,2595,2334, 603, 651, 69, 701, 268,2662,3411,2555,1380,1606, 503, + 448, 254,2371,2646, 574,1187,2309,1770, 322,2235,1292,1801, 305, 566,1133, 229, +2067,2057, 706, 167, 483,2002,2672,3295,1820,3561,3067, 316, 378,2746,3452,1112, + 136,1981, 507,1651,2917,1117, 285,4591, 182,2580,3522,1304, 335,3303,1835,2504, +1795,1792,2248, 674,1018,2106,2449,1857,2292,2845, 976,3047,1781,2600,2727,1389, +1281, 52,3152, 153, 265,3950, 672,3485,3951,4463, 430,1183, 365, 278,2169, 27, +1407,1336,2304, 209,1340,1730,2202,1852,2403,2883, 979,1737,1062, 631,2829,2542, +3876,2592, 825,2086,2226,3048,3625, 352,1417,3724, 542, 991, 431,1351,3938,1861, +2294, 826,1361,2927,3142,3503,1738, 463,2462,2723, 582,1916,1595,2808, 400,3845, +3891,2868,3621,2254, 58,2492,1123, 910,2160,2614,1372,1603,1196,1072,3385,1700, +3267,1980, 696, 480,2430, 920, 799,1570,2920,1951,2041,4047,2540,1321,4223,2469, +3562,2228,1271,2602, 401,2833,3351,2575,5157, 907,2312,1256, 410, 263,3507,1582, + 996, 678,1849,2316,1480, 908,3545,2237, 703,2322, 667,1826,2849,1531,2604,2999, +2407,3146,2151,2630,1786,3711, 469,3542, 497,3899,2409, 858, 837,4446,3393,1274, + 786, 620,1845,2001,3311, 484, 308,3367,1204,1815,3691,2332,1532,2557,1842,2020, +2724,1927,2333,4440, 567, 22,1673,2728,4475,1987,1858,1144,1597, 101,1832,3601, + 12, 974,3783,4391, 951,1412, 1,3720, 453,4608,4041, 528,1041,1027,3230,2628, +1129, 875,1051,3291,1203,2262,1069,2860,2799,2149,2615,3278, 144,1758,3040, 31, + 475,1680, 366,2685,3184, 311,1642,4008,2466,5036,1593,1493,2809, 216,1420,1668, + 233, 304,2128,3284, 232,1429,1768,1040,2008,3407,2740,2967,2543, 242,2133, 778, +1565,2022,2620, 505,2189,2756,1098,2273, 372,1614, 708, 553,2846,2094,2278, 169, +3626,2835,4161, 228,2674,3165, 809,1454,1309, 466,1705,1095, 900,3423, 880,2667, +3751,5258,2317,3109,2571,4317,2766,1503,1342, 866,4447,1118, 63,2076, 314,1881, +1348,1061, 172, 978,3515,1747, 532, 511,3970, 6, 601, 905,2699,3300,1751, 276, +1467,3725,2668, 65,4239,2544,2779,2556,1604, 578,2451,1802, 992,2331,2624,1320, +3446, 713,1513,1013, 103,2786,2447,1661, 886,1702, 916, 654,3574,2031,1556, 751, +2178,2821,2179,1498,1538,2176, 271, 914,2251,2080,1325, 638,1953,2937,3877,2432, +2754, 95,3265,1716, 260,1227,4083, 775, 106,1357,3254, 426,1607, 555,2480, 772, +1985, 244,2546, 474, 495,1046,2611,1851,2061, 71,2089,1675,2590, 742,3758,2843, +3222,1433, 267,2180,2576,2826,2233,2092,3913,2435, 956,1745,3075, 856,2113,1116, + 451, 3,1988,2896,1398, 993,2463,1878,2049,1341,2718,2721,2870,2108, 712,2904, +4363,2753,2324, 277,2872,2349,2649, 384, 987, 435, 691,3000, 922, 164,3939, 652, +1500,1184,4153,2482,3373,2165,4848,2335,3775,3508,3154,2806,2830,1554,2102,1664, +2530,1434,2408, 893,1547,2623,3447,2832,2242,2532,3169,2856,3223,2078, 49,3770, +3469, 462, 318, 656,2259,3250,3069, 679,1629,2758, 344,1138,1104,3120,1836,1283, +3115,2154,1437,4448, 934, 759,1999, 794,2862,1038, 533,2560,1722,2342, 855,2626, +1197,1663,4476,3127, 85,4240,2528, 25,1111,1181,3673, 407,3470,4561,2679,2713, + 768,1925,2841,3986,1544,1165, 932, 373,1240,2146,1930,2673, 721,4766, 354,4333, + 391,2963, 187, 61,3364,1442,1102, 330,1940,1767, 341,3809,4118, 393,2496,2062, +2211, 105, 331, 300, 439, 913,1332, 626, 379,3304,1557, 328, 689,3952, 309,1555, + 931, 317,2517,3027, 325, 569, 686,2107,3084, 60,1042,1333,2794, 264,3177,4014, +1628, 258,3712, 7,4464,1176,1043,1778, 683, 114,1975, 78,1492, 383,1886, 510, + 386, 645,5291,2891,2069,3305,4138,3867,2939,2603,2493,1935,1066,1848,3588,1015, +1282,1289,4609, 697,1453,3044,2666,3611,1856,2412, 54, 719,1330, 568,3778,2459, +1748, 788, 492, 551,1191,1000, 488,3394,3763, 282,1799, 348,2016,1523,3155,2390, +1049, 382,2019,1788,1170, 729,2968,3523, 897,3926,2785,2938,3292, 350,2319,3238, +1718,1717,2655,3453,3143,4465, 161,2889,2980,2009,1421, 56,1908,1640,2387,2232, +1917,1874,2477,4921, 148, 83,3438, 592,4245,2882,1822,1055, 741, 115,1496,1624, + 381,1638,4592,1020, 516,3214, 458, 947,4575,1432, 211,1514,2926,1865,2142, 189, + 852,1221,1400,1486, 882,2299,4036, 351, 28,1122, 700,6479,6480,6481,6482,6483, # last 512 +#Everything below is of no interest for detection purpose +5508,6484,3900,3414,3974,4441,4024,3537,4037,5628,5099,3633,6485,3148,6486,3636, +5509,3257,5510,5973,5445,5872,4941,4403,3174,4627,5873,6276,2286,4230,5446,5874, +5122,6102,6103,4162,5447,5123,5323,4849,6277,3980,3851,5066,4246,5774,5067,6278, +3001,2807,5695,3346,5775,5974,5158,5448,6487,5975,5976,5776,3598,6279,5696,4806, +4211,4154,6280,6488,6489,6490,6281,4212,5037,3374,4171,6491,4562,4807,4722,4827, +5977,6104,4532,4079,5159,5324,5160,4404,3858,5359,5875,3975,4288,4610,3486,4512, +5325,3893,5360,6282,6283,5560,2522,4231,5978,5186,5449,2569,3878,6284,5401,3578, +4415,6285,4656,5124,5979,2506,4247,4449,3219,3417,4334,4969,4329,6492,4576,4828, +4172,4416,4829,5402,6286,3927,3852,5361,4369,4830,4477,4867,5876,4173,6493,6105, +4657,6287,6106,5877,5450,6494,4155,4868,5451,3700,5629,4384,6288,6289,5878,3189, +4881,6107,6290,6495,4513,6496,4692,4515,4723,5100,3356,6497,6291,3810,4080,5561, +3570,4430,5980,6498,4355,5697,6499,4724,6108,6109,3764,4050,5038,5879,4093,3226, +6292,5068,5217,4693,3342,5630,3504,4831,4377,4466,4309,5698,4431,5777,6293,5778, +4272,3706,6110,5326,3752,4676,5327,4273,5403,4767,5631,6500,5699,5880,3475,5039, +6294,5562,5125,4348,4301,4482,4068,5126,4593,5700,3380,3462,5981,5563,3824,5404, +4970,5511,3825,4738,6295,6501,5452,4516,6111,5881,5564,6502,6296,5982,6503,4213, +4163,3454,6504,6112,4009,4450,6113,4658,6297,6114,3035,6505,6115,3995,4904,4739, +4563,4942,4110,5040,3661,3928,5362,3674,6506,5292,3612,4791,5565,4149,5983,5328, +5259,5021,4725,4577,4564,4517,4364,6298,5405,4578,5260,4594,4156,4157,5453,3592, +3491,6507,5127,5512,4709,4922,5984,5701,4726,4289,6508,4015,6116,5128,4628,3424, +4241,5779,6299,4905,6509,6510,5454,5702,5780,6300,4365,4923,3971,6511,5161,3270, +3158,5985,4100, 867,5129,5703,6117,5363,3695,3301,5513,4467,6118,6512,5455,4232, +4242,4629,6513,3959,4478,6514,5514,5329,5986,4850,5162,5566,3846,4694,6119,5456, +4869,5781,3779,6301,5704,5987,5515,4710,6302,5882,6120,4392,5364,5705,6515,6121, +6516,6517,3736,5988,5457,5989,4695,2457,5883,4551,5782,6303,6304,6305,5130,4971, +6122,5163,6123,4870,3263,5365,3150,4871,6518,6306,5783,5069,5706,3513,3498,4409, +5330,5632,5366,5458,5459,3991,5990,4502,3324,5991,5784,3696,4518,5633,4119,6519, +4630,5634,4417,5707,4832,5992,3418,6124,5993,5567,4768,5218,6520,4595,3458,5367, +6125,5635,6126,4202,6521,4740,4924,6307,3981,4069,4385,6308,3883,2675,4051,3834, +4302,4483,5568,5994,4972,4101,5368,6309,5164,5884,3922,6127,6522,6523,5261,5460, +5187,4164,5219,3538,5516,4111,3524,5995,6310,6311,5369,3181,3386,2484,5188,3464, +5569,3627,5708,6524,5406,5165,4677,4492,6312,4872,4851,5885,4468,5996,6313,5709, +5710,6128,2470,5886,6314,5293,4882,5785,3325,5461,5101,6129,5711,5786,6525,4906, +6526,6527,4418,5887,5712,4808,2907,3701,5713,5888,6528,3765,5636,5331,6529,6530, +3593,5889,3637,4943,3692,5714,5787,4925,6315,6130,5462,4405,6131,6132,6316,5262, +6531,6532,5715,3859,5716,5070,4696,5102,3929,5788,3987,4792,5997,6533,6534,3920, +4809,5000,5998,6535,2974,5370,6317,5189,5263,5717,3826,6536,3953,5001,4883,3190, +5463,5890,4973,5999,4741,6133,6134,3607,5570,6000,4711,3362,3630,4552,5041,6318, +6001,2950,2953,5637,4646,5371,4944,6002,2044,4120,3429,6319,6537,5103,4833,6538, +6539,4884,4647,3884,6003,6004,4758,3835,5220,5789,4565,5407,6540,6135,5294,4697, +4852,6320,6321,3206,4907,6541,6322,4945,6542,6136,6543,6323,6005,4631,3519,6544, +5891,6545,5464,3784,5221,6546,5571,4659,6547,6324,6137,5190,6548,3853,6549,4016, +4834,3954,6138,5332,3827,4017,3210,3546,4469,5408,5718,3505,4648,5790,5131,5638, +5791,5465,4727,4318,6325,6326,5792,4553,4010,4698,3439,4974,3638,4335,3085,6006, +5104,5042,5166,5892,5572,6327,4356,4519,5222,5573,5333,5793,5043,6550,5639,5071, +4503,6328,6139,6551,6140,3914,3901,5372,6007,5640,4728,4793,3976,3836,4885,6552, +4127,6553,4451,4102,5002,6554,3686,5105,6555,5191,5072,5295,4611,5794,5296,6556, +5893,5264,5894,4975,5466,5265,4699,4976,4370,4056,3492,5044,4886,6557,5795,4432, +4769,4357,5467,3940,4660,4290,6141,4484,4770,4661,3992,6329,4025,4662,5022,4632, +4835,4070,5297,4663,4596,5574,5132,5409,5895,6142,4504,5192,4664,5796,5896,3885, +5575,5797,5023,4810,5798,3732,5223,4712,5298,4084,5334,5468,6143,4052,4053,4336, +4977,4794,6558,5335,4908,5576,5224,4233,5024,4128,5469,5225,4873,6008,5045,4729, +4742,4633,3675,4597,6559,5897,5133,5577,5003,5641,5719,6330,6560,3017,2382,3854, +4406,4811,6331,4393,3964,4946,6561,2420,3722,6562,4926,4378,3247,1736,4442,6332, +5134,6333,5226,3996,2918,5470,4319,4003,4598,4743,4744,4485,3785,3902,5167,5004, +5373,4394,5898,6144,4874,1793,3997,6334,4085,4214,5106,5642,4909,5799,6009,4419, +4189,3330,5899,4165,4420,5299,5720,5227,3347,6145,4081,6335,2876,3930,6146,3293, +3786,3910,3998,5900,5300,5578,2840,6563,5901,5579,6147,3531,5374,6564,6565,5580, +4759,5375,6566,6148,3559,5643,6336,6010,5517,6337,6338,5721,5902,3873,6011,6339, +6567,5518,3868,3649,5722,6568,4771,4947,6569,6149,4812,6570,2853,5471,6340,6341, +5644,4795,6342,6012,5723,6343,5724,6013,4349,6344,3160,6150,5193,4599,4514,4493, +5168,4320,6345,4927,3666,4745,5169,5903,5005,4928,6346,5725,6014,4730,4203,5046, +4948,3395,5170,6015,4150,6016,5726,5519,6347,5047,3550,6151,6348,4197,4310,5904, +6571,5581,2965,6152,4978,3960,4291,5135,6572,5301,5727,4129,4026,5905,4853,5728, +5472,6153,6349,4533,2700,4505,5336,4678,3583,5073,2994,4486,3043,4554,5520,6350, +6017,5800,4487,6351,3931,4103,5376,6352,4011,4321,4311,4190,5136,6018,3988,3233, +4350,5906,5645,4198,6573,5107,3432,4191,3435,5582,6574,4139,5410,6353,5411,3944, +5583,5074,3198,6575,6354,4358,6576,5302,4600,5584,5194,5412,6577,6578,5585,5413, +5303,4248,5414,3879,4433,6579,4479,5025,4854,5415,6355,4760,4772,3683,2978,4700, +3797,4452,3965,3932,3721,4910,5801,6580,5195,3551,5907,3221,3471,3029,6019,3999, +5908,5909,5266,5267,3444,3023,3828,3170,4796,5646,4979,4259,6356,5647,5337,3694, +6357,5648,5338,4520,4322,5802,3031,3759,4071,6020,5586,4836,4386,5048,6581,3571, +4679,4174,4949,6154,4813,3787,3402,3822,3958,3215,3552,5268,4387,3933,4950,4359, +6021,5910,5075,3579,6358,4234,4566,5521,6359,3613,5049,6022,5911,3375,3702,3178, +4911,5339,4521,6582,6583,4395,3087,3811,5377,6023,6360,6155,4027,5171,5649,4421, +4249,2804,6584,2270,6585,4000,4235,3045,6156,5137,5729,4140,4312,3886,6361,4330, +6157,4215,6158,3500,3676,4929,4331,3713,4930,5912,4265,3776,3368,5587,4470,4855, +3038,4980,3631,6159,6160,4132,4680,6161,6362,3923,4379,5588,4255,6586,4121,6587, +6363,4649,6364,3288,4773,4774,6162,6024,6365,3543,6588,4274,3107,3737,5050,5803, +4797,4522,5589,5051,5730,3714,4887,5378,4001,4523,6163,5026,5522,4701,4175,2791, +3760,6589,5473,4224,4133,3847,4814,4815,4775,3259,5416,6590,2738,6164,6025,5304, +3733,5076,5650,4816,5590,6591,6165,6592,3934,5269,6593,3396,5340,6594,5804,3445, +3602,4042,4488,5731,5732,3525,5591,4601,5196,6166,6026,5172,3642,4612,3202,4506, +4798,6366,3818,5108,4303,5138,5139,4776,3332,4304,2915,3415,4434,5077,5109,4856, +2879,5305,4817,6595,5913,3104,3144,3903,4634,5341,3133,5110,5651,5805,6167,4057, +5592,2945,4371,5593,6596,3474,4182,6367,6597,6168,4507,4279,6598,2822,6599,4777, +4713,5594,3829,6169,3887,5417,6170,3653,5474,6368,4216,2971,5228,3790,4579,6369, +5733,6600,6601,4951,4746,4555,6602,5418,5475,6027,3400,4665,5806,6171,4799,6028, +5052,6172,3343,4800,4747,5006,6370,4556,4217,5476,4396,5229,5379,5477,3839,5914, +5652,5807,4714,3068,4635,5808,6173,5342,4192,5078,5419,5523,5734,6174,4557,6175, +4602,6371,6176,6603,5809,6372,5735,4260,3869,5111,5230,6029,5112,6177,3126,4681, +5524,5915,2706,3563,4748,3130,6178,4018,5525,6604,6605,5478,4012,4837,6606,4534, +4193,5810,4857,3615,5479,6030,4082,3697,3539,4086,5270,3662,4508,4931,5916,4912, +5811,5027,3888,6607,4397,3527,3302,3798,2775,2921,2637,3966,4122,4388,4028,4054, +1633,4858,5079,3024,5007,3982,3412,5736,6608,3426,3236,5595,3030,6179,3427,3336, +3279,3110,6373,3874,3039,5080,5917,5140,4489,3119,6374,5812,3405,4494,6031,4666, +4141,6180,4166,6032,5813,4981,6609,5081,4422,4982,4112,3915,5653,3296,3983,6375, +4266,4410,5654,6610,6181,3436,5082,6611,5380,6033,3819,5596,4535,5231,5306,5113, +6612,4952,5918,4275,3113,6613,6376,6182,6183,5814,3073,4731,4838,5008,3831,6614, +4888,3090,3848,4280,5526,5232,3014,5655,5009,5737,5420,5527,6615,5815,5343,5173, +5381,4818,6616,3151,4953,6617,5738,2796,3204,4360,2989,4281,5739,5174,5421,5197, +3132,5141,3849,5142,5528,5083,3799,3904,4839,5480,2880,4495,3448,6377,6184,5271, +5919,3771,3193,6034,6035,5920,5010,6036,5597,6037,6378,6038,3106,5422,6618,5423, +5424,4142,6619,4889,5084,4890,4313,5740,6620,3437,5175,5307,5816,4199,5198,5529, +5817,5199,5656,4913,5028,5344,3850,6185,2955,5272,5011,5818,4567,4580,5029,5921, +3616,5233,6621,6622,6186,4176,6039,6379,6380,3352,5200,5273,2908,5598,5234,3837, +5308,6623,6624,5819,4496,4323,5309,5201,6625,6626,4983,3194,3838,4167,5530,5922, +5274,6381,6382,3860,3861,5599,3333,4292,4509,6383,3553,5481,5820,5531,4778,6187, +3955,3956,4324,4389,4218,3945,4325,3397,2681,5923,4779,5085,4019,5482,4891,5382, +5383,6040,4682,3425,5275,4094,6627,5310,3015,5483,5657,4398,5924,3168,4819,6628, +5925,6629,5532,4932,4613,6041,6630,4636,6384,4780,4204,5658,4423,5821,3989,4683, +5822,6385,4954,6631,5345,6188,5425,5012,5384,3894,6386,4490,4104,6632,5741,5053, +6633,5823,5926,5659,5660,5927,6634,5235,5742,5824,4840,4933,4820,6387,4859,5928, +4955,6388,4143,3584,5825,5346,5013,6635,5661,6389,5014,5484,5743,4337,5176,5662, +6390,2836,6391,3268,6392,6636,6042,5236,6637,4158,6638,5744,5663,4471,5347,3663, +4123,5143,4293,3895,6639,6640,5311,5929,5826,3800,6189,6393,6190,5664,5348,3554, +3594,4749,4603,6641,5385,4801,6043,5827,4183,6642,5312,5426,4761,6394,5665,6191, +4715,2669,6643,6644,5533,3185,5427,5086,5930,5931,5386,6192,6044,6645,4781,4013, +5745,4282,4435,5534,4390,4267,6045,5746,4984,6046,2743,6193,3501,4087,5485,5932, +5428,4184,4095,5747,4061,5054,3058,3862,5933,5600,6646,5144,3618,6395,3131,5055, +5313,6396,4650,4956,3855,6194,3896,5202,4985,4029,4225,6195,6647,5828,5486,5829, +3589,3002,6648,6397,4782,5276,6649,6196,6650,4105,3803,4043,5237,5830,6398,4096, +3643,6399,3528,6651,4453,3315,4637,6652,3984,6197,5535,3182,3339,6653,3096,2660, +6400,6654,3449,5934,4250,4236,6047,6401,5831,6655,5487,3753,4062,5832,6198,6199, +6656,3766,6657,3403,4667,6048,6658,4338,2897,5833,3880,2797,3780,4326,6659,5748, +5015,6660,5387,4351,5601,4411,6661,3654,4424,5935,4339,4072,5277,4568,5536,6402, +6662,5238,6663,5349,5203,6200,5204,6201,5145,4536,5016,5056,4762,5834,4399,4957, +6202,6403,5666,5749,6664,4340,6665,5936,5177,5667,6666,6667,3459,4668,6404,6668, +6669,4543,6203,6670,4276,6405,4480,5537,6671,4614,5205,5668,6672,3348,2193,4763, +6406,6204,5937,5602,4177,5669,3419,6673,4020,6205,4443,4569,5388,3715,3639,6407, +6049,4058,6206,6674,5938,4544,6050,4185,4294,4841,4651,4615,5488,6207,6408,6051, +5178,3241,3509,5835,6208,4958,5836,4341,5489,5278,6209,2823,5538,5350,5206,5429, +6675,4638,4875,4073,3516,4684,4914,4860,5939,5603,5389,6052,5057,3237,5490,3791, +6676,6409,6677,4821,4915,4106,5351,5058,4243,5539,4244,5604,4842,4916,5239,3028, +3716,5837,5114,5605,5390,5940,5430,6210,4332,6678,5540,4732,3667,3840,6053,4305, +3408,5670,5541,6410,2744,5240,5750,6679,3234,5606,6680,5607,5671,3608,4283,4159, +4400,5352,4783,6681,6411,6682,4491,4802,6211,6412,5941,6413,6414,5542,5751,6683, +4669,3734,5942,6684,6415,5943,5059,3328,4670,4144,4268,6685,6686,6687,6688,4372, +3603,6689,5944,5491,4373,3440,6416,5543,4784,4822,5608,3792,4616,5838,5672,3514, +5391,6417,4892,6690,4639,6691,6054,5673,5839,6055,6692,6056,5392,6212,4038,5544, +5674,4497,6057,6693,5840,4284,5675,4021,4545,5609,6418,4454,6419,6213,4113,4472, +5314,3738,5087,5279,4074,5610,4959,4063,3179,4750,6058,6420,6214,3476,4498,4716, +5431,4960,4685,6215,5241,6694,6421,6216,6695,5841,5945,6422,3748,5946,5179,3905, +5752,5545,5947,4374,6217,4455,6423,4412,6218,4803,5353,6696,3832,5280,6219,4327, +4702,6220,6221,6059,4652,5432,6424,3749,4751,6425,5753,4986,5393,4917,5948,5030, +5754,4861,4733,6426,4703,6697,6222,4671,5949,4546,4961,5180,6223,5031,3316,5281, +6698,4862,4295,4934,5207,3644,6427,5842,5950,6428,6429,4570,5843,5282,6430,6224, +5088,3239,6060,6699,5844,5755,6061,6431,2701,5546,6432,5115,5676,4039,3993,3327, +4752,4425,5315,6433,3941,6434,5677,4617,4604,3074,4581,6225,5433,6435,6226,6062, +4823,5756,5116,6227,3717,5678,4717,5845,6436,5679,5846,6063,5847,6064,3977,3354, +6437,3863,5117,6228,5547,5394,4499,4524,6229,4605,6230,4306,4500,6700,5951,6065, +3693,5952,5089,4366,4918,6701,6231,5548,6232,6702,6438,4704,5434,6703,6704,5953, +4168,6705,5680,3420,6706,5242,4407,6066,3812,5757,5090,5954,4672,4525,3481,5681, +4618,5395,5354,5316,5955,6439,4962,6707,4526,6440,3465,4673,6067,6441,5682,6708, +5435,5492,5758,5683,4619,4571,4674,4804,4893,4686,5493,4753,6233,6068,4269,6442, +6234,5032,4705,5146,5243,5208,5848,6235,6443,4963,5033,4640,4226,6236,5849,3387, +6444,6445,4436,4437,5850,4843,5494,4785,4894,6709,4361,6710,5091,5956,3331,6237, +4987,5549,6069,6711,4342,3517,4473,5317,6070,6712,6071,4706,6446,5017,5355,6713, +6714,4988,5436,6447,4734,5759,6715,4735,4547,4456,4754,6448,5851,6449,6450,3547, +5852,5318,6451,6452,5092,4205,6716,6238,4620,4219,5611,6239,6072,4481,5760,5957, +5958,4059,6240,6453,4227,4537,6241,5761,4030,4186,5244,5209,3761,4457,4876,3337, +5495,5181,6242,5959,5319,5612,5684,5853,3493,5854,6073,4169,5613,5147,4895,6074, +5210,6717,5182,6718,3830,6243,2798,3841,6075,6244,5855,5614,3604,4606,5496,5685, +5118,5356,6719,6454,5960,5357,5961,6720,4145,3935,4621,5119,5962,4261,6721,6455, +4786,5963,4375,4582,6245,6246,6247,6076,5437,4877,5856,3376,4380,6248,4160,6722, +5148,6456,5211,6457,6723,4718,6458,6724,6249,5358,4044,3297,6459,6250,5857,5615, +5497,5245,6460,5498,6725,6251,6252,5550,3793,5499,2959,5396,6461,6462,4572,5093, +5500,5964,3806,4146,6463,4426,5762,5858,6077,6253,4755,3967,4220,5965,6254,4989, +5501,6464,4352,6726,6078,4764,2290,5246,3906,5438,5283,3767,4964,2861,5763,5094, +6255,6256,4622,5616,5859,5860,4707,6727,4285,4708,4824,5617,6257,5551,4787,5212, +4965,4935,4687,6465,6728,6466,5686,6079,3494,4413,2995,5247,5966,5618,6729,5967, +5764,5765,5687,5502,6730,6731,6080,5397,6467,4990,6258,6732,4538,5060,5619,6733, +4719,5688,5439,5018,5149,5284,5503,6734,6081,4607,6259,5120,3645,5861,4583,6260, +4584,4675,5620,4098,5440,6261,4863,2379,3306,4585,5552,5689,4586,5285,6735,4864, +6736,5286,6082,6737,4623,3010,4788,4381,4558,5621,4587,4896,3698,3161,5248,4353, +4045,6262,3754,5183,4588,6738,6263,6739,6740,5622,3936,6741,6468,6742,6264,5095, +6469,4991,5968,6743,4992,6744,6083,4897,6745,4256,5766,4307,3108,3968,4444,5287, +3889,4343,6084,4510,6085,4559,6086,4898,5969,6746,5623,5061,4919,5249,5250,5504, +5441,6265,5320,4878,3242,5862,5251,3428,6087,6747,4237,5624,5442,6266,5553,4539, +6748,2585,3533,5398,4262,6088,5150,4736,4438,6089,6267,5505,4966,6749,6268,6750, +6269,5288,5554,3650,6090,6091,4624,6092,5690,6751,5863,4270,5691,4277,5555,5864, +6752,5692,4720,4865,6470,5151,4688,4825,6753,3094,6754,6471,3235,4653,6755,5213, +5399,6756,3201,4589,5865,4967,6472,5866,6473,5019,3016,6757,5321,4756,3957,4573, +6093,4993,5767,4721,6474,6758,5625,6759,4458,6475,6270,6760,5556,4994,5214,5252, +6271,3875,5768,6094,5034,5506,4376,5769,6761,2120,6476,5253,5770,6762,5771,5970, +3990,5971,5557,5558,5772,6477,6095,2787,4641,5972,5121,6096,6097,6272,6763,3703, +5867,5507,6273,4206,6274,4789,6098,6764,3619,3646,3833,3804,2394,3788,4936,3978, +4866,4899,6099,6100,5559,6478,6765,3599,5868,6101,5869,5870,6275,6766,4527,6767) + diff --git a/libs/requests/packages/chardet/gb2312prober.py b/libs/requests/packages/chardet/gb2312prober.py new file mode 100755 index 00000000..91eb3925 --- /dev/null +++ b/libs/requests/packages/chardet/gb2312prober.py @@ -0,0 +1,41 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from mbcharsetprober import MultiByteCharSetProber +from codingstatemachine import CodingStateMachine +from chardistribution import GB2312DistributionAnalysis +from mbcssm import GB2312SMModel + +class GB2312Prober(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(GB2312SMModel) + self._mDistributionAnalyzer = GB2312DistributionAnalysis() + self.reset() + + def get_charset_name(self): + return "GB2312" diff --git a/libs/requests/packages/chardet/hebrewprober.py b/libs/requests/packages/chardet/hebrewprober.py new file mode 100755 index 00000000..a2b1eaa9 --- /dev/null +++ b/libs/requests/packages/chardet/hebrewprober.py @@ -0,0 +1,269 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Shy Shalom +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from charsetprober import CharSetProber +import constants + +# This prober doesn't actually recognize a language or a charset. +# It is a helper prober for the use of the Hebrew model probers + +### General ideas of the Hebrew charset recognition ### +# +# Four main charsets exist in Hebrew: +# "ISO-8859-8" - Visual Hebrew +# "windows-1255" - Logical Hebrew +# "ISO-8859-8-I" - Logical Hebrew +# "x-mac-hebrew" - ?? Logical Hebrew ?? +# +# Both "ISO" charsets use a completely identical set of code points, whereas +# "windows-1255" and "x-mac-hebrew" are two different proper supersets of +# these code points. windows-1255 defines additional characters in the range +# 0x80-0x9F as some misc punctuation marks as well as some Hebrew-specific +# diacritics and additional 'Yiddish' ligature letters in the range 0xc0-0xd6. +# x-mac-hebrew defines similar additional code points but with a different +# mapping. +# +# As far as an average Hebrew text with no diacritics is concerned, all four +# charsets are identical with respect to code points. Meaning that for the +# main Hebrew alphabet, all four map the same values to all 27 Hebrew letters +# (including final letters). +# +# The dominant difference between these charsets is their directionality. +# "Visual" directionality means that the text is ordered as if the renderer is +# not aware of a BIDI rendering algorithm. The renderer sees the text and +# draws it from left to right. The text itself when ordered naturally is read +# backwards. A buffer of Visual Hebrew generally looks like so: +# "[last word of first line spelled backwards] [whole line ordered backwards +# and spelled backwards] [first word of first line spelled backwards] +# [end of line] [last word of second line] ... etc' " +# adding punctuation marks, numbers and English text to visual text is +# naturally also "visual" and from left to right. +# +# "Logical" directionality means the text is ordered "naturally" according to +# the order it is read. It is the responsibility of the renderer to display +# the text from right to left. A BIDI algorithm is used to place general +# punctuation marks, numbers and English text in the text. +# +# Texts in x-mac-hebrew are almost impossible to find on the Internet. From +# what little evidence I could find, it seems that its general directionality +# is Logical. +# +# To sum up all of the above, the Hebrew probing mechanism knows about two +# charsets: +# Visual Hebrew - "ISO-8859-8" - backwards text - Words and sentences are +# backwards while line order is natural. For charset recognition purposes +# the line order is unimportant (In fact, for this implementation, even +# word order is unimportant). +# Logical Hebrew - "windows-1255" - normal, naturally ordered text. +# +# "ISO-8859-8-I" is a subset of windows-1255 and doesn't need to be +# specifically identified. +# "x-mac-hebrew" is also identified as windows-1255. A text in x-mac-hebrew +# that contain special punctuation marks or diacritics is displayed with +# some unconverted characters showing as question marks. This problem might +# be corrected using another model prober for x-mac-hebrew. Due to the fact +# that x-mac-hebrew texts are so rare, writing another model prober isn't +# worth the effort and performance hit. +# +#### The Prober #### +# +# The prober is divided between two SBCharSetProbers and a HebrewProber, +# all of which are managed, created, fed data, inquired and deleted by the +# SBCSGroupProber. The two SBCharSetProbers identify that the text is in +# fact some kind of Hebrew, Logical or Visual. The final decision about which +# one is it is made by the HebrewProber by combining final-letter scores +# with the scores of the two SBCharSetProbers to produce a final answer. +# +# The SBCSGroupProber is responsible for stripping the original text of HTML +# tags, English characters, numbers, low-ASCII punctuation characters, spaces +# and new lines. It reduces any sequence of such characters to a single space. +# The buffer fed to each prober in the SBCS group prober is pure text in +# high-ASCII. +# The two SBCharSetProbers (model probers) share the same language model: +# Win1255Model. +# The first SBCharSetProber uses the model normally as any other +# SBCharSetProber does, to recognize windows-1255, upon which this model was +# built. The second SBCharSetProber is told to make the pair-of-letter +# lookup in the language model backwards. This in practice exactly simulates +# a visual Hebrew model using the windows-1255 logical Hebrew model. +# +# The HebrewProber is not using any language model. All it does is look for +# final-letter evidence suggesting the text is either logical Hebrew or visual +# Hebrew. Disjointed from the model probers, the results of the HebrewProber +# alone are meaningless. HebrewProber always returns 0.00 as confidence +# since it never identifies a charset by itself. Instead, the pointer to the +# HebrewProber is passed to the model probers as a helper "Name Prober". +# When the Group prober receives a positive identification from any prober, +# it asks for the name of the charset identified. If the prober queried is a +# Hebrew model prober, the model prober forwards the call to the +# HebrewProber to make the final decision. In the HebrewProber, the +# decision is made according to the final-letters scores maintained and Both +# model probers scores. The answer is returned in the form of the name of the +# charset identified, either "windows-1255" or "ISO-8859-8". + +# windows-1255 / ISO-8859-8 code points of interest +FINAL_KAF = '\xea' +NORMAL_KAF = '\xeb' +FINAL_MEM = '\xed' +NORMAL_MEM = '\xee' +FINAL_NUN = '\xef' +NORMAL_NUN = '\xf0' +FINAL_PE = '\xf3' +NORMAL_PE = '\xf4' +FINAL_TSADI = '\xf5' +NORMAL_TSADI = '\xf6' + +# Minimum Visual vs Logical final letter score difference. +# If the difference is below this, don't rely solely on the final letter score distance. +MIN_FINAL_CHAR_DISTANCE = 5 + +# Minimum Visual vs Logical model score difference. +# If the difference is below this, don't rely at all on the model score distance. +MIN_MODEL_DISTANCE = 0.01 + +VISUAL_HEBREW_NAME = "ISO-8859-8" +LOGICAL_HEBREW_NAME = "windows-1255" + +class HebrewProber(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self._mLogicalProber = None + self._mVisualProber = None + self.reset() + + def reset(self): + self._mFinalCharLogicalScore = 0 + self._mFinalCharVisualScore = 0 + # The two last characters seen in the previous buffer, + # mPrev and mBeforePrev are initialized to space in order to simulate a word + # delimiter at the beginning of the data + self._mPrev = ' ' + self._mBeforePrev = ' ' + # These probers are owned by the group prober. + + def set_model_probers(self, logicalProber, visualProber): + self._mLogicalProber = logicalProber + self._mVisualProber = visualProber + + def is_final(self, c): + return c in [FINAL_KAF, FINAL_MEM, FINAL_NUN, FINAL_PE, FINAL_TSADI] + + def is_non_final(self, c): + # The normal Tsadi is not a good Non-Final letter due to words like + # 'lechotet' (to chat) containing an apostrophe after the tsadi. This + # apostrophe is converted to a space in FilterWithoutEnglishLetters causing + # the Non-Final tsadi to appear at an end of a word even though this is not + # the case in the original text. + # The letters Pe and Kaf rarely display a related behavior of not being a + # good Non-Final letter. Words like 'Pop', 'Winamp' and 'Mubarak' for + # example legally end with a Non-Final Pe or Kaf. However, the benefit of + # these letters as Non-Final letters outweighs the damage since these words + # are quite rare. + return c in [NORMAL_KAF, NORMAL_MEM, NORMAL_NUN, NORMAL_PE] + + def feed(self, aBuf): + # Final letter analysis for logical-visual decision. + # Look for evidence that the received buffer is either logical Hebrew or + # visual Hebrew. + # The following cases are checked: + # 1) A word longer than 1 letter, ending with a final letter. This is an + # indication that the text is laid out "naturally" since the final letter + # really appears at the end. +1 for logical score. + # 2) A word longer than 1 letter, ending with a Non-Final letter. In normal + # Hebrew, words ending with Kaf, Mem, Nun, Pe or Tsadi, should not end with + # the Non-Final form of that letter. Exceptions to this rule are mentioned + # above in isNonFinal(). This is an indication that the text is laid out + # backwards. +1 for visual score + # 3) A word longer than 1 letter, starting with a final letter. Final letters + # should not appear at the beginning of a word. This is an indication that + # the text is laid out backwards. +1 for visual score. + # + # The visual score and logical score are accumulated throughout the text and + # are finally checked against each other in GetCharSetName(). + # No checking for final letters in the middle of words is done since that case + # is not an indication for either Logical or Visual text. + # + # We automatically filter out all 7-bit characters (replace them with spaces) + # so the word boundary detection works properly. [MAP] + + if self.get_state() == constants.eNotMe: + # Both model probers say it's not them. No reason to continue. + return constants.eNotMe + + aBuf = self.filter_high_bit_only(aBuf) + + for cur in aBuf: + if cur == ' ': + # We stand on a space - a word just ended + if self._mBeforePrev != ' ': + # next-to-last char was not a space so self._mPrev is not a 1 letter word + if self.is_final(self._mPrev): + # case (1) [-2:not space][-1:final letter][cur:space] + self._mFinalCharLogicalScore += 1 + elif self.is_non_final(self._mPrev): + # case (2) [-2:not space][-1:Non-Final letter][cur:space] + self._mFinalCharVisualScore += 1 + else: + # Not standing on a space + if (self._mBeforePrev == ' ') and (self.is_final(self._mPrev)) and (cur != ' '): + # case (3) [-2:space][-1:final letter][cur:not space] + self._mFinalCharVisualScore += 1 + self._mBeforePrev = self._mPrev + self._mPrev = cur + + # Forever detecting, till the end or until both model probers return eNotMe (handled above) + return constants.eDetecting + + def get_charset_name(self): + # Make the decision: is it Logical or Visual? + # If the final letter score distance is dominant enough, rely on it. + finalsub = self._mFinalCharLogicalScore - self._mFinalCharVisualScore + if finalsub >= MIN_FINAL_CHAR_DISTANCE: + return LOGICAL_HEBREW_NAME + if finalsub <= -MIN_FINAL_CHAR_DISTANCE: + return VISUAL_HEBREW_NAME + + # It's not dominant enough, try to rely on the model scores instead. + modelsub = self._mLogicalProber.get_confidence() - self._mVisualProber.get_confidence() + if modelsub > MIN_MODEL_DISTANCE: + return LOGICAL_HEBREW_NAME + if modelsub < -MIN_MODEL_DISTANCE: + return VISUAL_HEBREW_NAME + + # Still no good, back to final letter distance, maybe it'll save the day. + if finalsub < 0.0: + return VISUAL_HEBREW_NAME + + # (finalsub > 0 - Logical) or (don't know what to do) default to Logical. + return LOGICAL_HEBREW_NAME + + def get_state(self): + # Remain active as long as any of the model probers are active. + if (self._mLogicalProber.get_state() == constants.eNotMe) and \ + (self._mVisualProber.get_state() == constants.eNotMe): + return constants.eNotMe + return constants.eDetecting diff --git a/libs/requests/packages/chardet/jisfreq.py b/libs/requests/packages/chardet/jisfreq.py new file mode 100755 index 00000000..5fe4a5c3 --- /dev/null +++ b/libs/requests/packages/chardet/jisfreq.py @@ -0,0 +1,567 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Sampling from about 20M text materials include literature and computer technology +# +# Japanese frequency table, applied to both S-JIS and EUC-JP +# They are sorted in order. + +# 128 --> 0.77094 +# 256 --> 0.85710 +# 512 --> 0.92635 +# 1024 --> 0.97130 +# 2048 --> 0.99431 +# +# Ideal Distribution Ratio = 0.92635 / (1-0.92635) = 12.58 +# Random Distribution Ration = 512 / (2965+62+83+86-512) = 0.191 +# +# Typical Distribution Ratio, 25% of IDR + +JIS_TYPICAL_DISTRIBUTION_RATIO = 3.0 + +# Char to FreqOrder table , +JIS_TABLE_SIZE = 4368 + +JISCharToFreqOrder = ( \ + 40, 1, 6, 182, 152, 180, 295,2127, 285, 381,3295,4304,3068,4606,3165,3510, # 16 +3511,1822,2785,4607,1193,2226,5070,4608, 171,2996,1247, 18, 179,5071, 856,1661, # 32 +1262,5072, 619, 127,3431,3512,3230,1899,1700, 232, 228,1294,1298, 284, 283,2041, # 48 +2042,1061,1062, 48, 49, 44, 45, 433, 434,1040,1041, 996, 787,2997,1255,4305, # 64 +2108,4609,1684,1648,5073,5074,5075,5076,5077,5078,3687,5079,4610,5080,3927,3928, # 80 +5081,3296,3432, 290,2285,1471,2187,5082,2580,2825,1303,2140,1739,1445,2691,3375, # 96 +1691,3297,4306,4307,4611, 452,3376,1182,2713,3688,3069,4308,5083,5084,5085,5086, # 112 +5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102, # 128 +5103,5104,5105,5106,5107,5108,5109,5110,5111,5112,4097,5113,5114,5115,5116,5117, # 144 +5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,5130,5131,5132,5133, # 160 +5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,5144,5145,5146,5147,5148,5149, # 176 +5150,5151,5152,4612,5153,5154,5155,5156,5157,5158,5159,5160,5161,5162,5163,5164, # 192 +5165,5166,5167,5168,5169,5170,5171,5172,5173,5174,5175,1472, 598, 618, 820,1205, # 208 +1309,1412,1858,1307,1692,5176,5177,5178,5179,5180,5181,5182,1142,1452,1234,1172, # 224 +1875,2043,2149,1793,1382,2973, 925,2404,1067,1241, 960,1377,2935,1491, 919,1217, # 240 +1865,2030,1406,1499,2749,4098,5183,5184,5185,5186,5187,5188,2561,4099,3117,1804, # 256 +2049,3689,4309,3513,1663,5189,3166,3118,3298,1587,1561,3433,5190,3119,1625,2998, # 272 +3299,4613,1766,3690,2786,4614,5191,5192,5193,5194,2161, 26,3377, 2,3929, 20, # 288 +3691, 47,4100, 50, 17, 16, 35, 268, 27, 243, 42, 155, 24, 154, 29, 184, # 304 + 4, 91, 14, 92, 53, 396, 33, 289, 9, 37, 64, 620, 21, 39, 321, 5, # 320 + 12, 11, 52, 13, 3, 208, 138, 0, 7, 60, 526, 141, 151,1069, 181, 275, # 336 +1591, 83, 132,1475, 126, 331, 829, 15, 69, 160, 59, 22, 157, 55,1079, 312, # 352 + 109, 38, 23, 25, 10, 19, 79,5195, 61, 382,1124, 8, 30,5196,5197,5198, # 368 +5199,5200,5201,5202,5203,5204,5205,5206, 89, 62, 74, 34,2416, 112, 139, 196, # 384 + 271, 149, 84, 607, 131, 765, 46, 88, 153, 683, 76, 874, 101, 258, 57, 80, # 400 + 32, 364, 121,1508, 169,1547, 68, 235, 145,2999, 41, 360,3027, 70, 63, 31, # 416 + 43, 259, 262,1383, 99, 533, 194, 66, 93, 846, 217, 192, 56, 106, 58, 565, # 432 + 280, 272, 311, 256, 146, 82, 308, 71, 100, 128, 214, 655, 110, 261, 104,1140, # 448 + 54, 51, 36, 87, 67,3070, 185,2618,2936,2020, 28,1066,2390,2059,5207,5208, # 464 +5209,5210,5211,5212,5213,5214,5215,5216,4615,5217,5218,5219,5220,5221,5222,5223, # 480 +5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,5234,5235,5236,3514,5237,5238, # 496 +5239,5240,5241,5242,5243,5244,2297,2031,4616,4310,3692,5245,3071,5246,3598,5247, # 512 +4617,3231,3515,5248,4101,4311,4618,3808,4312,4102,5249,4103,4104,3599,5250,5251, # 528 +5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,5264,5265,5266,5267, # 544 +5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,5279,5280,5281,5282,5283, # 560 +5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,5294,5295,5296,5297,5298,5299, # 576 +5300,5301,5302,5303,5304,5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315, # 592 +5316,5317,5318,5319,5320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331, # 608 +5332,5333,5334,5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347, # 624 +5348,5349,5350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363, # 640 +5364,5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379, # 656 +5380,5381, 363, 642,2787,2878,2788,2789,2316,3232,2317,3434,2011, 165,1942,3930, # 672 +3931,3932,3933,5382,4619,5383,4620,5384,5385,5386,5387,5388,5389,5390,5391,5392, # 688 +5393,5394,5395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,5408, # 704 +5409,5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424, # 720 +5425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,5440, # 736 +5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456, # 752 +5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472, # 768 +5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488, # 784 +5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,5504, # 800 +5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,5519,5520, # 816 +5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,5534,5535,5536, # 832 +5537,5538,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,5549,5550,5551,5552, # 848 +5553,5554,5555,5556,5557,5558,5559,5560,5561,5562,5563,5564,5565,5566,5567,5568, # 864 +5569,5570,5571,5572,5573,5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584, # 880 +5585,5586,5587,5588,5589,5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600, # 896 +5601,5602,5603,5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616, # 912 +5617,5618,5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632, # 928 +5633,5634,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648, # 944 +5649,5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664, # 960 +5665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,5680, # 976 +5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,5695,5696, # 992 +5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,5710,5711,5712, # 1008 +5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,5725,5726,5727,5728, # 1024 +5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5741,5742,5743,5744, # 1040 +5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,5755,5756,5757,5758,5759,5760, # 1056 +5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,5771,5772,5773,5774,5775,5776, # 1072 +5777,5778,5779,5780,5781,5782,5783,5784,5785,5786,5787,5788,5789,5790,5791,5792, # 1088 +5793,5794,5795,5796,5797,5798,5799,5800,5801,5802,5803,5804,5805,5806,5807,5808, # 1104 +5809,5810,5811,5812,5813,5814,5815,5816,5817,5818,5819,5820,5821,5822,5823,5824, # 1120 +5825,5826,5827,5828,5829,5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840, # 1136 +5841,5842,5843,5844,5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856, # 1152 +5857,5858,5859,5860,5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872, # 1168 +5873,5874,5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888, # 1184 +5889,5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904, # 1200 +5905,5906,5907,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920, # 1216 +5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936, # 1232 +5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951,5952, # 1248 +5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968, # 1264 +5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,5984, # 1280 +5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,5999,6000, # 1296 +6001,6002,6003,6004,6005,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,6016, # 1312 +6017,6018,6019,6020,6021,6022,6023,6024,6025,6026,6027,6028,6029,6030,6031,6032, # 1328 +6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,6044,6045,6046,6047,6048, # 1344 +6049,6050,6051,6052,6053,6054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064, # 1360 +6065,6066,6067,6068,6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080, # 1376 +6081,6082,6083,6084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096, # 1392 +6097,6098,6099,6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112, # 1408 +6113,6114,2044,2060,4621, 997,1235, 473,1186,4622, 920,3378,6115,6116, 379,1108, # 1424 +4313,2657,2735,3934,6117,3809, 636,3233, 573,1026,3693,3435,2974,3300,2298,4105, # 1440 + 854,2937,2463, 393,2581,2417, 539, 752,1280,2750,2480, 140,1161, 440, 708,1569, # 1456 + 665,2497,1746,1291,1523,3000, 164,1603, 847,1331, 537,1997, 486, 508,1693,2418, # 1472 +1970,2227, 878,1220, 299,1030, 969, 652,2751, 624,1137,3301,2619, 65,3302,2045, # 1488 +1761,1859,3120,1930,3694,3516, 663,1767, 852, 835,3695, 269, 767,2826,2339,1305, # 1504 + 896,1150, 770,1616,6118, 506,1502,2075,1012,2519, 775,2520,2975,2340,2938,4314, # 1520 +3028,2086,1224,1943,2286,6119,3072,4315,2240,1273,1987,3935,1557, 175, 597, 985, # 1536 +3517,2419,2521,1416,3029, 585, 938,1931,1007,1052,1932,1685,6120,3379,4316,4623, # 1552 + 804, 599,3121,1333,2128,2539,1159,1554,2032,3810, 687,2033,2904, 952, 675,1467, # 1568 +3436,6121,2241,1096,1786,2440,1543,1924, 980,1813,2228, 781,2692,1879, 728,1918, # 1584 +3696,4624, 548,1950,4625,1809,1088,1356,3303,2522,1944, 502, 972, 373, 513,2827, # 1600 + 586,2377,2391,1003,1976,1631,6122,2464,1084, 648,1776,4626,2141, 324, 962,2012, # 1616 +2177,2076,1384, 742,2178,1448,1173,1810, 222, 102, 301, 445, 125,2420, 662,2498, # 1632 + 277, 200,1476,1165,1068, 224,2562,1378,1446, 450,1880, 659, 791, 582,4627,2939, # 1648 +3936,1516,1274, 555,2099,3697,1020,1389,1526,3380,1762,1723,1787,2229, 412,2114, # 1664 +1900,2392,3518, 512,2597, 427,1925,2341,3122,1653,1686,2465,2499, 697, 330, 273, # 1680 + 380,2162, 951, 832, 780, 991,1301,3073, 965,2270,3519, 668,2523,2636,1286, 535, # 1696 +1407, 518, 671, 957,2658,2378, 267, 611,2197,3030,6123, 248,2299, 967,1799,2356, # 1712 + 850,1418,3437,1876,1256,1480,2828,1718,6124,6125,1755,1664,2405,6126,4628,2879, # 1728 +2829, 499,2179, 676,4629, 557,2329,2214,2090, 325,3234, 464, 811,3001, 992,2342, # 1744 +2481,1232,1469, 303,2242, 466,1070,2163, 603,1777,2091,4630,2752,4631,2714, 322, # 1760 +2659,1964,1768, 481,2188,1463,2330,2857,3600,2092,3031,2421,4632,2318,2070,1849, # 1776 +2598,4633,1302,2254,1668,1701,2422,3811,2905,3032,3123,2046,4106,1763,1694,4634, # 1792 +1604, 943,1724,1454, 917, 868,2215,1169,2940, 552,1145,1800,1228,1823,1955, 316, # 1808 +1080,2510, 361,1807,2830,4107,2660,3381,1346,1423,1134,4108,6127, 541,1263,1229, # 1824 +1148,2540, 545, 465,1833,2880,3438,1901,3074,2482, 816,3937, 713,1788,2500, 122, # 1840 +1575, 195,1451,2501,1111,6128, 859, 374,1225,2243,2483,4317, 390,1033,3439,3075, # 1856 +2524,1687, 266, 793,1440,2599, 946, 779, 802, 507, 897,1081, 528,2189,1292, 711, # 1872 +1866,1725,1167,1640, 753, 398,2661,1053, 246, 348,4318, 137,1024,3440,1600,2077, # 1888 +2129, 825,4319, 698, 238, 521, 187,2300,1157,2423,1641,1605,1464,1610,1097,2541, # 1904 +1260,1436, 759,2255,1814,2150, 705,3235, 409,2563,3304, 561,3033,2005,2564, 726, # 1920 +1956,2343,3698,4109, 949,3812,3813,3520,1669, 653,1379,2525, 881,2198, 632,2256, # 1936 +1027, 778,1074, 733,1957, 514,1481,2466, 554,2180, 702,3938,1606,1017,1398,6129, # 1952 +1380,3521, 921, 993,1313, 594, 449,1489,1617,1166, 768,1426,1360, 495,1794,3601, # 1968 +1177,3602,1170,4320,2344, 476, 425,3167,4635,3168,1424, 401,2662,1171,3382,1998, # 1984 +1089,4110, 477,3169, 474,6130,1909, 596,2831,1842, 494, 693,1051,1028,1207,3076, # 2000 + 606,2115, 727,2790,1473,1115, 743,3522, 630, 805,1532,4321,2021, 366,1057, 838, # 2016 + 684,1114,2142,4322,2050,1492,1892,1808,2271,3814,2424,1971,1447,1373,3305,1090, # 2032 +1536,3939,3523,3306,1455,2199, 336, 369,2331,1035, 584,2393, 902, 718,2600,6131, # 2048 +2753, 463,2151,1149,1611,2467, 715,1308,3124,1268, 343,1413,3236,1517,1347,2663, # 2064 +2093,3940,2022,1131,1553,2100,2941,1427,3441,2942,1323,2484,6132,1980, 872,2368, # 2080 +2441,2943, 320,2369,2116,1082, 679,1933,3941,2791,3815, 625,1143,2023, 422,2200, # 2096 +3816,6133, 730,1695, 356,2257,1626,2301,2858,2637,1627,1778, 937, 883,2906,2693, # 2112 +3002,1769,1086, 400,1063,1325,3307,2792,4111,3077, 456,2345,1046, 747,6134,1524, # 2128 + 884,1094,3383,1474,2164,1059, 974,1688,2181,2258,1047, 345,1665,1187, 358, 875, # 2144 +3170, 305, 660,3524,2190,1334,1135,3171,1540,1649,2542,1527, 927, 968,2793, 885, # 2160 +1972,1850, 482, 500,2638,1218,1109,1085,2543,1654,2034, 876, 78,2287,1482,1277, # 2176 + 861,1675,1083,1779, 724,2754, 454, 397,1132,1612,2332, 893, 672,1237, 257,2259, # 2192 +2370, 135,3384, 337,2244, 547, 352, 340, 709,2485,1400, 788,1138,2511, 540, 772, # 2208 +1682,2260,2272,2544,2013,1843,1902,4636,1999,1562,2288,4637,2201,1403,1533, 407, # 2224 + 576,3308,1254,2071, 978,3385, 170, 136,1201,3125,2664,3172,2394, 213, 912, 873, # 2240 +3603,1713,2202, 699,3604,3699, 813,3442, 493, 531,1054, 468,2907,1483, 304, 281, # 2256 +4112,1726,1252,2094, 339,2319,2130,2639, 756,1563,2944, 748, 571,2976,1588,2425, # 2272 +2715,1851,1460,2426,1528,1392,1973,3237, 288,3309, 685,3386, 296, 892,2716,2216, # 2288 +1570,2245, 722,1747,2217, 905,3238,1103,6135,1893,1441,1965, 251,1805,2371,3700, # 2304 +2601,1919,1078, 75,2182,1509,1592,1270,2640,4638,2152,6136,3310,3817, 524, 706, # 2320 +1075, 292,3818,1756,2602, 317, 98,3173,3605,3525,1844,2218,3819,2502, 814, 567, # 2336 + 385,2908,1534,6137, 534,1642,3239, 797,6138,1670,1529, 953,4323, 188,1071, 538, # 2352 + 178, 729,3240,2109,1226,1374,2000,2357,2977, 731,2468,1116,2014,2051,6139,1261, # 2368 +1593, 803,2859,2736,3443, 556, 682, 823,1541,6140,1369,2289,1706,2794, 845, 462, # 2384 +2603,2665,1361, 387, 162,2358,1740, 739,1770,1720,1304,1401,3241,1049, 627,1571, # 2400 +2427,3526,1877,3942,1852,1500, 431,1910,1503, 677, 297,2795, 286,1433,1038,1198, # 2416 +2290,1133,1596,4113,4639,2469,1510,1484,3943,6141,2442, 108, 712,4640,2372, 866, # 2432 +3701,2755,3242,1348, 834,1945,1408,3527,2395,3243,1811, 824, 994,1179,2110,1548, # 2448 +1453, 790,3003, 690,4324,4325,2832,2909,3820,1860,3821, 225,1748, 310, 346,1780, # 2464 +2470, 821,1993,2717,2796, 828, 877,3528,2860,2471,1702,2165,2910,2486,1789, 453, # 2480 + 359,2291,1676, 73,1164,1461,1127,3311, 421, 604, 314,1037, 589, 116,2487, 737, # 2496 + 837,1180, 111, 244, 735,6142,2261,1861,1362, 986, 523, 418, 581,2666,3822, 103, # 2512 + 855, 503,1414,1867,2488,1091, 657,1597, 979, 605,1316,4641,1021,2443,2078,2001, # 2528 +1209, 96, 587,2166,1032, 260,1072,2153, 173, 94, 226,3244, 819,2006,4642,4114, # 2544 +2203, 231,1744, 782, 97,2667, 786,3387, 887, 391, 442,2219,4326,1425,6143,2694, # 2560 + 633,1544,1202, 483,2015, 592,2052,1958,2472,1655, 419, 129,4327,3444,3312,1714, # 2576 +1257,3078,4328,1518,1098, 865,1310,1019,1885,1512,1734, 469,2444, 148, 773, 436, # 2592 +1815,1868,1128,1055,4329,1245,2756,3445,2154,1934,1039,4643, 579,1238, 932,2320, # 2608 + 353, 205, 801, 115,2428, 944,2321,1881, 399,2565,1211, 678, 766,3944, 335,2101, # 2624 +1459,1781,1402,3945,2737,2131,1010, 844, 981,1326,1013, 550,1816,1545,2620,1335, # 2640 +1008, 371,2881, 936,1419,1613,3529,1456,1395,2273,1834,2604,1317,2738,2503, 416, # 2656 +1643,4330, 806,1126, 229, 591,3946,1314,1981,1576,1837,1666, 347,1790, 977,3313, # 2672 + 764,2861,1853, 688,2429,1920,1462, 77, 595, 415,2002,3034, 798,1192,4115,6144, # 2688 +2978,4331,3035,2695,2582,2072,2566, 430,2430,1727, 842,1396,3947,3702, 613, 377, # 2704 + 278, 236,1417,3388,3314,3174, 757,1869, 107,3530,6145,1194, 623,2262, 207,1253, # 2720 +2167,3446,3948, 492,1117,1935, 536,1838,2757,1246,4332, 696,2095,2406,1393,1572, # 2736 +3175,1782, 583, 190, 253,1390,2230, 830,3126,3389, 934,3245,1703,1749,2979,1870, # 2752 +2545,1656,2204, 869,2346,4116,3176,1817, 496,1764,4644, 942,1504, 404,1903,1122, # 2768 +1580,3606,2945,1022, 515, 372,1735, 955,2431,3036,6146,2797,1110,2302,2798, 617, # 2784 +6147, 441, 762,1771,3447,3607,3608,1904, 840,3037, 86, 939,1385, 572,1370,2445, # 2800 +1336, 114,3703, 898, 294, 203,3315, 703,1583,2274, 429, 961,4333,1854,1951,3390, # 2816 +2373,3704,4334,1318,1381, 966,1911,2322,1006,1155, 309, 989, 458,2718,1795,1372, # 2832 +1203, 252,1689,1363,3177, 517,1936, 168,1490, 562, 193,3823,1042,4117,1835, 551, # 2848 + 470,4645, 395, 489,3448,1871,1465,2583,2641, 417,1493, 279,1295, 511,1236,1119, # 2864 + 72,1231,1982,1812,3004, 871,1564, 984,3449,1667,2696,2096,4646,2347,2833,1673, # 2880 +3609, 695,3246,2668, 807,1183,4647, 890, 388,2333,1801,1457,2911,1765,1477,1031, # 2896 +3316,3317,1278,3391,2799,2292,2526, 163,3450,4335,2669,1404,1802,6148,2323,2407, # 2912 +1584,1728,1494,1824,1269, 298, 909,3318,1034,1632, 375, 776,1683,2061, 291, 210, # 2928 +1123, 809,1249,1002,2642,3038, 206,1011,2132, 144, 975, 882,1565, 342, 667, 754, # 2944 +1442,2143,1299,2303,2062, 447, 626,2205,1221,2739,2912,1144,1214,2206,2584, 760, # 2960 +1715, 614, 950,1281,2670,2621, 810, 577,1287,2546,4648, 242,2168, 250,2643, 691, # 2976 + 123,2644, 647, 313,1029, 689,1357,2946,1650, 216, 771,1339,1306, 808,2063, 549, # 2992 + 913,1371,2913,2914,6149,1466,1092,1174,1196,1311,2605,2396,1783,1796,3079, 406, # 3008 +2671,2117,3949,4649, 487,1825,2220,6150,2915, 448,2348,1073,6151,2397,1707, 130, # 3024 + 900,1598, 329, 176,1959,2527,1620,6152,2275,4336,3319,1983,2191,3705,3610,2155, # 3040 +3706,1912,1513,1614,6153,1988, 646, 392,2304,1589,3320,3039,1826,1239,1352,1340, # 3056 +2916, 505,2567,1709,1437,2408,2547, 906,6154,2672, 384,1458,1594,1100,1329, 710, # 3072 + 423,3531,2064,2231,2622,1989,2673,1087,1882, 333, 841,3005,1296,2882,2379, 580, # 3088 +1937,1827,1293,2585, 601, 574, 249,1772,4118,2079,1120, 645, 901,1176,1690, 795, # 3104 +2207, 478,1434, 516,1190,1530, 761,2080, 930,1264, 355, 435,1552, 644,1791, 987, # 3120 + 220,1364,1163,1121,1538, 306,2169,1327,1222, 546,2645, 218, 241, 610,1704,3321, # 3136 +1984,1839,1966,2528, 451,6155,2586,3707,2568, 907,3178, 254,2947, 186,1845,4650, # 3152 + 745, 432,1757, 428,1633, 888,2246,2221,2489,3611,2118,1258,1265, 956,3127,1784, # 3168 +4337,2490, 319, 510, 119, 457,3612, 274,2035,2007,4651,1409,3128, 970,2758, 590, # 3184 +2800, 661,2247,4652,2008,3950,1420,1549,3080,3322,3951,1651,1375,2111, 485,2491, # 3200 +1429,1156,6156,2548,2183,1495, 831,1840,2529,2446, 501,1657, 307,1894,3247,1341, # 3216 + 666, 899,2156,1539,2549,1559, 886, 349,2208,3081,2305,1736,3824,2170,2759,1014, # 3232 +1913,1386, 542,1397,2948, 490, 368, 716, 362, 159, 282,2569,1129,1658,1288,1750, # 3248 +2674, 276, 649,2016, 751,1496, 658,1818,1284,1862,2209,2087,2512,3451, 622,2834, # 3264 + 376, 117,1060,2053,1208,1721,1101,1443, 247,1250,3179,1792,3952,2760,2398,3953, # 3280 +6157,2144,3708, 446,2432,1151,2570,3452,2447,2761,2835,1210,2448,3082, 424,2222, # 3296 +1251,2449,2119,2836, 504,1581,4338, 602, 817, 857,3825,2349,2306, 357,3826,1470, # 3312 +1883,2883, 255, 958, 929,2917,3248, 302,4653,1050,1271,1751,2307,1952,1430,2697, # 3328 +2719,2359, 354,3180, 777, 158,2036,4339,1659,4340,4654,2308,2949,2248,1146,2232, # 3344 +3532,2720,1696,2623,3827,6158,3129,1550,2698,1485,1297,1428, 637, 931,2721,2145, # 3360 + 914,2550,2587, 81,2450, 612, 827,2646,1242,4655,1118,2884, 472,1855,3181,3533, # 3376 +3534, 569,1353,2699,1244,1758,2588,4119,2009,2762,2171,3709,1312,1531,6159,1152, # 3392 +1938, 134,1830, 471,3710,2276,1112,1535,3323,3453,3535, 982,1337,2950, 488, 826, # 3408 + 674,1058,1628,4120,2017, 522,2399, 211, 568,1367,3454, 350, 293,1872,1139,3249, # 3424 +1399,1946,3006,1300,2360,3324, 588, 736,6160,2606, 744, 669,3536,3828,6161,1358, # 3440 + 199, 723, 848, 933, 851,1939,1505,1514,1338,1618,1831,4656,1634,3613, 443,2740, # 3456 +3829, 717,1947, 491,1914,6162,2551,1542,4121,1025,6163,1099,1223, 198,3040,2722, # 3472 + 370, 410,1905,2589, 998,1248,3182,2380, 519,1449,4122,1710, 947, 928,1153,4341, # 3488 +2277, 344,2624,1511, 615, 105, 161,1212,1076,1960,3130,2054,1926,1175,1906,2473, # 3504 + 414,1873,2801,6164,2309, 315,1319,3325, 318,2018,2146,2157, 963, 631, 223,4342, # 3520 +4343,2675, 479,3711,1197,2625,3712,2676,2361,6165,4344,4123,6166,2451,3183,1886, # 3536 +2184,1674,1330,1711,1635,1506, 799, 219,3250,3083,3954,1677,3713,3326,2081,3614, # 3552 +1652,2073,4657,1147,3041,1752, 643,1961, 147,1974,3955,6167,1716,2037, 918,3007, # 3568 +1994, 120,1537, 118, 609,3184,4345, 740,3455,1219, 332,1615,3830,6168,1621,2980, # 3584 +1582, 783, 212, 553,2350,3714,1349,2433,2082,4124, 889,6169,2310,1275,1410, 973, # 3600 + 166,1320,3456,1797,1215,3185,2885,1846,2590,2763,4658, 629, 822,3008, 763, 940, # 3616 +1990,2862, 439,2409,1566,1240,1622, 926,1282,1907,2764, 654,2210,1607, 327,1130, # 3632 +3956,1678,1623,6170,2434,2192, 686, 608,3831,3715, 903,3957,3042,6171,2741,1522, # 3648 +1915,1105,1555,2552,1359, 323,3251,4346,3457, 738,1354,2553,2311,2334,1828,2003, # 3664 +3832,1753,2351,1227,6172,1887,4125,1478,6173,2410,1874,1712,1847, 520,1204,2607, # 3680 + 264,4659, 836,2677,2102, 600,4660,3833,2278,3084,6174,4347,3615,1342, 640, 532, # 3696 + 543,2608,1888,2400,2591,1009,4348,1497, 341,1737,3616,2723,1394, 529,3252,1321, # 3712 + 983,4661,1515,2120, 971,2592, 924, 287,1662,3186,4349,2700,4350,1519, 908,1948, # 3728 +2452, 156, 796,1629,1486,2223,2055, 694,4126,1259,1036,3392,1213,2249,2742,1889, # 3744 +1230,3958,1015, 910, 408, 559,3617,4662, 746, 725, 935,4663,3959,3009,1289, 563, # 3760 + 867,4664,3960,1567,2981,2038,2626, 988,2263,2381,4351, 143,2374, 704,1895,6175, # 3776 +1188,3716,2088, 673,3085,2362,4352, 484,1608,1921,2765,2918, 215, 904,3618,3537, # 3792 + 894, 509, 976,3043,2701,3961,4353,2837,2982, 498,6176,6177,1102,3538,1332,3393, # 3808 +1487,1636,1637, 233, 245,3962, 383, 650, 995,3044, 460,1520,1206,2352, 749,3327, # 3824 + 530, 700, 389,1438,1560,1773,3963,2264, 719,2951,2724,3834, 870,1832,1644,1000, # 3840 + 839,2474,3717, 197,1630,3394, 365,2886,3964,1285,2133, 734, 922, 818,1106, 732, # 3856 + 480,2083,1774,3458, 923,2279,1350, 221,3086, 85,2233,2234,3835,1585,3010,2147, # 3872 +1387,1705,2382,1619,2475, 133, 239,2802,1991,1016,2084,2383, 411,2838,1113, 651, # 3888 +1985,1160,3328, 990,1863,3087,1048,1276,2647, 265,2627,1599,3253,2056, 150, 638, # 3904 +2019, 656, 853, 326,1479, 680,1439,4354,1001,1759, 413,3459,3395,2492,1431, 459, # 3920 +4355,1125,3329,2265,1953,1450,2065,2863, 849, 351,2678,3131,3254,3255,1104,1577, # 3936 + 227,1351,1645,2453,2193,1421,2887, 812,2121, 634, 95,2435, 201,2312,4665,1646, # 3952 +1671,2743,1601,2554,2702,2648,2280,1315,1366,2089,3132,1573,3718,3965,1729,1189, # 3968 + 328,2679,1077,1940,1136, 558,1283, 964,1195, 621,2074,1199,1743,3460,3619,1896, # 3984 +1916,1890,3836,2952,1154,2112,1064, 862, 378,3011,2066,2113,2803,1568,2839,6178, # 4000 +3088,2919,1941,1660,2004,1992,2194, 142, 707,1590,1708,1624,1922,1023,1836,1233, # 4016 +1004,2313, 789, 741,3620,6179,1609,2411,1200,4127,3719,3720,4666,2057,3721, 593, # 4032 +2840, 367,2920,1878,6180,3461,1521, 628,1168, 692,2211,2649, 300, 720,2067,2571, # 4048 +2953,3396, 959,2504,3966,3539,3462,1977, 701,6181, 954,1043, 800, 681, 183,3722, # 4064 +1803,1730,3540,4128,2103, 815,2314, 174, 467, 230,2454,1093,2134, 755,3541,3397, # 4080 +1141,1162,6182,1738,2039, 270,3256,2513,1005,1647,2185,3837, 858,1679,1897,1719, # 4096 +2954,2324,1806, 402, 670, 167,4129,1498,2158,2104, 750,6183, 915, 189,1680,1551, # 4112 + 455,4356,1501,2455, 405,1095,2955, 338,1586,1266,1819, 570, 641,1324, 237,1556, # 4128 +2650,1388,3723,6184,1368,2384,1343,1978,3089,2436, 879,3724, 792,1191, 758,3012, # 4144 +1411,2135,1322,4357, 240,4667,1848,3725,1574,6185, 420,3045,1546,1391, 714,4358, # 4160 +1967, 941,1864, 863, 664, 426, 560,1731,2680,1785,2864,1949,2363, 403,3330,1415, # 4176 +1279,2136,1697,2335, 204, 721,2097,3838, 90,6186,2085,2505, 191,3967, 124,2148, # 4192 +1376,1798,1178,1107,1898,1405, 860,4359,1243,1272,2375,2983,1558,2456,1638, 113, # 4208 +3621, 578,1923,2609, 880, 386,4130, 784,2186,2266,1422,2956,2172,1722, 497, 263, # 4224 +2514,1267,2412,2610, 177,2703,3542, 774,1927,1344, 616,1432,1595,1018, 172,4360, # 4240 +2325, 911,4361, 438,1468,3622, 794,3968,2024,2173,1681,1829,2957, 945, 895,3090, # 4256 + 575,2212,2476, 475,2401,2681, 785,2744,1745,2293,2555,1975,3133,2865, 394,4668, # 4272 +3839, 635,4131, 639, 202,1507,2195,2766,1345,1435,2572,3726,1908,1184,1181,2457, # 4288 +3727,3134,4362, 843,2611, 437, 916,4669, 234, 769,1884,3046,3047,3623, 833,6187, # 4304 +1639,2250,2402,1355,1185,2010,2047, 999, 525,1732,1290,1488,2612, 948,1578,3728, # 4320 +2413,2477,1216,2725,2159, 334,3840,1328,3624,2921,1525,4132, 564,1056, 891,4363, # 4336 +1444,1698,2385,2251,3729,1365,2281,2235,1717,6188, 864,3841,2515, 444, 527,2767, # 4352 +2922,3625, 544, 461,6189, 566, 209,2437,3398,2098,1065,2068,3331,3626,3257,2137, # 4368 #last 512 +#Everything below is of no interest for detection purpose +2138,2122,3730,2888,1995,1820,1044,6190,6191,6192,6193,6194,6195,6196,6197,6198, # 4384 +6199,6200,6201,6202,6203,6204,6205,4670,6206,6207,6208,6209,6210,6211,6212,6213, # 4400 +6214,6215,6216,6217,6218,6219,6220,6221,6222,6223,6224,6225,6226,6227,6228,6229, # 4416 +6230,6231,6232,6233,6234,6235,6236,6237,3187,6238,6239,3969,6240,6241,6242,6243, # 4432 +6244,4671,6245,6246,4672,6247,6248,4133,6249,6250,4364,6251,2923,2556,2613,4673, # 4448 +4365,3970,6252,6253,6254,6255,4674,6256,6257,6258,2768,2353,4366,4675,4676,3188, # 4464 +4367,3463,6259,4134,4677,4678,6260,2267,6261,3842,3332,4368,3543,6262,6263,6264, # 4480 +3013,1954,1928,4135,4679,6265,6266,2478,3091,6267,4680,4369,6268,6269,1699,6270, # 4496 +3544,4136,4681,6271,4137,6272,4370,2804,6273,6274,2593,3971,3972,4682,6275,2236, # 4512 +4683,6276,6277,4684,6278,6279,4138,3973,4685,6280,6281,3258,6282,6283,6284,6285, # 4528 +3974,4686,2841,3975,6286,6287,3545,6288,6289,4139,4687,4140,6290,4141,6291,4142, # 4544 +6292,6293,3333,6294,6295,6296,4371,6297,3399,6298,6299,4372,3976,6300,6301,6302, # 4560 +4373,6303,6304,3843,3731,6305,4688,4374,6306,6307,3259,2294,6308,3732,2530,4143, # 4576 +6309,4689,6310,6311,6312,3048,6313,6314,4690,3733,2237,6315,6316,2282,3334,6317, # 4592 +6318,3844,6319,6320,4691,6321,3400,4692,6322,4693,6323,3049,6324,4375,6325,3977, # 4608 +6326,6327,6328,3546,6329,4694,3335,6330,4695,4696,6331,6332,6333,6334,4376,3978, # 4624 +6335,4697,3979,4144,6336,3980,4698,6337,6338,6339,6340,6341,4699,4700,4701,6342, # 4640 +6343,4702,6344,6345,4703,6346,6347,4704,6348,4705,4706,3135,6349,4707,6350,4708, # 4656 +6351,4377,6352,4709,3734,4145,6353,2506,4710,3189,6354,3050,4711,3981,6355,3547, # 4672 +3014,4146,4378,3735,2651,3845,3260,3136,2224,1986,6356,3401,6357,4712,2594,3627, # 4688 +3137,2573,3736,3982,4713,3628,4714,4715,2682,3629,4716,6358,3630,4379,3631,6359, # 4704 +6360,6361,3983,6362,6363,6364,6365,4147,3846,4717,6366,6367,3737,2842,6368,4718, # 4720 +2628,6369,3261,6370,2386,6371,6372,3738,3984,4719,3464,4720,3402,6373,2924,3336, # 4736 +4148,2866,6374,2805,3262,4380,2704,2069,2531,3138,2806,2984,6375,2769,6376,4721, # 4752 +4722,3403,6377,6378,3548,6379,6380,2705,3092,1979,4149,2629,3337,2889,6381,3338, # 4768 +4150,2557,3339,4381,6382,3190,3263,3739,6383,4151,4723,4152,2558,2574,3404,3191, # 4784 +6384,6385,4153,6386,4724,4382,6387,6388,4383,6389,6390,4154,6391,4725,3985,6392, # 4800 +3847,4155,6393,6394,6395,6396,6397,3465,6398,4384,6399,6400,6401,6402,6403,6404, # 4816 +4156,6405,6406,6407,6408,2123,6409,6410,2326,3192,4726,6411,6412,6413,6414,4385, # 4832 +4157,6415,6416,4158,6417,3093,3848,6418,3986,6419,6420,3849,6421,6422,6423,4159, # 4848 +6424,6425,4160,6426,3740,6427,6428,6429,6430,3987,6431,4727,6432,2238,6433,6434, # 4864 +4386,3988,6435,6436,3632,6437,6438,2843,6439,6440,6441,6442,3633,6443,2958,6444, # 4880 +6445,3466,6446,2364,4387,3850,6447,4388,2959,3340,6448,3851,6449,4728,6450,6451, # 4896 +3264,4729,6452,3193,6453,4389,4390,2706,3341,4730,6454,3139,6455,3194,6456,3051, # 4912 +2124,3852,1602,4391,4161,3853,1158,3854,4162,3989,4392,3990,4731,4732,4393,2040, # 4928 +4163,4394,3265,6457,2807,3467,3855,6458,6459,6460,3991,3468,4733,4734,6461,3140, # 4944 +2960,6462,4735,6463,6464,6465,6466,4736,4737,4738,4739,6467,6468,4164,2403,3856, # 4960 +6469,6470,2770,2844,6471,4740,6472,6473,6474,6475,6476,6477,6478,3195,6479,4741, # 4976 +4395,6480,2867,6481,4742,2808,6482,2493,4165,6483,6484,6485,6486,2295,4743,6487, # 4992 +6488,6489,3634,6490,6491,6492,6493,6494,6495,6496,2985,4744,6497,6498,4745,6499, # 5008 +6500,2925,3141,4166,6501,6502,4746,6503,6504,4747,6505,6506,6507,2890,6508,6509, # 5024 +6510,6511,6512,6513,6514,6515,6516,6517,6518,6519,3469,4167,6520,6521,6522,4748, # 5040 +4396,3741,4397,4749,4398,3342,2125,4750,6523,4751,4752,4753,3052,6524,2961,4168, # 5056 +6525,4754,6526,4755,4399,2926,4169,6527,3857,6528,4400,4170,6529,4171,6530,6531, # 5072 +2595,6532,6533,6534,6535,3635,6536,6537,6538,6539,6540,6541,6542,4756,6543,6544, # 5088 +6545,6546,6547,6548,4401,6549,6550,6551,6552,4402,3405,4757,4403,6553,6554,6555, # 5104 +4172,3742,6556,6557,6558,3992,3636,6559,6560,3053,2726,6561,3549,4173,3054,4404, # 5120 +6562,6563,3993,4405,3266,3550,2809,4406,6564,6565,6566,4758,4759,6567,3743,6568, # 5136 +4760,3744,4761,3470,6569,6570,6571,4407,6572,3745,4174,6573,4175,2810,4176,3196, # 5152 +4762,6574,4177,6575,6576,2494,2891,3551,6577,6578,3471,6579,4408,6580,3015,3197, # 5168 +6581,3343,2532,3994,3858,6582,3094,3406,4409,6583,2892,4178,4763,4410,3016,4411, # 5184 +6584,3995,3142,3017,2683,6585,4179,6586,6587,4764,4412,6588,6589,4413,6590,2986, # 5200 +6591,2962,3552,6592,2963,3472,6593,6594,4180,4765,6595,6596,2225,3267,4414,6597, # 5216 +3407,3637,4766,6598,6599,3198,6600,4415,6601,3859,3199,6602,3473,4767,2811,4416, # 5232 +1856,3268,3200,2575,3996,3997,3201,4417,6603,3095,2927,6604,3143,6605,2268,6606, # 5248 +3998,3860,3096,2771,6607,6608,3638,2495,4768,6609,3861,6610,3269,2745,4769,4181, # 5264 +3553,6611,2845,3270,6612,6613,6614,3862,6615,6616,4770,4771,6617,3474,3999,4418, # 5280 +4419,6618,3639,3344,6619,4772,4182,6620,2126,6621,6622,6623,4420,4773,6624,3018, # 5296 +6625,4774,3554,6626,4183,2025,3746,6627,4184,2707,6628,4421,4422,3097,1775,4185, # 5312 +3555,6629,6630,2868,6631,6632,4423,6633,6634,4424,2414,2533,2928,6635,4186,2387, # 5328 +6636,4775,6637,4187,6638,1891,4425,3202,3203,6639,6640,4776,6641,3345,6642,6643, # 5344 +3640,6644,3475,3346,3641,4000,6645,3144,6646,3098,2812,4188,3642,3204,6647,3863, # 5360 +3476,6648,3864,6649,4426,4001,6650,6651,6652,2576,6653,4189,4777,6654,6655,6656, # 5376 +2846,6657,3477,3205,4002,6658,4003,6659,3347,2252,6660,6661,6662,4778,6663,6664, # 5392 +6665,6666,6667,6668,6669,4779,4780,2048,6670,3478,3099,6671,3556,3747,4004,6672, # 5408 +6673,6674,3145,4005,3748,6675,6676,6677,6678,6679,3408,6680,6681,6682,6683,3206, # 5424 +3207,6684,6685,4781,4427,6686,4782,4783,4784,6687,6688,6689,4190,6690,6691,3479, # 5440 +6692,2746,6693,4428,6694,6695,6696,6697,6698,6699,4785,6700,6701,3208,2727,6702, # 5456 +3146,6703,6704,3409,2196,6705,4429,6706,6707,6708,2534,1996,6709,6710,6711,2747, # 5472 +6712,6713,6714,4786,3643,6715,4430,4431,6716,3557,6717,4432,4433,6718,6719,6720, # 5488 +6721,3749,6722,4006,4787,6723,6724,3644,4788,4434,6725,6726,4789,2772,6727,6728, # 5504 +6729,6730,6731,2708,3865,2813,4435,6732,6733,4790,4791,3480,6734,6735,6736,6737, # 5520 +4436,3348,6738,3410,4007,6739,6740,4008,6741,6742,4792,3411,4191,6743,6744,6745, # 5536 +6746,6747,3866,6748,3750,6749,6750,6751,6752,6753,6754,6755,3867,6756,4009,6757, # 5552 +4793,4794,6758,2814,2987,6759,6760,6761,4437,6762,6763,6764,6765,3645,6766,6767, # 5568 +3481,4192,6768,3751,6769,6770,2174,6771,3868,3752,6772,6773,6774,4193,4795,4438, # 5584 +3558,4796,4439,6775,4797,6776,6777,4798,6778,4799,3559,4800,6779,6780,6781,3482, # 5600 +6782,2893,6783,6784,4194,4801,4010,6785,6786,4440,6787,4011,6788,6789,6790,6791, # 5616 +6792,6793,4802,6794,6795,6796,4012,6797,6798,6799,6800,3349,4803,3483,6801,4804, # 5632 +4195,6802,4013,6803,6804,4196,6805,4014,4015,6806,2847,3271,2848,6807,3484,6808, # 5648 +6809,6810,4441,6811,4442,4197,4443,3272,4805,6812,3412,4016,1579,6813,6814,4017, # 5664 +6815,3869,6816,2964,6817,4806,6818,6819,4018,3646,6820,6821,4807,4019,4020,6822, # 5680 +6823,3560,6824,6825,4021,4444,6826,4198,6827,6828,4445,6829,6830,4199,4808,6831, # 5696 +6832,6833,3870,3019,2458,6834,3753,3413,3350,6835,4809,3871,4810,3561,4446,6836, # 5712 +6837,4447,4811,4812,6838,2459,4448,6839,4449,6840,6841,4022,3872,6842,4813,4814, # 5728 +6843,6844,4815,4200,4201,4202,6845,4023,6846,6847,4450,3562,3873,6848,6849,4816, # 5744 +4817,6850,4451,4818,2139,6851,3563,6852,6853,3351,6854,6855,3352,4024,2709,3414, # 5760 +4203,4452,6856,4204,6857,6858,3874,3875,6859,6860,4819,6861,6862,6863,6864,4453, # 5776 +3647,6865,6866,4820,6867,6868,6869,6870,4454,6871,2869,6872,6873,4821,6874,3754, # 5792 +6875,4822,4205,6876,6877,6878,3648,4206,4455,6879,4823,6880,4824,3876,6881,3055, # 5808 +4207,6882,3415,6883,6884,6885,4208,4209,6886,4210,3353,6887,3354,3564,3209,3485, # 5824 +2652,6888,2728,6889,3210,3755,6890,4025,4456,6891,4825,6892,6893,6894,6895,4211, # 5840 +6896,6897,6898,4826,6899,6900,4212,6901,4827,6902,2773,3565,6903,4828,6904,6905, # 5856 +6906,6907,3649,3650,6908,2849,3566,6909,3567,3100,6910,6911,6912,6913,6914,6915, # 5872 +4026,6916,3355,4829,3056,4457,3756,6917,3651,6918,4213,3652,2870,6919,4458,6920, # 5888 +2438,6921,6922,3757,2774,4830,6923,3356,4831,4832,6924,4833,4459,3653,2507,6925, # 5904 +4834,2535,6926,6927,3273,4027,3147,6928,3568,6929,6930,6931,4460,6932,3877,4461, # 5920 +2729,3654,6933,6934,6935,6936,2175,4835,2630,4214,4028,4462,4836,4215,6937,3148, # 5936 +4216,4463,4837,4838,4217,6938,6939,2850,4839,6940,4464,6941,6942,6943,4840,6944, # 5952 +4218,3274,4465,6945,6946,2710,6947,4841,4466,6948,6949,2894,6950,6951,4842,6952, # 5968 +4219,3057,2871,6953,6954,6955,6956,4467,6957,2711,6958,6959,6960,3275,3101,4843, # 5984 +6961,3357,3569,6962,4844,6963,6964,4468,4845,3570,6965,3102,4846,3758,6966,4847, # 6000 +3878,4848,4849,4029,6967,2929,3879,4850,4851,6968,6969,1733,6970,4220,6971,6972, # 6016 +6973,6974,6975,6976,4852,6977,6978,6979,6980,6981,6982,3759,6983,6984,6985,3486, # 6032 +3487,6986,3488,3416,6987,6988,6989,6990,6991,6992,6993,6994,6995,6996,6997,4853, # 6048 +6998,6999,4030,7000,7001,3211,7002,7003,4221,7004,7005,3571,4031,7006,3572,7007, # 6064 +2614,4854,2577,7008,7009,2965,3655,3656,4855,2775,3489,3880,4222,4856,3881,4032, # 6080 +3882,3657,2730,3490,4857,7010,3149,7011,4469,4858,2496,3491,4859,2283,7012,7013, # 6096 +7014,2365,4860,4470,7015,7016,3760,7017,7018,4223,1917,7019,7020,7021,4471,7022, # 6112 +2776,4472,7023,7024,7025,7026,4033,7027,3573,4224,4861,4034,4862,7028,7029,1929, # 6128 +3883,4035,7030,4473,3058,7031,2536,3761,3884,7032,4036,7033,2966,2895,1968,4474, # 6144 +3276,4225,3417,3492,4226,2105,7034,7035,1754,2596,3762,4227,4863,4475,3763,4864, # 6160 +3764,2615,2777,3103,3765,3658,3418,4865,2296,3766,2815,7036,7037,7038,3574,2872, # 6176 +3277,4476,7039,4037,4477,7040,7041,4038,7042,7043,7044,7045,7046,7047,2537,7048, # 6192 +7049,7050,7051,7052,7053,7054,4478,7055,7056,3767,3659,4228,3575,7057,7058,4229, # 6208 +7059,7060,7061,3660,7062,3212,7063,3885,4039,2460,7064,7065,7066,7067,7068,7069, # 6224 +7070,7071,7072,7073,7074,4866,3768,4867,7075,7076,7077,7078,4868,3358,3278,2653, # 6240 +7079,7080,4479,3886,7081,7082,4869,7083,7084,7085,7086,7087,7088,2538,7089,7090, # 6256 +7091,4040,3150,3769,4870,4041,2896,3359,4230,2930,7092,3279,7093,2967,4480,3213, # 6272 +4481,3661,7094,7095,7096,7097,7098,7099,7100,7101,7102,2461,3770,7103,7104,4231, # 6288 +3151,7105,7106,7107,4042,3662,7108,7109,4871,3663,4872,4043,3059,7110,7111,7112, # 6304 +3493,2988,7113,4873,7114,7115,7116,3771,4874,7117,7118,4232,4875,7119,3576,2336, # 6320 +4876,7120,4233,3419,4044,4877,4878,4482,4483,4879,4484,4234,7121,3772,4880,1045, # 6336 +3280,3664,4881,4882,7122,7123,7124,7125,4883,7126,2778,7127,4485,4486,7128,4884, # 6352 +3214,3887,7129,7130,3215,7131,4885,4045,7132,7133,4046,7134,7135,7136,7137,7138, # 6368 +7139,7140,7141,7142,7143,4235,7144,4886,7145,7146,7147,4887,7148,7149,7150,4487, # 6384 +4047,4488,7151,7152,4888,4048,2989,3888,7153,3665,7154,4049,7155,7156,7157,7158, # 6400 +7159,7160,2931,4889,4890,4489,7161,2631,3889,4236,2779,7162,7163,4891,7164,3060, # 6416 +7165,1672,4892,7166,4893,4237,3281,4894,7167,7168,3666,7169,3494,7170,7171,4050, # 6432 +7172,7173,3104,3360,3420,4490,4051,2684,4052,7174,4053,7175,7176,7177,2253,4054, # 6448 +7178,7179,4895,7180,3152,3890,3153,4491,3216,7181,7182,7183,2968,4238,4492,4055, # 6464 +7184,2990,7185,2479,7186,7187,4493,7188,7189,7190,7191,7192,4896,7193,4897,2969, # 6480 +4494,4898,7194,3495,7195,7196,4899,4495,7197,3105,2731,7198,4900,7199,7200,7201, # 6496 +4056,7202,3361,7203,7204,4496,4901,4902,7205,4497,7206,7207,2315,4903,7208,4904, # 6512 +7209,4905,2851,7210,7211,3577,7212,3578,4906,7213,4057,3667,4907,7214,4058,2354, # 6528 +3891,2376,3217,3773,7215,7216,7217,7218,7219,4498,7220,4908,3282,2685,7221,3496, # 6544 +4909,2632,3154,4910,7222,2337,7223,4911,7224,7225,7226,4912,4913,3283,4239,4499, # 6560 +7227,2816,7228,7229,7230,7231,7232,7233,7234,4914,4500,4501,7235,7236,7237,2686, # 6576 +7238,4915,7239,2897,4502,7240,4503,7241,2516,7242,4504,3362,3218,7243,7244,7245, # 6592 +4916,7246,7247,4505,3363,7248,7249,7250,7251,3774,4506,7252,7253,4917,7254,7255, # 6608 +3284,2991,4918,4919,3219,3892,4920,3106,3497,4921,7256,7257,7258,4922,7259,4923, # 6624 +3364,4507,4508,4059,7260,4240,3498,7261,7262,4924,7263,2992,3893,4060,3220,7264, # 6640 +7265,7266,7267,7268,7269,4509,3775,7270,2817,7271,4061,4925,4510,3776,7272,4241, # 6656 +4511,3285,7273,7274,3499,7275,7276,7277,4062,4512,4926,7278,3107,3894,7279,7280, # 6672 +4927,7281,4513,7282,7283,3668,7284,7285,4242,4514,4243,7286,2058,4515,4928,4929, # 6688 +4516,7287,3286,4244,7288,4517,7289,7290,7291,3669,7292,7293,4930,4931,4932,2355, # 6704 +4933,7294,2633,4518,7295,4245,7296,7297,4519,7298,7299,4520,4521,4934,7300,4246, # 6720 +4522,7301,7302,7303,3579,7304,4247,4935,7305,4936,7306,7307,7308,7309,3777,7310, # 6736 +4523,7311,7312,7313,4248,3580,7314,4524,3778,4249,7315,3581,7316,3287,7317,3221, # 6752 +7318,4937,7319,7320,7321,7322,7323,7324,4938,4939,7325,4525,7326,7327,7328,4063, # 6768 +7329,7330,4940,7331,7332,4941,7333,4526,7334,3500,2780,1741,4942,2026,1742,7335, # 6784 +7336,3582,4527,2388,7337,7338,7339,4528,7340,4250,4943,7341,7342,7343,4944,7344, # 6800 +7345,7346,3020,7347,4945,7348,7349,7350,7351,3895,7352,3896,4064,3897,7353,7354, # 6816 +7355,4251,7356,7357,3898,7358,3779,7359,3780,3288,7360,7361,4529,7362,4946,4530, # 6832 +2027,7363,3899,4531,4947,3222,3583,7364,4948,7365,7366,7367,7368,4949,3501,4950, # 6848 +3781,4951,4532,7369,2517,4952,4252,4953,3155,7370,4954,4955,4253,2518,4533,7371, # 6864 +7372,2712,4254,7373,7374,7375,3670,4956,3671,7376,2389,3502,4065,7377,2338,7378, # 6880 +7379,7380,7381,3061,7382,4957,7383,7384,7385,7386,4958,4534,7387,7388,2993,7389, # 6896 +3062,7390,4959,7391,7392,7393,4960,3108,4961,7394,4535,7395,4962,3421,4536,7396, # 6912 +4963,7397,4964,1857,7398,4965,7399,7400,2176,3584,4966,7401,7402,3422,4537,3900, # 6928 +3585,7403,3782,7404,2852,7405,7406,7407,4538,3783,2654,3423,4967,4539,7408,3784, # 6944 +3586,2853,4540,4541,7409,3901,7410,3902,7411,7412,3785,3109,2327,3903,7413,7414, # 6960 +2970,4066,2932,7415,7416,7417,3904,3672,3424,7418,4542,4543,4544,7419,4968,7420, # 6976 +7421,4255,7422,7423,7424,7425,7426,4067,7427,3673,3365,4545,7428,3110,2559,3674, # 6992 +7429,7430,3156,7431,7432,3503,7433,3425,4546,7434,3063,2873,7435,3223,4969,4547, # 7008 +4548,2898,4256,4068,7436,4069,3587,3786,2933,3787,4257,4970,4971,3788,7437,4972, # 7024 +3064,7438,4549,7439,7440,7441,7442,7443,4973,3905,7444,2874,7445,7446,7447,7448, # 7040 +3021,7449,4550,3906,3588,4974,7450,7451,3789,3675,7452,2578,7453,4070,7454,7455, # 7056 +7456,4258,3676,7457,4975,7458,4976,4259,3790,3504,2634,4977,3677,4551,4260,7459, # 7072 +7460,7461,7462,3907,4261,4978,7463,7464,7465,7466,4979,4980,7467,7468,2213,4262, # 7088 +7469,7470,7471,3678,4981,7472,2439,7473,4263,3224,3289,7474,3908,2415,4982,7475, # 7104 +4264,7476,4983,2655,7477,7478,2732,4552,2854,2875,7479,7480,4265,7481,4553,4984, # 7120 +7482,7483,4266,7484,3679,3366,3680,2818,2781,2782,3367,3589,4554,3065,7485,4071, # 7136 +2899,7486,7487,3157,2462,4072,4555,4073,4985,4986,3111,4267,2687,3368,4556,4074, # 7152 +3791,4268,7488,3909,2783,7489,2656,1962,3158,4557,4987,1963,3159,3160,7490,3112, # 7168 +4988,4989,3022,4990,4991,3792,2855,7491,7492,2971,4558,7493,7494,4992,7495,7496, # 7184 +7497,7498,4993,7499,3426,4559,4994,7500,3681,4560,4269,4270,3910,7501,4075,4995, # 7200 +4271,7502,7503,4076,7504,4996,7505,3225,4997,4272,4077,2819,3023,7506,7507,2733, # 7216 +4561,7508,4562,7509,3369,3793,7510,3590,2508,7511,7512,4273,3113,2994,2616,7513, # 7232 +7514,7515,7516,7517,7518,2820,3911,4078,2748,7519,7520,4563,4998,7521,7522,7523, # 7248 +7524,4999,4274,7525,4564,3682,2239,4079,4565,7526,7527,7528,7529,5000,7530,7531, # 7264 +5001,4275,3794,7532,7533,7534,3066,5002,4566,3161,7535,7536,4080,7537,3162,7538, # 7280 +7539,4567,7540,7541,7542,7543,7544,7545,5003,7546,4568,7547,7548,7549,7550,7551, # 7296 +7552,7553,7554,7555,7556,5004,7557,7558,7559,5005,7560,3795,7561,4569,7562,7563, # 7312 +7564,2821,3796,4276,4277,4081,7565,2876,7566,5006,7567,7568,2900,7569,3797,3912, # 7328 +7570,7571,7572,4278,7573,7574,7575,5007,7576,7577,5008,7578,7579,4279,2934,7580, # 7344 +7581,5009,7582,4570,7583,4280,7584,7585,7586,4571,4572,3913,7587,4573,3505,7588, # 7360 +5010,7589,7590,7591,7592,3798,4574,7593,7594,5011,7595,4281,7596,7597,7598,4282, # 7376 +5012,7599,7600,5013,3163,7601,5014,7602,3914,7603,7604,2734,4575,4576,4577,7605, # 7392 +7606,7607,7608,7609,3506,5015,4578,7610,4082,7611,2822,2901,2579,3683,3024,4579, # 7408 +3507,7612,4580,7613,3226,3799,5016,7614,7615,7616,7617,7618,7619,7620,2995,3290, # 7424 +7621,4083,7622,5017,7623,7624,7625,7626,7627,4581,3915,7628,3291,7629,5018,7630, # 7440 +7631,7632,7633,4084,7634,7635,3427,3800,7636,7637,4582,7638,5019,4583,5020,7639, # 7456 +3916,7640,3801,5021,4584,4283,7641,7642,3428,3591,2269,7643,2617,7644,4585,3592, # 7472 +7645,4586,2902,7646,7647,3227,5022,7648,4587,7649,4284,7650,7651,7652,4588,2284, # 7488 +7653,5023,7654,7655,7656,4589,5024,3802,7657,7658,5025,3508,4590,7659,7660,7661, # 7504 +1969,5026,7662,7663,3684,1821,2688,7664,2028,2509,4285,7665,2823,1841,7666,2689, # 7520 +3114,7667,3917,4085,2160,5027,5028,2972,7668,5029,7669,7670,7671,3593,4086,7672, # 7536 +4591,4087,5030,3803,7673,7674,7675,7676,7677,7678,7679,4286,2366,4592,4593,3067, # 7552 +2328,7680,7681,4594,3594,3918,2029,4287,7682,5031,3919,3370,4288,4595,2856,7683, # 7568 +3509,7684,7685,5032,5033,7686,7687,3804,2784,7688,7689,7690,7691,3371,7692,7693, # 7584 +2877,5034,7694,7695,3920,4289,4088,7696,7697,7698,5035,7699,5036,4290,5037,5038, # 7600 +5039,7700,7701,7702,5040,5041,3228,7703,1760,7704,5042,3229,4596,2106,4089,7705, # 7616 +4597,2824,5043,2107,3372,7706,4291,4090,5044,7707,4091,7708,5045,3025,3805,4598, # 7632 +4292,4293,4294,3373,7709,4599,7710,5046,7711,7712,5047,5048,3806,7713,7714,7715, # 7648 +5049,7716,7717,7718,7719,4600,5050,7720,7721,7722,5051,7723,4295,3429,7724,7725, # 7664 +7726,7727,3921,7728,3292,5052,4092,7729,7730,7731,7732,7733,7734,7735,5053,5054, # 7680 +7736,7737,7738,7739,3922,3685,7740,7741,7742,7743,2635,5055,7744,5056,4601,7745, # 7696 +7746,2560,7747,7748,7749,7750,3923,7751,7752,7753,7754,7755,4296,2903,7756,7757, # 7712 +7758,7759,7760,3924,7761,5057,4297,7762,7763,5058,4298,7764,4093,7765,7766,5059, # 7728 +3925,7767,7768,7769,7770,7771,7772,7773,7774,7775,7776,3595,7777,4299,5060,4094, # 7744 +7778,3293,5061,7779,7780,4300,7781,7782,4602,7783,3596,7784,7785,3430,2367,7786, # 7760 +3164,5062,5063,4301,7787,7788,4095,5064,5065,7789,3374,3115,7790,7791,7792,7793, # 7776 +7794,7795,7796,3597,4603,7797,7798,3686,3116,3807,5066,7799,7800,5067,7801,7802, # 7792 +4604,4302,5068,4303,4096,7803,7804,3294,7805,7806,5069,4605,2690,7807,3026,7808, # 7808 +7809,7810,7811,7812,7813,7814,7815,7816,7817,7818,7819,7820,7821,7822,7823,7824, # 7824 +7825,7826,7827,7828,7829,7830,7831,7832,7833,7834,7835,7836,7837,7838,7839,7840, # 7840 +7841,7842,7843,7844,7845,7846,7847,7848,7849,7850,7851,7852,7853,7854,7855,7856, # 7856 +7857,7858,7859,7860,7861,7862,7863,7864,7865,7866,7867,7868,7869,7870,7871,7872, # 7872 +7873,7874,7875,7876,7877,7878,7879,7880,7881,7882,7883,7884,7885,7886,7887,7888, # 7888 +7889,7890,7891,7892,7893,7894,7895,7896,7897,7898,7899,7900,7901,7902,7903,7904, # 7904 +7905,7906,7907,7908,7909,7910,7911,7912,7913,7914,7915,7916,7917,7918,7919,7920, # 7920 +7921,7922,7923,7924,3926,7925,7926,7927,7928,7929,7930,7931,7932,7933,7934,7935, # 7936 +7936,7937,7938,7939,7940,7941,7942,7943,7944,7945,7946,7947,7948,7949,7950,7951, # 7952 +7952,7953,7954,7955,7956,7957,7958,7959,7960,7961,7962,7963,7964,7965,7966,7967, # 7968 +7968,7969,7970,7971,7972,7973,7974,7975,7976,7977,7978,7979,7980,7981,7982,7983, # 7984 +7984,7985,7986,7987,7988,7989,7990,7991,7992,7993,7994,7995,7996,7997,7998,7999, # 8000 +8000,8001,8002,8003,8004,8005,8006,8007,8008,8009,8010,8011,8012,8013,8014,8015, # 8016 +8016,8017,8018,8019,8020,8021,8022,8023,8024,8025,8026,8027,8028,8029,8030,8031, # 8032 +8032,8033,8034,8035,8036,8037,8038,8039,8040,8041,8042,8043,8044,8045,8046,8047, # 8048 +8048,8049,8050,8051,8052,8053,8054,8055,8056,8057,8058,8059,8060,8061,8062,8063, # 8064 +8064,8065,8066,8067,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079, # 8080 +8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095, # 8096 +8096,8097,8098,8099,8100,8101,8102,8103,8104,8105,8106,8107,8108,8109,8110,8111, # 8112 +8112,8113,8114,8115,8116,8117,8118,8119,8120,8121,8122,8123,8124,8125,8126,8127, # 8128 +8128,8129,8130,8131,8132,8133,8134,8135,8136,8137,8138,8139,8140,8141,8142,8143, # 8144 +8144,8145,8146,8147,8148,8149,8150,8151,8152,8153,8154,8155,8156,8157,8158,8159, # 8160 +8160,8161,8162,8163,8164,8165,8166,8167,8168,8169,8170,8171,8172,8173,8174,8175, # 8176 +8176,8177,8178,8179,8180,8181,8182,8183,8184,8185,8186,8187,8188,8189,8190,8191, # 8192 +8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8203,8204,8205,8206,8207, # 8208 +8208,8209,8210,8211,8212,8213,8214,8215,8216,8217,8218,8219,8220,8221,8222,8223, # 8224 +8224,8225,8226,8227,8228,8229,8230,8231,8232,8233,8234,8235,8236,8237,8238,8239, # 8240 +8240,8241,8242,8243,8244,8245,8246,8247,8248,8249,8250,8251,8252,8253,8254,8255, # 8256 +8256,8257,8258,8259,8260,8261,8262,8263,8264,8265,8266,8267,8268,8269,8270,8271) # 8272 diff --git a/libs/requests/packages/chardet/jpcntx.py b/libs/requests/packages/chardet/jpcntx.py new file mode 100755 index 00000000..93db4a9c --- /dev/null +++ b/libs/requests/packages/chardet/jpcntx.py @@ -0,0 +1,210 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import constants + +NUM_OF_CATEGORY = 6 +DONT_KNOW = -1 +ENOUGH_REL_THRESHOLD = 100 +MAX_REL_THRESHOLD = 1000 +MINIMUM_DATA_THRESHOLD = 4 + +# This is hiragana 2-char sequence table, the number in each cell represents its frequency category +jp2CharContext = ( \ +(0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1), +(2,4,0,4,0,3,0,4,0,3,4,4,4,2,4,3,3,4,3,2,3,3,4,2,3,3,3,2,4,1,4,3,3,1,5,4,3,4,3,4,3,5,3,0,3,5,4,2,0,3,1,0,3,3,0,3,3,0,1,1,0,4,3,0,3,3,0,4,0,2,0,3,5,5,5,5,4,0,4,1,0,3,4), +(0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2), +(0,4,0,5,0,5,0,4,0,4,5,4,4,3,5,3,5,1,5,3,4,3,4,4,3,4,3,3,4,3,5,4,4,3,5,5,3,5,5,5,3,5,5,3,4,5,5,3,1,3,2,0,3,4,0,4,2,0,4,2,1,5,3,2,3,5,0,4,0,2,0,5,4,4,5,4,5,0,4,0,0,4,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,4,0,3,0,3,0,4,5,4,3,3,3,3,4,3,5,4,4,3,5,4,4,3,4,3,4,4,4,4,5,3,4,4,3,4,5,5,4,5,5,1,4,5,4,3,0,3,3,1,3,3,0,4,4,0,3,3,1,5,3,3,3,5,0,4,0,3,0,4,4,3,4,3,3,0,4,1,1,3,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,4,0,3,0,3,0,4,0,3,4,4,3,2,2,1,2,1,3,1,3,3,3,3,3,4,3,1,3,3,5,3,3,0,4,3,0,5,4,3,3,5,4,4,3,4,4,5,0,1,2,0,1,2,0,2,2,0,1,0,0,5,2,2,1,4,0,3,0,1,0,4,4,3,5,4,3,0,2,1,0,4,3), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,5,0,4,0,2,1,4,4,2,4,1,4,2,4,2,4,3,3,3,4,3,3,3,3,1,4,2,3,3,3,1,4,4,1,1,1,4,3,3,2,0,2,4,3,2,0,3,3,0,3,1,1,0,0,0,3,3,0,4,2,2,3,4,0,4,0,3,0,4,4,5,3,4,4,0,3,0,0,1,4), +(1,4,0,4,0,4,0,4,0,3,5,4,4,3,4,3,5,4,3,3,4,3,5,4,4,4,4,3,4,2,4,3,3,1,5,4,3,2,4,5,4,5,5,4,4,5,4,4,0,3,2,2,3,3,0,4,3,1,3,2,1,4,3,3,4,5,0,3,0,2,0,4,5,5,4,5,4,0,4,0,0,5,4), +(0,5,0,5,0,4,0,3,0,4,4,3,4,3,3,3,4,0,4,4,4,3,4,3,4,3,3,1,4,2,4,3,4,0,5,4,1,4,5,4,4,5,3,2,4,3,4,3,2,4,1,3,3,3,2,3,2,0,4,3,3,4,3,3,3,4,0,4,0,3,0,4,5,4,4,4,3,0,4,1,0,1,3), +(0,3,1,4,0,3,0,2,0,3,4,4,3,1,4,2,3,3,4,3,4,3,4,3,4,4,3,2,3,1,5,4,4,1,4,4,3,5,4,4,3,5,5,4,3,4,4,3,1,2,3,1,2,2,0,3,2,0,3,1,0,5,3,3,3,4,3,3,3,3,4,4,4,4,5,4,2,0,3,3,2,4,3), +(0,2,0,3,0,1,0,1,0,0,3,2,0,0,2,0,1,0,2,1,3,3,3,1,2,3,1,0,1,0,4,2,1,1,3,3,0,4,3,3,1,4,3,3,0,3,3,2,0,0,0,0,1,0,0,2,0,0,0,0,0,4,1,0,2,3,2,2,2,1,3,3,3,4,4,3,2,0,3,1,0,3,3), +(0,4,0,4,0,3,0,3,0,4,4,4,3,3,3,3,3,3,4,3,4,2,4,3,4,3,3,2,4,3,4,5,4,1,4,5,3,5,4,5,3,5,4,0,3,5,5,3,1,3,3,2,2,3,0,3,4,1,3,3,2,4,3,3,3,4,0,4,0,3,0,4,5,4,4,5,3,0,4,1,0,3,4), +(0,2,0,3,0,3,0,0,0,2,2,2,1,0,1,0,0,0,3,0,3,0,3,0,1,3,1,0,3,1,3,3,3,1,3,3,3,0,1,3,1,3,4,0,0,3,1,1,0,3,2,0,0,0,0,1,3,0,1,0,0,3,3,2,0,3,0,0,0,0,0,3,4,3,4,3,3,0,3,0,0,2,3), +(2,3,0,3,0,2,0,1,0,3,3,4,3,1,3,1,1,1,3,1,4,3,4,3,3,3,0,0,3,1,5,4,3,1,4,3,2,5,5,4,4,4,4,3,3,4,4,4,0,2,1,1,3,2,0,1,2,0,0,1,0,4,1,3,3,3,0,3,0,1,0,4,4,4,5,5,3,0,2,0,0,4,4), +(0,2,0,1,0,3,1,3,0,2,3,3,3,0,3,1,0,0,3,0,3,2,3,1,3,2,1,1,0,0,4,2,1,0,2,3,1,4,3,2,0,4,4,3,1,3,1,3,0,1,0,0,1,0,0,0,1,0,0,0,0,4,1,1,1,2,0,3,0,0,0,3,4,2,4,3,2,0,1,0,0,3,3), +(0,1,0,4,0,5,0,4,0,2,4,4,2,3,3,2,3,3,5,3,3,3,4,3,4,2,3,0,4,3,3,3,4,1,4,3,2,1,5,5,3,4,5,1,3,5,4,2,0,3,3,0,1,3,0,4,2,0,1,3,1,4,3,3,3,3,0,3,0,1,0,3,4,4,4,5,5,0,3,0,1,4,5), +(0,2,0,3,0,3,0,0,0,2,3,1,3,0,4,0,1,1,3,0,3,4,3,2,3,1,0,3,3,2,3,1,3,0,2,3,0,2,1,4,1,2,2,0,0,3,3,0,0,2,0,0,0,1,0,0,0,0,2,2,0,3,2,1,3,3,0,2,0,2,0,0,3,3,1,2,4,0,3,0,2,2,3), +(2,4,0,5,0,4,0,4,0,2,4,4,4,3,4,3,3,3,1,2,4,3,4,3,4,4,5,0,3,3,3,3,2,0,4,3,1,4,3,4,1,4,4,3,3,4,4,3,1,2,3,0,4,2,0,4,1,0,3,3,0,4,3,3,3,4,0,4,0,2,0,3,5,3,4,5,2,0,3,0,0,4,5), +(0,3,0,4,0,1,0,1,0,1,3,2,2,1,3,0,3,0,2,0,2,0,3,0,2,0,0,0,1,0,1,1,0,0,3,1,0,0,0,4,0,3,1,0,2,1,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,4,2,2,3,1,0,3,0,0,0,1,4,4,4,3,0,0,4,0,0,1,4), +(1,4,1,5,0,3,0,3,0,4,5,4,4,3,5,3,3,4,4,3,4,1,3,3,3,3,2,1,4,1,5,4,3,1,4,4,3,5,4,4,3,5,4,3,3,4,4,4,0,3,3,1,2,3,0,3,1,0,3,3,0,5,4,4,4,4,4,4,3,3,5,4,4,3,3,5,4,0,3,2,0,4,4), +(0,2,0,3,0,1,0,0,0,1,3,3,3,2,4,1,3,0,3,1,3,0,2,2,1,1,0,0,2,0,4,3,1,0,4,3,0,4,4,4,1,4,3,1,1,3,3,1,0,2,0,0,1,3,0,0,0,0,2,0,0,4,3,2,4,3,5,4,3,3,3,4,3,3,4,3,3,0,2,1,0,3,3), +(0,2,0,4,0,3,0,2,0,2,5,5,3,4,4,4,4,1,4,3,3,0,4,3,4,3,1,3,3,2,4,3,0,3,4,3,0,3,4,4,2,4,4,0,4,5,3,3,2,2,1,1,1,2,0,1,5,0,3,3,2,4,3,3,3,4,0,3,0,2,0,4,4,3,5,5,0,0,3,0,2,3,3), +(0,3,0,4,0,3,0,1,0,3,4,3,3,1,3,3,3,0,3,1,3,0,4,3,3,1,1,0,3,0,3,3,0,0,4,4,0,1,5,4,3,3,5,0,3,3,4,3,0,2,0,1,1,1,0,1,3,0,1,2,1,3,3,2,3,3,0,3,0,1,0,1,3,3,4,4,1,0,1,2,2,1,3), +(0,1,0,4,0,4,0,3,0,1,3,3,3,2,3,1,1,0,3,0,3,3,4,3,2,4,2,0,1,0,4,3,2,0,4,3,0,5,3,3,2,4,4,4,3,3,3,4,0,1,3,0,0,1,0,0,1,0,0,0,0,4,2,3,3,3,0,3,0,0,0,4,4,4,5,3,2,0,3,3,0,3,5), +(0,2,0,3,0,0,0,3,0,1,3,0,2,0,0,0,1,0,3,1,1,3,3,0,0,3,0,0,3,0,2,3,1,0,3,1,0,3,3,2,0,4,2,2,0,2,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,2,1,2,0,1,0,1,0,0,0,1,3,1,2,0,0,0,1,0,0,1,4), +(0,3,0,3,0,5,0,1,0,2,4,3,1,3,3,2,1,1,5,2,1,0,5,1,2,0,0,0,3,3,2,2,3,2,4,3,0,0,3,3,1,3,3,0,2,5,3,4,0,3,3,0,1,2,0,2,2,0,3,2,0,2,2,3,3,3,0,2,0,1,0,3,4,4,2,5,4,0,3,0,0,3,5), +(0,3,0,3,0,3,0,1,0,3,3,3,3,0,3,0,2,0,2,1,1,0,2,0,1,0,0,0,2,1,0,0,1,0,3,2,0,0,3,3,1,2,3,1,0,3,3,0,0,1,0,0,0,0,0,2,0,0,0,0,0,2,3,1,2,3,0,3,0,1,0,3,2,1,0,4,3,0,1,1,0,3,3), +(0,4,0,5,0,3,0,3,0,4,5,5,4,3,5,3,4,3,5,3,3,2,5,3,4,4,4,3,4,3,4,5,5,3,4,4,3,4,4,5,4,4,4,3,4,5,5,4,2,3,4,2,3,4,0,3,3,1,4,3,2,4,3,3,5,5,0,3,0,3,0,5,5,5,5,4,4,0,4,0,1,4,4), +(0,4,0,4,0,3,0,3,0,3,5,4,4,2,3,2,5,1,3,2,5,1,4,2,3,2,3,3,4,3,3,3,3,2,5,4,1,3,3,5,3,4,4,0,4,4,3,1,1,3,1,0,2,3,0,2,3,0,3,0,0,4,3,1,3,4,0,3,0,2,0,4,4,4,3,4,5,0,4,0,0,3,4), +(0,3,0,3,0,3,1,2,0,3,4,4,3,3,3,0,2,2,4,3,3,1,3,3,3,1,1,0,3,1,4,3,2,3,4,4,2,4,4,4,3,4,4,3,2,4,4,3,1,3,3,1,3,3,0,4,1,0,2,2,1,4,3,2,3,3,5,4,3,3,5,4,4,3,3,0,4,0,3,2,2,4,4), +(0,2,0,1,0,0,0,0,0,1,2,1,3,0,0,0,0,0,2,0,1,2,1,0,0,1,0,0,0,0,3,0,0,1,0,1,1,3,1,0,0,0,1,1,0,1,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,1,2,2,0,3,4,0,0,0,1,1,0,0,1,0,0,0,0,0,1,1), +(0,1,0,0,0,1,0,0,0,0,4,0,4,1,4,0,3,0,4,0,3,0,4,0,3,0,3,0,4,1,5,1,4,0,0,3,0,5,0,5,2,0,1,0,0,0,2,1,4,0,1,3,0,0,3,0,0,3,1,1,4,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0), +(1,4,0,5,0,3,0,2,0,3,5,4,4,3,4,3,5,3,4,3,3,0,4,3,3,3,3,3,3,2,4,4,3,1,3,4,4,5,4,4,3,4,4,1,3,5,4,3,3,3,1,2,2,3,3,1,3,1,3,3,3,5,3,3,4,5,0,3,0,3,0,3,4,3,4,4,3,0,3,0,2,4,3), +(0,1,0,4,0,0,0,0,0,1,4,0,4,1,4,2,4,0,3,0,1,0,1,0,0,0,0,0,2,0,3,1,1,1,0,3,0,0,0,1,2,1,0,0,1,1,1,1,0,1,0,0,0,1,0,0,3,0,0,0,0,3,2,0,2,2,0,1,0,0,0,2,3,2,3,3,0,0,0,0,2,1,0), +(0,5,1,5,0,3,0,3,0,5,4,4,5,1,5,3,3,0,4,3,4,3,5,3,4,3,3,2,4,3,4,3,3,0,3,3,1,4,4,3,4,4,4,3,4,5,5,3,2,3,1,1,3,3,1,3,1,1,3,3,2,4,5,3,3,5,0,4,0,3,0,4,4,3,5,3,3,0,3,4,0,4,3), +(0,5,0,5,0,3,0,2,0,4,4,3,5,2,4,3,3,3,4,4,4,3,5,3,5,3,3,1,4,0,4,3,3,0,3,3,0,4,4,4,4,5,4,3,3,5,5,3,2,3,1,2,3,2,0,1,0,0,3,2,2,4,4,3,1,5,0,4,0,3,0,4,3,1,3,2,1,0,3,3,0,3,3), +(0,4,0,5,0,5,0,4,0,4,5,5,5,3,4,3,3,2,5,4,4,3,5,3,5,3,4,0,4,3,4,4,3,2,4,4,3,4,5,4,4,5,5,0,3,5,5,4,1,3,3,2,3,3,1,3,1,0,4,3,1,4,4,3,4,5,0,4,0,2,0,4,3,4,4,3,3,0,4,0,0,5,5), +(0,4,0,4,0,5,0,1,1,3,3,4,4,3,4,1,3,0,5,1,3,0,3,1,3,1,1,0,3,0,3,3,4,0,4,3,0,4,4,4,3,4,4,0,3,5,4,1,0,3,0,0,2,3,0,3,1,0,3,1,0,3,2,1,3,5,0,3,0,1,0,3,2,3,3,4,4,0,2,2,0,4,4), +(2,4,0,5,0,4,0,3,0,4,5,5,4,3,5,3,5,3,5,3,5,2,5,3,4,3,3,4,3,4,5,3,2,1,5,4,3,2,3,4,5,3,4,1,2,5,4,3,0,3,3,0,3,2,0,2,3,0,4,1,0,3,4,3,3,5,0,3,0,1,0,4,5,5,5,4,3,0,4,2,0,3,5), +(0,5,0,4,0,4,0,2,0,5,4,3,4,3,4,3,3,3,4,3,4,2,5,3,5,3,4,1,4,3,4,4,4,0,3,5,0,4,4,4,4,5,3,1,3,4,5,3,3,3,3,3,3,3,0,2,2,0,3,3,2,4,3,3,3,5,3,4,1,3,3,5,3,2,0,0,0,0,4,3,1,3,3), +(0,1,0,3,0,3,0,1,0,1,3,3,3,2,3,3,3,0,3,0,0,0,3,1,3,0,0,0,2,2,2,3,0,0,3,2,0,1,2,4,1,3,3,0,0,3,3,3,0,1,0,0,2,1,0,0,3,0,3,1,0,3,0,0,1,3,0,2,0,1,0,3,3,1,3,3,0,0,1,1,0,3,3), +(0,2,0,3,0,2,1,4,0,2,2,3,1,1,3,1,1,0,2,0,3,1,2,3,1,3,0,0,1,0,4,3,2,3,3,3,1,4,2,3,3,3,3,1,0,3,1,4,0,1,1,0,1,2,0,1,1,0,1,1,0,3,1,3,2,2,0,1,0,0,0,2,3,3,3,1,0,0,0,0,0,2,3), +(0,5,0,4,0,5,0,2,0,4,5,5,3,3,4,3,3,1,5,4,4,2,4,4,4,3,4,2,4,3,5,5,4,3,3,4,3,3,5,5,4,5,5,1,3,4,5,3,1,4,3,1,3,3,0,3,3,1,4,3,1,4,5,3,3,5,0,4,0,3,0,5,3,3,1,4,3,0,4,0,1,5,3), +(0,5,0,5,0,4,0,2,0,4,4,3,4,3,3,3,3,3,5,4,4,4,4,4,4,5,3,3,5,2,4,4,4,3,4,4,3,3,4,4,5,5,3,3,4,3,4,3,3,4,3,3,3,3,1,2,2,1,4,3,3,5,4,4,3,4,0,4,0,3,0,4,4,4,4,4,1,0,4,2,0,2,4), +(0,4,0,4,0,3,0,1,0,3,5,2,3,0,3,0,2,1,4,2,3,3,4,1,4,3,3,2,4,1,3,3,3,0,3,3,0,0,3,3,3,5,3,3,3,3,3,2,0,2,0,0,2,0,0,2,0,0,1,0,0,3,1,2,2,3,0,3,0,2,0,4,4,3,3,4,1,0,3,0,0,2,4), +(0,0,0,4,0,0,0,0,0,0,1,0,1,0,2,0,0,0,0,0,1,0,2,0,1,0,0,0,0,0,3,1,3,0,3,2,0,0,0,1,0,3,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,4,0,2,0,0,0,0,0,0,2), +(0,2,1,3,0,2,0,2,0,3,3,3,3,1,3,1,3,3,3,3,3,3,4,2,2,1,2,1,4,0,4,3,1,3,3,3,2,4,3,5,4,3,3,3,3,3,3,3,0,1,3,0,2,0,0,1,0,0,1,0,0,4,2,0,2,3,0,3,3,0,3,3,4,2,3,1,4,0,1,2,0,2,3), +(0,3,0,3,0,1,0,3,0,2,3,3,3,0,3,1,2,0,3,3,2,3,3,2,3,2,3,1,3,0,4,3,2,0,3,3,1,4,3,3,2,3,4,3,1,3,3,1,1,0,1,1,0,1,0,1,0,1,0,0,0,4,1,1,0,3,0,3,1,0,2,3,3,3,3,3,1,0,0,2,0,3,3), +(0,0,0,0,0,0,0,0,0,0,3,0,2,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,3,0,3,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,2,0,2,3,0,0,0,0,0,0,0,0,3), +(0,2,0,3,1,3,0,3,0,2,3,3,3,1,3,1,3,1,3,1,3,3,3,1,3,0,2,3,1,1,4,3,3,2,3,3,1,2,2,4,1,3,3,0,1,4,2,3,0,1,3,0,3,0,0,1,3,0,2,0,0,3,3,2,1,3,0,3,0,2,0,3,4,4,4,3,1,0,3,0,0,3,3), +(0,2,0,1,0,2,0,0,0,1,3,2,2,1,3,0,1,1,3,0,3,2,3,1,2,0,2,0,1,1,3,3,3,0,3,3,1,1,2,3,2,3,3,1,2,3,2,0,0,1,0,0,0,0,0,0,3,0,1,0,0,2,1,2,1,3,0,3,0,0,0,3,4,4,4,3,2,0,2,0,0,2,4), +(0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,3,1,0,0,0,0,0,0,0,3), +(0,3,0,3,0,2,0,3,0,3,3,3,2,3,2,2,2,0,3,1,3,3,3,2,3,3,0,0,3,0,3,2,2,0,2,3,1,4,3,4,3,3,2,3,1,5,4,4,0,3,1,2,1,3,0,3,1,1,2,0,2,3,1,3,1,3,0,3,0,1,0,3,3,4,4,2,1,0,2,1,0,2,4), +(0,1,0,3,0,1,0,2,0,1,4,2,5,1,4,0,2,0,2,1,3,1,4,0,2,1,0,0,2,1,4,1,1,0,3,3,0,5,1,3,2,3,3,1,0,3,2,3,0,1,0,0,0,0,0,0,1,0,0,0,0,4,0,1,0,3,0,2,0,1,0,3,3,3,4,3,3,0,0,0,0,2,3), +(0,0,0,1,0,0,0,0,0,0,2,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,1,0,0,0,0,0,3), +(0,1,0,3,0,4,0,3,0,2,4,3,1,0,3,2,2,1,3,1,2,2,3,1,1,1,2,1,3,0,1,2,0,1,3,2,1,3,0,5,5,1,0,0,1,3,2,1,0,3,0,0,1,0,0,0,0,0,3,4,0,1,1,1,3,2,0,2,0,1,0,2,3,3,1,2,3,0,1,0,1,0,4), +(0,0,0,1,0,3,0,3,0,2,2,1,0,0,4,0,3,0,3,1,3,0,3,0,3,0,1,0,3,0,3,1,3,0,3,3,0,0,1,2,1,1,1,0,1,2,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,2,2,1,2,0,0,2,0,0,0,0,2,3,3,3,3,0,0,0,0,1,4), +(0,0,0,3,0,3,0,0,0,0,3,1,1,0,3,0,1,0,2,0,1,0,0,0,0,0,0,0,1,0,3,0,2,0,2,3,0,0,2,2,3,1,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,2,3), +(2,4,0,5,0,5,0,4,0,3,4,3,3,3,4,3,3,3,4,3,4,4,5,4,5,5,5,2,3,0,5,5,4,1,5,4,3,1,5,4,3,4,4,3,3,4,3,3,0,3,2,0,2,3,0,3,0,0,3,3,0,5,3,2,3,3,0,3,0,3,0,3,4,5,4,5,3,0,4,3,0,3,4), +(0,3,0,3,0,3,0,3,0,3,3,4,3,2,3,2,3,0,4,3,3,3,3,3,3,3,3,0,3,2,4,3,3,1,3,4,3,4,4,4,3,4,4,3,2,4,4,1,0,2,0,0,1,1,0,2,0,0,3,1,0,5,3,2,1,3,0,3,0,1,2,4,3,2,4,3,3,0,3,2,0,4,4), +(0,3,0,3,0,1,0,0,0,1,4,3,3,2,3,1,3,1,4,2,3,2,4,2,3,4,3,0,2,2,3,3,3,0,3,3,3,0,3,4,1,3,3,0,3,4,3,3,0,1,1,0,1,0,0,0,4,0,3,0,0,3,1,2,1,3,0,4,0,1,0,4,3,3,4,3,3,0,2,0,0,3,3), +(0,3,0,4,0,1,0,3,0,3,4,3,3,0,3,3,3,1,3,1,3,3,4,3,3,3,0,0,3,1,5,3,3,1,3,3,2,5,4,3,3,4,5,3,2,5,3,4,0,1,0,0,0,0,0,2,0,0,1,1,0,4,2,2,1,3,0,3,0,2,0,4,4,3,5,3,2,0,1,1,0,3,4), +(0,5,0,4,0,5,0,2,0,4,4,3,3,2,3,3,3,1,4,3,4,1,5,3,4,3,4,0,4,2,4,3,4,1,5,4,0,4,4,4,4,5,4,1,3,5,4,2,1,4,1,1,3,2,0,3,1,0,3,2,1,4,3,3,3,4,0,4,0,3,0,4,4,4,3,3,3,0,4,2,0,3,4), +(1,4,0,4,0,3,0,1,0,3,3,3,1,1,3,3,2,2,3,3,1,0,3,2,2,1,2,0,3,1,2,1,2,0,3,2,0,2,2,3,3,4,3,0,3,3,1,2,0,1,1,3,1,2,0,0,3,0,1,1,0,3,2,2,3,3,0,3,0,0,0,2,3,3,4,3,3,0,1,0,0,1,4), +(0,4,0,4,0,4,0,0,0,3,4,4,3,1,4,2,3,2,3,3,3,1,4,3,4,0,3,0,4,2,3,3,2,2,5,4,2,1,3,4,3,4,3,1,3,3,4,2,0,2,1,0,3,3,0,0,2,0,3,1,0,4,4,3,4,3,0,4,0,1,0,2,4,4,4,4,4,0,3,2,0,3,3), +(0,0,0,1,0,4,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,3,2,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,2), +(0,2,0,3,0,4,0,4,0,1,3,3,3,0,4,0,2,1,2,1,1,1,2,0,3,1,1,0,1,0,3,1,0,0,3,3,2,0,1,1,0,0,0,0,0,1,0,2,0,2,2,0,3,1,0,0,1,0,1,1,0,1,2,0,3,0,0,0,0,1,0,0,3,3,4,3,1,0,1,0,3,0,2), +(0,0,0,3,0,5,0,0,0,0,1,0,2,0,3,1,0,1,3,0,0,0,2,0,0,0,1,0,0,0,1,1,0,0,4,0,0,0,2,3,0,1,4,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,1,0,0,0,0,0,0,0,2,0,0,3,0,0,0,0,0,3), +(0,2,0,5,0,5,0,1,0,2,4,3,3,2,5,1,3,2,3,3,3,0,4,1,2,0,3,0,4,0,2,2,1,1,5,3,0,0,1,4,2,3,2,0,3,3,3,2,0,2,4,1,1,2,0,1,1,0,3,1,0,1,3,1,2,3,0,2,0,0,0,1,3,5,4,4,4,0,3,0,0,1,3), +(0,4,0,5,0,4,0,4,0,4,5,4,3,3,4,3,3,3,4,3,4,4,5,3,4,5,4,2,4,2,3,4,3,1,4,4,1,3,5,4,4,5,5,4,4,5,5,5,2,3,3,1,4,3,1,3,3,0,3,3,1,4,3,4,4,4,0,3,0,4,0,3,3,4,4,5,0,0,4,3,0,4,5), +(0,4,0,4,0,3,0,3,0,3,4,4,4,3,3,2,4,3,4,3,4,3,5,3,4,3,2,1,4,2,4,4,3,1,3,4,2,4,5,5,3,4,5,4,1,5,4,3,0,3,2,2,3,2,1,3,1,0,3,3,3,5,3,3,3,5,4,4,2,3,3,4,3,3,3,2,1,0,3,2,1,4,3), +(0,4,0,5,0,4,0,3,0,3,5,5,3,2,4,3,4,0,5,4,4,1,4,4,4,3,3,3,4,3,5,5,2,3,3,4,1,2,5,5,3,5,5,2,3,5,5,4,0,3,2,0,3,3,1,1,5,1,4,1,0,4,3,2,3,5,0,4,0,3,0,5,4,3,4,3,0,0,4,1,0,4,4), +(1,3,0,4,0,2,0,2,0,2,5,5,3,3,3,3,3,0,4,2,3,4,4,4,3,4,0,0,3,4,5,4,3,3,3,3,2,5,5,4,5,5,5,4,3,5,5,5,1,3,1,0,1,0,0,3,2,0,4,2,0,5,2,3,2,4,1,3,0,3,0,4,5,4,5,4,3,0,4,2,0,5,4), +(0,3,0,4,0,5,0,3,0,3,4,4,3,2,3,2,3,3,3,3,3,2,4,3,3,2,2,0,3,3,3,3,3,1,3,3,3,0,4,4,3,4,4,1,1,4,4,2,0,3,1,0,1,1,0,4,1,0,2,3,1,3,3,1,3,4,0,3,0,1,0,3,1,3,0,0,1,0,2,0,0,4,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,3,0,2,0,3,0,1,5,4,3,3,3,1,4,2,1,2,3,4,4,2,4,4,5,0,3,1,4,3,4,0,4,3,3,3,2,3,2,5,3,4,3,2,2,3,0,0,3,0,2,1,0,1,2,0,0,0,0,2,1,1,3,1,0,2,0,4,0,3,4,4,4,5,2,0,2,0,0,1,3), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,1,1,0,0,0,4,2,1,1,0,1,0,3,2,0,0,3,1,1,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,1,0,0,0,2,0,0,0,1,4,0,4,2,1,0,0,0,0,0,1), +(0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,3,1,0,0,0,2,0,2,1,0,0,1,2,1,0,1,1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,1,3,1,0,0,0,0,0,1,0,0,2,1,0,0,0,0,0,0,0,0,2), +(0,4,0,4,0,4,0,3,0,4,4,3,4,2,4,3,2,0,4,4,4,3,5,3,5,3,3,2,4,2,4,3,4,3,1,4,0,2,3,4,4,4,3,3,3,4,4,4,3,4,1,3,4,3,2,1,2,1,3,3,3,4,4,3,3,5,0,4,0,3,0,4,3,3,3,2,1,0,3,0,0,3,3), +(0,4,0,3,0,3,0,3,0,3,5,5,3,3,3,3,4,3,4,3,3,3,4,4,4,3,3,3,3,4,3,5,3,3,1,3,2,4,5,5,5,5,4,3,4,5,5,3,2,2,3,3,3,3,2,3,3,1,2,3,2,4,3,3,3,4,0,4,0,2,0,4,3,2,2,1,2,0,3,0,0,4,1), +) + +class JapaneseContextAnalysis: + def __init__(self): + self.reset() + + def reset(self): + self._mTotalRel = 0 # total sequence received + self._mRelSample = [0] * NUM_OF_CATEGORY # category counters, each interger counts sequence in its category + self._mNeedToSkipCharNum = 0 # if last byte in current buffer is not the last byte of a character, we need to know how many bytes to skip in next buffer + self._mLastCharOrder = -1 # The order of previous char + self._mDone = constants.False # If this flag is set to constants.True, detection is done and conclusion has been made + + def feed(self, aBuf, aLen): + if self._mDone: return + + # The buffer we got is byte oriented, and a character may span in more than one + # buffers. In case the last one or two byte in last buffer is not complete, we + # record how many byte needed to complete that character and skip these bytes here. + # We can choose to record those bytes as well and analyse the character once it + # is complete, but since a character will not make much difference, by simply skipping + # this character will simply our logic and improve performance. + i = self._mNeedToSkipCharNum + while i < aLen: + order, charLen = self.get_order(aBuf[i:i+2]) + i += charLen + if i > aLen: + self._mNeedToSkipCharNum = i - aLen + self._mLastCharOrder = -1 + else: + if (order != -1) and (self._mLastCharOrder != -1): + self._mTotalRel += 1 + if self._mTotalRel > MAX_REL_THRESHOLD: + self._mDone = constants.True + break + self._mRelSample[jp2CharContext[self._mLastCharOrder][order]] += 1 + self._mLastCharOrder = order + + def got_enough_data(self): + return self._mTotalRel > ENOUGH_REL_THRESHOLD + + def get_confidence(self): + # This is just one way to calculate confidence. It works well for me. + if self._mTotalRel > MINIMUM_DATA_THRESHOLD: + return (self._mTotalRel - self._mRelSample[0]) / self._mTotalRel + else: + return DONT_KNOW + + def get_order(self, aStr): + return -1, 1 + +class SJISContextAnalysis(JapaneseContextAnalysis): + def get_order(self, aStr): + if not aStr: return -1, 1 + # find out current char's byte length + if ((aStr[0] >= '\x81') and (aStr[0] <= '\x9F')) or \ + ((aStr[0] >= '\xE0') and (aStr[0] <= '\xFC')): + charLen = 2 + else: + charLen = 1 + + # return its order if it is hiragana + if len(aStr) > 1: + if (aStr[0] == '\202') and \ + (aStr[1] >= '\x9F') and \ + (aStr[1] <= '\xF1'): + return ord(aStr[1]) - 0x9F, charLen + + return -1, charLen + +class EUCJPContextAnalysis(JapaneseContextAnalysis): + def get_order(self, aStr): + if not aStr: return -1, 1 + # find out current char's byte length + if (aStr[0] == '\x8E') or \ + ((aStr[0] >= '\xA1') and (aStr[0] <= '\xFE')): + charLen = 2 + elif aStr[0] == '\x8F': + charLen = 3 + else: + charLen = 1 + + # return its order if it is hiragana + if len(aStr) > 1: + if (aStr[0] == '\xA4') and \ + (aStr[1] >= '\xA1') and \ + (aStr[1] <= '\xF3'): + return ord(aStr[1]) - 0xA1, charLen + + return -1, charLen diff --git a/libs/requests/packages/chardet/langbulgarianmodel.py b/libs/requests/packages/chardet/langbulgarianmodel.py new file mode 100755 index 00000000..bf5641e7 --- /dev/null +++ b/libs/requests/packages/chardet/langbulgarianmodel.py @@ -0,0 +1,228 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import constants + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +# this table is modified base on win1251BulgarianCharToOrderMap, so +# only number <64 is sure valid + +Latin5_BulgarianCharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 77, 90, 99,100, 72,109,107,101, 79,185, 81,102, 76, 94, 82, # 40 +110,186,108, 91, 74,119, 84, 96,111,187,115,253,253,253,253,253, # 50 +253, 65, 69, 70, 66, 63, 68,112,103, 92,194,104, 95, 86, 87, 71, # 60 +116,195, 85, 93, 97,113,196,197,198,199,200,253,253,253,253,253, # 70 +194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209, # 80 +210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225, # 90 + 81,226,227,228,229,230,105,231,232,233,234,235,236, 45,237,238, # a0 + 31, 32, 35, 43, 37, 44, 55, 47, 40, 59, 33, 46, 38, 36, 41, 30, # b0 + 39, 28, 34, 51, 48, 49, 53, 50, 54, 57, 61,239, 67,240, 60, 56, # c0 + 1, 18, 9, 20, 11, 3, 23, 15, 2, 26, 12, 10, 14, 6, 4, 13, # d0 + 7, 8, 5, 19, 29, 25, 22, 21, 27, 24, 17, 75, 52,241, 42, 16, # e0 + 62,242,243,244, 58,245, 98,246,247,248,249,250,251, 91,252,253, # f0 +) + +win1251BulgarianCharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 77, 90, 99,100, 72,109,107,101, 79,185, 81,102, 76, 94, 82, # 40 +110,186,108, 91, 74,119, 84, 96,111,187,115,253,253,253,253,253, # 50 +253, 65, 69, 70, 66, 63, 68,112,103, 92,194,104, 95, 86, 87, 71, # 60 +116,195, 85, 93, 97,113,196,197,198,199,200,253,253,253,253,253, # 70 +206,207,208,209,210,211,212,213,120,214,215,216,217,218,219,220, # 80 +221, 78, 64, 83,121, 98,117,105,222,223,224,225,226,227,228,229, # 90 + 88,230,231,232,233,122, 89,106,234,235,236,237,238, 45,239,240, # a0 + 73, 80,118,114,241,242,243,244,245, 62, 58,246,247,248,249,250, # b0 + 31, 32, 35, 43, 37, 44, 55, 47, 40, 59, 33, 46, 38, 36, 41, 30, # c0 + 39, 28, 34, 51, 48, 49, 53, 50, 54, 57, 61,251, 67,252, 60, 56, # d0 + 1, 18, 9, 20, 11, 3, 23, 15, 2, 26, 12, 10, 14, 6, 4, 13, # e0 + 7, 8, 5, 19, 29, 25, 22, 21, 27, 24, 17, 75, 52,253, 42, 16, # f0 +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 96.9392% +# first 1024 sequences:3.0618% +# rest sequences: 0.2992% +# negative sequences: 0.0020% +BulgarianLangModel = ( \ +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,2,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,2,2,3,2,2,1,2,2, +3,1,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,3,3,3,3,3,3,3,0,3,0,1, +0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,3,3,0,3,1,0, +0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,2,3,3,3,3,3,3,3,3,0,3,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,1,3,2,3,3,3,3,3,3,3,3,0,3,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,2,2,1,3,3,3,3,2,2,2,1,1,2,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,2,3,2,2,3,3,1,1,2,3,3,2,3,3,3,3,2,1,2,0,2,0,3,0,0, +0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,1,3,3,3,3,3,2,3,2,3,3,3,3,3,2,3,3,1,3,0,3,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,1,3,3,2,3,3,3,1,3,3,2,3,2,2,2,0,0,2,0,2,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,0,3,3,3,2,2,3,3,3,1,2,2,3,2,1,1,2,0,2,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,2,3,3,1,2,3,2,2,2,3,3,3,3,3,2,2,3,1,2,0,2,1,2,0,0, +0,0,0,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,1,3,3,3,3,3,2,3,3,3,2,3,3,2,3,2,2,2,3,1,2,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,1,1,1,2,2,1,3,1,3,2,2,3,0,0,1,0,1,0,1,0,0, +0,0,0,1,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,2,2,3,2,2,3,1,2,1,1,1,2,3,1,3,1,2,2,0,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,1,3,2,2,3,3,1,2,3,1,1,3,3,3,3,1,2,2,1,1,1,0,2,0,2,0,1, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,2,2,3,3,3,2,2,1,1,2,0,2,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,0,1,2,1,3,3,2,3,3,3,3,3,2,3,2,1,0,3,1,2,1,2,1,2,3,2,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,2,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,1,3,3,2,3,3,2,2,2,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,0,3,3,3,3,3,2,1,1,2,1,3,3,0,3,1,1,1,1,3,2,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,2,2,2,3,3,3,3,3,3,3,3,3,3,3,1,1,3,1,3,3,2,3,2,2,2,3,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,3,2,2,3,2,1,1,1,1,1,3,1,3,1,1,0,0,0,1,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,2,0,3,2,0,3,0,2,0,0,2,1,3,1,0,0,1,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,2,1,1,1,1,2,1,1,2,1,1,1,2,2,1,2,1,1,1,0,1,1,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,2,1,3,1,1,2,1,3,2,1,1,0,1,2,3,2,1,1,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,2,2,1,0,1,0,0,1,0,0,0,2,1,0,3,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,2,3,2,3,3,1,3,2,1,1,1,2,1,1,2,1,3,0,1,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,2,2,3,3,2,3,2,2,2,3,1,2,2,1,1,2,1,1,2,2,0,1,1,0,1,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,3,1,0,2,2,1,3,2,1,0,0,2,0,2,0,1,0,0,0,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,1,2,0,2,3,1,2,3,2,0,1,3,1,2,1,1,1,0,0,1,0,0,2,2,2,3, +2,2,2,2,1,2,1,1,2,2,1,1,2,0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,1, +3,3,3,3,3,2,1,2,2,1,2,0,2,0,1,0,1,2,1,2,1,1,0,0,0,1,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,2,3,3,1,1,3,1,0,3,2,1,0,0,0,1,2,0,2,0,1,0,0,0,1,0,1,2,1,2,2, +1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,0,1,2,1,1,1,0,0,0,0,0,1,1,0,0, +3,1,0,1,0,2,3,2,2,2,3,2,2,2,2,2,1,0,2,1,2,1,1,1,0,1,2,1,2,2,2,1, +1,1,2,2,2,2,1,2,1,1,0,1,2,1,2,2,2,1,1,1,0,1,1,1,1,2,0,1,0,0,0,0, +2,3,2,3,3,0,0,2,1,0,2,1,0,0,0,0,2,3,0,2,0,0,0,0,0,1,0,0,2,0,1,2, +2,1,2,1,2,2,1,1,1,2,1,1,1,0,1,2,2,1,1,1,1,1,0,1,1,1,0,0,1,2,0,0, +3,3,2,2,3,0,2,3,1,1,2,0,0,0,1,0,0,2,0,2,0,0,0,1,0,1,0,1,2,0,2,2, +1,1,1,1,2,1,0,1,2,2,2,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,1,1,0,0, +2,3,2,3,3,0,0,3,0,1,1,0,1,0,0,0,2,2,1,2,0,0,0,0,0,0,0,0,2,0,1,2, +2,2,1,1,1,1,1,2,2,2,1,0,2,0,1,0,1,0,0,1,0,1,0,0,1,0,0,0,0,1,0,0, +3,3,3,3,2,2,2,2,2,0,2,1,1,1,1,2,1,2,1,1,0,2,0,1,0,1,0,0,2,0,1,2, +1,1,1,1,1,1,1,2,2,1,1,0,2,0,1,0,2,0,0,1,1,1,0,0,2,0,0,0,1,1,0,0, +2,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,0,0,0,0,0,0,1,2,0,1,2, +2,2,2,1,1,2,1,1,2,2,2,1,2,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,0,0, +2,3,3,3,3,0,2,2,0,2,1,0,0,0,1,1,1,2,0,2,0,0,0,3,0,0,0,0,2,0,2,2, +1,1,1,2,1,2,1,1,2,2,2,1,2,0,1,1,1,0,1,1,1,1,0,2,1,0,0,0,1,1,0,0, +2,3,3,3,3,0,2,1,0,0,2,0,0,0,0,0,1,2,0,2,0,0,0,0,0,0,0,0,2,0,1,2, +1,1,1,2,1,1,1,1,2,2,2,0,1,0,1,1,1,0,0,1,1,1,0,0,1,0,0,0,0,1,0,0, +3,3,2,2,3,0,1,0,1,0,0,0,0,0,0,0,1,1,0,3,0,0,0,0,0,0,0,0,1,0,2,2, +1,1,1,1,1,2,1,1,2,2,1,2,2,1,0,1,1,1,1,1,0,1,0,0,1,0,0,0,1,1,0,0, +3,1,0,1,0,2,2,2,2,3,2,1,1,1,2,3,0,0,1,0,2,1,1,0,1,1,1,1,2,1,1,1, +1,2,2,1,2,1,2,2,1,1,0,1,2,1,2,2,1,1,1,0,0,1,1,1,2,1,0,1,0,0,0,0, +2,1,0,1,0,3,1,2,2,2,2,1,2,2,1,1,1,0,2,1,2,2,1,1,2,1,1,0,2,1,1,1, +1,2,2,2,2,2,2,2,1,2,0,1,1,0,2,1,1,1,1,1,0,0,1,1,1,1,0,1,0,0,0,0, +2,1,1,1,1,2,2,2,2,1,2,2,2,1,2,2,1,1,2,1,2,3,2,2,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,3,2,0,1,2,0,1,2,1,1,0,1,0,1,2,1,2,0,0,0,1,1,0,0,0,1,0,0,2, +1,1,0,0,1,1,0,1,1,1,1,0,2,0,1,1,1,0,0,1,1,0,0,0,0,1,0,0,0,1,0,0, +2,0,0,0,0,1,2,2,2,2,2,2,2,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,2,1,1,1, +1,2,2,2,2,1,1,2,1,2,1,1,1,0,2,1,2,1,1,1,0,2,1,1,1,1,0,1,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, +1,1,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,3,2,0,0,0,0,1,0,0,0,0,0,0,1,1,0,2,0,0,0,0,0,0,0,0,1,0,1,2, +1,1,1,1,1,1,0,0,2,2,2,2,2,0,1,1,0,1,1,1,1,1,0,0,1,0,0,0,1,1,0,1, +2,3,1,2,1,0,1,1,0,2,2,2,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,0,1,2, +1,1,1,1,2,1,1,1,1,1,1,1,1,0,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,1,0,0, +2,2,2,2,2,0,0,2,0,0,2,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,0,2,2, +1,1,1,1,1,0,0,1,2,1,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,2,0,1,1,0,0,0,1,0,0,2,0,2,0,0,0,0,0,0,0,0,0,0,1,1, +0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,3,2,0,0,1,0,0,1,0,0,0,0,0,0,1,0,2,0,0,0,1,0,0,0,0,0,0,0,2, +1,1,0,0,1,0,0,0,1,1,0,0,1,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,1,2,2,2,1,2,1,2,2,1,1,2,1,1,1,0,1,1,1,1,2,0,1,0,1,1,1,1,0,1,1, +1,1,2,1,1,1,1,1,1,0,0,1,2,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0, +1,0,0,1,3,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,1,0,0,1,0,2,0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,0,2,0,0,1, +0,2,0,1,0,0,1,1,2,0,1,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,1,1,0,2,1,0,1,1,1,0,0,1,0,2,0,1,0,0,0,0,0,0,0,0,0,1, +0,1,0,0,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,2,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1, +0,1,0,1,1,1,0,0,1,1,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,0,1,2,1,1,1,1,1,1,2,2,1,0,0,1,0,1,0,0,0,0,1,1,1,1,0,0,0, +1,1,2,1,1,1,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,1,2,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +0,1,1,0,1,1,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0, +1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,2,0,0,2,0,1,0,0,1,0,0,1, +1,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, +1,1,1,1,1,1,1,2,0,0,0,0,0,0,2,1,0,1,1,0,0,1,1,1,0,1,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +) + +Latin5BulgarianModel = { \ + 'charToOrderMap': Latin5_BulgarianCharToOrderMap, + 'precedenceMatrix': BulgarianLangModel, + 'mTypicalPositiveRatio': 0.969392, + 'keepEnglishLetter': constants.False, + 'charsetName': "ISO-8859-5" +} + +Win1251BulgarianModel = { \ + 'charToOrderMap': win1251BulgarianCharToOrderMap, + 'precedenceMatrix': BulgarianLangModel, + 'mTypicalPositiveRatio': 0.969392, + 'keepEnglishLetter': constants.False, + 'charsetName': "windows-1251" +} diff --git a/libs/requests/packages/chardet/langcyrillicmodel.py b/libs/requests/packages/chardet/langcyrillicmodel.py new file mode 100755 index 00000000..e604cc73 --- /dev/null +++ b/libs/requests/packages/chardet/langcyrillicmodel.py @@ -0,0 +1,329 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import constants + +# KOI8-R language model +# Character Mapping Table: +KOI8R_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, # 80 +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, # 90 +223,224,225, 68,226,227,228,229,230,231,232,233,234,235,236,237, # a0 +238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253, # b0 + 27, 3, 21, 28, 13, 2, 39, 19, 26, 4, 23, 11, 8, 12, 5, 1, # c0 + 15, 16, 9, 7, 6, 14, 24, 10, 17, 18, 20, 25, 30, 29, 22, 54, # d0 + 59, 37, 44, 58, 41, 48, 53, 46, 55, 42, 60, 36, 49, 38, 31, 34, # e0 + 35, 43, 45, 32, 40, 52, 56, 33, 61, 62, 51, 57, 47, 63, 50, 70, # f0 +) + +win1251_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, +239,240,241,242,243,244,245,246, 68,247,248,249,250,251,252,253, + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +) + +latin5_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255, +) + +macCyrillic_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, +239,240,241,242,243,244,245,246,247,248,249,250,251,252, 68, 16, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27,255, +) + +IBM855_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194, 68,195,196,197,198,199,200,201,202,203,204,205, +206,207,208,209,210,211,212,213,214,215,216,217, 27, 59, 54, 70, + 3, 37, 21, 44, 28, 58, 13, 41, 2, 48, 39, 53, 19, 46,218,219, +220,221,222,223,224, 26, 55, 4, 42,225,226,227,228, 23, 60,229, +230,231,232,233,234,235, 11, 36,236,237,238,239,240,241,242,243, + 8, 49, 12, 38, 5, 31, 1, 34, 15,244,245,246,247, 35, 16,248, + 43, 9, 45, 7, 32, 6, 40, 14, 52, 24, 56, 10, 33, 17, 61,249, +250, 18, 62, 20, 51, 25, 57, 30, 47, 29, 63, 22, 50,251,252,255, +) + +IBM866_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 97.6601% +# first 1024 sequences: 2.3389% +# rest sequences: 0.1237% +# negative sequences: 0.0009% +RussianLangModel = ( \ +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,1,3,3,3,2,3,2,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,2,2,2,2,2,0,0,2, +3,3,3,2,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,2,3,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,2,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,2,3,3,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1, +0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1, +0,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,2,2,2,3,1,3,3,1,3,3,3,3,2,2,3,0,2,2,2,3,3,2,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,3,3,2,2,3,2,3,3,3,2,1,2,2,0,1,2,2,2,2,2,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,3,0,2,2,3,3,2,1,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,1,2,3,2,2,3,2,3,3,3,3,2,2,3,0,3,2,2,3,1,1,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,3,3,3,3,2,2,2,0,3,3,3,2,2,2,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,2,3,2,2,0,1,3,2,1,2,2,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,2,1,1,3,0,1,1,1,1,2,1,1,0,2,2,2,1,2,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,2,2,2,2,1,3,2,3,2,3,2,1,2,2,0,1,1,2,1,2,1,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,2,3,3,3,2,2,2,2,0,2,2,2,2,3,1,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,2,3,2,2,3,3,3,3,3,3,3,3,3,1,3,2,0,0,3,3,3,3,2,3,3,3,3,2,3,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,3,2,2,3,3,0,2,1,0,3,2,3,2,3,0,0,1,2,0,0,1,0,1,2,1,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,3,0,2,3,3,3,3,2,3,3,3,3,1,2,2,0,0,2,3,2,2,2,3,2,3,2,2,3,0,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,0,2,3,2,3,0,1,2,3,3,2,0,2,3,0,0,2,3,2,2,0,1,3,1,3,2,2,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,3,0,2,3,3,3,3,3,3,3,3,2,1,3,2,0,0,2,2,3,3,3,2,3,3,0,2,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,2,2,2,3,3,0,0,1,1,1,1,1,2,0,0,1,1,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,3,3,3,3,3,0,3,2,3,3,2,3,2,0,2,1,0,1,1,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,2,2,2,2,3,1,3,2,3,1,1,2,1,0,2,2,2,2,1,3,1,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +2,2,3,3,3,3,3,1,2,2,1,3,1,0,3,0,0,3,0,0,0,1,1,0,1,2,1,0,0,0,0,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,2,1,1,3,3,3,2,2,1,2,2,3,1,1,2,0,0,2,2,1,3,0,0,2,1,1,2,1,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,3,3,3,1,2,2,2,1,2,1,3,3,1,1,2,1,2,1,2,2,0,2,0,0,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,3,2,1,3,2,2,3,2,0,3,2,0,3,0,1,0,1,1,0,0,1,1,1,1,0,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,3,3,3,2,2,2,3,3,1,2,1,2,1,0,1,0,1,1,0,1,0,0,2,1,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,1,1,2,1,2,3,3,2,2,1,2,2,3,0,2,1,0,0,2,2,3,2,1,2,2,2,2,2,3,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,1,1,0,1,1,2,2,1,1,3,0,0,1,3,1,1,1,0,0,0,1,0,1,1,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,3,3,3,2,0,0,0,2,1,0,1,0,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,0,2,3,2,2,2,1,2,2,2,1,2,1,0,0,1,1,1,0,2,0,1,1,1,0,0,1,1, +1,0,0,0,0,0,1,2,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,0,0,0,0,1,0,0,0,0,3,0,1,2,1,0,0,0,0,0,0,0,1,1,0,0,1,1, +1,0,1,0,1,2,0,0,1,1,2,1,0,1,1,1,1,0,1,1,1,1,0,1,0,0,1,0,0,1,1,0, +2,2,3,2,2,2,3,1,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,0,1,0,1,1,1,0,2,1, +1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,0,1,1,0, +3,3,3,2,2,2,2,3,2,2,1,1,2,2,2,2,1,1,3,1,2,1,2,0,0,1,1,0,1,0,2,1, +1,1,1,1,1,2,1,0,1,1,1,1,0,1,0,0,1,1,0,0,1,0,1,0,0,1,0,0,0,1,1,0, +2,0,0,1,0,3,2,2,2,2,1,2,1,2,1,2,0,0,0,2,1,2,2,1,1,2,2,0,1,1,0,2, +1,1,1,1,1,0,1,1,1,2,1,1,1,2,1,0,1,2,1,1,1,1,0,1,1,1,0,0,1,0,0,1, +1,3,2,2,2,1,1,1,2,3,0,0,0,0,2,0,2,2,1,0,0,0,0,0,0,1,0,0,0,0,1,1, +1,0,1,1,0,1,0,1,1,0,1,1,0,2,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0, +2,3,2,3,2,1,2,2,2,2,1,0,0,0,2,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,2,1, +1,1,2,1,0,2,0,0,1,0,1,0,0,1,0,0,1,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0, +3,0,0,1,0,2,2,2,3,2,2,2,2,2,2,2,0,0,0,2,1,2,1,1,1,2,2,0,0,0,1,2, +1,1,1,1,1,0,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1, +2,3,2,3,3,2,0,1,1,1,0,0,1,0,2,0,1,1,3,1,0,0,0,0,0,0,0,1,0,0,2,1, +1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,0,0,1,1,0,1,0,0,0,0,0,0,1,0, +2,3,3,3,3,1,2,2,2,2,0,1,1,0,2,1,1,1,2,1,0,1,1,0,0,1,0,1,0,0,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,2,0,0,1,1,2,2,1,0,0,2,0,1,1,3,0,0,1,0,0,0,0,0,1,0,1,2,1, +1,1,2,0,1,1,1,0,1,0,1,1,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,1,0,1,1,0, +1,3,2,3,2,1,0,0,2,2,2,0,1,0,2,0,1,1,1,0,1,0,0,0,3,0,1,1,0,0,2,1, +1,1,1,0,1,1,0,0,0,0,1,1,0,1,0,0,2,1,1,0,1,0,0,0,1,0,1,0,0,1,1,0, +3,1,2,1,1,2,2,2,2,2,2,1,2,2,1,1,0,0,0,2,2,2,0,0,0,1,2,1,0,1,0,1, +2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,2,1,1,1,0,1,0,1,1,0,1,1,1,0,0,1, +3,0,0,0,0,2,0,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,0,1,0,1,1,0,0,1,0,1, +1,1,0,0,1,0,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1, +1,3,3,2,2,0,0,0,2,2,0,0,0,1,2,0,1,1,2,0,0,0,0,0,0,0,0,1,0,0,2,1, +0,1,1,0,0,1,1,0,0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +2,3,2,3,2,0,0,0,0,1,1,0,0,0,2,0,2,0,2,0,0,0,0,0,1,0,0,1,0,0,1,1, +1,1,2,0,1,2,1,0,1,1,2,1,1,1,1,1,2,1,1,0,1,0,0,1,1,1,1,1,0,1,1,0, +1,3,2,2,2,1,0,0,2,2,1,0,1,2,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,1, +0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,0,2,3,1,2,2,2,2,2,2,1,1,0,0,0,1,0,1,0,2,1,1,1,0,0,0,0,1, +1,1,0,1,1,0,1,1,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +2,0,2,0,0,1,0,3,2,1,2,1,2,2,0,1,0,0,0,2,1,0,0,2,1,1,1,1,0,2,0,2, +2,1,1,1,1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,0,0,0,1,1,1,1,0,1,0,0,1, +1,2,2,2,2,1,0,0,1,0,0,0,0,0,2,0,1,1,1,1,0,0,0,0,1,0,1,2,0,0,2,0, +1,0,1,1,1,2,1,0,1,0,1,1,0,0,1,0,1,1,1,0,1,0,0,0,1,0,0,1,0,1,1,0, +2,1,2,2,2,0,3,0,1,1,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,0,1,1,1,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0, +1,2,2,3,2,2,0,0,1,1,2,0,1,2,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1, +0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0, +2,2,1,1,2,1,2,2,2,2,2,1,2,2,0,1,0,0,0,1,2,2,2,1,2,1,1,1,1,1,2,1, +1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,0,1, +1,2,2,2,2,0,1,0,2,2,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0, +0,0,1,0,0,1,0,0,0,0,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,0,2,2,2,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1, +0,1,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,0,0,1,0,0,1,1,2,0,0,0,0,1,0,1,0,0,1,0,0,2,0,0,0,1, +0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,1,1,2,0,2,1,1,1,1,0,2,2,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1, +0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,0,2,1,2,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0, +0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +1,0,0,0,0,2,0,1,2,1,0,1,1,1,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1, +0,0,0,0,0,1,0,0,1,1,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1, +2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,1,0,1,0,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,0,1,1,0,1,0,1,0,0,0,0,1,1,0,1,1,0,0,0,0,0,1,0,1,1,0,1,0,0,0, +0,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, +) + +Koi8rModel = { \ + 'charToOrderMap': KOI8R_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': constants.False, + 'charsetName': "KOI8-R" +} + +Win1251CyrillicModel = { \ + 'charToOrderMap': win1251_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': constants.False, + 'charsetName': "windows-1251" +} + +Latin5CyrillicModel = { \ + 'charToOrderMap': latin5_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': constants.False, + 'charsetName': "ISO-8859-5" +} + +MacCyrillicModel = { \ + 'charToOrderMap': macCyrillic_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': constants.False, + 'charsetName': "MacCyrillic" +}; + +Ibm866Model = { \ + 'charToOrderMap': IBM866_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': constants.False, + 'charsetName': "IBM866" +} + +Ibm855Model = { \ + 'charToOrderMap': IBM855_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': constants.False, + 'charsetName': "IBM855" +} diff --git a/libs/requests/packages/chardet/langgreekmodel.py b/libs/requests/packages/chardet/langgreekmodel.py new file mode 100755 index 00000000..ec6d49e8 --- /dev/null +++ b/libs/requests/packages/chardet/langgreekmodel.py @@ -0,0 +1,225 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import constants + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin7_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 82,100,104, 94, 98,101,116,102,111,187,117, 92, 88,113, 85, # 40 + 79,118,105, 83, 67,114,119, 95, 99,109,188,253,253,253,253,253, # 50 +253, 72, 70, 80, 81, 60, 96, 93, 89, 68,120, 97, 77, 86, 69, 55, # 60 + 78,115, 65, 66, 58, 76,106,103, 87,107,112,253,253,253,253,253, # 70 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 80 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 90 +253,233, 90,253,253,253,253,253,253,253,253,253,253, 74,253,253, # a0 +253,253,253,253,247,248, 61, 36, 46, 71, 73,253, 54,253,108,123, # b0 +110, 31, 51, 43, 41, 34, 91, 40, 52, 47, 44, 53, 38, 49, 59, 39, # c0 + 35, 48,250, 37, 33, 45, 56, 50, 84, 57,120,121, 17, 18, 22, 15, # d0 +124, 1, 29, 20, 21, 3, 32, 13, 25, 5, 11, 16, 10, 6, 30, 4, # e0 + 9, 8, 14, 7, 2, 12, 28, 23, 42, 24, 64, 75, 19, 26, 27,253, # f0 +) + +win1253_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 82,100,104, 94, 98,101,116,102,111,187,117, 92, 88,113, 85, # 40 + 79,118,105, 83, 67,114,119, 95, 99,109,188,253,253,253,253,253, # 50 +253, 72, 70, 80, 81, 60, 96, 93, 89, 68,120, 97, 77, 86, 69, 55, # 60 + 78,115, 65, 66, 58, 76,106,103, 87,107,112,253,253,253,253,253, # 70 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 80 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 90 +253,233, 61,253,253,253,253,253,253,253,253,253,253, 74,253,253, # a0 +253,253,253,253,247,253,253, 36, 46, 71, 73,253, 54,253,108,123, # b0 +110, 31, 51, 43, 41, 34, 91, 40, 52, 47, 44, 53, 38, 49, 59, 39, # c0 + 35, 48,250, 37, 33, 45, 56, 50, 84, 57,120,121, 17, 18, 22, 15, # d0 +124, 1, 29, 20, 21, 3, 32, 13, 25, 5, 11, 16, 10, 6, 30, 4, # e0 + 9, 8, 14, 7, 2, 12, 28, 23, 42, 24, 64, 75, 19, 26, 27,253, # f0 +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 98.2851% +# first 1024 sequences:1.7001% +# rest sequences: 0.0359% +# negative sequences: 0.0148% +GreekLangModel = ( \ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,2,2,3,3,3,3,3,3,3,3,1,3,3,3,0,2,2,3,3,0,3,0,3,2,0,3,3,3,0, +3,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,0,3,3,0,3,2,3,3,0,3,2,3,3,3,0,0,3,0,3,0,3,3,2,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,2,3,2,2,3,3,3,3,3,3,3,3,0,3,3,3,3,0,2,3,3,0,3,3,3,3,2,3,3,3,0, +2,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,0,2,1,3,3,3,3,2,3,3,2,3,3,2,0, +0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,3,3,0,3,3,3,3,3,3,3,3,3,3,0,3,2,3,3,0, +2,0,1,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,3,0,0,0,0,3,3,0,3,1,3,3,3,0,3,3,0,3,3,3,3,0,0,0,0, +2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,0,3,0,3,3,3,3,3,0,3,2,2,2,3,0,2,3,3,3,3,3,2,3,3,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,3,2,2,2,3,3,3,3,0,3,1,3,3,3,3,2,3,3,3,3,3,3,3,2,2,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,3,0,0,0,3,3,2,3,3,3,3,3,0,0,3,2,3,0,2,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,3,0,0,3,3,0,2,3,0,3,0,3,3,3,0,0,3,0,3,0,2,2,3,3,0,0, +0,0,1,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,3,2,3,3,3,3,0,3,3,3,3,3,0,3,3,2,3,2,3,3,2,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,2,3,2,3,3,3,3,3,3,0,2,3,2,3,2,2,2,3,2,3,3,2,3,0,2,2,2,3,0, +2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,0,3,3,3,2,3,3,0,0,3,0,3,0,0,0,3,2,0,3,0,3,0,0,2,0,2,0, +0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,3,3,0,3,0,0,0,3,3,0,3,3,3,0,0,1,2,3,0, +3,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,0,3,2,2,3,3,0,3,3,3,3,3,2,1,3,0,3,2,3,3,2,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,3,0,2,3,3,3,3,3,3,0,0,3,0,3,0,0,0,3,3,0,3,2,3,0,0,3,3,3,0, +3,0,0,0,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,0,3,0,3,0,0,0,3,2,0,3,2,3,0,0,3,2,3,0, +2,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,1,2,2,3,3,3,3,3,3,0,2,3,0,3,0,0,0,3,3,0,3,0,2,0,0,2,3,1,0, +2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,3,0,3,0,3,3,2,3,0,3,3,3,3,3,3,0,3,3,3,0,2,3,0,0,3,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,0,0,3,0,0,0,3,3,0,3,0,2,3,3,0,0,3,0,3,0,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,0,3,3,3,3,3,3,0,0,3,0,2,0,0,0,3,3,0,3,0,3,0,0,2,0,2,0, +0,0,0,0,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,3,0,3,0,2,0,3,2,0,3,2,3,2,3,0,0,3,2,3,2,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,2,3,3,3,3,3,0,0,0,3,0,2,1,0,0,3,2,2,2,0,3,0,0,2,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,2,0,3,0,3,0,3,3,0,2,1,2,3,3,0,0,3,0,3,0,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,3,0,3,3,3,3,3,3,0,2,3,0,3,0,0,0,2,1,0,2,2,3,0,0,2,2,2,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,2,3,3,3,2,3,0,0,1,3,0,2,0,0,0,0,3,0,1,0,2,0,0,1,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,1,0,3,0,0,0,3,2,0,3,2,3,3,3,0,0,3,0,3,2,2,2,1,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,0,0,3,0,0,0,0,2,0,2,3,3,2,2,2,2,3,0,2,0,2,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,2,0,0,0,0,0,0,2,3,0,2,0,2,3,2,0,0,3,0,3,0,3,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,3,2,3,3,2,2,3,0,2,0,3,0,0,0,2,0,0,0,0,1,2,0,2,0,2,0, +0,2,0,2,0,2,2,0,0,1,0,2,2,2,0,2,2,2,0,2,2,2,0,0,2,0,0,1,0,0,0,0, +0,2,0,3,3,2,0,0,0,0,0,0,1,3,0,2,0,2,2,2,0,0,2,0,3,0,0,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,2,3,2,0,2,2,0,2,0,2,2,0,2,0,2,2,2,0,0,0,0,0,0,2,3,0,0,0,2, +0,1,2,0,0,0,0,2,2,0,0,0,2,1,0,2,2,0,0,0,0,0,0,1,0,2,0,0,0,0,0,0, +0,0,2,1,0,2,3,2,2,3,2,3,2,0,0,3,3,3,0,0,3,2,0,0,0,1,1,0,2,0,2,2, +0,2,0,2,0,2,2,0,0,2,0,2,2,2,0,2,2,2,2,0,0,2,0,0,0,2,0,1,0,0,0,0, +0,3,0,3,3,2,2,0,3,0,0,0,2,2,0,2,2,2,1,2,0,0,1,2,2,0,0,3,0,0,0,2, +0,1,2,0,0,0,1,2,0,0,0,0,0,0,0,2,2,0,1,0,0,2,0,0,0,2,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,2,2,0,0,0,2,0,2,3,3,0,2,0,0,0,0,0,0,2,2,2,0,2,2,0,2,0,2, +0,2,2,0,0,2,2,2,2,1,0,0,2,2,0,2,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0, +0,2,0,3,2,3,0,0,0,3,0,0,2,2,0,2,0,2,2,2,0,0,2,0,0,0,0,0,0,0,0,2, +0,0,2,2,0,0,2,2,2,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,3,2,0,2,2,2,2,2,0,0,0,2,0,0,0,0,2,0,1,0,0,2,0,1,0,0,0, +0,2,2,2,0,2,2,0,1,2,0,2,2,2,0,2,2,2,2,1,2,2,0,0,2,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,2,0,2,0,2,2,0,0,0,0,1,2,1,0,0,2,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,3,2,3,0,0,2,0,0,0,2,2,0,2,0,0,0,1,0,0,2,0,2,0,2,2,0,0,0,0, +0,0,2,0,0,0,0,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0, +0,2,2,3,2,2,0,0,0,0,0,0,1,3,0,2,0,2,2,0,0,0,1,0,2,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,0,2,0,3,2,0,2,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,2,0,0,0,0,1,1,0,0,2,1,2,0,2,2,0,1,0,0,1,0,0,0,2,0,0,0,0,0,0, +0,3,0,2,2,2,0,0,2,0,0,0,2,0,0,0,2,3,0,2,0,0,0,0,0,0,2,2,0,0,0,2, +0,1,2,0,0,0,1,2,2,1,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,1,2,0,2,2,0,2,0,0,2,0,0,0,0,1,2,1,0,2,1,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,3,1,2,2,0,2,0,0,0,0,2,0,0,0,2,0,0,3,0,0,0,0,2,2,2,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,1,0,2,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,2, +0,2,2,0,0,2,2,2,2,2,0,1,2,0,0,0,2,2,0,1,0,2,0,0,2,2,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,0,0,0,0,2,0,2,0,0,0,0,2, +0,1,2,0,0,0,0,2,2,1,0,1,0,1,0,2,2,2,1,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,2,0,1,2,0,0,0,0,0,0,0,0,0,0,2,0,0,2,2,0,0,0,0,1,0,0,0,0,0,0,2, +0,2,2,0,0,0,0,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0, +0,2,2,2,2,0,0,0,3,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0,1, +0,0,2,0,0,0,0,1,2,0,0,0,0,0,0,2,2,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,2,0,2,2,2,0,0,2,0,0,0,0,0,0,0,2,2,2,0,0,0,2,0,0,0,0,0,0,0,0,2, +0,0,1,0,0,0,0,2,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,3,0,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,2, +0,0,2,0,0,0,0,2,2,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,0,2,2,1,0,0,0,0,0,0,2,0,0,2,0,2,2,2,0,0,0,0,0,0,2,0,0,0,0,2, +0,0,2,0,0,2,0,2,2,0,0,0,0,2,0,2,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0, +0,0,3,0,0,0,2,2,0,2,2,0,0,0,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0, +0,2,2,2,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1, +0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,2,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,2,0,0,0,2,0,0,0,0,0,1,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,2,0,0,0, +0,2,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,2,0,2,0,0,0, +0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,2,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +Latin7GreekModel = { \ + 'charToOrderMap': Latin7_CharToOrderMap, + 'precedenceMatrix': GreekLangModel, + 'mTypicalPositiveRatio': 0.982851, + 'keepEnglishLetter': constants.False, + 'charsetName': "ISO-8859-7" +} + +Win1253GreekModel = { \ + 'charToOrderMap': win1253_CharToOrderMap, + 'precedenceMatrix': GreekLangModel, + 'mTypicalPositiveRatio': 0.982851, + 'keepEnglishLetter': constants.False, + 'charsetName': "windows-1253" +} diff --git a/libs/requests/packages/chardet/langhebrewmodel.py b/libs/requests/packages/chardet/langhebrewmodel.py new file mode 100755 index 00000000..a8bcc65b --- /dev/null +++ b/libs/requests/packages/chardet/langhebrewmodel.py @@ -0,0 +1,201 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Simon Montagu +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Shoshannah Forbes - original C code (?) +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import constants + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Windows-1255 language model +# Character Mapping Table: +win1255_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 69, 91, 79, 80, 92, 89, 97, 90, 68,111,112, 82, 73, 95, 85, # 40 + 78,121, 86, 71, 67,102,107, 84,114,103,115,253,253,253,253,253, # 50 +253, 50, 74, 60, 61, 42, 76, 70, 64, 53,105, 93, 56, 65, 54, 49, # 60 + 66,110, 51, 43, 44, 63, 81, 77, 98, 75,108,253,253,253,253,253, # 70 +124,202,203,204,205, 40, 58,206,207,208,209,210,211,212,213,214, +215, 83, 52, 47, 46, 72, 32, 94,216,113,217,109,218,219,220,221, + 34,116,222,118,100,223,224,117,119,104,125,225,226, 87, 99,227, +106,122,123,228, 55,229,230,101,231,232,120,233, 48, 39, 57,234, + 30, 59, 41, 88, 33, 37, 36, 31, 29, 35,235, 62, 28,236,126,237, +238, 38, 45,239,240,241,242,243,127,244,245,246,247,248,249,250, + 9, 8, 20, 16, 3, 2, 24, 14, 22, 1, 25, 15, 4, 11, 6, 23, + 12, 19, 13, 26, 18, 27, 21, 17, 7, 10, 5,251,252,128, 96,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 98.4004% +# first 1024 sequences: 1.5981% +# rest sequences: 0.087% +# negative sequences: 0.0015% +HebrewLangModel = ( \ +0,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,2,3,2,1,2,0,1,0,0, +3,0,3,1,0,0,1,3,2,0,1,1,2,0,2,2,2,1,1,1,1,2,1,1,1,2,0,0,2,2,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2, +1,2,1,2,1,2,0,0,2,0,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2, +1,2,1,3,1,1,0,0,2,0,0,0,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,0,1,2,2,1,3, +1,2,1,1,2,2,0,0,2,2,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,1,0,1,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,2,2,2,2,3,2, +1,2,1,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,2,3,2,2,3,2,2,2,1,2,2,2,2, +1,2,1,1,2,2,0,1,2,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,2,2,2,2,2, +0,2,0,2,2,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,0,2,2,2, +0,2,1,2,2,2,0,0,2,1,0,0,0,0,1,0,1,0,0,0,0,0,0,2,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,2,1,2,3,2,2,2, +1,2,1,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,1,0,2,0,2, +0,2,1,2,2,2,0,0,1,2,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,2,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,2,3,2,2,3,2,1,2,1,1,1, +0,1,1,1,1,1,3,0,1,0,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,0,0,1,0,0,0,0, +0,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,2,1,2,3,3,2,3,3,3,3,2,3,2,1,2,0,2,1,2, +0,2,0,2,2,2,0,0,1,2,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,1,2,2,3,3,2,3,2,3,2,2,3,1,2,2,0,2,2,2, +0,2,1,2,2,2,0,0,1,2,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,2,2,2,3,3,3,3,1,3,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,3,3,2,3,2,2,2,1,2,2,0,2,2,2,2, +0,2,0,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,1,3,2,3,3,2,3,3,2,2,1,2,2,2,2,2,2, +0,2,1,2,1,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,2,3,3,2,3,3,3,3,2,3,2,3,3,3,3,3,2,2,2,2,2,2,2,1, +0,2,0,1,2,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,1,2,3,3,3,3,3,3,3,2,3,2,3,2,1,2,3,0,2,1,2,2, +0,2,1,1,2,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,2,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,3,2,1,3,1,2,2,2,1,2,3,3,1,2,1,2,2,2,2, +0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,0,2,3,3,3,1,3,3,3,1,2,2,2,2,1,1,2,2,2,2,2,2, +0,2,0,1,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,2,2,3,3,3,2,1,2,3,2,3,2,2,2,2,1,2,1,1,1,2,2, +0,2,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1,0,0,0,0,0, +1,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,3,2,3,1,2,2,2,2,3,2,3,1,1,2,2,1,2,2,1,1,0,2,2,2,2, +0,1,0,1,2,2,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,0,0,1,1,0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,0,1,0,1,1,0,1,1,0,0,0,1,1,0,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +3,2,2,1,2,2,2,2,2,2,2,1,2,2,1,2,2,1,1,1,1,1,1,1,1,2,1,1,0,3,3,3, +0,3,0,2,2,2,2,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +2,2,2,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,1,2,2,2,1,1,1,2,0,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,0,0,0,0, +0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,0,2,1,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,3,1,1,2,2,2,2,2,1,2,2,2,1,1,2,2,2,2,2,2,2,1,2,2,1,0,1,1,1,1,0, +0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,1,1,1,1,2,1,1,2,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,0,0, +2,1,1,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,1,2,1,2,1,1,1,1,0,0,0,0, +0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,1,2,1,1,2,1,1,1,2,1,2,1,2,0,1,0,1, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,1,2,2,2,1,2,2,2,2,2,2,2,2,1,2,1,1,1,1,1,1,2,1,2,1,1,0,1,0,1, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,1,1,1,1,1,1,0,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,1,1,1,0,1,0,0,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0, +0,1,1,1,2,1,2,2,2,0,2,0,2,0,1,1,2,1,1,1,1,2,1,0,1,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,1,0,0,0,0,0,1,0,1,2,2,0,1,0,0,1,1,2,2,1,2,0,2,0,0,0,1,2,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,2,1,2,0,2,0,0,1,1,1,1,1,1,0,1,0,0,0,1,0,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,1,0,2,1,1,0,1,0,0,1,1,1,2,2,0,0,1,0,0,0,1,0,0,1, +1,1,2,1,0,1,1,1,0,1,0,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,2,1, +0,2,0,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,0,0,1,0,1,1,1,1,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,1,0,0,0,1,1,0,1, +2,0,1,0,1,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,0,1,1,2,1,1,2,0,1,0,0,0,1,1,0,1, +1,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,0,0,2,1,1,2,0,2,0,0,0,1,1,0,1, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,2,1,1,0,1,0,0,2,2,1,2,1,1,0,1,0,0,0,1,1,0,1, +2,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,1,0,1, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,2,1,1,1,0,2,1,1,0,0,0,2,1,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,1,1,0,2,1,1,0,1,0,0,0,1,1,0,1, +2,2,1,1,1,0,1,1,0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,2,1,1,0,1,0,0,1,1,0,1,2,1,0,2,0,0,0,1,1,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0, +0,1,0,0,2,0,2,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,1,1,1,0,1,0,0,1,0,0,0,1,0,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,1,0,1,1,0,0,1,0,0,2,1,1,1,1,1,0,1,0,0,0,0,1,0,1, +0,1,1,1,2,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,1,0,0,0,0,0,1,1,1,1,1,0,1,0,0,0,1,1,0,0, +) + +Win1255HebrewModel = { \ + 'charToOrderMap': win1255_CharToOrderMap, + 'precedenceMatrix': HebrewLangModel, + 'mTypicalPositiveRatio': 0.984004, + 'keepEnglishLetter': constants.False, + 'charsetName': "windows-1255" +} diff --git a/libs/requests/packages/chardet/langhungarianmodel.py b/libs/requests/packages/chardet/langhungarianmodel.py new file mode 100755 index 00000000..d635f03c --- /dev/null +++ b/libs/requests/packages/chardet/langhungarianmodel.py @@ -0,0 +1,225 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import constants + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin2_HungarianCharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 28, 40, 54, 45, 32, 50, 49, 38, 39, 53, 36, 41, 34, 35, 47, + 46, 71, 43, 33, 37, 57, 48, 64, 68, 55, 52,253,253,253,253,253, +253, 2, 18, 26, 17, 1, 27, 12, 20, 9, 22, 7, 6, 13, 4, 8, + 23, 67, 10, 5, 3, 21, 19, 65, 62, 16, 11,253,253,253,253,253, +159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174, +175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190, +191,192,193,194,195,196,197, 75,198,199,200,201,202,203,204,205, + 79,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, +221, 51, 81,222, 78,223,224,225,226, 44,227,228,229, 61,230,231, +232,233,234, 58,235, 66, 59,236,237,238, 60, 69, 63,239,240,241, + 82, 14, 74,242, 70, 80,243, 72,244, 15, 83, 77, 84, 30, 76, 85, +245,246,247, 25, 73, 42, 24,248,249,250, 31, 56, 29,251,252,253, +) + +win1250HungarianCharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 28, 40, 54, 45, 32, 50, 49, 38, 39, 53, 36, 41, 34, 35, 47, + 46, 72, 43, 33, 37, 57, 48, 64, 68, 55, 52,253,253,253,253,253, +253, 2, 18, 26, 17, 1, 27, 12, 20, 9, 22, 7, 6, 13, 4, 8, + 23, 67, 10, 5, 3, 21, 19, 65, 62, 16, 11,253,253,253,253,253, +161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176, +177,178,179,180, 78,181, 69,182,183,184,185,186,187,188,189,190, +191,192,193,194,195,196,197, 76,198,199,200,201,202,203,204,205, + 81,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, +221, 51, 83,222, 80,223,224,225,226, 44,227,228,229, 61,230,231, +232,233,234, 58,235, 66, 59,236,237,238, 60, 70, 63,239,240,241, + 84, 14, 75,242, 71, 82,243, 73,244, 15, 85, 79, 86, 30, 77, 87, +245,246,247, 25, 74, 42, 24,248,249,250, 31, 56, 29,251,252,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 94.7368% +# first 1024 sequences:5.2623% +# rest sequences: 0.8894% +# negative sequences: 0.0009% +HungarianLangModel = ( \ +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,2,2,3,3,1,1,2,2,2,2,2,1,2, +3,2,2,3,3,3,3,3,2,3,3,3,3,3,3,1,2,3,3,3,3,2,3,3,1,1,3,3,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0, +3,2,1,3,3,3,3,3,2,3,3,3,3,3,1,1,2,3,3,3,3,3,3,3,1,1,3,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,1,1,2,3,3,3,1,3,3,3,3,3,1,3,3,2,2,0,3,2,3, +0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,2,3,3,2,3,3,3,3,3,2,3,3,2,2,3,2,3,2,0,3,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,3,3,2,3,3,3,1,2,3,2,2,3,1,2,3,3,2,2,0,3,3,3, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,3,2,3,3,3,3,2,3,3,3,3,0,2,3,2, +0,0,0,1,1,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,1,1,1,3,3,2,1,3,2,2,3,2,1,3,2,2,1,0,3,3,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,2,2,3,3,3,3,3,1,2,3,3,3,3,1,2,1,3,3,3,3,2,2,3,1,1,3,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,1,3,3,3,3,3,2,2,1,3,3,3,0,1,1,2, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,2,3,3,3,2,0,3,2,3, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,2,3,2,3,3,3,1,3,2,2,2,3,1,1,3,3,1,1,0,3,3,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,2,3,3,3,2,3,2,3,3,3,2,3,3,3,3,3,1,2,3,2,2,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,1,3,3,2,2,1,3,3,3,1,1,3,1,2,3,2,3,2,2,2,1,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,1,1,3,3,3,3,3,1,2,3,3,3,3,1,2,1,3,3,3,2,2,3,2,1,0,3,2,0,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,3,3,3,3,3,1,2,3,3,3,3,1,1,0,3,3,3,3,0,2,3,0,0,2,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,2,2,2,2,3,3,0,1,2,3,2,3,2,2,3,2,1,2,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,3,3,3,3,3,1,2,3,3,3,2,1,2,3,3,2,2,2,3,2,3,3,1,3,3,1,1,0,2,3,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,1,2,2,2,2,3,3,3,1,1,1,3,3,1,1,3,1,1,3,2,1,2,3,1,1,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,1,2,1,1,3,3,1,1,1,1,3,3,1,1,2,2,1,2,1,1,2,2,1,1,0,2,2,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,1,1,2,1,1,3,3,1,0,1,1,3,3,2,0,1,1,2,3,1,0,2,2,1,0,0,1,3,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,2,1,3,3,3,3,3,1,2,3,2,3,3,2,1,1,3,2,3,2,1,2,2,0,1,2,1,0,0,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,2,2,2,2,3,1,2,2,1,1,3,3,0,3,2,1,2,3,2,1,3,3,1,1,0,2,1,3, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,2,3,3,3,2,1,1,3,3,1,1,1,2,2,3,2,3,2,2,2,1,0,2,2,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +1,0,0,3,3,3,3,3,0,0,3,3,2,3,0,0,0,2,3,3,1,0,1,2,0,0,1,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,2,3,3,3,3,3,1,2,3,3,2,2,1,1,0,3,3,2,2,1,2,2,1,0,2,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,2,1,3,1,2,3,3,2,2,1,1,2,2,1,1,1,1,3,2,1,1,1,1,2,1,0,1,2,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +2,3,3,1,1,1,1,1,3,3,3,0,1,1,3,3,1,1,1,1,1,2,2,0,3,1,1,2,0,2,1,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,1,0,1,2,1,2,2,0,1,2,3,1,2,0,0,0,2,1,1,1,1,1,2,0,0,1,1,0,0,0,0, +1,2,1,2,2,2,1,2,1,2,0,2,0,2,2,1,1,2,1,1,2,1,1,1,0,1,0,0,0,1,1,0, +1,1,1,2,3,2,3,3,0,1,2,2,3,1,0,1,0,2,1,2,2,0,1,1,0,0,1,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,3,3,2,2,1,0,0,3,2,3,2,0,0,0,1,1,3,0,0,1,1,0,0,2,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,2,2,3,3,1,0,1,3,2,3,1,1,1,0,1,1,1,1,1,3,1,0,0,2,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,1,2,2,2,1,0,1,2,3,3,2,0,0,0,2,1,1,1,2,1,1,1,0,1,1,1,0,0,0, +1,2,2,2,2,2,1,1,1,2,0,2,1,1,1,1,1,2,1,1,1,1,1,1,0,1,1,1,0,0,1,1, +3,2,2,1,0,0,1,1,2,2,0,3,0,1,2,1,1,0,0,1,1,1,0,1,1,1,1,0,2,1,1,1, +2,2,1,1,1,2,1,2,1,1,1,1,1,1,1,2,1,1,1,2,3,1,1,1,1,1,1,1,1,1,0,1, +2,3,3,0,1,0,0,0,3,3,1,0,0,1,2,2,1,0,0,0,0,2,0,0,1,1,1,0,2,1,1,1, +2,1,1,1,1,1,1,2,1,1,0,1,1,0,1,1,1,0,1,2,1,1,0,1,1,1,1,1,1,1,0,1, +2,3,3,0,1,0,0,0,2,2,0,0,0,0,1,2,2,0,0,0,0,1,0,0,1,1,0,0,2,0,1,0, +2,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,2,0,1,1,1,1,1,0,1, +3,2,2,0,1,0,1,0,2,3,2,0,0,1,2,2,1,0,0,1,1,1,0,0,2,1,0,1,2,2,1,1, +2,1,1,1,1,1,1,2,1,1,1,1,1,1,0,2,1,0,1,1,0,1,1,1,0,1,1,2,1,1,0,1, +2,2,2,0,0,1,0,0,2,2,1,1,0,0,2,1,1,0,0,0,1,2,0,0,2,1,0,0,2,1,1,1, +2,1,1,1,1,2,1,2,1,1,1,2,2,1,1,2,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1, +1,2,3,0,0,0,1,0,3,2,1,0,0,1,2,1,1,0,0,0,0,2,1,0,1,1,0,0,2,1,2,1, +1,1,0,0,0,1,0,1,1,1,1,1,2,0,0,1,0,0,0,2,0,0,1,1,1,1,1,1,1,1,0,1, +3,0,0,2,1,2,2,1,0,0,2,1,2,2,0,0,0,2,1,1,1,0,1,1,0,0,1,1,2,0,0,0, +1,2,1,2,2,1,1,2,1,2,0,1,1,1,1,1,1,1,1,1,2,1,1,0,0,1,1,1,1,0,0,1, +1,3,2,0,0,0,1,0,2,2,2,0,0,0,2,2,1,0,0,0,0,3,1,1,1,1,0,0,2,1,1,1, +2,1,0,1,1,1,0,1,1,1,1,1,1,1,0,2,1,0,0,1,0,1,1,0,1,1,1,1,1,1,0,1, +2,3,2,0,0,0,1,0,2,2,0,0,0,0,2,1,1,0,0,0,0,2,1,0,1,1,0,0,2,1,1,0, +2,1,1,1,1,2,1,2,1,2,0,1,1,1,0,2,1,1,1,2,1,1,1,1,0,1,1,1,1,1,0,1, +3,1,1,2,2,2,3,2,1,1,2,2,1,1,0,1,0,2,2,1,1,1,1,1,0,0,1,1,0,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,0,0,0,0,0,2,2,0,0,0,0,2,2,1,0,0,0,1,1,0,0,1,2,0,0,2,1,1,1, +2,2,1,1,1,2,1,2,1,1,0,1,1,1,1,2,1,1,1,2,1,1,1,1,0,1,2,1,1,1,0,1, +1,0,0,1,2,3,2,1,0,0,2,0,1,1,0,0,0,1,1,1,1,0,1,1,0,0,1,0,0,0,0,0, +1,2,1,2,1,2,1,1,1,2,0,2,1,1,1,0,1,2,0,0,1,1,1,0,0,0,0,0,0,0,0,0, +2,3,2,0,0,0,0,0,1,1,2,1,0,0,1,1,1,0,0,0,0,2,0,0,1,1,0,0,2,1,1,1, +2,1,1,1,1,1,1,2,1,0,1,1,1,1,0,2,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1, +1,2,2,0,1,1,1,0,2,2,2,0,0,0,3,2,1,0,0,0,1,1,0,0,1,1,0,1,1,1,0,0, +1,1,0,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,0,0,1,1,1,0,1,0,1, +2,1,0,2,1,1,2,2,1,1,2,1,1,1,0,0,0,1,1,0,1,1,1,1,0,0,1,1,1,0,0,0, +1,2,2,2,2,2,1,1,1,2,0,2,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,1,0, +1,2,3,0,0,0,1,0,2,2,0,0,0,0,2,2,0,0,0,0,0,1,0,0,1,0,0,0,2,0,1,0, +2,1,1,1,1,1,0,2,0,0,0,1,2,1,1,1,1,0,1,2,0,1,0,1,0,1,1,1,0,1,0,1, +2,2,2,0,0,0,1,0,2,1,2,0,0,0,1,1,2,0,0,0,0,1,0,0,1,1,0,0,2,1,0,1, +2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,0,1,1,1,1,1,0,1, +1,2,2,0,0,0,1,0,2,2,2,0,0,0,1,1,0,0,0,0,0,1,1,0,2,0,0,1,1,1,0,1, +1,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,0,0,1,1,0,1,0,1,1,1,1,1,0,0,0,1, +1,0,0,1,0,1,2,1,0,0,1,1,1,2,0,0,0,1,1,0,1,0,1,1,0,0,1,0,0,0,0,0, +0,2,1,2,1,1,1,1,1,2,0,2,0,1,1,0,1,2,1,0,1,1,1,0,0,0,0,0,0,1,0,0, +2,1,1,0,1,2,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,2,1,0,1, +2,2,1,1,1,1,1,2,1,1,0,1,1,1,1,2,1,1,1,2,1,1,0,1,0,1,1,1,1,1,0,1, +1,2,2,0,0,0,0,0,1,1,0,0,0,0,2,1,0,0,0,0,0,2,0,0,2,2,0,0,2,0,0,1, +2,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,0,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1, +1,1,2,0,0,3,1,0,2,1,1,1,0,0,1,1,1,0,0,0,1,1,0,0,0,1,0,0,1,0,1,0, +1,2,1,0,1,1,1,2,1,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,1,0,0,0,1,0,0, +2,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,2,0,0,0, +2,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,2,1,1,0,0,1,1,1,1,1,0,1, +2,1,1,1,2,1,1,1,0,1,1,2,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,0,1,1,1,1,1,0,0,1,1,2,1,0,0,0,1,1,0,0,0,1,1,0,0,1,0,1,0,0,0, +1,2,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,1,0,0, +2,0,0,0,1,1,1,1,0,0,1,1,0,0,0,0,0,1,1,1,2,0,0,1,0,0,1,0,1,0,0,0, +0,1,1,1,1,1,1,1,1,2,0,1,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,1,0,0,2,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0, +0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,0,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +0,1,1,1,1,1,0,0,1,1,0,1,0,1,0,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +0,0,0,1,0,0,0,0,0,0,1,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,1,1,0,1,0,0,1,1,0,1,0,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +2,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0,1,0,1,0,1,1,1,0,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,1,1,1,1,1,0,1,1,0,1,0,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +) + +Latin2HungarianModel = { \ + 'charToOrderMap': Latin2_HungarianCharToOrderMap, + 'precedenceMatrix': HungarianLangModel, + 'mTypicalPositiveRatio': 0.947368, + 'keepEnglishLetter': constants.True, + 'charsetName': "ISO-8859-2" +} + +Win1250HungarianModel = { \ + 'charToOrderMap': win1250HungarianCharToOrderMap, + 'precedenceMatrix': HungarianLangModel, + 'mTypicalPositiveRatio': 0.947368, + 'keepEnglishLetter': constants.True, + 'charsetName': "windows-1250" +} diff --git a/libs/requests/packages/chardet/langthaimodel.py b/libs/requests/packages/chardet/langthaimodel.py new file mode 100755 index 00000000..96ec054f --- /dev/null +++ b/libs/requests/packages/chardet/langthaimodel.py @@ -0,0 +1,200 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import constants + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# The following result for thai was collected from a limited sample (1M). + +# Character Mapping Table: +TIS620CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,182,106,107,100,183,184,185,101, 94,186,187,108,109,110,111, # 40 +188,189,190, 89, 95,112,113,191,192,193,194,253,253,253,253,253, # 50 +253, 64, 72, 73,114, 74,115,116,102, 81,201,117, 90,103, 78, 82, # 60 + 96,202, 91, 79, 84,104,105, 97, 98, 92,203,253,253,253,253,253, # 70 +209,210,211,212,213, 88,214,215,216,217,218,219,220,118,221,222, +223,224, 99, 85, 83,225,226,227,228,229,230,231,232,233,234,235, +236, 5, 30,237, 24,238, 75, 8, 26, 52, 34, 51,119, 47, 58, 57, + 49, 53, 55, 43, 20, 19, 44, 14, 48, 3, 17, 25, 39, 62, 31, 54, + 45, 9, 16, 2, 61, 15,239, 12, 42, 46, 18, 21, 76, 4, 66, 63, + 22, 10, 1, 36, 23, 13, 40, 27, 32, 35, 86,240,241,242,243,244, + 11, 28, 41, 29, 33,245, 50, 37, 6, 7, 67, 77, 38, 93,246,247, + 68, 56, 59, 65, 69, 60, 70, 80, 71, 87,248,249,250,251,252,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 92.6386% +# first 1024 sequences:7.3177% +# rest sequences: 1.0230% +# negative sequences: 0.0436% +ThaiLangModel = ( \ +0,1,3,3,3,3,0,0,3,3,0,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3,3,0,3,3,3,3, +0,3,3,0,0,0,1,3,0,3,3,2,3,3,0,1,2,3,3,3,3,0,2,0,2,0,0,3,2,1,2,2, +3,0,3,3,2,3,0,0,3,3,0,3,3,0,3,3,3,3,3,3,3,3,3,0,3,2,3,0,2,2,2,3, +0,2,3,0,0,0,0,1,0,1,2,3,1,1,3,2,2,0,1,1,0,0,1,0,0,0,0,0,0,0,1,1, +3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,3,3,2,3,2,3,3,2,2,2, +3,1,2,3,0,3,3,2,2,1,2,3,3,1,2,0,1,3,0,1,0,0,1,0,0,0,0,0,0,0,1,1, +3,3,2,2,3,3,3,3,1,2,3,3,3,3,3,2,2,2,2,3,3,2,2,3,3,2,2,3,2,3,2,2, +3,3,1,2,3,1,2,2,3,3,1,0,2,1,0,0,3,1,2,1,0,0,1,0,0,0,0,0,0,1,0,1, +3,3,3,3,3,3,2,2,3,3,3,3,2,3,2,2,3,3,2,2,3,2,2,2,2,1,1,3,1,2,1,1, +3,2,1,0,2,1,0,1,0,1,1,0,1,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,3,2,3,2,3,3,2,2,3,2,3,3,2,3,1,1,2,3,2,2,2,3,2,2,2,2,2,1,2,1, +2,2,1,1,3,3,2,1,0,1,2,2,0,1,3,0,0,0,1,1,0,0,0,0,0,2,3,0,0,2,1,1, +3,3,2,3,3,2,0,0,3,3,0,3,3,0,2,2,3,1,2,2,1,1,1,0,2,2,2,0,2,2,1,1, +0,2,1,0,2,0,0,2,0,1,0,0,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,2,3,3,2,0,0,3,3,0,2,3,0,2,1,2,2,2,2,1,2,0,0,2,2,2,0,2,2,1,1, +0,2,1,0,2,0,0,2,0,1,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,2,3,2,3,2,0,2,2,1,3,2,1,3,2,1,2,3,2,2,3,0,2,3,2,2,1,2,2,2,2, +1,2,2,0,0,0,0,2,0,1,2,0,1,1,1,0,1,0,3,1,1,0,0,0,0,0,0,0,0,0,1,0, +3,3,2,3,3,2,3,2,2,2,3,2,2,3,2,2,1,2,3,2,2,3,1,3,2,2,2,3,2,2,2,3, +3,2,1,3,0,1,1,1,0,2,1,1,1,1,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,2,0,0, +1,0,0,3,0,3,3,3,3,3,0,0,3,0,2,2,3,3,3,3,3,0,0,0,1,1,3,0,0,0,0,2, +0,0,1,0,0,0,0,0,0,0,2,3,0,0,0,3,0,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +2,0,3,3,3,3,0,0,2,3,0,0,3,0,3,3,2,3,3,3,3,3,0,0,3,3,3,0,0,0,3,3, +0,0,3,0,0,0,0,2,0,0,2,1,1,3,0,0,1,0,0,2,3,0,1,0,0,0,0,0,0,0,1,0, +3,3,3,3,2,3,3,3,3,3,3,3,1,2,1,3,3,2,2,1,2,2,2,3,1,1,2,0,2,1,2,1, +2,2,1,0,0,0,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0, +3,0,2,1,2,3,3,3,0,2,0,2,2,0,2,1,3,2,2,1,2,1,0,0,2,2,1,0,2,1,2,2, +0,1,1,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,3,3,1,1,3,0,2,3,1,1,3,2,1,1,2,0,2,2,3,2,1,1,1,1,1,2, +3,0,0,1,3,1,2,1,2,0,3,0,0,0,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, +3,3,1,1,3,2,3,3,3,1,3,2,1,3,2,1,3,2,2,2,2,1,3,3,1,2,1,3,1,2,3,0, +2,1,1,3,2,2,2,1,2,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2, +3,3,2,3,2,3,3,2,3,2,3,2,3,3,2,1,0,3,2,2,2,1,2,2,2,1,2,2,1,2,1,1, +2,2,2,3,0,1,3,1,1,1,1,0,1,1,0,2,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,3,2,2,1,1,3,2,3,2,3,2,0,3,2,2,1,2,0,2,2,2,1,2,2,2,2,1, +3,2,1,2,2,1,0,2,0,1,0,0,1,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,2,3,1,2,3,3,2,2,3,0,1,1,2,0,3,3,2,2,3,0,1,1,3,0,0,0,0, +3,1,0,3,3,0,2,0,2,1,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,3,2,3,3,0,1,3,1,1,2,1,2,1,1,3,1,1,0,2,3,1,1,1,1,1,1,1,1, +3,1,1,2,2,2,2,1,1,1,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,2,2,1,1,2,1,3,3,2,3,2,2,3,2,2,3,1,2,2,1,2,0,3,2,1,2,2,2,2,2,1, +3,2,1,2,2,2,1,1,1,1,0,0,1,1,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,1,3,3,0,2,1,0,3,2,0,0,3,1,0,1,1,0,1,0,0,0,0,0,1, +1,0,0,1,0,3,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,2,2,2,3,0,0,1,3,0,3,2,0,3,2,2,3,3,3,3,3,1,0,2,2,2,0,2,2,1,2, +0,2,3,0,0,0,0,1,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,0,2,3,1,3,3,2,3,3,0,3,3,0,3,2,2,3,2,3,3,3,0,0,2,2,3,0,1,1,1,3, +0,0,3,0,0,0,2,2,0,1,3,0,1,2,2,2,3,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1, +3,2,3,3,2,0,3,3,2,2,3,1,3,2,1,3,2,0,1,2,2,0,2,3,2,1,0,3,0,0,0,0, +3,0,0,2,3,1,3,0,0,3,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,3,2,2,2,1,2,0,1,3,1,1,3,1,3,0,0,2,1,1,1,1,2,1,1,1,0,2,1,0,1, +1,2,0,0,0,3,1,1,0,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0,3,1,0,0,0,1,0, +3,3,3,3,2,2,2,2,2,1,3,1,1,1,2,0,1,1,2,1,2,1,3,2,0,0,3,1,1,1,1,1, +3,1,0,2,3,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,2,3,0,3,3,0,2,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,1,3,0,0,1,2,0,0,2,0,3,3,2,3,3,3,2,3,0,0,2,2,2,0,0,0,2,2, +0,0,1,0,0,0,0,3,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +0,0,0,3,0,2,0,0,0,0,0,0,0,0,0,0,1,2,3,1,3,3,0,0,1,0,3,0,0,0,0,0, +0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,1,2,3,1,2,3,1,0,3,0,2,2,1,0,2,1,1,2,0,1,0,0,1,1,1,1,0,1,0,0, +1,0,0,0,0,1,1,0,3,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,0,1,1,1,3,1,2,2,2,2,2,2,1,1,1,1,0,3,1,0,1,3,1,1,1,1, +1,1,0,2,0,1,3,1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1, +3,0,2,2,1,3,3,2,3,3,0,1,1,0,2,2,1,2,1,3,3,1,0,0,3,2,0,0,0,0,2,1, +0,1,0,0,0,0,1,2,0,1,1,3,1,1,2,2,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,3,0,0,1,0,0,0,3,0,0,3,0,3,1,0,1,1,1,3,2,0,0,0,3,0,0,0,0,2,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,1,3,2,1,3,3,1,2,2,0,1,2,1,0,1,2,0,0,0,0,0,3,0,0,0,3,0,0,0,0, +3,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,2,0,3,3,3,2,2,0,1,1,0,1,3,0,0,0,2,2,0,0,0,0,3,1,0,1,0,0,0, +0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,2,3,1,2,0,0,2,1,0,3,1,0,1,2,0,1,1,1,1,3,0,0,3,1,1,0,2,2,1,1, +0,2,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,3,1,2,0,0,2,2,0,1,2,0,1,0,1,3,1,2,1,0,0,0,2,0,3,0,0,0,1,0, +0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,1,2,2,0,0,0,2,0,2,1,0,1,1,0,1,1,1,2,1,0,0,1,1,1,0,2,1,1,1, +0,1,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1, +0,0,0,2,0,1,3,1,1,1,1,0,0,0,0,3,2,0,1,0,0,0,1,2,0,0,0,1,0,0,0,0, +0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,2,3,2,2,0,0,0,1,0,0,0,0,2,3,2,1,2,2,3,0,0,0,2,3,1,0,0,0,1,1, +0,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0, +3,3,2,2,0,1,0,0,0,0,2,0,2,0,1,0,0,0,1,1,0,0,0,2,1,0,1,0,1,1,0,0, +0,1,0,2,0,0,1,0,3,0,1,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,1,0,0,1,0,0,0,0,0,1,1,2,0,0,0,0,1,0,0,1,3,1,0,0,0,0,1,1,0,0, +0,1,0,0,0,0,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0, +3,3,1,1,1,1,2,3,0,0,2,1,1,1,1,1,0,2,1,1,0,0,0,2,1,0,1,2,1,1,0,1, +2,1,0,3,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,3,1,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1, +0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,0,0,0,0,0,0,1,2,1,0,1,1,0,2,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,2,0,0,0,1,3,0,1,0,0,0,2,0,0,0,0,0,0,0,1,2,0,0,0,0,0, +3,3,0,0,1,1,2,0,0,1,2,1,0,1,1,1,0,1,1,0,0,2,1,1,0,1,0,0,1,1,1,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,1,0,0,0,0,1,0,0,0,0,3,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,0,0,1,1,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,0,1,2,0,1,2,0,0,1,1,0,2,0,1,0,0,1,0,0,0,0,1,0,0,0,2,0,0,0,0, +1,0,0,1,0,1,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,0,0,0,0,0,0,0,1,1,0,1,1,0,2,1,3,0,0,0,0,1,1,0,0,0,0,0,0,0,3, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,1,0,0,2,0,0,2,0,0,1,1,2,0,0,1,1,0,0,0,1,0,0,0,1,1,0,0,0, +1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,3,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0, +1,0,0,0,0,0,0,0,0,1,0,0,0,0,2,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,1,0,0,2,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +TIS620ThaiModel = { \ + 'charToOrderMap': TIS620CharToOrderMap, + 'precedenceMatrix': ThaiLangModel, + 'mTypicalPositiveRatio': 0.926386, + 'keepEnglishLetter': constants.False, + 'charsetName': "TIS-620" +} diff --git a/libs/requests/packages/chardet/latin1prober.py b/libs/requests/packages/chardet/latin1prober.py new file mode 100755 index 00000000..b46129ba --- /dev/null +++ b/libs/requests/packages/chardet/latin1prober.py @@ -0,0 +1,136 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from charsetprober import CharSetProber +import constants +import operator + +FREQ_CAT_NUM = 4 + +UDF = 0 # undefined +OTH = 1 # other +ASC = 2 # ascii capital letter +ASS = 3 # ascii small letter +ACV = 4 # accent capital vowel +ACO = 5 # accent capital other +ASV = 6 # accent small vowel +ASO = 7 # accent small other +CLASS_NUM = 8 # total classes + +Latin1_CharToClass = ( \ + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 00 - 07 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 08 - 0F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 10 - 17 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 18 - 1F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 20 - 27 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 28 - 2F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 30 - 37 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 38 - 3F + OTH, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 40 - 47 + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 48 - 4F + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 50 - 57 + ASC, ASC, ASC, OTH, OTH, OTH, OTH, OTH, # 58 - 5F + OTH, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 60 - 67 + ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 68 - 6F + ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 70 - 77 + ASS, ASS, ASS, OTH, OTH, OTH, OTH, OTH, # 78 - 7F + OTH, UDF, OTH, ASO, OTH, OTH, OTH, OTH, # 80 - 87 + OTH, OTH, ACO, OTH, ACO, UDF, ACO, UDF, # 88 - 8F + UDF, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 90 - 97 + OTH, OTH, ASO, OTH, ASO, UDF, ASO, ACO, # 98 - 9F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A0 - A7 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A8 - AF + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B0 - B7 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B8 - BF + ACV, ACV, ACV, ACV, ACV, ACV, ACO, ACO, # C0 - C7 + ACV, ACV, ACV, ACV, ACV, ACV, ACV, ACV, # C8 - CF + ACO, ACO, ACV, ACV, ACV, ACV, ACV, OTH, # D0 - D7 + ACV, ACV, ACV, ACV, ACV, ACO, ACO, ACO, # D8 - DF + ASV, ASV, ASV, ASV, ASV, ASV, ASO, ASO, # E0 - E7 + ASV, ASV, ASV, ASV, ASV, ASV, ASV, ASV, # E8 - EF + ASO, ASO, ASV, ASV, ASV, ASV, ASV, OTH, # F0 - F7 + ASV, ASV, ASV, ASV, ASV, ASO, ASO, ASO, # F8 - FF +) + +# 0 : illegal +# 1 : very unlikely +# 2 : normal +# 3 : very likely +Latin1ClassModel = ( \ +# UDF OTH ASC ASS ACV ACO ASV ASO + 0, 0, 0, 0, 0, 0, 0, 0, # UDF + 0, 3, 3, 3, 3, 3, 3, 3, # OTH + 0, 3, 3, 3, 3, 3, 3, 3, # ASC + 0, 3, 3, 3, 1, 1, 3, 3, # ASS + 0, 3, 3, 3, 1, 2, 1, 2, # ACV + 0, 3, 3, 3, 3, 3, 3, 3, # ACO + 0, 3, 1, 3, 1, 1, 1, 3, # ASV + 0, 3, 1, 3, 1, 1, 3, 3, # ASO +) + +class Latin1Prober(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self.reset() + + def reset(self): + self._mLastCharClass = OTH + self._mFreqCounter = [0] * FREQ_CAT_NUM + CharSetProber.reset(self) + + def get_charset_name(self): + return "windows-1252" + + def feed(self, aBuf): + aBuf = self.filter_with_english_letters(aBuf) + for c in aBuf: + charClass = Latin1_CharToClass[ord(c)] + freq = Latin1ClassModel[(self._mLastCharClass * CLASS_NUM) + charClass] + if freq == 0: + self._mState = constants.eNotMe + break + self._mFreqCounter[freq] += 1 + self._mLastCharClass = charClass + + return self.get_state() + + def get_confidence(self): + if self.get_state() == constants.eNotMe: + return 0.01 + + total = reduce(operator.add, self._mFreqCounter) + if total < 0.01: + confidence = 0.0 + else: + confidence = (self._mFreqCounter[3] / total) - (self._mFreqCounter[1] * 20.0 / total) + if confidence < 0.0: + confidence = 0.0 + # lower the confidence of latin1 so that other more accurate detector + # can take priority. + confidence = confidence * 0.5 + return confidence diff --git a/libs/requests/packages/chardet/mbcharsetprober.py b/libs/requests/packages/chardet/mbcharsetprober.py new file mode 100755 index 00000000..a8131445 --- /dev/null +++ b/libs/requests/packages/chardet/mbcharsetprober.py @@ -0,0 +1,82 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Proofpoint, Inc. +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import constants, sys +from constants import eStart, eError, eItsMe +from charsetprober import CharSetProber + +class MultiByteCharSetProber(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self._mDistributionAnalyzer = None + self._mCodingSM = None + self._mLastChar = ['\x00', '\x00'] + + def reset(self): + CharSetProber.reset(self) + if self._mCodingSM: + self._mCodingSM.reset() + if self._mDistributionAnalyzer: + self._mDistributionAnalyzer.reset() + self._mLastChar = ['\x00', '\x00'] + + def get_charset_name(self): + pass + + def feed(self, aBuf): + aLen = len(aBuf) + for i in range(0, aLen): + codingState = self._mCodingSM.next_state(aBuf[i]) + if codingState == eError: + if constants._debug: + sys.stderr.write(self.get_charset_name() + ' prober hit error at byte ' + str(i) + '\n') + self._mState = constants.eNotMe + break + elif codingState == eItsMe: + self._mState = constants.eFoundIt + break + elif codingState == eStart: + charLen = self._mCodingSM.get_current_charlen() + if i == 0: + self._mLastChar[1] = aBuf[0] + self._mDistributionAnalyzer.feed(self._mLastChar, charLen) + else: + self._mDistributionAnalyzer.feed(aBuf[i-1:i+1], charLen) + + self._mLastChar[0] = aBuf[aLen - 1] + + if self.get_state() == constants.eDetecting: + if self._mDistributionAnalyzer.got_enough_data() and \ + (self.get_confidence() > constants.SHORTCUT_THRESHOLD): + self._mState = constants.eFoundIt + + return self.get_state() + + def get_confidence(self): + return self._mDistributionAnalyzer.get_confidence() diff --git a/libs/requests/packages/chardet/mbcsgroupprober.py b/libs/requests/packages/chardet/mbcsgroupprober.py new file mode 100755 index 00000000..941cc3e3 --- /dev/null +++ b/libs/requests/packages/chardet/mbcsgroupprober.py @@ -0,0 +1,50 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Proofpoint, Inc. +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from charsetgroupprober import CharSetGroupProber +from utf8prober import UTF8Prober +from sjisprober import SJISProber +from eucjpprober import EUCJPProber +from gb2312prober import GB2312Prober +from euckrprober import EUCKRProber +from big5prober import Big5Prober +from euctwprober import EUCTWProber + +class MBCSGroupProber(CharSetGroupProber): + def __init__(self): + CharSetGroupProber.__init__(self) + self._mProbers = [ \ + UTF8Prober(), + SJISProber(), + EUCJPProber(), + GB2312Prober(), + EUCKRProber(), + Big5Prober(), + EUCTWProber()] + self.reset() diff --git a/libs/requests/packages/chardet/mbcssm.py b/libs/requests/packages/chardet/mbcssm.py new file mode 100755 index 00000000..e46c1ffe --- /dev/null +++ b/libs/requests/packages/chardet/mbcssm.py @@ -0,0 +1,514 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from constants import eStart, eError, eItsMe + +# BIG5 + +BIG5_cls = ( \ + 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as legal value + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,1, # 78 - 7f + 4,4,4,4,4,4,4,4, # 80 - 87 + 4,4,4,4,4,4,4,4, # 88 - 8f + 4,4,4,4,4,4,4,4, # 90 - 97 + 4,4,4,4,4,4,4,4, # 98 - 9f + 4,3,3,3,3,3,3,3, # a0 - a7 + 3,3,3,3,3,3,3,3, # a8 - af + 3,3,3,3,3,3,3,3, # b0 - b7 + 3,3,3,3,3,3,3,3, # b8 - bf + 3,3,3,3,3,3,3,3, # c0 - c7 + 3,3,3,3,3,3,3,3, # c8 - cf + 3,3,3,3,3,3,3,3, # d0 - d7 + 3,3,3,3,3,3,3,3, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,3,3,3, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,3,3,0) # f8 - ff + +BIG5_st = ( \ + eError,eStart,eStart, 3,eError,eError,eError,eError,#00-07 + eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eError,#08-0f + eError,eStart,eStart,eStart,eStart,eStart,eStart,eStart)#10-17 + +Big5CharLenTable = (0, 1, 1, 2, 0) + +Big5SMModel = {'classTable': BIG5_cls, + 'classFactor': 5, + 'stateTable': BIG5_st, + 'charLenTable': Big5CharLenTable, + 'name': 'Big5'} + +# EUC-JP + +EUCJP_cls = ( \ + 4,4,4,4,4,4,4,4, # 00 - 07 + 4,4,4,4,4,4,5,5, # 08 - 0f + 4,4,4,4,4,4,4,4, # 10 - 17 + 4,4,4,5,4,4,4,4, # 18 - 1f + 4,4,4,4,4,4,4,4, # 20 - 27 + 4,4,4,4,4,4,4,4, # 28 - 2f + 4,4,4,4,4,4,4,4, # 30 - 37 + 4,4,4,4,4,4,4,4, # 38 - 3f + 4,4,4,4,4,4,4,4, # 40 - 47 + 4,4,4,4,4,4,4,4, # 48 - 4f + 4,4,4,4,4,4,4,4, # 50 - 57 + 4,4,4,4,4,4,4,4, # 58 - 5f + 4,4,4,4,4,4,4,4, # 60 - 67 + 4,4,4,4,4,4,4,4, # 68 - 6f + 4,4,4,4,4,4,4,4, # 70 - 77 + 4,4,4,4,4,4,4,4, # 78 - 7f + 5,5,5,5,5,5,5,5, # 80 - 87 + 5,5,5,5,5,5,1,3, # 88 - 8f + 5,5,5,5,5,5,5,5, # 90 - 97 + 5,5,5,5,5,5,5,5, # 98 - 9f + 5,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,2,2,2, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,2,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,0,5) # f8 - ff + +EUCJP_st = ( \ + 3, 4, 3, 5,eStart,eError,eError,eError,#00-07 + eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe,eStart,eError,eStart,eError,eError,eError,#10-17 + eError,eError,eStart,eError,eError,eError, 3,eError,#18-1f + 3,eError,eError,eError,eStart,eStart,eStart,eStart)#20-27 + +EUCJPCharLenTable = (2, 2, 2, 3, 1, 0) + +EUCJPSMModel = {'classTable': EUCJP_cls, + 'classFactor': 6, + 'stateTable': EUCJP_st, + 'charLenTable': EUCJPCharLenTable, + 'name': 'EUC-JP'} + +# EUC-KR + +EUCKR_cls = ( \ + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 1,1,1,1,1,1,1,1, # 40 - 47 + 1,1,1,1,1,1,1,1, # 48 - 4f + 1,1,1,1,1,1,1,1, # 50 - 57 + 1,1,1,1,1,1,1,1, # 58 - 5f + 1,1,1,1,1,1,1,1, # 60 - 67 + 1,1,1,1,1,1,1,1, # 68 - 6f + 1,1,1,1,1,1,1,1, # 70 - 77 + 1,1,1,1,1,1,1,1, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,3,3,3, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,3,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 2,2,2,2,2,2,2,2, # e0 - e7 + 2,2,2,2,2,2,2,2, # e8 - ef + 2,2,2,2,2,2,2,2, # f0 - f7 + 2,2,2,2,2,2,2,0) # f8 - ff + +EUCKR_st = ( + eError,eStart, 3,eError,eError,eError,eError,eError,#00-07 + eItsMe,eItsMe,eItsMe,eItsMe,eError,eError,eStart,eStart)#08-0f + +EUCKRCharLenTable = (0, 1, 2, 0) + +EUCKRSMModel = {'classTable': EUCKR_cls, + 'classFactor': 4, + 'stateTable': EUCKR_st, + 'charLenTable': EUCKRCharLenTable, + 'name': 'EUC-KR'} + +# EUC-TW + +EUCTW_cls = ( \ + 2,2,2,2,2,2,2,2, # 00 - 07 + 2,2,2,2,2,2,0,0, # 08 - 0f + 2,2,2,2,2,2,2,2, # 10 - 17 + 2,2,2,0,2,2,2,2, # 18 - 1f + 2,2,2,2,2,2,2,2, # 20 - 27 + 2,2,2,2,2,2,2,2, # 28 - 2f + 2,2,2,2,2,2,2,2, # 30 - 37 + 2,2,2,2,2,2,2,2, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,2, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,6,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,3,4,4,4,4,4,4, # a0 - a7 + 5,5,1,1,1,1,1,1, # a8 - af + 1,1,1,1,1,1,1,1, # b0 - b7 + 1,1,1,1,1,1,1,1, # b8 - bf + 1,1,3,1,3,3,3,3, # c0 - c7 + 3,3,3,3,3,3,3,3, # c8 - cf + 3,3,3,3,3,3,3,3, # d0 - d7 + 3,3,3,3,3,3,3,3, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,3,3,3, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,3,3,0) # f8 - ff + +EUCTW_st = ( \ + eError,eError,eStart, 3, 3, 3, 4,eError,#00-07 + eError,eError,eError,eError,eError,eError,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eError,eStart,eError,#10-17 + eStart,eStart,eStart,eError,eError,eError,eError,eError,#18-1f + 5,eError,eError,eError,eStart,eError,eStart,eStart,#20-27 + eStart,eError,eStart,eStart,eStart,eStart,eStart,eStart)#28-2f + +EUCTWCharLenTable = (0, 0, 1, 2, 2, 2, 3) + +EUCTWSMModel = {'classTable': EUCTW_cls, + 'classFactor': 7, + 'stateTable': EUCTW_st, + 'charLenTable': EUCTWCharLenTable, + 'name': 'x-euc-tw'} + +# GB2312 + +GB2312_cls = ( \ + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 3,3,3,3,3,3,3,3, # 30 - 37 + 3,3,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,4, # 78 - 7f + 5,6,6,6,6,6,6,6, # 80 - 87 + 6,6,6,6,6,6,6,6, # 88 - 8f + 6,6,6,6,6,6,6,6, # 90 - 97 + 6,6,6,6,6,6,6,6, # 98 - 9f + 6,6,6,6,6,6,6,6, # a0 - a7 + 6,6,6,6,6,6,6,6, # a8 - af + 6,6,6,6,6,6,6,6, # b0 - b7 + 6,6,6,6,6,6,6,6, # b8 - bf + 6,6,6,6,6,6,6,6, # c0 - c7 + 6,6,6,6,6,6,6,6, # c8 - cf + 6,6,6,6,6,6,6,6, # d0 - d7 + 6,6,6,6,6,6,6,6, # d8 - df + 6,6,6,6,6,6,6,6, # e0 - e7 + 6,6,6,6,6,6,6,6, # e8 - ef + 6,6,6,6,6,6,6,6, # f0 - f7 + 6,6,6,6,6,6,6,0) # f8 - ff + +GB2312_st = ( \ + eError,eStart,eStart,eStart,eStart,eStart, 3,eError,#00-07 + eError,eError,eError,eError,eError,eError,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eError,eError,eStart,#10-17 + 4,eError,eStart,eStart,eError,eError,eError,eError,#18-1f + eError,eError, 5,eError,eError,eError,eItsMe,eError,#20-27 + eError,eError,eStart,eStart,eStart,eStart,eStart,eStart)#28-2f + +# To be accurate, the length of class 6 can be either 2 or 4. +# But it is not necessary to discriminate between the two since +# it is used for frequency analysis only, and we are validing +# each code range there as well. So it is safe to set it to be +# 2 here. +GB2312CharLenTable = (0, 1, 1, 1, 1, 1, 2) + +GB2312SMModel = {'classTable': GB2312_cls, + 'classFactor': 7, + 'stateTable': GB2312_st, + 'charLenTable': GB2312CharLenTable, + 'name': 'GB2312'} + +# Shift_JIS + +SJIS_cls = ( \ + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,1, # 78 - 7f + 3,3,3,3,3,3,3,3, # 80 - 87 + 3,3,3,3,3,3,3,3, # 88 - 8f + 3,3,3,3,3,3,3,3, # 90 - 97 + 3,3,3,3,3,3,3,3, # 98 - 9f + #0xa0 is illegal in sjis encoding, but some pages does + #contain such byte. We need to be more error forgiven. + 2,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,2,2,2, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,2,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,4,4,4, # e8 - ef + 4,4,4,4,4,4,4,4, # f0 - f7 + 4,4,4,4,4,0,0,0) # f8 - ff + +SJIS_st = ( \ + eError,eStart,eStart, 3,eError,eError,eError,eError,#00-07 + eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe,eError,eError,eStart,eStart,eStart,eStart)#10-17 + +SJISCharLenTable = (0, 1, 1, 2, 0, 0) + +SJISSMModel = {'classTable': SJIS_cls, + 'classFactor': 6, + 'stateTable': SJIS_st, + 'charLenTable': SJISCharLenTable, + 'name': 'Shift_JIS'} + +# UCS2-BE + +UCS2BE_cls = ( \ + 0,0,0,0,0,0,0,0, # 00 - 07 + 0,0,1,0,0,2,0,0, # 08 - 0f + 0,0,0,0,0,0,0,0, # 10 - 17 + 0,0,0,3,0,0,0,0, # 18 - 1f + 0,0,0,0,0,0,0,0, # 20 - 27 + 0,3,3,3,3,3,0,0, # 28 - 2f + 0,0,0,0,0,0,0,0, # 30 - 37 + 0,0,0,0,0,0,0,0, # 38 - 3f + 0,0,0,0,0,0,0,0, # 40 - 47 + 0,0,0,0,0,0,0,0, # 48 - 4f + 0,0,0,0,0,0,0,0, # 50 - 57 + 0,0,0,0,0,0,0,0, # 58 - 5f + 0,0,0,0,0,0,0,0, # 60 - 67 + 0,0,0,0,0,0,0,0, # 68 - 6f + 0,0,0,0,0,0,0,0, # 70 - 77 + 0,0,0,0,0,0,0,0, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,0,0,0,0,0,0,0, # a0 - a7 + 0,0,0,0,0,0,0,0, # a8 - af + 0,0,0,0,0,0,0,0, # b0 - b7 + 0,0,0,0,0,0,0,0, # b8 - bf + 0,0,0,0,0,0,0,0, # c0 - c7 + 0,0,0,0,0,0,0,0, # c8 - cf + 0,0,0,0,0,0,0,0, # d0 - d7 + 0,0,0,0,0,0,0,0, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,4,5) # f8 - ff + +UCS2BE_st = ( \ + 5, 7, 7,eError, 4, 3,eError,eError,#00-07 + eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe, 6, 6, 6, 6,eError,eError,#10-17 + 6, 6, 6, 6, 6,eItsMe, 6, 6,#18-1f + 6, 6, 6, 6, 5, 7, 7,eError,#20-27 + 5, 8, 6, 6,eError, 6, 6, 6,#28-2f + 6, 6, 6, 6,eError,eError,eStart,eStart)#30-37 + +UCS2BECharLenTable = (2, 2, 2, 0, 2, 2) + +UCS2BESMModel = {'classTable': UCS2BE_cls, + 'classFactor': 6, + 'stateTable': UCS2BE_st, + 'charLenTable': UCS2BECharLenTable, + 'name': 'UTF-16BE'} + +# UCS2-LE + +UCS2LE_cls = ( \ + 0,0,0,0,0,0,0,0, # 00 - 07 + 0,0,1,0,0,2,0,0, # 08 - 0f + 0,0,0,0,0,0,0,0, # 10 - 17 + 0,0,0,3,0,0,0,0, # 18 - 1f + 0,0,0,0,0,0,0,0, # 20 - 27 + 0,3,3,3,3,3,0,0, # 28 - 2f + 0,0,0,0,0,0,0,0, # 30 - 37 + 0,0,0,0,0,0,0,0, # 38 - 3f + 0,0,0,0,0,0,0,0, # 40 - 47 + 0,0,0,0,0,0,0,0, # 48 - 4f + 0,0,0,0,0,0,0,0, # 50 - 57 + 0,0,0,0,0,0,0,0, # 58 - 5f + 0,0,0,0,0,0,0,0, # 60 - 67 + 0,0,0,0,0,0,0,0, # 68 - 6f + 0,0,0,0,0,0,0,0, # 70 - 77 + 0,0,0,0,0,0,0,0, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,0,0,0,0,0,0,0, # a0 - a7 + 0,0,0,0,0,0,0,0, # a8 - af + 0,0,0,0,0,0,0,0, # b0 - b7 + 0,0,0,0,0,0,0,0, # b8 - bf + 0,0,0,0,0,0,0,0, # c0 - c7 + 0,0,0,0,0,0,0,0, # c8 - cf + 0,0,0,0,0,0,0,0, # d0 - d7 + 0,0,0,0,0,0,0,0, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,4,5) # f8 - ff + +UCS2LE_st = ( \ + 6, 6, 7, 6, 4, 3,eError,eError,#00-07 + eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe, 5, 5, 5,eError,eItsMe,eError,#10-17 + 5, 5, 5,eError, 5,eError, 6, 6,#18-1f + 7, 6, 8, 8, 5, 5, 5,eError,#20-27 + 5, 5, 5,eError,eError,eError, 5, 5,#28-2f + 5, 5, 5,eError, 5,eError,eStart,eStart)#30-37 + +UCS2LECharLenTable = (2, 2, 2, 2, 2, 2) + +UCS2LESMModel = {'classTable': UCS2LE_cls, + 'classFactor': 6, + 'stateTable': UCS2LE_st, + 'charLenTable': UCS2LECharLenTable, + 'name': 'UTF-16LE'} + +# UTF-8 + +UTF8_cls = ( \ + 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as a legal value + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 1,1,1,1,1,1,1,1, # 40 - 47 + 1,1,1,1,1,1,1,1, # 48 - 4f + 1,1,1,1,1,1,1,1, # 50 - 57 + 1,1,1,1,1,1,1,1, # 58 - 5f + 1,1,1,1,1,1,1,1, # 60 - 67 + 1,1,1,1,1,1,1,1, # 68 - 6f + 1,1,1,1,1,1,1,1, # 70 - 77 + 1,1,1,1,1,1,1,1, # 78 - 7f + 2,2,2,2,3,3,3,3, # 80 - 87 + 4,4,4,4,4,4,4,4, # 88 - 8f + 4,4,4,4,4,4,4,4, # 90 - 97 + 4,4,4,4,4,4,4,4, # 98 - 9f + 5,5,5,5,5,5,5,5, # a0 - a7 + 5,5,5,5,5,5,5,5, # a8 - af + 5,5,5,5,5,5,5,5, # b0 - b7 + 5,5,5,5,5,5,5,5, # b8 - bf + 0,0,6,6,6,6,6,6, # c0 - c7 + 6,6,6,6,6,6,6,6, # c8 - cf + 6,6,6,6,6,6,6,6, # d0 - d7 + 6,6,6,6,6,6,6,6, # d8 - df + 7,8,8,8,8,8,8,8, # e0 - e7 + 8,8,8,8,8,9,8,8, # e8 - ef + 10,11,11,11,11,11,11,11, # f0 - f7 + 12,13,13,13,14,15,0,0) # f8 - ff + +UTF8_st = ( \ + eError,eStart,eError,eError,eError,eError, 12, 10,#00-07 + 9, 11, 8, 7, 6, 5, 4, 3,#08-0f + eError,eError,eError,eError,eError,eError,eError,eError,#10-17 + eError,eError,eError,eError,eError,eError,eError,eError,#18-1f + eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,#20-27 + eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,#28-2f + eError,eError, 5, 5, 5, 5,eError,eError,#30-37 + eError,eError,eError,eError,eError,eError,eError,eError,#38-3f + eError,eError,eError, 5, 5, 5,eError,eError,#40-47 + eError,eError,eError,eError,eError,eError,eError,eError,#48-4f + eError,eError, 7, 7, 7, 7,eError,eError,#50-57 + eError,eError,eError,eError,eError,eError,eError,eError,#58-5f + eError,eError,eError,eError, 7, 7,eError,eError,#60-67 + eError,eError,eError,eError,eError,eError,eError,eError,#68-6f + eError,eError, 9, 9, 9, 9,eError,eError,#70-77 + eError,eError,eError,eError,eError,eError,eError,eError,#78-7f + eError,eError,eError,eError,eError, 9,eError,eError,#80-87 + eError,eError,eError,eError,eError,eError,eError,eError,#88-8f + eError,eError, 12, 12, 12, 12,eError,eError,#90-97 + eError,eError,eError,eError,eError,eError,eError,eError,#98-9f + eError,eError,eError,eError,eError, 12,eError,eError,#a0-a7 + eError,eError,eError,eError,eError,eError,eError,eError,#a8-af + eError,eError, 12, 12, 12,eError,eError,eError,#b0-b7 + eError,eError,eError,eError,eError,eError,eError,eError,#b8-bf + eError,eError,eStart,eStart,eStart,eStart,eError,eError,#c0-c7 + eError,eError,eError,eError,eError,eError,eError,eError)#c8-cf + +UTF8CharLenTable = (0, 1, 0, 0, 0, 0, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6) + +UTF8SMModel = {'classTable': UTF8_cls, + 'classFactor': 16, + 'stateTable': UTF8_st, + 'charLenTable': UTF8CharLenTable, + 'name': 'UTF-8'} diff --git a/libs/requests/packages/chardet/sbcharsetprober.py b/libs/requests/packages/chardet/sbcharsetprober.py new file mode 100755 index 00000000..da071163 --- /dev/null +++ b/libs/requests/packages/chardet/sbcharsetprober.py @@ -0,0 +1,106 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import constants, sys +from charsetprober import CharSetProber + +SAMPLE_SIZE = 64 +SB_ENOUGH_REL_THRESHOLD = 1024 +POSITIVE_SHORTCUT_THRESHOLD = 0.95 +NEGATIVE_SHORTCUT_THRESHOLD = 0.05 +SYMBOL_CAT_ORDER = 250 +NUMBER_OF_SEQ_CAT = 4 +POSITIVE_CAT = NUMBER_OF_SEQ_CAT - 1 +#NEGATIVE_CAT = 0 + +class SingleByteCharSetProber(CharSetProber): + def __init__(self, model, reversed=constants.False, nameProber=None): + CharSetProber.__init__(self) + self._mModel = model + self._mReversed = reversed # TRUE if we need to reverse every pair in the model lookup + self._mNameProber = nameProber # Optional auxiliary prober for name decision + self.reset() + + def reset(self): + CharSetProber.reset(self) + self._mLastOrder = 255 # char order of last character + self._mSeqCounters = [0] * NUMBER_OF_SEQ_CAT + self._mTotalSeqs = 0 + self._mTotalChar = 0 + self._mFreqChar = 0 # characters that fall in our sampling range + + def get_charset_name(self): + if self._mNameProber: + return self._mNameProber.get_charset_name() + else: + return self._mModel['charsetName'] + + def feed(self, aBuf): + if not self._mModel['keepEnglishLetter']: + aBuf = self.filter_without_english_letters(aBuf) + aLen = len(aBuf) + if not aLen: + return self.get_state() + for c in aBuf: + order = self._mModel['charToOrderMap'][ord(c)] + if order < SYMBOL_CAT_ORDER: + self._mTotalChar += 1 + if order < SAMPLE_SIZE: + self._mFreqChar += 1 + if self._mLastOrder < SAMPLE_SIZE: + self._mTotalSeqs += 1 + if not self._mReversed: + self._mSeqCounters[self._mModel['precedenceMatrix'][(self._mLastOrder * SAMPLE_SIZE) + order]] += 1 + else: # reverse the order of the letters in the lookup + self._mSeqCounters[self._mModel['precedenceMatrix'][(order * SAMPLE_SIZE) + self._mLastOrder]] += 1 + self._mLastOrder = order + + if self.get_state() == constants.eDetecting: + if self._mTotalSeqs > SB_ENOUGH_REL_THRESHOLD: + cf = self.get_confidence() + if cf > POSITIVE_SHORTCUT_THRESHOLD: + if constants._debug: + sys.stderr.write('%s confidence = %s, we have a winner\n' % (self._mModel['charsetName'], cf)) + self._mState = constants.eFoundIt + elif cf < NEGATIVE_SHORTCUT_THRESHOLD: + if constants._debug: + sys.stderr.write('%s confidence = %s, below negative shortcut threshhold %s\n' % (self._mModel['charsetName'], cf, NEGATIVE_SHORTCUT_THRESHOLD)) + self._mState = constants.eNotMe + + return self.get_state() + + def get_confidence(self): + r = 0.01 + if self._mTotalSeqs > 0: +# print self._mSeqCounters[POSITIVE_CAT], self._mTotalSeqs, self._mModel['mTypicalPositiveRatio'] + r = (1.0 * self._mSeqCounters[POSITIVE_CAT]) / self._mTotalSeqs / self._mModel['mTypicalPositiveRatio'] +# print r, self._mFreqChar, self._mTotalChar + r = r * self._mFreqChar / self._mTotalChar + if r >= 1.0: + r = 0.99 + return r diff --git a/libs/requests/packages/chardet/sbcsgroupprober.py b/libs/requests/packages/chardet/sbcsgroupprober.py new file mode 100755 index 00000000..d19160c8 --- /dev/null +++ b/libs/requests/packages/chardet/sbcsgroupprober.py @@ -0,0 +1,64 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import constants, sys +from charsetgroupprober import CharSetGroupProber +from sbcharsetprober import SingleByteCharSetProber +from langcyrillicmodel import Win1251CyrillicModel, Koi8rModel, Latin5CyrillicModel, MacCyrillicModel, Ibm866Model, Ibm855Model +from langgreekmodel import Latin7GreekModel, Win1253GreekModel +from langbulgarianmodel import Latin5BulgarianModel, Win1251BulgarianModel +from langhungarianmodel import Latin2HungarianModel, Win1250HungarianModel +from langthaimodel import TIS620ThaiModel +from langhebrewmodel import Win1255HebrewModel +from hebrewprober import HebrewProber + +class SBCSGroupProber(CharSetGroupProber): + def __init__(self): + CharSetGroupProber.__init__(self) + self._mProbers = [ \ + SingleByteCharSetProber(Win1251CyrillicModel), + SingleByteCharSetProber(Koi8rModel), + SingleByteCharSetProber(Latin5CyrillicModel), + SingleByteCharSetProber(MacCyrillicModel), + SingleByteCharSetProber(Ibm866Model), + SingleByteCharSetProber(Ibm855Model), + SingleByteCharSetProber(Latin7GreekModel), + SingleByteCharSetProber(Win1253GreekModel), + SingleByteCharSetProber(Latin5BulgarianModel), + SingleByteCharSetProber(Win1251BulgarianModel), + SingleByteCharSetProber(Latin2HungarianModel), + SingleByteCharSetProber(Win1250HungarianModel), + SingleByteCharSetProber(TIS620ThaiModel), + ] + hebrewProber = HebrewProber() + logicalHebrewProber = SingleByteCharSetProber(Win1255HebrewModel, constants.False, hebrewProber) + visualHebrewProber = SingleByteCharSetProber(Win1255HebrewModel, constants.True, hebrewProber) + hebrewProber.set_model_probers(logicalHebrewProber, visualHebrewProber) + self._mProbers.extend([hebrewProber, logicalHebrewProber, visualHebrewProber]) + + self.reset() diff --git a/libs/requests/packages/chardet/sjisprober.py b/libs/requests/packages/chardet/sjisprober.py new file mode 100755 index 00000000..fea2690c --- /dev/null +++ b/libs/requests/packages/chardet/sjisprober.py @@ -0,0 +1,85 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from mbcharsetprober import MultiByteCharSetProber +from codingstatemachine import CodingStateMachine +from chardistribution import SJISDistributionAnalysis +from jpcntx import SJISContextAnalysis +from mbcssm import SJISSMModel +import constants, sys +from constants import eStart, eError, eItsMe + +class SJISProber(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(SJISSMModel) + self._mDistributionAnalyzer = SJISDistributionAnalysis() + self._mContextAnalyzer = SJISContextAnalysis() + self.reset() + + def reset(self): + MultiByteCharSetProber.reset(self) + self._mContextAnalyzer.reset() + + def get_charset_name(self): + return "SHIFT_JIS" + + def feed(self, aBuf): + aLen = len(aBuf) + for i in range(0, aLen): + codingState = self._mCodingSM.next_state(aBuf[i]) + if codingState == eError: + if constants._debug: + sys.stderr.write(self.get_charset_name() + ' prober hit error at byte ' + str(i) + '\n') + self._mState = constants.eNotMe + break + elif codingState == eItsMe: + self._mState = constants.eFoundIt + break + elif codingState == eStart: + charLen = self._mCodingSM.get_current_charlen() + if i == 0: + self._mLastChar[1] = aBuf[0] + self._mContextAnalyzer.feed(self._mLastChar[2 - charLen :], charLen) + self._mDistributionAnalyzer.feed(self._mLastChar, charLen) + else: + self._mContextAnalyzer.feed(aBuf[i + 1 - charLen : i + 3 - charLen], charLen) + self._mDistributionAnalyzer.feed(aBuf[i - 1 : i + 1], charLen) + + self._mLastChar[0] = aBuf[aLen - 1] + + if self.get_state() == constants.eDetecting: + if self._mContextAnalyzer.got_enough_data() and \ + (self.get_confidence() > constants.SHORTCUT_THRESHOLD): + self._mState = constants.eFoundIt + + return self.get_state() + + def get_confidence(self): + contxtCf = self._mContextAnalyzer.get_confidence() + distribCf = self._mDistributionAnalyzer.get_confidence() + return max(contxtCf, distribCf) diff --git a/libs/requests/packages/chardet/universaldetector.py b/libs/requests/packages/chardet/universaldetector.py new file mode 100755 index 00000000..809df227 --- /dev/null +++ b/libs/requests/packages/chardet/universaldetector.py @@ -0,0 +1,154 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import constants, sys +from latin1prober import Latin1Prober # windows-1252 +from mbcsgroupprober import MBCSGroupProber # multi-byte character sets +from sbcsgroupprober import SBCSGroupProber # single-byte character sets +from escprober import EscCharSetProber # ISO-2122, etc. +import re + +MINIMUM_THRESHOLD = 0.20 +ePureAscii = 0 +eEscAscii = 1 +eHighbyte = 2 + +class UniversalDetector: + def __init__(self): + self._highBitDetector = re.compile(r'[\x80-\xFF]') + self._escDetector = re.compile(r'(\033|~{)') + self._mEscCharSetProber = None + self._mCharSetProbers = [] + self.reset() + + def reset(self): + self.result = {'encoding': None, 'confidence': 0.0} + self.done = constants.False + self._mStart = constants.True + self._mGotData = constants.False + self._mInputState = ePureAscii + self._mLastChar = '' + if self._mEscCharSetProber: + self._mEscCharSetProber.reset() + for prober in self._mCharSetProbers: + prober.reset() + + def feed(self, aBuf): + if self.done: return + + aLen = len(aBuf) + if not aLen: return + + if not self._mGotData: + # If the data starts with BOM, we know it is UTF + if aBuf[:3] == '\xEF\xBB\xBF': + # EF BB BF UTF-8 with BOM + self.result = {'encoding': "UTF-8", 'confidence': 1.0} + elif aBuf[:4] == '\xFF\xFE\x00\x00': + # FF FE 00 00 UTF-32, little-endian BOM + self.result = {'encoding': "UTF-32LE", 'confidence': 1.0} + elif aBuf[:4] == '\x00\x00\xFE\xFF': + # 00 00 FE FF UTF-32, big-endian BOM + self.result = {'encoding': "UTF-32BE", 'confidence': 1.0} + elif aBuf[:4] == '\xFE\xFF\x00\x00': + # FE FF 00 00 UCS-4, unusual octet order BOM (3412) + self.result = {'encoding': "X-ISO-10646-UCS-4-3412", 'confidence': 1.0} + elif aBuf[:4] == '\x00\x00\xFF\xFE': + # 00 00 FF FE UCS-4, unusual octet order BOM (2143) + self.result = {'encoding': "X-ISO-10646-UCS-4-2143", 'confidence': 1.0} + elif aBuf[:2] == '\xFF\xFE': + # FF FE UTF-16, little endian BOM + self.result = {'encoding': "UTF-16LE", 'confidence': 1.0} + elif aBuf[:2] == '\xFE\xFF': + # FE FF UTF-16, big endian BOM + self.result = {'encoding': "UTF-16BE", 'confidence': 1.0} + + self._mGotData = constants.True + if self.result['encoding'] and (self.result['confidence'] > 0.0): + self.done = constants.True + return + + if self._mInputState == ePureAscii: + if self._highBitDetector.search(aBuf): + self._mInputState = eHighbyte + elif (self._mInputState == ePureAscii) and self._escDetector.search(self._mLastChar + aBuf): + self._mInputState = eEscAscii + + self._mLastChar = aBuf[-1] + + if self._mInputState == eEscAscii: + if not self._mEscCharSetProber: + self._mEscCharSetProber = EscCharSetProber() + if self._mEscCharSetProber.feed(aBuf) == constants.eFoundIt: + self.result = {'encoding': self._mEscCharSetProber.get_charset_name(), + 'confidence': self._mEscCharSetProber.get_confidence()} + self.done = constants.True + elif self._mInputState == eHighbyte: + if not self._mCharSetProbers: + self._mCharSetProbers = [MBCSGroupProber(), SBCSGroupProber(), Latin1Prober()] + for prober in self._mCharSetProbers: + if prober.feed(aBuf) == constants.eFoundIt: + self.result = {'encoding': prober.get_charset_name(), + 'confidence': prober.get_confidence()} + self.done = constants.True + break + + def close(self): + if self.done: return + if not self._mGotData: + if constants._debug: + sys.stderr.write('no data received!\n') + return + self.done = constants.True + + if self._mInputState == ePureAscii: + self.result = {'encoding': 'ascii', 'confidence': 1.0} + return self.result + + if self._mInputState == eHighbyte: + proberConfidence = None + maxProberConfidence = 0.0 + maxProber = None + for prober in self._mCharSetProbers: + if not prober: continue + proberConfidence = prober.get_confidence() + if proberConfidence > maxProberConfidence: + maxProberConfidence = proberConfidence + maxProber = prober + if maxProber and (maxProberConfidence > MINIMUM_THRESHOLD): + self.result = {'encoding': maxProber.get_charset_name(), + 'confidence': maxProber.get_confidence()} + return self.result + + if constants._debug: + sys.stderr.write('no probers hit minimum threshhold\n') + for prober in self._mCharSetProbers[0].mProbers: + if not prober: continue + sys.stderr.write('%s confidence = %s\n' % \ + (prober.get_charset_name(), \ + prober.get_confidence())) diff --git a/libs/requests/packages/chardet/utf8prober.py b/libs/requests/packages/chardet/utf8prober.py new file mode 100755 index 00000000..c1792bb3 --- /dev/null +++ b/libs/requests/packages/chardet/utf8prober.py @@ -0,0 +1,76 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import constants, sys +from constants import eStart, eError, eItsMe +from charsetprober import CharSetProber +from codingstatemachine import CodingStateMachine +from mbcssm import UTF8SMModel + +ONE_CHAR_PROB = 0.5 + +class UTF8Prober(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(UTF8SMModel) + self.reset() + + def reset(self): + CharSetProber.reset(self) + self._mCodingSM.reset() + self._mNumOfMBChar = 0 + + def get_charset_name(self): + return "utf-8" + + def feed(self, aBuf): + for c in aBuf: + codingState = self._mCodingSM.next_state(c) + if codingState == eError: + self._mState = constants.eNotMe + break + elif codingState == eItsMe: + self._mState = constants.eFoundIt + break + elif codingState == eStart: + if self._mCodingSM.get_current_charlen() >= 2: + self._mNumOfMBChar += 1 + + if self.get_state() == constants.eDetecting: + if self.get_confidence() > constants.SHORTCUT_THRESHOLD: + self._mState = constants.eFoundIt + + return self.get_state() + + def get_confidence(self): + unlike = 0.99 + if self._mNumOfMBChar < 6: + for i in range(0, self._mNumOfMBChar): + unlike = unlike * ONE_CHAR_PROB + return 1.0 - unlike + else: + return unlike diff --git a/libs/requests/packages/chardet2/__init__.py b/libs/requests/packages/chardet2/__init__.py new file mode 100644 index 00000000..4005f1f2 --- /dev/null +++ b/libs/requests/packages/chardet2/__init__.py @@ -0,0 +1,26 @@ +######################## BEGIN LICENSE BLOCK ######################## +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +__version__ = "2.0.1" + +def detect(aBuf): + from . import universaldetector + u = universaldetector.UniversalDetector() + u.reset() + u.feed(aBuf) + u.close() + return u.result diff --git a/libs/requests/packages/chardet2/big5freq.py b/libs/requests/packages/chardet2/big5freq.py new file mode 100644 index 00000000..c1b0f3ce --- /dev/null +++ b/libs/requests/packages/chardet2/big5freq.py @@ -0,0 +1,923 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Big5 frequency table +# by Taiwan's Mandarin Promotion Council +# +# +# 128 --> 0.42261 +# 256 --> 0.57851 +# 512 --> 0.74851 +# 1024 --> 0.89384 +# 2048 --> 0.97583 +# +# Ideal Distribution Ratio = 0.74851/(1-0.74851) =2.98 +# Random Distribution Ration = 512/(5401-512)=0.105 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR + +BIG5_TYPICAL_DISTRIBUTION_RATIO = 0.75 + +#Char to FreqOrder table +BIG5_TABLE_SIZE = 5376 + +Big5CharToFreqOrder = ( \ + 1,1801,1506, 255,1431, 198, 9, 82, 6,5008, 177, 202,3681,1256,2821, 110, # 16 +3814, 33,3274, 261, 76, 44,2114, 16,2946,2187,1176, 659,3971, 26,3451,2653, # 32 +1198,3972,3350,4202, 410,2215, 302, 590, 361,1964, 8, 204, 58,4510,5009,1932, # 48 + 63,5010,5011, 317,1614, 75, 222, 159,4203,2417,1480,5012,3555,3091, 224,2822, # 64 +3682, 3, 10,3973,1471, 29,2787,1135,2866,1940, 873, 130,3275,1123, 312,5013, # 80 +4511,2052, 507, 252, 682,5014, 142,1915, 124, 206,2947, 34,3556,3204, 64, 604, # 96 +5015,2501,1977,1978, 155,1991, 645, 641,1606,5016,3452, 337, 72, 406,5017, 80, # 112 + 630, 238,3205,1509, 263, 939,1092,2654, 756,1440,1094,3453, 449, 69,2987, 591, # 128 + 179,2096, 471, 115,2035,1844, 60, 50,2988, 134, 806,1869, 734,2036,3454, 180, # 144 + 995,1607, 156, 537,2907, 688,5018, 319,1305, 779,2145, 514,2379, 298,4512, 359, # 160 +2502, 90,2716,1338, 663, 11, 906,1099,2553, 20,2441, 182, 532,1716,5019, 732, # 176 +1376,4204,1311,1420,3206, 25,2317,1056, 113, 399, 382,1950, 242,3455,2474, 529, # 192 +3276, 475,1447,3683,5020, 117, 21, 656, 810,1297,2300,2334,3557,5021, 126,4205, # 208 + 706, 456, 150, 613,4513, 71,1118,2037,4206, 145,3092, 85, 835, 486,2115,1246, # 224 +1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,5022,2128,2359, 347,3815, 221, # 240 +3558,3135,5023,1956,1153,4207, 83, 296,1199,3093, 192, 624, 93,5024, 822,1898, # 256 +2823,3136, 795,2065, 991,1554,1542,1592, 27, 43,2867, 859, 139,1456, 860,4514, # 272 + 437, 712,3974, 164,2397,3137, 695, 211,3037,2097, 195,3975,1608,3559,3560,3684, # 288 +3976, 234, 811,2989,2098,3977,2233,1441,3561,1615,2380, 668,2077,1638, 305, 228, # 304 +1664,4515, 467, 415,5025, 262,2099,1593, 239, 108, 300, 200,1033, 512,1247,2078, # 320 +5026,5027,2176,3207,3685,2682, 593, 845,1062,3277, 88,1723,2038,3978,1951, 212, # 336 + 266, 152, 149, 468,1899,4208,4516, 77, 187,5028,3038, 37, 5,2990,5029,3979, # 352 +5030,5031, 39,2524,4517,2908,3208,2079, 55, 148, 74,4518, 545, 483,1474,1029, # 368 +1665, 217,1870,1531,3138,1104,2655,4209, 24, 172,3562, 900,3980,3563,3564,4519, # 384 + 32,1408,2824,1312, 329, 487,2360,2251,2717, 784,2683, 4,3039,3351,1427,1789, # 400 + 188, 109, 499,5032,3686,1717,1790, 888,1217,3040,4520,5033,3565,5034,3352,1520, # 416 +3687,3981, 196,1034, 775,5035,5036, 929,1816, 249, 439, 38,5037,1063,5038, 794, # 432 +3982,1435,2301, 46, 178,3278,2066,5039,2381,5040, 214,1709,4521, 804, 35, 707, # 448 + 324,3688,1601,2554, 140, 459,4210,5041,5042,1365, 839, 272, 978,2262,2580,3456, # 464 +2129,1363,3689,1423, 697, 100,3094, 48, 70,1231, 495,3139,2196,5043,1294,5044, # 480 +2080, 462, 586,1042,3279, 853, 256, 988, 185,2382,3457,1698, 434,1084,5045,3458, # 496 + 314,2625,2788,4522,2335,2336, 569,2285, 637,1817,2525, 757,1162,1879,1616,3459, # 512 + 287,1577,2116, 768,4523,1671,2868,3566,2526,1321,3816, 909,2418,5046,4211, 933, # 528 +3817,4212,2053,2361,1222,4524, 765,2419,1322, 786,4525,5047,1920,1462,1677,2909, # 544 +1699,5048,4526,1424,2442,3140,3690,2600,3353,1775,1941,3460,3983,4213, 309,1369, # 560 +1130,2825, 364,2234,1653,1299,3984,3567,3985,3986,2656, 525,1085,3041, 902,2001, # 576 +1475, 964,4527, 421,1845,1415,1057,2286, 940,1364,3141, 376,4528,4529,1381, 7, # 592 +2527, 983,2383, 336,1710,2684,1846, 321,3461, 559,1131,3042,2752,1809,1132,1313, # 608 + 265,1481,1858,5049, 352,1203,2826,3280, 167,1089, 420,2827, 776, 792,1724,3568, # 624 +4214,2443,3281,5050,4215,5051, 446, 229, 333,2753, 901,3818,1200,1557,4530,2657, # 640 +1921, 395,2754,2685,3819,4216,1836, 125, 916,3209,2626,4531,5052,5053,3820,5054, # 656 +5055,5056,4532,3142,3691,1133,2555,1757,3462,1510,2318,1409,3569,5057,2146, 438, # 672 +2601,2910,2384,3354,1068, 958,3043, 461, 311,2869,2686,4217,1916,3210,4218,1979, # 688 + 383, 750,2755,2627,4219, 274, 539, 385,1278,1442,5058,1154,1965, 384, 561, 210, # 704 + 98,1295,2556,3570,5059,1711,2420,1482,3463,3987,2911,1257, 129,5060,3821, 642, # 720 + 523,2789,2790,2658,5061, 141,2235,1333, 68, 176, 441, 876, 907,4220, 603,2602, # 736 + 710, 171,3464, 404, 549, 18,3143,2398,1410,3692,1666,5062,3571,4533,2912,4534, # 752 +5063,2991, 368,5064, 146, 366, 99, 871,3693,1543, 748, 807,1586,1185, 22,2263, # 768 + 379,3822,3211,5065,3212, 505,1942,2628,1992,1382,2319,5066, 380,2362, 218, 702, # 784 +1818,1248,3465,3044,3572,3355,3282,5067,2992,3694, 930,3283,3823,5068, 59,5069, # 800 + 585, 601,4221, 497,3466,1112,1314,4535,1802,5070,1223,1472,2177,5071, 749,1837, # 816 + 690,1900,3824,1773,3988,1476, 429,1043,1791,2236,2117, 917,4222, 447,1086,1629, # 832 +5072, 556,5073,5074,2021,1654, 844,1090, 105, 550, 966,1758,2828,1008,1783, 686, # 848 +1095,5075,2287, 793,1602,5076,3573,2603,4536,4223,2948,2302,4537,3825, 980,2503, # 864 + 544, 353, 527,4538, 908,2687,2913,5077, 381,2629,1943,1348,5078,1341,1252, 560, # 880 +3095,5079,3467,2870,5080,2054, 973, 886,2081, 143,4539,5081,5082, 157,3989, 496, # 896 +4224, 57, 840, 540,2039,4540,4541,3468,2118,1445, 970,2264,1748,1966,2082,4225, # 912 +3144,1234,1776,3284,2829,3695, 773,1206,2130,1066,2040,1326,3990,1738,1725,4226, # 928 + 279,3145, 51,1544,2604, 423,1578,2131,2067, 173,4542,1880,5083,5084,1583, 264, # 944 + 610,3696,4543,2444, 280, 154,5085,5086,5087,1739, 338,1282,3096, 693,2871,1411, # 960 +1074,3826,2445,5088,4544,5089,5090,1240, 952,2399,5091,2914,1538,2688, 685,1483, # 976 +4227,2475,1436, 953,4228,2055,4545, 671,2400, 79,4229,2446,3285, 608, 567,2689, # 992 +3469,4230,4231,1691, 393,1261,1792,2401,5092,4546,5093,5094,5095,5096,1383,1672, # 1008 +3827,3213,1464, 522,1119, 661,1150, 216, 675,4547,3991,1432,3574, 609,4548,2690, # 1024 +2402,5097,5098,5099,4232,3045, 0,5100,2476, 315, 231,2447, 301,3356,4549,2385, # 1040 +5101, 233,4233,3697,1819,4550,4551,5102, 96,1777,1315,2083,5103, 257,5104,1810, # 1056 +3698,2718,1139,1820,4234,2022,1124,2164,2791,1778,2659,5105,3097, 363,1655,3214, # 1072 +5106,2993,5107,5108,5109,3992,1567,3993, 718, 103,3215, 849,1443, 341,3357,2949, # 1088 +1484,5110,1712, 127, 67, 339,4235,2403, 679,1412, 821,5111,5112, 834, 738, 351, # 1104 +2994,2147, 846, 235,1497,1881, 418,1993,3828,2719, 186,1100,2148,2756,3575,1545, # 1120 +1355,2950,2872,1377, 583,3994,4236,2581,2995,5113,1298,3699,1078,2557,3700,2363, # 1136 + 78,3829,3830, 267,1289,2100,2002,1594,4237, 348, 369,1274,2197,2178,1838,4552, # 1152 +1821,2830,3701,2757,2288,2003,4553,2951,2758, 144,3358, 882,4554,3995,2759,3470, # 1168 +4555,2915,5114,4238,1726, 320,5115,3996,3046, 788,2996,5116,2831,1774,1327,2873, # 1184 +3997,2832,5117,1306,4556,2004,1700,3831,3576,2364,2660, 787,2023, 506, 824,3702, # 1200 + 534, 323,4557,1044,3359,2024,1901, 946,3471,5118,1779,1500,1678,5119,1882,4558, # 1216 + 165, 243,4559,3703,2528, 123, 683,4239, 764,4560, 36,3998,1793, 589,2916, 816, # 1232 + 626,1667,3047,2237,1639,1555,1622,3832,3999,5120,4000,2874,1370,1228,1933, 891, # 1248 +2084,2917, 304,4240,5121, 292,2997,2720,3577, 691,2101,4241,1115,4561, 118, 662, # 1264 +5122, 611,1156, 854,2386,1316,2875, 2, 386, 515,2918,5123,5124,3286, 868,2238, # 1280 +1486, 855,2661, 785,2216,3048,5125,1040,3216,3578,5126,3146, 448,5127,1525,5128, # 1296 +2165,4562,5129,3833,5130,4242,2833,3579,3147, 503, 818,4001,3148,1568, 814, 676, # 1312 +1444, 306,1749,5131,3834,1416,1030, 197,1428, 805,2834,1501,4563,5132,5133,5134, # 1328 +1994,5135,4564,5136,5137,2198, 13,2792,3704,2998,3149,1229,1917,5138,3835,2132, # 1344 +5139,4243,4565,2404,3580,5140,2217,1511,1727,1120,5141,5142, 646,3836,2448, 307, # 1360 +5143,5144,1595,3217,5145,5146,5147,3705,1113,1356,4002,1465,2529,2530,5148, 519, # 1376 +5149, 128,2133, 92,2289,1980,5150,4003,1512, 342,3150,2199,5151,2793,2218,1981, # 1392 +3360,4244, 290,1656,1317, 789, 827,2365,5152,3837,4566, 562, 581,4004,5153, 401, # 1408 +4567,2252, 94,4568,5154,1399,2794,5155,1463,2025,4569,3218,1944,5156, 828,1105, # 1424 +4245,1262,1394,5157,4246, 605,4570,5158,1784,2876,5159,2835, 819,2102, 578,2200, # 1440 +2952,5160,1502, 436,3287,4247,3288,2836,4005,2919,3472,3473,5161,2721,2320,5162, # 1456 +5163,2337,2068, 23,4571, 193, 826,3838,2103, 699,1630,4248,3098, 390,1794,1064, # 1472 +3581,5164,1579,3099,3100,1400,5165,4249,1839,1640,2877,5166,4572,4573, 137,4250, # 1488 + 598,3101,1967, 780, 104, 974,2953,5167, 278, 899, 253, 402, 572, 504, 493,1339, # 1504 +5168,4006,1275,4574,2582,2558,5169,3706,3049,3102,2253, 565,1334,2722, 863, 41, # 1520 +5170,5171,4575,5172,1657,2338, 19, 463,2760,4251, 606,5173,2999,3289,1087,2085, # 1536 +1323,2662,3000,5174,1631,1623,1750,4252,2691,5175,2878, 791,2723,2663,2339, 232, # 1552 +2421,5176,3001,1498,5177,2664,2630, 755,1366,3707,3290,3151,2026,1609, 119,1918, # 1568 +3474, 862,1026,4253,5178,4007,3839,4576,4008,4577,2265,1952,2477,5179,1125, 817, # 1584 +4254,4255,4009,1513,1766,2041,1487,4256,3050,3291,2837,3840,3152,5180,5181,1507, # 1600 +5182,2692, 733, 40,1632,1106,2879, 345,4257, 841,2531, 230,4578,3002,1847,3292, # 1616 +3475,5183,1263, 986,3476,5184, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562, # 1632 +4010,4011,2954, 967,2761,2665,1349, 592,2134,1692,3361,3003,1995,4258,1679,4012, # 1648 +1902,2188,5185, 739,3708,2724,1296,1290,5186,4259,2201,2202,1922,1563,2605,2559, # 1664 +1871,2762,3004,5187, 435,5188, 343,1108, 596, 17,1751,4579,2239,3477,3709,5189, # 1680 +4580, 294,3582,2955,1693, 477, 979, 281,2042,3583, 643,2043,3710,2631,2795,2266, # 1696 +1031,2340,2135,2303,3584,4581, 367,1249,2560,5190,3585,5191,4582,1283,3362,2005, # 1712 + 240,1762,3363,4583,4584, 836,1069,3153, 474,5192,2149,2532, 268,3586,5193,3219, # 1728 +1521,1284,5194,1658,1546,4260,5195,3587,3588,5196,4261,3364,2693,1685,4262, 961, # 1744 +1673,2632, 190,2006,2203,3841,4585,4586,5197, 570,2504,3711,1490,5198,4587,2633, # 1760 +3293,1957,4588, 584,1514, 396,1045,1945,5199,4589,1968,2449,5200,5201,4590,4013, # 1776 + 619,5202,3154,3294, 215,2007,2796,2561,3220,4591,3221,4592, 763,4263,3842,4593, # 1792 +5203,5204,1958,1767,2956,3365,3712,1174, 452,1477,4594,3366,3155,5205,2838,1253, # 1808 +2387,2189,1091,2290,4264, 492,5206, 638,1169,1825,2136,1752,4014, 648, 926,1021, # 1824 +1324,4595, 520,4596, 997, 847,1007, 892,4597,3843,2267,1872,3713,2405,1785,4598, # 1840 +1953,2957,3103,3222,1728,4265,2044,3714,4599,2008,1701,3156,1551, 30,2268,4266, # 1856 +5207,2027,4600,3589,5208, 501,5209,4267, 594,3478,2166,1822,3590,3479,3591,3223, # 1872 + 829,2839,4268,5210,1680,3157,1225,4269,5211,3295,4601,4270,3158,2341,5212,4602, # 1888 +4271,5213,4015,4016,5214,1848,2388,2606,3367,5215,4603, 374,4017, 652,4272,4273, # 1904 + 375,1140, 798,5216,5217,5218,2366,4604,2269, 546,1659, 138,3051,2450,4605,5219, # 1920 +2254, 612,1849, 910, 796,3844,1740,1371, 825,3845,3846,5220,2920,2562,5221, 692, # 1936 + 444,3052,2634, 801,4606,4274,5222,1491, 244,1053,3053,4275,4276, 340,5223,4018, # 1952 +1041,3005, 293,1168, 87,1357,5224,1539, 959,5225,2240, 721, 694,4277,3847, 219, # 1968 +1478, 644,1417,3368,2666,1413,1401,1335,1389,4019,5226,5227,3006,2367,3159,1826, # 1984 + 730,1515, 184,2840, 66,4607,5228,1660,2958, 246,3369, 378,1457, 226,3480, 975, # 2000 +4020,2959,1264,3592, 674, 696,5229, 163,5230,1141,2422,2167, 713,3593,3370,4608, # 2016 +4021,5231,5232,1186, 15,5233,1079,1070,5234,1522,3224,3594, 276,1050,2725, 758, # 2032 +1126, 653,2960,3296,5235,2342, 889,3595,4022,3104,3007, 903,1250,4609,4023,3481, # 2048 +3596,1342,1681,1718, 766,3297, 286, 89,2961,3715,5236,1713,5237,2607,3371,3008, # 2064 +5238,2962,2219,3225,2880,5239,4610,2505,2533, 181, 387,1075,4024, 731,2190,3372, # 2080 +5240,3298, 310, 313,3482,2304, 770,4278, 54,3054, 189,4611,3105,3848,4025,5241, # 2096 +1230,1617,1850, 355,3597,4279,4612,3373, 111,4280,3716,1350,3160,3483,3055,4281, # 2112 +2150,3299,3598,5242,2797,4026,4027,3009, 722,2009,5243,1071, 247,1207,2343,2478, # 2128 +1378,4613,2010, 864,1437,1214,4614, 373,3849,1142,2220, 667,4615, 442,2763,2563, # 2144 +3850,4028,1969,4282,3300,1840, 837, 170,1107, 934,1336,1883,5244,5245,2119,4283, # 2160 +2841, 743,1569,5246,4616,4284, 582,2389,1418,3484,5247,1803,5248, 357,1395,1729, # 2176 +3717,3301,2423,1564,2241,5249,3106,3851,1633,4617,1114,2086,4285,1532,5250, 482, # 2192 +2451,4618,5251,5252,1492, 833,1466,5253,2726,3599,1641,2842,5254,1526,1272,3718, # 2208 +4286,1686,1795, 416,2564,1903,1954,1804,5255,3852,2798,3853,1159,2321,5256,2881, # 2224 +4619,1610,1584,3056,2424,2764, 443,3302,1163,3161,5257,5258,4029,5259,4287,2506, # 2240 +3057,4620,4030,3162,2104,1647,3600,2011,1873,4288,5260,4289, 431,3485,5261, 250, # 2256 + 97, 81,4290,5262,1648,1851,1558, 160, 848,5263, 866, 740,1694,5264,2204,2843, # 2272 +3226,4291,4621,3719,1687, 950,2479, 426, 469,3227,3720,3721,4031,5265,5266,1188, # 2288 + 424,1996, 861,3601,4292,3854,2205,2694, 168,1235,3602,4293,5267,2087,1674,4622, # 2304 +3374,3303, 220,2565,1009,5268,3855, 670,3010, 332,1208, 717,5269,5270,3603,2452, # 2320 +4032,3375,5271, 513,5272,1209,2882,3376,3163,4623,1080,5273,5274,5275,5276,2534, # 2336 +3722,3604, 815,1587,4033,4034,5277,3605,3486,3856,1254,4624,1328,3058,1390,4035, # 2352 +1741,4036,3857,4037,5278, 236,3858,2453,3304,5279,5280,3723,3859,1273,3860,4625, # 2368 +5281, 308,5282,4626, 245,4627,1852,2480,1307,2583, 430, 715,2137,2454,5283, 270, # 2384 + 199,2883,4038,5284,3606,2727,1753, 761,1754, 725,1661,1841,4628,3487,3724,5285, # 2400 +5286, 587, 14,3305, 227,2608, 326, 480,2270, 943,2765,3607, 291, 650,1884,5287, # 2416 +1702,1226, 102,1547, 62,3488, 904,4629,3489,1164,4294,5288,5289,1224,1548,2766, # 2432 + 391, 498,1493,5290,1386,1419,5291,2056,1177,4630, 813, 880,1081,2368, 566,1145, # 2448 +4631,2291,1001,1035,2566,2609,2242, 394,1286,5292,5293,2069,5294, 86,1494,1730, # 2464 +4039, 491,1588, 745, 897,2963, 843,3377,4040,2767,2884,3306,1768, 998,2221,2070, # 2480 + 397,1827,1195,1970,3725,3011,3378, 284,5295,3861,2507,2138,2120,1904,5296,4041, # 2496 +2151,4042,4295,1036,3490,1905, 114,2567,4296, 209,1527,5297,5298,2964,2844,2635, # 2512 +2390,2728,3164, 812,2568,5299,3307,5300,1559, 737,1885,3726,1210, 885, 28,2695, # 2528 +3608,3862,5301,4297,1004,1780,4632,5302, 346,1982,2222,2696,4633,3863,1742, 797, # 2544 +1642,4043,1934,1072,1384,2152, 896,4044,3308,3727,3228,2885,3609,5303,2569,1959, # 2560 +4634,2455,1786,5304,5305,5306,4045,4298,1005,1308,3728,4299,2729,4635,4636,1528, # 2576 +2610, 161,1178,4300,1983, 987,4637,1101,4301, 631,4046,1157,3229,2425,1343,1241, # 2592 +1016,2243,2570, 372, 877,2344,2508,1160, 555,1935, 911,4047,5307, 466,1170, 169, # 2608 +1051,2921,2697,3729,2481,3012,1182,2012,2571,1251,2636,5308, 992,2345,3491,1540, # 2624 +2730,1201,2071,2406,1997,2482,5309,4638, 528,1923,2191,1503,1874,1570,2369,3379, # 2640 +3309,5310, 557,1073,5311,1828,3492,2088,2271,3165,3059,3107, 767,3108,2799,4639, # 2656 +1006,4302,4640,2346,1267,2179,3730,3230, 778,4048,3231,2731,1597,2667,5312,4641, # 2672 +5313,3493,5314,5315,5316,3310,2698,1433,3311, 131, 95,1504,4049, 723,4303,3166, # 2688 +1842,3610,2768,2192,4050,2028,2105,3731,5317,3013,4051,1218,5318,3380,3232,4052, # 2704 +4304,2584, 248,1634,3864, 912,5319,2845,3732,3060,3865, 654, 53,5320,3014,5321, # 2720 +1688,4642, 777,3494,1032,4053,1425,5322, 191, 820,2121,2846, 971,4643, 931,3233, # 2736 + 135, 664, 783,3866,1998, 772,2922,1936,4054,3867,4644,2923,3234, 282,2732, 640, # 2752 +1372,3495,1127, 922, 325,3381,5323,5324, 711,2045,5325,5326,4055,2223,2800,1937, # 2768 +4056,3382,2224,2255,3868,2305,5327,4645,3869,1258,3312,4057,3235,2139,2965,4058, # 2784 +4059,5328,2225, 258,3236,4646, 101,1227,5329,3313,1755,5330,1391,3314,5331,2924, # 2800 +2057, 893,5332,5333,5334,1402,4305,2347,5335,5336,3237,3611,5337,5338, 878,1325, # 2816 +1781,2801,4647, 259,1385,2585, 744,1183,2272,4648,5339,4060,2509,5340, 684,1024, # 2832 +4306,5341, 472,3612,3496,1165,3315,4061,4062, 322,2153, 881, 455,1695,1152,1340, # 2848 + 660, 554,2154,4649,1058,4650,4307, 830,1065,3383,4063,4651,1924,5342,1703,1919, # 2864 +5343, 932,2273, 122,5344,4652, 947, 677,5345,3870,2637, 297,1906,1925,2274,4653, # 2880 +2322,3316,5346,5347,4308,5348,4309, 84,4310, 112, 989,5349, 547,1059,4064, 701, # 2896 +3613,1019,5350,4311,5351,3497, 942, 639, 457,2306,2456, 993,2966, 407, 851, 494, # 2912 +4654,3384, 927,5352,1237,5353,2426,3385, 573,4312, 680, 921,2925,1279,1875, 285, # 2928 + 790,1448,1984, 719,2168,5354,5355,4655,4065,4066,1649,5356,1541, 563,5357,1077, # 2944 +5358,3386,3061,3498, 511,3015,4067,4068,3733,4069,1268,2572,3387,3238,4656,4657, # 2960 +5359, 535,1048,1276,1189,2926,2029,3167,1438,1373,2847,2967,1134,2013,5360,4313, # 2976 +1238,2586,3109,1259,5361, 700,5362,2968,3168,3734,4314,5363,4315,1146,1876,1907, # 2992 +4658,2611,4070, 781,2427, 132,1589, 203, 147, 273,2802,2407, 898,1787,2155,4071, # 3008 +4072,5364,3871,2803,5365,5366,4659,4660,5367,3239,5368,1635,3872, 965,5369,1805, # 3024 +2699,1516,3614,1121,1082,1329,3317,4073,1449,3873, 65,1128,2848,2927,2769,1590, # 3040 +3874,5370,5371, 12,2668, 45, 976,2587,3169,4661, 517,2535,1013,1037,3240,5372, # 3056 +3875,2849,5373,3876,5374,3499,5375,2612, 614,1999,2323,3877,3110,2733,2638,5376, # 3072 +2588,4316, 599,1269,5377,1811,3735,5378,2700,3111, 759,1060, 489,1806,3388,3318, # 3088 +1358,5379,5380,2391,1387,1215,2639,2256, 490,5381,5382,4317,1759,2392,2348,5383, # 3104 +4662,3878,1908,4074,2640,1807,3241,4663,3500,3319,2770,2349, 874,5384,5385,3501, # 3120 +3736,1859, 91,2928,3737,3062,3879,4664,5386,3170,4075,2669,5387,3502,1202,1403, # 3136 +3880,2969,2536,1517,2510,4665,3503,2511,5388,4666,5389,2701,1886,1495,1731,4076, # 3152 +2370,4667,5390,2030,5391,5392,4077,2702,1216, 237,2589,4318,2324,4078,3881,4668, # 3168 +4669,2703,3615,3504, 445,4670,5393,5394,5395,5396,2771, 61,4079,3738,1823,4080, # 3184 +5397, 687,2046, 935, 925, 405,2670, 703,1096,1860,2734,4671,4081,1877,1367,2704, # 3200 +3389, 918,2106,1782,2483, 334,3320,1611,1093,4672, 564,3171,3505,3739,3390, 945, # 3216 +2641,2058,4673,5398,1926, 872,4319,5399,3506,2705,3112, 349,4320,3740,4082,4674, # 3232 +3882,4321,3741,2156,4083,4675,4676,4322,4677,2408,2047, 782,4084, 400, 251,4323, # 3248 +1624,5400,5401, 277,3742, 299,1265, 476,1191,3883,2122,4324,4325,1109, 205,5402, # 3264 +2590,1000,2157,3616,1861,5403,5404,5405,4678,5406,4679,2573, 107,2484,2158,4085, # 3280 +3507,3172,5407,1533, 541,1301, 158, 753,4326,2886,3617,5408,1696, 370,1088,4327, # 3296 +4680,3618, 579, 327, 440, 162,2244, 269,1938,1374,3508, 968,3063, 56,1396,3113, # 3312 +2107,3321,3391,5409,1927,2159,4681,3016,5410,3619,5411,5412,3743,4682,2485,5413, # 3328 +2804,5414,1650,4683,5415,2613,5416,5417,4086,2671,3392,1149,3393,4087,3884,4088, # 3344 +5418,1076, 49,5419, 951,3242,3322,3323, 450,2850, 920,5420,1812,2805,2371,4328, # 3360 +1909,1138,2372,3885,3509,5421,3243,4684,1910,1147,1518,2428,4685,3886,5422,4686, # 3376 +2393,2614, 260,1796,3244,5423,5424,3887,3324, 708,5425,3620,1704,5426,3621,1351, # 3392 +1618,3394,3017,1887, 944,4329,3395,4330,3064,3396,4331,5427,3744, 422, 413,1714, # 3408 +3325, 500,2059,2350,4332,2486,5428,1344,1911, 954,5429,1668,5430,5431,4089,2409, # 3424 +4333,3622,3888,4334,5432,2307,1318,2512,3114, 133,3115,2887,4687, 629, 31,2851, # 3440 +2706,3889,4688, 850, 949,4689,4090,2970,1732,2089,4335,1496,1853,5433,4091, 620, # 3456 +3245, 981,1242,3745,3397,1619,3746,1643,3326,2140,2457,1971,1719,3510,2169,5434, # 3472 +3246,5435,5436,3398,1829,5437,1277,4690,1565,2048,5438,1636,3623,3116,5439, 869, # 3488 +2852, 655,3890,3891,3117,4092,3018,3892,1310,3624,4691,5440,5441,5442,1733, 558, # 3504 +4692,3747, 335,1549,3065,1756,4336,3748,1946,3511,1830,1291,1192, 470,2735,2108, # 3520 +2806, 913,1054,4093,5443,1027,5444,3066,4094,4693, 982,2672,3399,3173,3512,3247, # 3536 +3248,1947,2807,5445, 571,4694,5446,1831,5447,3625,2591,1523,2429,5448,2090, 984, # 3552 +4695,3749,1960,5449,3750, 852, 923,2808,3513,3751, 969,1519, 999,2049,2325,1705, # 3568 +5450,3118, 615,1662, 151, 597,4095,2410,2326,1049, 275,4696,3752,4337, 568,3753, # 3584 +3626,2487,4338,3754,5451,2430,2275, 409,3249,5452,1566,2888,3514,1002, 769,2853, # 3600 + 194,2091,3174,3755,2226,3327,4339, 628,1505,5453,5454,1763,2180,3019,4096, 521, # 3616 +1161,2592,1788,2206,2411,4697,4097,1625,4340,4341, 412, 42,3119, 464,5455,2642, # 3632 +4698,3400,1760,1571,2889,3515,2537,1219,2207,3893,2643,2141,2373,4699,4700,3328, # 3648 +1651,3401,3627,5456,5457,3628,2488,3516,5458,3756,5459,5460,2276,2092, 460,5461, # 3664 +4701,5462,3020, 962, 588,3629, 289,3250,2644,1116, 52,5463,3067,1797,5464,5465, # 3680 +5466,1467,5467,1598,1143,3757,4342,1985,1734,1067,4702,1280,3402, 465,4703,1572, # 3696 + 510,5468,1928,2245,1813,1644,3630,5469,4704,3758,5470,5471,2673,1573,1534,5472, # 3712 +5473, 536,1808,1761,3517,3894,3175,2645,5474,5475,5476,4705,3518,2929,1912,2809, # 3728 +5477,3329,1122, 377,3251,5478, 360,5479,5480,4343,1529, 551,5481,2060,3759,1769, # 3744 +2431,5482,2930,4344,3330,3120,2327,2109,2031,4706,1404, 136,1468,1479, 672,1171, # 3760 +3252,2308, 271,3176,5483,2772,5484,2050, 678,2736, 865,1948,4707,5485,2014,4098, # 3776 +2971,5486,2737,2227,1397,3068,3760,4708,4709,1735,2931,3403,3631,5487,3895, 509, # 3792 +2854,2458,2890,3896,5488,5489,3177,3178,4710,4345,2538,4711,2309,1166,1010, 552, # 3808 + 681,1888,5490,5491,2972,2973,4099,1287,1596,1862,3179, 358, 453, 736, 175, 478, # 3824 +1117, 905,1167,1097,5492,1854,1530,5493,1706,5494,2181,3519,2292,3761,3520,3632, # 3840 +4346,2093,4347,5495,3404,1193,2489,4348,1458,2193,2208,1863,1889,1421,3331,2932, # 3856 +3069,2182,3521, 595,2123,5496,4100,5497,5498,4349,1707,2646, 223,3762,1359, 751, # 3872 +3121, 183,3522,5499,2810,3021, 419,2374, 633, 704,3897,2394, 241,5500,5501,5502, # 3888 + 838,3022,3763,2277,2773,2459,3898,1939,2051,4101,1309,3122,2246,1181,5503,1136, # 3904 +2209,3899,2375,1446,4350,2310,4712,5504,5505,4351,1055,2615, 484,3764,5506,4102, # 3920 + 625,4352,2278,3405,1499,4353,4103,5507,4104,4354,3253,2279,2280,3523,5508,5509, # 3936 +2774, 808,2616,3765,3406,4105,4355,3123,2539, 526,3407,3900,4356, 955,5510,1620, # 3952 +4357,2647,2432,5511,1429,3766,1669,1832, 994, 928,5512,3633,1260,5513,5514,5515, # 3968 +1949,2293, 741,2933,1626,4358,2738,2460, 867,1184, 362,3408,1392,5516,5517,4106, # 3984 +4359,1770,1736,3254,2934,4713,4714,1929,2707,1459,1158,5518,3070,3409,2891,1292, # 4000 +1930,2513,2855,3767,1986,1187,2072,2015,2617,4360,5519,2574,2514,2170,3768,2490, # 4016 +3332,5520,3769,4715,5521,5522, 666,1003,3023,1022,3634,4361,5523,4716,1814,2257, # 4032 + 574,3901,1603, 295,1535, 705,3902,4362, 283, 858, 417,5524,5525,3255,4717,4718, # 4048 +3071,1220,1890,1046,2281,2461,4107,1393,1599, 689,2575, 388,4363,5526,2491, 802, # 4064 +5527,2811,3903,2061,1405,2258,5528,4719,3904,2110,1052,1345,3256,1585,5529, 809, # 4080 +5530,5531,5532, 575,2739,3524, 956,1552,1469,1144,2328,5533,2329,1560,2462,3635, # 4096 +3257,4108, 616,2210,4364,3180,2183,2294,5534,1833,5535,3525,4720,5536,1319,3770, # 4112 +3771,1211,3636,1023,3258,1293,2812,5537,5538,5539,3905, 607,2311,3906, 762,2892, # 4128 +1439,4365,1360,4721,1485,3072,5540,4722,1038,4366,1450,2062,2648,4367,1379,4723, # 4144 +2593,5541,5542,4368,1352,1414,2330,2935,1172,5543,5544,3907,3908,4724,1798,1451, # 4160 +5545,5546,5547,5548,2936,4109,4110,2492,2351, 411,4111,4112,3637,3333,3124,4725, # 4176 +1561,2674,1452,4113,1375,5549,5550, 47,2974, 316,5551,1406,1591,2937,3181,5552, # 4192 +1025,2142,3125,3182, 354,2740, 884,2228,4369,2412, 508,3772, 726,3638, 996,2433, # 4208 +3639, 729,5553, 392,2194,1453,4114,4726,3773,5554,5555,2463,3640,2618,1675,2813, # 4224 + 919,2352,2975,2353,1270,4727,4115, 73,5556,5557, 647,5558,3259,2856,2259,1550, # 4240 +1346,3024,5559,1332, 883,3526,5560,5561,5562,5563,3334,2775,5564,1212, 831,1347, # 4256 +4370,4728,2331,3909,1864,3073, 720,3910,4729,4730,3911,5565,4371,5566,5567,4731, # 4272 +5568,5569,1799,4732,3774,2619,4733,3641,1645,2376,4734,5570,2938, 669,2211,2675, # 4288 +2434,5571,2893,5572,5573,1028,3260,5574,4372,2413,5575,2260,1353,5576,5577,4735, # 4304 +3183, 518,5578,4116,5579,4373,1961,5580,2143,4374,5581,5582,3025,2354,2355,3912, # 4320 + 516,1834,1454,4117,2708,4375,4736,2229,2620,1972,1129,3642,5583,2776,5584,2976, # 4336 +1422, 577,1470,3026,1524,3410,5585,5586, 432,4376,3074,3527,5587,2594,1455,2515, # 4352 +2230,1973,1175,5588,1020,2741,4118,3528,4737,5589,2742,5590,1743,1361,3075,3529, # 4368 +2649,4119,4377,4738,2295, 895, 924,4378,2171, 331,2247,3076, 166,1627,3077,1098, # 4384 +5591,1232,2894,2231,3411,4739, 657, 403,1196,2377, 542,3775,3412,1600,4379,3530, # 4400 +5592,4740,2777,3261, 576, 530,1362,4741,4742,2540,2676,3776,4120,5593, 842,3913, # 4416 +5594,2814,2032,1014,4121, 213,2709,3413, 665, 621,4380,5595,3777,2939,2435,5596, # 4432 +2436,3335,3643,3414,4743,4381,2541,4382,4744,3644,1682,4383,3531,1380,5597, 724, # 4448 +2282, 600,1670,5598,1337,1233,4745,3126,2248,5599,1621,4746,5600, 651,4384,5601, # 4464 +1612,4385,2621,5602,2857,5603,2743,2312,3078,5604, 716,2464,3079, 174,1255,2710, # 4480 +4122,3645, 548,1320,1398, 728,4123,1574,5605,1891,1197,3080,4124,5606,3081,3082, # 4496 +3778,3646,3779, 747,5607, 635,4386,4747,5608,5609,5610,4387,5611,5612,4748,5613, # 4512 +3415,4749,2437, 451,5614,3780,2542,2073,4388,2744,4389,4125,5615,1764,4750,5616, # 4528 +4390, 350,4751,2283,2395,2493,5617,4391,4126,2249,1434,4127, 488,4752, 458,4392, # 4544 +4128,3781, 771,1330,2396,3914,2576,3184,2160,2414,1553,2677,3185,4393,5618,2494, # 4560 +2895,2622,1720,2711,4394,3416,4753,5619,2543,4395,5620,3262,4396,2778,5621,2016, # 4576 +2745,5622,1155,1017,3782,3915,5623,3336,2313, 201,1865,4397,1430,5624,4129,5625, # 4592 +5626,5627,5628,5629,4398,1604,5630, 414,1866, 371,2595,4754,4755,3532,2017,3127, # 4608 +4756,1708, 960,4399, 887, 389,2172,1536,1663,1721,5631,2232,4130,2356,2940,1580, # 4624 +5632,5633,1744,4757,2544,4758,4759,5634,4760,5635,2074,5636,4761,3647,3417,2896, # 4640 +4400,5637,4401,2650,3418,2815, 673,2712,2465, 709,3533,4131,3648,4402,5638,1148, # 4656 + 502, 634,5639,5640,1204,4762,3649,1575,4763,2623,3783,5641,3784,3128, 948,3263, # 4672 + 121,1745,3916,1110,5642,4403,3083,2516,3027,4132,3785,1151,1771,3917,1488,4133, # 4688 +1987,5643,2438,3534,5644,5645,2094,5646,4404,3918,1213,1407,2816, 531,2746,2545, # 4704 +3264,1011,1537,4764,2779,4405,3129,1061,5647,3786,3787,1867,2897,5648,2018, 120, # 4720 +4406,4407,2063,3650,3265,2314,3919,2678,3419,1955,4765,4134,5649,3535,1047,2713, # 4736 +1266,5650,1368,4766,2858, 649,3420,3920,2546,2747,1102,2859,2679,5651,5652,2000, # 4752 +5653,1111,3651,2977,5654,2495,3921,3652,2817,1855,3421,3788,5655,5656,3422,2415, # 4768 +2898,3337,3266,3653,5657,2577,5658,3654,2818,4135,1460, 856,5659,3655,5660,2899, # 4784 +2978,5661,2900,3922,5662,4408, 632,2517, 875,3923,1697,3924,2296,5663,5664,4767, # 4800 +3028,1239, 580,4768,4409,5665, 914, 936,2075,1190,4136,1039,2124,5666,5667,5668, # 4816 +5669,3423,1473,5670,1354,4410,3925,4769,2173,3084,4137, 915,3338,4411,4412,3339, # 4832 +1605,1835,5671,2748, 398,3656,4413,3926,4138, 328,1913,2860,4139,3927,1331,4414, # 4848 +3029, 937,4415,5672,3657,4140,4141,3424,2161,4770,3425, 524, 742, 538,3085,1012, # 4864 +5673,5674,3928,2466,5675, 658,1103, 225,3929,5676,5677,4771,5678,4772,5679,3267, # 4880 +1243,5680,4142, 963,2250,4773,5681,2714,3658,3186,5682,5683,2596,2332,5684,4774, # 4896 +5685,5686,5687,3536, 957,3426,2547,2033,1931,2941,2467, 870,2019,3659,1746,2780, # 4912 +2781,2439,2468,5688,3930,5689,3789,3130,3790,3537,3427,3791,5690,1179,3086,5691, # 4928 +3187,2378,4416,3792,2548,3188,3131,2749,4143,5692,3428,1556,2549,2297, 977,2901, # 4944 +2034,4144,1205,3429,5693,1765,3430,3189,2125,1271, 714,1689,4775,3538,5694,2333, # 4960 +3931, 533,4417,3660,2184, 617,5695,2469,3340,3539,2315,5696,5697,3190,5698,5699, # 4976 +3932,1988, 618, 427,2651,3540,3431,5700,5701,1244,1690,5702,2819,4418,4776,5703, # 4992 +3541,4777,5704,2284,1576, 473,3661,4419,3432, 972,5705,3662,5706,3087,5707,5708, # 5008 +4778,4779,5709,3793,4145,4146,5710, 153,4780, 356,5711,1892,2902,4420,2144, 408, # 5024 + 803,2357,5712,3933,5713,4421,1646,2578,2518,4781,4782,3934,5714,3935,4422,5715, # 5040 +2416,3433, 752,5716,5717,1962,3341,2979,5718, 746,3030,2470,4783,4423,3794, 698, # 5056 +4784,1893,4424,3663,2550,4785,3664,3936,5719,3191,3434,5720,1824,1302,4147,2715, # 5072 +3937,1974,4425,5721,4426,3192, 823,1303,1288,1236,2861,3542,4148,3435, 774,3938, # 5088 +5722,1581,4786,1304,2862,3939,4787,5723,2440,2162,1083,3268,4427,4149,4428, 344, # 5104 +1173, 288,2316, 454,1683,5724,5725,1461,4788,4150,2597,5726,5727,4789, 985, 894, # 5120 +5728,3436,3193,5729,1914,2942,3795,1989,5730,2111,1975,5731,4151,5732,2579,1194, # 5136 + 425,5733,4790,3194,1245,3796,4429,5734,5735,2863,5736, 636,4791,1856,3940, 760, # 5152 +1800,5737,4430,2212,1508,4792,4152,1894,1684,2298,5738,5739,4793,4431,4432,2213, # 5168 + 479,5740,5741, 832,5742,4153,2496,5743,2980,2497,3797, 990,3132, 627,1815,2652, # 5184 +4433,1582,4434,2126,2112,3543,4794,5744, 799,4435,3195,5745,4795,2113,1737,3031, # 5200 +1018, 543, 754,4436,3342,1676,4796,4797,4154,4798,1489,5746,3544,5747,2624,2903, # 5216 +4155,5748,5749,2981,5750,5751,5752,5753,3196,4799,4800,2185,1722,5754,3269,3270, # 5232 +1843,3665,1715, 481, 365,1976,1857,5755,5756,1963,2498,4801,5757,2127,3666,3271, # 5248 + 433,1895,2064,2076,5758, 602,2750,5759,5760,5761,5762,5763,3032,1628,3437,5764, # 5264 +3197,4802,4156,2904,4803,2519,5765,2551,2782,5766,5767,5768,3343,4804,2905,5769, # 5280 +4805,5770,2864,4806,4807,1221,2982,4157,2520,5771,5772,5773,1868,1990,5774,5775, # 5296 +5776,1896,5777,5778,4808,1897,4158, 318,5779,2095,4159,4437,5780,5781, 485,5782, # 5312 + 938,3941, 553,2680, 116,5783,3942,3667,5784,3545,2681,2783,3438,3344,2820,5785, # 5328 +3668,2943,4160,1747,2944,2983,5786,5787, 207,5788,4809,5789,4810,2521,5790,3033, # 5344 + 890,3669,3943,5791,1878,3798,3439,5792,2186,2358,3440,1652,5793,5794,5795, 941, # 5360 +2299, 208,3546,4161,2020, 330,4438,3944,2906,2499,3799,4439,4811,5796,5797,5798, # 5376 #last 512 +#Everything below is of no interest for detection purpose +2522,1613,4812,5799,3345,3945,2523,5800,4162,5801,1637,4163,2471,4813,3946,5802, # 5392 +2500,3034,3800,5803,5804,2195,4814,5805,2163,5806,5807,5808,5809,5810,5811,5812, # 5408 +5813,5814,5815,5816,5817,5818,5819,5820,5821,5822,5823,5824,5825,5826,5827,5828, # 5424 +5829,5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840,5841,5842,5843,5844, # 5440 +5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856,5857,5858,5859,5860, # 5456 +5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872,5873,5874,5875,5876, # 5472 +5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888,5889,5890,5891,5892, # 5488 +5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904,5905,5906,5907,5908, # 5504 +5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920,5921,5922,5923,5924, # 5520 +5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936,5937,5938,5939,5940, # 5536 +5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951,5952,5953,5954,5955,5956, # 5552 +5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968,5969,5970,5971,5972, # 5568 +5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,5984,5985,5986,5987,5988, # 5584 +5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,5999,6000,6001,6002,6003,6004, # 5600 +6005,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,6016,6017,6018,6019,6020, # 5616 +6021,6022,6023,6024,6025,6026,6027,6028,6029,6030,6031,6032,6033,6034,6035,6036, # 5632 +6037,6038,6039,6040,6041,6042,6043,6044,6045,6046,6047,6048,6049,6050,6051,6052, # 5648 +6053,6054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064,6065,6066,6067,6068, # 5664 +6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084, # 5680 +6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,6100, # 5696 +6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112,6113,6114,6115,6116, # 5712 +6117,6118,6119,6120,6121,6122,6123,6124,6125,6126,6127,6128,6129,6130,6131,6132, # 5728 +6133,6134,6135,6136,6137,6138,6139,6140,6141,6142,6143,6144,6145,6146,6147,6148, # 5744 +6149,6150,6151,6152,6153,6154,6155,6156,6157,6158,6159,6160,6161,6162,6163,6164, # 5760 +6165,6166,6167,6168,6169,6170,6171,6172,6173,6174,6175,6176,6177,6178,6179,6180, # 5776 +6181,6182,6183,6184,6185,6186,6187,6188,6189,6190,6191,6192,6193,6194,6195,6196, # 5792 +6197,6198,6199,6200,6201,6202,6203,6204,6205,6206,6207,6208,6209,6210,6211,6212, # 5808 +6213,6214,6215,6216,6217,6218,6219,6220,6221,6222,6223,3670,6224,6225,6226,6227, # 5824 +6228,6229,6230,6231,6232,6233,6234,6235,6236,6237,6238,6239,6240,6241,6242,6243, # 5840 +6244,6245,6246,6247,6248,6249,6250,6251,6252,6253,6254,6255,6256,6257,6258,6259, # 5856 +6260,6261,6262,6263,6264,6265,6266,6267,6268,6269,6270,6271,6272,6273,6274,6275, # 5872 +6276,6277,6278,6279,6280,6281,6282,6283,6284,6285,4815,6286,6287,6288,6289,6290, # 5888 +6291,6292,4816,6293,6294,6295,6296,6297,6298,6299,6300,6301,6302,6303,6304,6305, # 5904 +6306,6307,6308,6309,6310,6311,4817,4818,6312,6313,6314,6315,6316,6317,6318,4819, # 5920 +6319,6320,6321,6322,6323,6324,6325,6326,6327,6328,6329,6330,6331,6332,6333,6334, # 5936 +6335,6336,6337,4820,6338,6339,6340,6341,6342,6343,6344,6345,6346,6347,6348,6349, # 5952 +6350,6351,6352,6353,6354,6355,6356,6357,6358,6359,6360,6361,6362,6363,6364,6365, # 5968 +6366,6367,6368,6369,6370,6371,6372,6373,6374,6375,6376,6377,6378,6379,6380,6381, # 5984 +6382,6383,6384,6385,6386,6387,6388,6389,6390,6391,6392,6393,6394,6395,6396,6397, # 6000 +6398,6399,6400,6401,6402,6403,6404,6405,6406,6407,6408,6409,6410,3441,6411,6412, # 6016 +6413,6414,6415,6416,6417,6418,6419,6420,6421,6422,6423,6424,6425,4440,6426,6427, # 6032 +6428,6429,6430,6431,6432,6433,6434,6435,6436,6437,6438,6439,6440,6441,6442,6443, # 6048 +6444,6445,6446,6447,6448,6449,6450,6451,6452,6453,6454,4821,6455,6456,6457,6458, # 6064 +6459,6460,6461,6462,6463,6464,6465,6466,6467,6468,6469,6470,6471,6472,6473,6474, # 6080 +6475,6476,6477,3947,3948,6478,6479,6480,6481,3272,4441,6482,6483,6484,6485,4442, # 6096 +6486,6487,6488,6489,6490,6491,6492,6493,6494,6495,6496,4822,6497,6498,6499,6500, # 6112 +6501,6502,6503,6504,6505,6506,6507,6508,6509,6510,6511,6512,6513,6514,6515,6516, # 6128 +6517,6518,6519,6520,6521,6522,6523,6524,6525,6526,6527,6528,6529,6530,6531,6532, # 6144 +6533,6534,6535,6536,6537,6538,6539,6540,6541,6542,6543,6544,6545,6546,6547,6548, # 6160 +6549,6550,6551,6552,6553,6554,6555,6556,2784,6557,4823,6558,6559,6560,6561,6562, # 6176 +6563,6564,6565,6566,6567,6568,6569,3949,6570,6571,6572,4824,6573,6574,6575,6576, # 6192 +6577,6578,6579,6580,6581,6582,6583,4825,6584,6585,6586,3950,2785,6587,6588,6589, # 6208 +6590,6591,6592,6593,6594,6595,6596,6597,6598,6599,6600,6601,6602,6603,6604,6605, # 6224 +6606,6607,6608,6609,6610,6611,6612,4826,6613,6614,6615,4827,6616,6617,6618,6619, # 6240 +6620,6621,6622,6623,6624,6625,4164,6626,6627,6628,6629,6630,6631,6632,6633,6634, # 6256 +3547,6635,4828,6636,6637,6638,6639,6640,6641,6642,3951,2984,6643,6644,6645,6646, # 6272 +6647,6648,6649,4165,6650,4829,6651,6652,4830,6653,6654,6655,6656,6657,6658,6659, # 6288 +6660,6661,6662,4831,6663,6664,6665,6666,6667,6668,6669,6670,6671,4166,6672,4832, # 6304 +3952,6673,6674,6675,6676,4833,6677,6678,6679,4167,6680,6681,6682,3198,6683,6684, # 6320 +6685,6686,6687,6688,6689,6690,6691,6692,6693,6694,6695,6696,6697,4834,6698,6699, # 6336 +6700,6701,6702,6703,6704,6705,6706,6707,6708,6709,6710,6711,6712,6713,6714,6715, # 6352 +6716,6717,6718,6719,6720,6721,6722,6723,6724,6725,6726,6727,6728,6729,6730,6731, # 6368 +6732,6733,6734,4443,6735,6736,6737,6738,6739,6740,6741,6742,6743,6744,6745,4444, # 6384 +6746,6747,6748,6749,6750,6751,6752,6753,6754,6755,6756,6757,6758,6759,6760,6761, # 6400 +6762,6763,6764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,6775,6776,6777, # 6416 +6778,6779,6780,6781,4168,6782,6783,3442,6784,6785,6786,6787,6788,6789,6790,6791, # 6432 +4169,6792,6793,6794,6795,6796,6797,6798,6799,6800,6801,6802,6803,6804,6805,6806, # 6448 +6807,6808,6809,6810,6811,4835,6812,6813,6814,4445,6815,6816,4446,6817,6818,6819, # 6464 +6820,6821,6822,6823,6824,6825,6826,6827,6828,6829,6830,6831,6832,6833,6834,6835, # 6480 +3548,6836,6837,6838,6839,6840,6841,6842,6843,6844,6845,6846,4836,6847,6848,6849, # 6496 +6850,6851,6852,6853,6854,3953,6855,6856,6857,6858,6859,6860,6861,6862,6863,6864, # 6512 +6865,6866,6867,6868,6869,6870,6871,6872,6873,6874,6875,6876,6877,3199,6878,6879, # 6528 +6880,6881,6882,4447,6883,6884,6885,6886,6887,6888,6889,6890,6891,6892,6893,6894, # 6544 +6895,6896,6897,6898,6899,6900,6901,6902,6903,6904,4170,6905,6906,6907,6908,6909, # 6560 +6910,6911,6912,6913,6914,6915,6916,6917,6918,6919,6920,6921,6922,6923,6924,6925, # 6576 +6926,6927,4837,6928,6929,6930,6931,6932,6933,6934,6935,6936,3346,6937,6938,4838, # 6592 +6939,6940,6941,4448,6942,6943,6944,6945,6946,4449,6947,6948,6949,6950,6951,6952, # 6608 +6953,6954,6955,6956,6957,6958,6959,6960,6961,6962,6963,6964,6965,6966,6967,6968, # 6624 +6969,6970,6971,6972,6973,6974,6975,6976,6977,6978,6979,6980,6981,6982,6983,6984, # 6640 +6985,6986,6987,6988,6989,6990,6991,6992,6993,6994,3671,6995,6996,6997,6998,4839, # 6656 +6999,7000,7001,7002,3549,7003,7004,7005,7006,7007,7008,7009,7010,7011,7012,7013, # 6672 +7014,7015,7016,7017,7018,7019,7020,7021,7022,7023,7024,7025,7026,7027,7028,7029, # 6688 +7030,4840,7031,7032,7033,7034,7035,7036,7037,7038,4841,7039,7040,7041,7042,7043, # 6704 +7044,7045,7046,7047,7048,7049,7050,7051,7052,7053,7054,7055,7056,7057,7058,7059, # 6720 +7060,7061,7062,7063,7064,7065,7066,7067,7068,7069,7070,2985,7071,7072,7073,7074, # 6736 +7075,7076,7077,7078,7079,7080,4842,7081,7082,7083,7084,7085,7086,7087,7088,7089, # 6752 +7090,7091,7092,7093,7094,7095,7096,7097,7098,7099,7100,7101,7102,7103,7104,7105, # 6768 +7106,7107,7108,7109,7110,7111,7112,7113,7114,7115,7116,7117,7118,4450,7119,7120, # 6784 +7121,7122,7123,7124,7125,7126,7127,7128,7129,7130,7131,7132,7133,7134,7135,7136, # 6800 +7137,7138,7139,7140,7141,7142,7143,4843,7144,7145,7146,7147,7148,7149,7150,7151, # 6816 +7152,7153,7154,7155,7156,7157,7158,7159,7160,7161,7162,7163,7164,7165,7166,7167, # 6832 +7168,7169,7170,7171,7172,7173,7174,7175,7176,7177,7178,7179,7180,7181,7182,7183, # 6848 +7184,7185,7186,7187,7188,4171,4172,7189,7190,7191,7192,7193,7194,7195,7196,7197, # 6864 +7198,7199,7200,7201,7202,7203,7204,7205,7206,7207,7208,7209,7210,7211,7212,7213, # 6880 +7214,7215,7216,7217,7218,7219,7220,7221,7222,7223,7224,7225,7226,7227,7228,7229, # 6896 +7230,7231,7232,7233,7234,7235,7236,7237,7238,7239,7240,7241,7242,7243,7244,7245, # 6912 +7246,7247,7248,7249,7250,7251,7252,7253,7254,7255,7256,7257,7258,7259,7260,7261, # 6928 +7262,7263,7264,7265,7266,7267,7268,7269,7270,7271,7272,7273,7274,7275,7276,7277, # 6944 +7278,7279,7280,7281,7282,7283,7284,7285,7286,7287,7288,7289,7290,7291,7292,7293, # 6960 +7294,7295,7296,4844,7297,7298,7299,7300,7301,7302,7303,7304,7305,7306,7307,7308, # 6976 +7309,7310,7311,7312,7313,7314,7315,7316,4451,7317,7318,7319,7320,7321,7322,7323, # 6992 +7324,7325,7326,7327,7328,7329,7330,7331,7332,7333,7334,7335,7336,7337,7338,7339, # 7008 +7340,7341,7342,7343,7344,7345,7346,7347,7348,7349,7350,7351,7352,7353,4173,7354, # 7024 +7355,4845,7356,7357,7358,7359,7360,7361,7362,7363,7364,7365,7366,7367,7368,7369, # 7040 +7370,7371,7372,7373,7374,7375,7376,7377,7378,7379,7380,7381,7382,7383,7384,7385, # 7056 +7386,7387,7388,4846,7389,7390,7391,7392,7393,7394,7395,7396,7397,7398,7399,7400, # 7072 +7401,7402,7403,7404,7405,3672,7406,7407,7408,7409,7410,7411,7412,7413,7414,7415, # 7088 +7416,7417,7418,7419,7420,7421,7422,7423,7424,7425,7426,7427,7428,7429,7430,7431, # 7104 +7432,7433,7434,7435,7436,7437,7438,7439,7440,7441,7442,7443,7444,7445,7446,7447, # 7120 +7448,7449,7450,7451,7452,7453,4452,7454,3200,7455,7456,7457,7458,7459,7460,7461, # 7136 +7462,7463,7464,7465,7466,7467,7468,7469,7470,7471,7472,7473,7474,4847,7475,7476, # 7152 +7477,3133,7478,7479,7480,7481,7482,7483,7484,7485,7486,7487,7488,7489,7490,7491, # 7168 +7492,7493,7494,7495,7496,7497,7498,7499,7500,7501,7502,3347,7503,7504,7505,7506, # 7184 +7507,7508,7509,7510,7511,7512,7513,7514,7515,7516,7517,7518,7519,7520,7521,4848, # 7200 +7522,7523,7524,7525,7526,7527,7528,7529,7530,7531,7532,7533,7534,7535,7536,7537, # 7216 +7538,7539,7540,7541,7542,7543,7544,7545,7546,7547,7548,7549,3801,4849,7550,7551, # 7232 +7552,7553,7554,7555,7556,7557,7558,7559,7560,7561,7562,7563,7564,7565,7566,7567, # 7248 +7568,7569,3035,7570,7571,7572,7573,7574,7575,7576,7577,7578,7579,7580,7581,7582, # 7264 +7583,7584,7585,7586,7587,7588,7589,7590,7591,7592,7593,7594,7595,7596,7597,7598, # 7280 +7599,7600,7601,7602,7603,7604,7605,7606,7607,7608,7609,7610,7611,7612,7613,7614, # 7296 +7615,7616,4850,7617,7618,3802,7619,7620,7621,7622,7623,7624,7625,7626,7627,7628, # 7312 +7629,7630,7631,7632,4851,7633,7634,7635,7636,7637,7638,7639,7640,7641,7642,7643, # 7328 +7644,7645,7646,7647,7648,7649,7650,7651,7652,7653,7654,7655,7656,7657,7658,7659, # 7344 +7660,7661,7662,7663,7664,7665,7666,7667,7668,7669,7670,4453,7671,7672,7673,7674, # 7360 +7675,7676,7677,7678,7679,7680,7681,7682,7683,7684,7685,7686,7687,7688,7689,7690, # 7376 +7691,7692,7693,7694,7695,7696,7697,3443,7698,7699,7700,7701,7702,4454,7703,7704, # 7392 +7705,7706,7707,7708,7709,7710,7711,7712,7713,2472,7714,7715,7716,7717,7718,7719, # 7408 +7720,7721,7722,7723,7724,7725,7726,7727,7728,7729,7730,7731,3954,7732,7733,7734, # 7424 +7735,7736,7737,7738,7739,7740,7741,7742,7743,7744,7745,7746,7747,7748,7749,7750, # 7440 +3134,7751,7752,4852,7753,7754,7755,4853,7756,7757,7758,7759,7760,4174,7761,7762, # 7456 +7763,7764,7765,7766,7767,7768,7769,7770,7771,7772,7773,7774,7775,7776,7777,7778, # 7472 +7779,7780,7781,7782,7783,7784,7785,7786,7787,7788,7789,7790,7791,7792,7793,7794, # 7488 +7795,7796,7797,7798,7799,7800,7801,7802,7803,7804,7805,4854,7806,7807,7808,7809, # 7504 +7810,7811,7812,7813,7814,7815,7816,7817,7818,7819,7820,7821,7822,7823,7824,7825, # 7520 +4855,7826,7827,7828,7829,7830,7831,7832,7833,7834,7835,7836,7837,7838,7839,7840, # 7536 +7841,7842,7843,7844,7845,7846,7847,3955,7848,7849,7850,7851,7852,7853,7854,7855, # 7552 +7856,7857,7858,7859,7860,3444,7861,7862,7863,7864,7865,7866,7867,7868,7869,7870, # 7568 +7871,7872,7873,7874,7875,7876,7877,7878,7879,7880,7881,7882,7883,7884,7885,7886, # 7584 +7887,7888,7889,7890,7891,4175,7892,7893,7894,7895,7896,4856,4857,7897,7898,7899, # 7600 +7900,2598,7901,7902,7903,7904,7905,7906,7907,7908,4455,7909,7910,7911,7912,7913, # 7616 +7914,3201,7915,7916,7917,7918,7919,7920,7921,4858,7922,7923,7924,7925,7926,7927, # 7632 +7928,7929,7930,7931,7932,7933,7934,7935,7936,7937,7938,7939,7940,7941,7942,7943, # 7648 +7944,7945,7946,7947,7948,7949,7950,7951,7952,7953,7954,7955,7956,7957,7958,7959, # 7664 +7960,7961,7962,7963,7964,7965,7966,7967,7968,7969,7970,7971,7972,7973,7974,7975, # 7680 +7976,7977,7978,7979,7980,7981,4859,7982,7983,7984,7985,7986,7987,7988,7989,7990, # 7696 +7991,7992,7993,7994,7995,7996,4860,7997,7998,7999,8000,8001,8002,8003,8004,8005, # 7712 +8006,8007,8008,8009,8010,8011,8012,8013,8014,8015,8016,4176,8017,8018,8019,8020, # 7728 +8021,8022,8023,4861,8024,8025,8026,8027,8028,8029,8030,8031,8032,8033,8034,8035, # 7744 +8036,4862,4456,8037,8038,8039,8040,4863,8041,8042,8043,8044,8045,8046,8047,8048, # 7760 +8049,8050,8051,8052,8053,8054,8055,8056,8057,8058,8059,8060,8061,8062,8063,8064, # 7776 +8065,8066,8067,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079,8080, # 7792 +8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095,8096, # 7808 +8097,8098,8099,4864,4177,8100,8101,8102,8103,8104,8105,8106,8107,8108,8109,8110, # 7824 +8111,8112,8113,8114,8115,8116,8117,8118,8119,8120,4178,8121,8122,8123,8124,8125, # 7840 +8126,8127,8128,8129,8130,8131,8132,8133,8134,8135,8136,8137,8138,8139,8140,8141, # 7856 +8142,8143,8144,8145,4865,4866,8146,8147,8148,8149,8150,8151,8152,8153,8154,8155, # 7872 +8156,8157,8158,8159,8160,8161,8162,8163,8164,8165,4179,8166,8167,8168,8169,8170, # 7888 +8171,8172,8173,8174,8175,8176,8177,8178,8179,8180,8181,4457,8182,8183,8184,8185, # 7904 +8186,8187,8188,8189,8190,8191,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201, # 7920 +8202,8203,8204,8205,8206,8207,8208,8209,8210,8211,8212,8213,8214,8215,8216,8217, # 7936 +8218,8219,8220,8221,8222,8223,8224,8225,8226,8227,8228,8229,8230,8231,8232,8233, # 7952 +8234,8235,8236,8237,8238,8239,8240,8241,8242,8243,8244,8245,8246,8247,8248,8249, # 7968 +8250,8251,8252,8253,8254,8255,8256,3445,8257,8258,8259,8260,8261,8262,4458,8263, # 7984 +8264,8265,8266,8267,8268,8269,8270,8271,8272,4459,8273,8274,8275,8276,3550,8277, # 8000 +8278,8279,8280,8281,8282,8283,8284,8285,8286,8287,8288,8289,4460,8290,8291,8292, # 8016 +8293,8294,8295,8296,8297,8298,8299,8300,8301,8302,8303,8304,8305,8306,8307,4867, # 8032 +8308,8309,8310,8311,8312,3551,8313,8314,8315,8316,8317,8318,8319,8320,8321,8322, # 8048 +8323,8324,8325,8326,4868,8327,8328,8329,8330,8331,8332,8333,8334,8335,8336,8337, # 8064 +8338,8339,8340,8341,8342,8343,8344,8345,8346,8347,8348,8349,8350,8351,8352,8353, # 8080 +8354,8355,8356,8357,8358,8359,8360,8361,8362,8363,4869,4461,8364,8365,8366,8367, # 8096 +8368,8369,8370,4870,8371,8372,8373,8374,8375,8376,8377,8378,8379,8380,8381,8382, # 8112 +8383,8384,8385,8386,8387,8388,8389,8390,8391,8392,8393,8394,8395,8396,8397,8398, # 8128 +8399,8400,8401,8402,8403,8404,8405,8406,8407,8408,8409,8410,4871,8411,8412,8413, # 8144 +8414,8415,8416,8417,8418,8419,8420,8421,8422,4462,8423,8424,8425,8426,8427,8428, # 8160 +8429,8430,8431,8432,8433,2986,8434,8435,8436,8437,8438,8439,8440,8441,8442,8443, # 8176 +8444,8445,8446,8447,8448,8449,8450,8451,8452,8453,8454,8455,8456,8457,8458,8459, # 8192 +8460,8461,8462,8463,8464,8465,8466,8467,8468,8469,8470,8471,8472,8473,8474,8475, # 8208 +8476,8477,8478,4180,8479,8480,8481,8482,8483,8484,8485,8486,8487,8488,8489,8490, # 8224 +8491,8492,8493,8494,8495,8496,8497,8498,8499,8500,8501,8502,8503,8504,8505,8506, # 8240 +8507,8508,8509,8510,8511,8512,8513,8514,8515,8516,8517,8518,8519,8520,8521,8522, # 8256 +8523,8524,8525,8526,8527,8528,8529,8530,8531,8532,8533,8534,8535,8536,8537,8538, # 8272 +8539,8540,8541,8542,8543,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554, # 8288 +8555,8556,8557,8558,8559,8560,8561,8562,8563,8564,4872,8565,8566,8567,8568,8569, # 8304 +8570,8571,8572,8573,4873,8574,8575,8576,8577,8578,8579,8580,8581,8582,8583,8584, # 8320 +8585,8586,8587,8588,8589,8590,8591,8592,8593,8594,8595,8596,8597,8598,8599,8600, # 8336 +8601,8602,8603,8604,8605,3803,8606,8607,8608,8609,8610,8611,8612,8613,4874,3804, # 8352 +8614,8615,8616,8617,8618,8619,8620,8621,3956,8622,8623,8624,8625,8626,8627,8628, # 8368 +8629,8630,8631,8632,8633,8634,8635,8636,8637,8638,2865,8639,8640,8641,8642,8643, # 8384 +8644,8645,8646,8647,8648,8649,8650,8651,8652,8653,8654,8655,8656,4463,8657,8658, # 8400 +8659,4875,4876,8660,8661,8662,8663,8664,8665,8666,8667,8668,8669,8670,8671,8672, # 8416 +8673,8674,8675,8676,8677,8678,8679,8680,8681,4464,8682,8683,8684,8685,8686,8687, # 8432 +8688,8689,8690,8691,8692,8693,8694,8695,8696,8697,8698,8699,8700,8701,8702,8703, # 8448 +8704,8705,8706,8707,8708,8709,2261,8710,8711,8712,8713,8714,8715,8716,8717,8718, # 8464 +8719,8720,8721,8722,8723,8724,8725,8726,8727,8728,8729,8730,8731,8732,8733,4181, # 8480 +8734,8735,8736,8737,8738,8739,8740,8741,8742,8743,8744,8745,8746,8747,8748,8749, # 8496 +8750,8751,8752,8753,8754,8755,8756,8757,8758,8759,8760,8761,8762,8763,4877,8764, # 8512 +8765,8766,8767,8768,8769,8770,8771,8772,8773,8774,8775,8776,8777,8778,8779,8780, # 8528 +8781,8782,8783,8784,8785,8786,8787,8788,4878,8789,4879,8790,8791,8792,4880,8793, # 8544 +8794,8795,8796,8797,8798,8799,8800,8801,4881,8802,8803,8804,8805,8806,8807,8808, # 8560 +8809,8810,8811,8812,8813,8814,8815,3957,8816,8817,8818,8819,8820,8821,8822,8823, # 8576 +8824,8825,8826,8827,8828,8829,8830,8831,8832,8833,8834,8835,8836,8837,8838,8839, # 8592 +8840,8841,8842,8843,8844,8845,8846,8847,4882,8848,8849,8850,8851,8852,8853,8854, # 8608 +8855,8856,8857,8858,8859,8860,8861,8862,8863,8864,8865,8866,8867,8868,8869,8870, # 8624 +8871,8872,8873,8874,8875,8876,8877,8878,8879,8880,8881,8882,8883,8884,3202,8885, # 8640 +8886,8887,8888,8889,8890,8891,8892,8893,8894,8895,8896,8897,8898,8899,8900,8901, # 8656 +8902,8903,8904,8905,8906,8907,8908,8909,8910,8911,8912,8913,8914,8915,8916,8917, # 8672 +8918,8919,8920,8921,8922,8923,8924,4465,8925,8926,8927,8928,8929,8930,8931,8932, # 8688 +4883,8933,8934,8935,8936,8937,8938,8939,8940,8941,8942,8943,2214,8944,8945,8946, # 8704 +8947,8948,8949,8950,8951,8952,8953,8954,8955,8956,8957,8958,8959,8960,8961,8962, # 8720 +8963,8964,8965,4884,8966,8967,8968,8969,8970,8971,8972,8973,8974,8975,8976,8977, # 8736 +8978,8979,8980,8981,8982,8983,8984,8985,8986,8987,8988,8989,8990,8991,8992,4885, # 8752 +8993,8994,8995,8996,8997,8998,8999,9000,9001,9002,9003,9004,9005,9006,9007,9008, # 8768 +9009,9010,9011,9012,9013,9014,9015,9016,9017,9018,9019,9020,9021,4182,9022,9023, # 8784 +9024,9025,9026,9027,9028,9029,9030,9031,9032,9033,9034,9035,9036,9037,9038,9039, # 8800 +9040,9041,9042,9043,9044,9045,9046,9047,9048,9049,9050,9051,9052,9053,9054,9055, # 8816 +9056,9057,9058,9059,9060,9061,9062,9063,4886,9064,9065,9066,9067,9068,9069,4887, # 8832 +9070,9071,9072,9073,9074,9075,9076,9077,9078,9079,9080,9081,9082,9083,9084,9085, # 8848 +9086,9087,9088,9089,9090,9091,9092,9093,9094,9095,9096,9097,9098,9099,9100,9101, # 8864 +9102,9103,9104,9105,9106,9107,9108,9109,9110,9111,9112,9113,9114,9115,9116,9117, # 8880 +9118,9119,9120,9121,9122,9123,9124,9125,9126,9127,9128,9129,9130,9131,9132,9133, # 8896 +9134,9135,9136,9137,9138,9139,9140,9141,3958,9142,9143,9144,9145,9146,9147,9148, # 8912 +9149,9150,9151,4888,9152,9153,9154,9155,9156,9157,9158,9159,9160,9161,9162,9163, # 8928 +9164,9165,9166,9167,9168,9169,9170,9171,9172,9173,9174,9175,4889,9176,9177,9178, # 8944 +9179,9180,9181,9182,9183,9184,9185,9186,9187,9188,9189,9190,9191,9192,9193,9194, # 8960 +9195,9196,9197,9198,9199,9200,9201,9202,9203,4890,9204,9205,9206,9207,9208,9209, # 8976 +9210,9211,9212,9213,9214,9215,9216,9217,9218,9219,9220,9221,9222,4466,9223,9224, # 8992 +9225,9226,9227,9228,9229,9230,9231,9232,9233,9234,9235,9236,9237,9238,9239,9240, # 9008 +9241,9242,9243,9244,9245,4891,9246,9247,9248,9249,9250,9251,9252,9253,9254,9255, # 9024 +9256,9257,4892,9258,9259,9260,9261,4893,4894,9262,9263,9264,9265,9266,9267,9268, # 9040 +9269,9270,9271,9272,9273,4467,9274,9275,9276,9277,9278,9279,9280,9281,9282,9283, # 9056 +9284,9285,3673,9286,9287,9288,9289,9290,9291,9292,9293,9294,9295,9296,9297,9298, # 9072 +9299,9300,9301,9302,9303,9304,9305,9306,9307,9308,9309,9310,9311,9312,9313,9314, # 9088 +9315,9316,9317,9318,9319,9320,9321,9322,4895,9323,9324,9325,9326,9327,9328,9329, # 9104 +9330,9331,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,9343,9344,9345, # 9120 +9346,9347,4468,9348,9349,9350,9351,9352,9353,9354,9355,9356,9357,9358,9359,9360, # 9136 +9361,9362,9363,9364,9365,9366,9367,9368,9369,9370,9371,9372,9373,4896,9374,4469, # 9152 +9375,9376,9377,9378,9379,4897,9380,9381,9382,9383,9384,9385,9386,9387,9388,9389, # 9168 +9390,9391,9392,9393,9394,9395,9396,9397,9398,9399,9400,9401,9402,9403,9404,9405, # 9184 +9406,4470,9407,2751,9408,9409,3674,3552,9410,9411,9412,9413,9414,9415,9416,9417, # 9200 +9418,9419,9420,9421,4898,9422,9423,9424,9425,9426,9427,9428,9429,3959,9430,9431, # 9216 +9432,9433,9434,9435,9436,4471,9437,9438,9439,9440,9441,9442,9443,9444,9445,9446, # 9232 +9447,9448,9449,9450,3348,9451,9452,9453,9454,9455,9456,9457,9458,9459,9460,9461, # 9248 +9462,9463,9464,9465,9466,9467,9468,9469,9470,9471,9472,4899,9473,9474,9475,9476, # 9264 +9477,4900,9478,9479,9480,9481,9482,9483,9484,9485,9486,9487,9488,3349,9489,9490, # 9280 +9491,9492,9493,9494,9495,9496,9497,9498,9499,9500,9501,9502,9503,9504,9505,9506, # 9296 +9507,9508,9509,9510,9511,9512,9513,9514,9515,9516,9517,9518,9519,9520,4901,9521, # 9312 +9522,9523,9524,9525,9526,4902,9527,9528,9529,9530,9531,9532,9533,9534,9535,9536, # 9328 +9537,9538,9539,9540,9541,9542,9543,9544,9545,9546,9547,9548,9549,9550,9551,9552, # 9344 +9553,9554,9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567,9568, # 9360 +9569,9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,9581,9582,9583,9584, # 9376 +3805,9585,9586,9587,9588,9589,9590,9591,9592,9593,9594,9595,9596,9597,9598,9599, # 9392 +9600,9601,9602,4903,9603,9604,9605,9606,9607,4904,9608,9609,9610,9611,9612,9613, # 9408 +9614,4905,9615,9616,9617,9618,9619,9620,9621,9622,9623,9624,9625,9626,9627,9628, # 9424 +9629,9630,9631,9632,4906,9633,9634,9635,9636,9637,9638,9639,9640,9641,9642,9643, # 9440 +4907,9644,9645,9646,9647,9648,9649,9650,9651,9652,9653,9654,9655,9656,9657,9658, # 9456 +9659,9660,9661,9662,9663,9664,9665,9666,9667,9668,9669,9670,9671,9672,4183,9673, # 9472 +9674,9675,9676,9677,4908,9678,9679,9680,9681,4909,9682,9683,9684,9685,9686,9687, # 9488 +9688,9689,9690,4910,9691,9692,9693,3675,9694,9695,9696,2945,9697,9698,9699,9700, # 9504 +9701,9702,9703,9704,9705,4911,9706,9707,9708,9709,9710,9711,9712,9713,9714,9715, # 9520 +9716,9717,9718,9719,9720,9721,9722,9723,9724,9725,9726,9727,9728,9729,9730,9731, # 9536 +9732,9733,9734,9735,4912,9736,9737,9738,9739,9740,4913,9741,9742,9743,9744,9745, # 9552 +9746,9747,9748,9749,9750,9751,9752,9753,9754,9755,9756,9757,9758,4914,9759,9760, # 9568 +9761,9762,9763,9764,9765,9766,9767,9768,9769,9770,9771,9772,9773,9774,9775,9776, # 9584 +9777,9778,9779,9780,9781,9782,4915,9783,9784,9785,9786,9787,9788,9789,9790,9791, # 9600 +9792,9793,4916,9794,9795,9796,9797,9798,9799,9800,9801,9802,9803,9804,9805,9806, # 9616 +9807,9808,9809,9810,9811,9812,9813,9814,9815,9816,9817,9818,9819,9820,9821,9822, # 9632 +9823,9824,9825,9826,9827,9828,9829,9830,9831,9832,9833,9834,9835,9836,9837,9838, # 9648 +9839,9840,9841,9842,9843,9844,9845,9846,9847,9848,9849,9850,9851,9852,9853,9854, # 9664 +9855,9856,9857,9858,9859,9860,9861,9862,9863,9864,9865,9866,9867,9868,4917,9869, # 9680 +9870,9871,9872,9873,9874,9875,9876,9877,9878,9879,9880,9881,9882,9883,9884,9885, # 9696 +9886,9887,9888,9889,9890,9891,9892,4472,9893,9894,9895,9896,9897,3806,9898,9899, # 9712 +9900,9901,9902,9903,9904,9905,9906,9907,9908,9909,9910,9911,9912,9913,9914,4918, # 9728 +9915,9916,9917,4919,9918,9919,9920,9921,4184,9922,9923,9924,9925,9926,9927,9928, # 9744 +9929,9930,9931,9932,9933,9934,9935,9936,9937,9938,9939,9940,9941,9942,9943,9944, # 9760 +9945,9946,4920,9947,9948,9949,9950,9951,9952,9953,9954,9955,4185,9956,9957,9958, # 9776 +9959,9960,9961,9962,9963,9964,9965,4921,9966,9967,9968,4473,9969,9970,9971,9972, # 9792 +9973,9974,9975,9976,9977,4474,9978,9979,9980,9981,9982,9983,9984,9985,9986,9987, # 9808 +9988,9989,9990,9991,9992,9993,9994,9995,9996,9997,9998,9999,10000,10001,10002,10003, # 9824 +10004,10005,10006,10007,10008,10009,10010,10011,10012,10013,10014,10015,10016,10017,10018,10019, # 9840 +10020,10021,4922,10022,4923,10023,10024,10025,10026,10027,10028,10029,10030,10031,10032,10033, # 9856 +10034,10035,10036,10037,10038,10039,10040,10041,10042,10043,10044,10045,10046,10047,10048,4924, # 9872 +10049,10050,10051,10052,10053,10054,10055,10056,10057,10058,10059,10060,10061,10062,10063,10064, # 9888 +10065,10066,10067,10068,10069,10070,10071,10072,10073,10074,10075,10076,10077,10078,10079,10080, # 9904 +10081,10082,10083,10084,10085,10086,10087,4475,10088,10089,10090,10091,10092,10093,10094,10095, # 9920 +10096,10097,4476,10098,10099,10100,10101,10102,10103,10104,10105,10106,10107,10108,10109,10110, # 9936 +10111,2174,10112,10113,10114,10115,10116,10117,10118,10119,10120,10121,10122,10123,10124,10125, # 9952 +10126,10127,10128,10129,10130,10131,10132,10133,10134,10135,10136,10137,10138,10139,10140,3807, # 9968 +4186,4925,10141,10142,10143,10144,10145,10146,10147,4477,4187,10148,10149,10150,10151,10152, # 9984 +10153,4188,10154,10155,10156,10157,10158,10159,10160,10161,4926,10162,10163,10164,10165,10166, #10000 +10167,10168,10169,10170,10171,10172,10173,10174,10175,10176,10177,10178,10179,10180,10181,10182, #10016 +10183,10184,10185,10186,10187,10188,10189,10190,10191,10192,3203,10193,10194,10195,10196,10197, #10032 +10198,10199,10200,4478,10201,10202,10203,10204,4479,10205,10206,10207,10208,10209,10210,10211, #10048 +10212,10213,10214,10215,10216,10217,10218,10219,10220,10221,10222,10223,10224,10225,10226,10227, #10064 +10228,10229,10230,10231,10232,10233,10234,4927,10235,10236,10237,10238,10239,10240,10241,10242, #10080 +10243,10244,10245,10246,10247,10248,10249,10250,10251,10252,10253,10254,10255,10256,10257,10258, #10096 +10259,10260,10261,10262,10263,10264,10265,10266,10267,10268,10269,10270,10271,10272,10273,4480, #10112 +4928,4929,10274,10275,10276,10277,10278,10279,10280,10281,10282,10283,10284,10285,10286,10287, #10128 +10288,10289,10290,10291,10292,10293,10294,10295,10296,10297,10298,10299,10300,10301,10302,10303, #10144 +10304,10305,10306,10307,10308,10309,10310,10311,10312,10313,10314,10315,10316,10317,10318,10319, #10160 +10320,10321,10322,10323,10324,10325,10326,10327,10328,10329,10330,10331,10332,10333,10334,4930, #10176 +10335,10336,10337,10338,10339,10340,10341,10342,4931,10343,10344,10345,10346,10347,10348,10349, #10192 +10350,10351,10352,10353,10354,10355,3088,10356,2786,10357,10358,10359,10360,4189,10361,10362, #10208 +10363,10364,10365,10366,10367,10368,10369,10370,10371,10372,10373,10374,10375,4932,10376,10377, #10224 +10378,10379,10380,10381,10382,10383,10384,10385,10386,10387,10388,10389,10390,10391,10392,4933, #10240 +10393,10394,10395,4934,10396,10397,10398,10399,10400,10401,10402,10403,10404,10405,10406,10407, #10256 +10408,10409,10410,10411,10412,3446,10413,10414,10415,10416,10417,10418,10419,10420,10421,10422, #10272 +10423,4935,10424,10425,10426,10427,10428,10429,10430,4936,10431,10432,10433,10434,10435,10436, #10288 +10437,10438,10439,10440,10441,10442,10443,4937,10444,10445,10446,10447,4481,10448,10449,10450, #10304 +10451,10452,10453,10454,10455,10456,10457,10458,10459,10460,10461,10462,10463,10464,10465,10466, #10320 +10467,10468,10469,10470,10471,10472,10473,10474,10475,10476,10477,10478,10479,10480,10481,10482, #10336 +10483,10484,10485,10486,10487,10488,10489,10490,10491,10492,10493,10494,10495,10496,10497,10498, #10352 +10499,10500,10501,10502,10503,10504,10505,4938,10506,10507,10508,10509,10510,2552,10511,10512, #10368 +10513,10514,10515,10516,3447,10517,10518,10519,10520,10521,10522,10523,10524,10525,10526,10527, #10384 +10528,10529,10530,10531,10532,10533,10534,10535,10536,10537,10538,10539,10540,10541,10542,10543, #10400 +4482,10544,4939,10545,10546,10547,10548,10549,10550,10551,10552,10553,10554,10555,10556,10557, #10416 +10558,10559,10560,10561,10562,10563,10564,10565,10566,10567,3676,4483,10568,10569,10570,10571, #10432 +10572,3448,10573,10574,10575,10576,10577,10578,10579,10580,10581,10582,10583,10584,10585,10586, #10448 +10587,10588,10589,10590,10591,10592,10593,10594,10595,10596,10597,10598,10599,10600,10601,10602, #10464 +10603,10604,10605,10606,10607,10608,10609,10610,10611,10612,10613,10614,10615,10616,10617,10618, #10480 +10619,10620,10621,10622,10623,10624,10625,10626,10627,4484,10628,10629,10630,10631,10632,4940, #10496 +10633,10634,10635,10636,10637,10638,10639,10640,10641,10642,10643,10644,10645,10646,10647,10648, #10512 +10649,10650,10651,10652,10653,10654,10655,10656,4941,10657,10658,10659,2599,10660,10661,10662, #10528 +10663,10664,10665,10666,3089,10667,10668,10669,10670,10671,10672,10673,10674,10675,10676,10677, #10544 +10678,10679,10680,4942,10681,10682,10683,10684,10685,10686,10687,10688,10689,10690,10691,10692, #10560 +10693,10694,10695,10696,10697,4485,10698,10699,10700,10701,10702,10703,10704,4943,10705,3677, #10576 +10706,10707,10708,10709,10710,10711,10712,4944,10713,10714,10715,10716,10717,10718,10719,10720, #10592 +10721,10722,10723,10724,10725,10726,10727,10728,4945,10729,10730,10731,10732,10733,10734,10735, #10608 +10736,10737,10738,10739,10740,10741,10742,10743,10744,10745,10746,10747,10748,10749,10750,10751, #10624 +10752,10753,10754,10755,10756,10757,10758,10759,10760,10761,4946,10762,10763,10764,10765,10766, #10640 +10767,4947,4948,10768,10769,10770,10771,10772,10773,10774,10775,10776,10777,10778,10779,10780, #10656 +10781,10782,10783,10784,10785,10786,10787,10788,10789,10790,10791,10792,10793,10794,10795,10796, #10672 +10797,10798,10799,10800,10801,10802,10803,10804,10805,10806,10807,10808,10809,10810,10811,10812, #10688 +10813,10814,10815,10816,10817,10818,10819,10820,10821,10822,10823,10824,10825,10826,10827,10828, #10704 +10829,10830,10831,10832,10833,10834,10835,10836,10837,10838,10839,10840,10841,10842,10843,10844, #10720 +10845,10846,10847,10848,10849,10850,10851,10852,10853,10854,10855,10856,10857,10858,10859,10860, #10736 +10861,10862,10863,10864,10865,10866,10867,10868,10869,10870,10871,10872,10873,10874,10875,10876, #10752 +10877,10878,4486,10879,10880,10881,10882,10883,10884,10885,4949,10886,10887,10888,10889,10890, #10768 +10891,10892,10893,10894,10895,10896,10897,10898,10899,10900,10901,10902,10903,10904,10905,10906, #10784 +10907,10908,10909,10910,10911,10912,10913,10914,10915,10916,10917,10918,10919,4487,10920,10921, #10800 +10922,10923,10924,10925,10926,10927,10928,10929,10930,10931,10932,4950,10933,10934,10935,10936, #10816 +10937,10938,10939,10940,10941,10942,10943,10944,10945,10946,10947,10948,10949,4488,10950,10951, #10832 +10952,10953,10954,10955,10956,10957,10958,10959,4190,10960,10961,10962,10963,10964,10965,10966, #10848 +10967,10968,10969,10970,10971,10972,10973,10974,10975,10976,10977,10978,10979,10980,10981,10982, #10864 +10983,10984,10985,10986,10987,10988,10989,10990,10991,10992,10993,10994,10995,10996,10997,10998, #10880 +10999,11000,11001,11002,11003,11004,11005,11006,3960,11007,11008,11009,11010,11011,11012,11013, #10896 +11014,11015,11016,11017,11018,11019,11020,11021,11022,11023,11024,11025,11026,11027,11028,11029, #10912 +11030,11031,11032,4951,11033,11034,11035,11036,11037,11038,11039,11040,11041,11042,11043,11044, #10928 +11045,11046,11047,4489,11048,11049,11050,11051,4952,11052,11053,11054,11055,11056,11057,11058, #10944 +4953,11059,11060,11061,11062,11063,11064,11065,11066,11067,11068,11069,11070,11071,4954,11072, #10960 +11073,11074,11075,11076,11077,11078,11079,11080,11081,11082,11083,11084,11085,11086,11087,11088, #10976 +11089,11090,11091,11092,11093,11094,11095,11096,11097,11098,11099,11100,11101,11102,11103,11104, #10992 +11105,11106,11107,11108,11109,11110,11111,11112,11113,11114,11115,3808,11116,11117,11118,11119, #11008 +11120,11121,11122,11123,11124,11125,11126,11127,11128,11129,11130,11131,11132,11133,11134,4955, #11024 +11135,11136,11137,11138,11139,11140,11141,11142,11143,11144,11145,11146,11147,11148,11149,11150, #11040 +11151,11152,11153,11154,11155,11156,11157,11158,11159,11160,11161,4956,11162,11163,11164,11165, #11056 +11166,11167,11168,11169,11170,11171,11172,11173,11174,11175,11176,11177,11178,11179,11180,4957, #11072 +11181,11182,11183,11184,11185,11186,4958,11187,11188,11189,11190,11191,11192,11193,11194,11195, #11088 +11196,11197,11198,11199,11200,3678,11201,11202,11203,11204,11205,11206,4191,11207,11208,11209, #11104 +11210,11211,11212,11213,11214,11215,11216,11217,11218,11219,11220,11221,11222,11223,11224,11225, #11120 +11226,11227,11228,11229,11230,11231,11232,11233,11234,11235,11236,11237,11238,11239,11240,11241, #11136 +11242,11243,11244,11245,11246,11247,11248,11249,11250,11251,4959,11252,11253,11254,11255,11256, #11152 +11257,11258,11259,11260,11261,11262,11263,11264,11265,11266,11267,11268,11269,11270,11271,11272, #11168 +11273,11274,11275,11276,11277,11278,11279,11280,11281,11282,11283,11284,11285,11286,11287,11288, #11184 +11289,11290,11291,11292,11293,11294,11295,11296,11297,11298,11299,11300,11301,11302,11303,11304, #11200 +11305,11306,11307,11308,11309,11310,11311,11312,11313,11314,3679,11315,11316,11317,11318,4490, #11216 +11319,11320,11321,11322,11323,11324,11325,11326,11327,11328,11329,11330,11331,11332,11333,11334, #11232 +11335,11336,11337,11338,11339,11340,11341,11342,11343,11344,11345,11346,11347,4960,11348,11349, #11248 +11350,11351,11352,11353,11354,11355,11356,11357,11358,11359,11360,11361,11362,11363,11364,11365, #11264 +11366,11367,11368,11369,11370,11371,11372,11373,11374,11375,11376,11377,3961,4961,11378,11379, #11280 +11380,11381,11382,11383,11384,11385,11386,11387,11388,11389,11390,11391,11392,11393,11394,11395, #11296 +11396,11397,4192,11398,11399,11400,11401,11402,11403,11404,11405,11406,11407,11408,11409,11410, #11312 +11411,4962,11412,11413,11414,11415,11416,11417,11418,11419,11420,11421,11422,11423,11424,11425, #11328 +11426,11427,11428,11429,11430,11431,11432,11433,11434,11435,11436,11437,11438,11439,11440,11441, #11344 +11442,11443,11444,11445,11446,11447,11448,11449,11450,11451,11452,11453,11454,11455,11456,11457, #11360 +11458,11459,11460,11461,11462,11463,11464,11465,11466,11467,11468,11469,4963,11470,11471,4491, #11376 +11472,11473,11474,11475,4964,11476,11477,11478,11479,11480,11481,11482,11483,11484,11485,11486, #11392 +11487,11488,11489,11490,11491,11492,4965,11493,11494,11495,11496,11497,11498,11499,11500,11501, #11408 +11502,11503,11504,11505,11506,11507,11508,11509,11510,11511,11512,11513,11514,11515,11516,11517, #11424 +11518,11519,11520,11521,11522,11523,11524,11525,11526,11527,11528,11529,3962,11530,11531,11532, #11440 +11533,11534,11535,11536,11537,11538,11539,11540,11541,11542,11543,11544,11545,11546,11547,11548, #11456 +11549,11550,11551,11552,11553,11554,11555,11556,11557,11558,11559,11560,11561,11562,11563,11564, #11472 +4193,4194,11565,11566,11567,11568,11569,11570,11571,11572,11573,11574,11575,11576,11577,11578, #11488 +11579,11580,11581,11582,11583,11584,11585,11586,11587,11588,11589,11590,11591,4966,4195,11592, #11504 +11593,11594,11595,11596,11597,11598,11599,11600,11601,11602,11603,11604,3090,11605,11606,11607, #11520 +11608,11609,11610,4967,11611,11612,11613,11614,11615,11616,11617,11618,11619,11620,11621,11622, #11536 +11623,11624,11625,11626,11627,11628,11629,11630,11631,11632,11633,11634,11635,11636,11637,11638, #11552 +11639,11640,11641,11642,11643,11644,11645,11646,11647,11648,11649,11650,11651,11652,11653,11654, #11568 +11655,11656,11657,11658,11659,11660,11661,11662,11663,11664,11665,11666,11667,11668,11669,11670, #11584 +11671,11672,11673,11674,4968,11675,11676,11677,11678,11679,11680,11681,11682,11683,11684,11685, #11600 +11686,11687,11688,11689,11690,11691,11692,11693,3809,11694,11695,11696,11697,11698,11699,11700, #11616 +11701,11702,11703,11704,11705,11706,11707,11708,11709,11710,11711,11712,11713,11714,11715,11716, #11632 +11717,11718,3553,11719,11720,11721,11722,11723,11724,11725,11726,11727,11728,11729,11730,4969, #11648 +11731,11732,11733,11734,11735,11736,11737,11738,11739,11740,4492,11741,11742,11743,11744,11745, #11664 +11746,11747,11748,11749,11750,11751,11752,4970,11753,11754,11755,11756,11757,11758,11759,11760, #11680 +11761,11762,11763,11764,11765,11766,11767,11768,11769,11770,11771,11772,11773,11774,11775,11776, #11696 +11777,11778,11779,11780,11781,11782,11783,11784,11785,11786,11787,11788,11789,11790,4971,11791, #11712 +11792,11793,11794,11795,11796,11797,4972,11798,11799,11800,11801,11802,11803,11804,11805,11806, #11728 +11807,11808,11809,11810,4973,11811,11812,11813,11814,11815,11816,11817,11818,11819,11820,11821, #11744 +11822,11823,11824,11825,11826,11827,11828,11829,11830,11831,11832,11833,11834,3680,3810,11835, #11760 +11836,4974,11837,11838,11839,11840,11841,11842,11843,11844,11845,11846,11847,11848,11849,11850, #11776 +11851,11852,11853,11854,11855,11856,11857,11858,11859,11860,11861,11862,11863,11864,11865,11866, #11792 +11867,11868,11869,11870,11871,11872,11873,11874,11875,11876,11877,11878,11879,11880,11881,11882, #11808 +11883,11884,4493,11885,11886,11887,11888,11889,11890,11891,11892,11893,11894,11895,11896,11897, #11824 +11898,11899,11900,11901,11902,11903,11904,11905,11906,11907,11908,11909,11910,11911,11912,11913, #11840 +11914,11915,4975,11916,11917,11918,11919,11920,11921,11922,11923,11924,11925,11926,11927,11928, #11856 +11929,11930,11931,11932,11933,11934,11935,11936,11937,11938,11939,11940,11941,11942,11943,11944, #11872 +11945,11946,11947,11948,11949,4976,11950,11951,11952,11953,11954,11955,11956,11957,11958,11959, #11888 +11960,11961,11962,11963,11964,11965,11966,11967,11968,11969,11970,11971,11972,11973,11974,11975, #11904 +11976,11977,11978,11979,11980,11981,11982,11983,11984,11985,11986,11987,4196,11988,11989,11990, #11920 +11991,11992,4977,11993,11994,11995,11996,11997,11998,11999,12000,12001,12002,12003,12004,12005, #11936 +12006,12007,12008,12009,12010,12011,12012,12013,12014,12015,12016,12017,12018,12019,12020,12021, #11952 +12022,12023,12024,12025,12026,12027,12028,12029,12030,12031,12032,12033,12034,12035,12036,12037, #11968 +12038,12039,12040,12041,12042,12043,12044,12045,12046,12047,12048,12049,12050,12051,12052,12053, #11984 +12054,12055,12056,12057,12058,12059,12060,12061,4978,12062,12063,12064,12065,12066,12067,12068, #12000 +12069,12070,12071,12072,12073,12074,12075,12076,12077,12078,12079,12080,12081,12082,12083,12084, #12016 +12085,12086,12087,12088,12089,12090,12091,12092,12093,12094,12095,12096,12097,12098,12099,12100, #12032 +12101,12102,12103,12104,12105,12106,12107,12108,12109,12110,12111,12112,12113,12114,12115,12116, #12048 +12117,12118,12119,12120,12121,12122,12123,4979,12124,12125,12126,12127,12128,4197,12129,12130, #12064 +12131,12132,12133,12134,12135,12136,12137,12138,12139,12140,12141,12142,12143,12144,12145,12146, #12080 +12147,12148,12149,12150,12151,12152,12153,12154,4980,12155,12156,12157,12158,12159,12160,4494, #12096 +12161,12162,12163,12164,3811,12165,12166,12167,12168,12169,4495,12170,12171,4496,12172,12173, #12112 +12174,12175,12176,3812,12177,12178,12179,12180,12181,12182,12183,12184,12185,12186,12187,12188, #12128 +12189,12190,12191,12192,12193,12194,12195,12196,12197,12198,12199,12200,12201,12202,12203,12204, #12144 +12205,12206,12207,12208,12209,12210,12211,12212,12213,12214,12215,12216,12217,12218,12219,12220, #12160 +12221,4981,12222,12223,12224,12225,12226,12227,12228,12229,12230,12231,12232,12233,12234,12235, #12176 +4982,12236,12237,12238,12239,12240,12241,12242,12243,12244,12245,4983,12246,12247,12248,12249, #12192 +4984,12250,12251,12252,12253,12254,12255,12256,12257,12258,12259,12260,12261,12262,12263,12264, #12208 +4985,12265,4497,12266,12267,12268,12269,12270,12271,12272,12273,12274,12275,12276,12277,12278, #12224 +12279,12280,12281,12282,12283,12284,12285,12286,12287,4986,12288,12289,12290,12291,12292,12293, #12240 +12294,12295,12296,2473,12297,12298,12299,12300,12301,12302,12303,12304,12305,12306,12307,12308, #12256 +12309,12310,12311,12312,12313,12314,12315,12316,12317,12318,12319,3963,12320,12321,12322,12323, #12272 +12324,12325,12326,12327,12328,12329,12330,12331,12332,4987,12333,12334,12335,12336,12337,12338, #12288 +12339,12340,12341,12342,12343,12344,12345,12346,12347,12348,12349,12350,12351,12352,12353,12354, #12304 +12355,12356,12357,12358,12359,3964,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369, #12320 +12370,3965,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384, #12336 +12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400, #12352 +12401,12402,12403,12404,12405,12406,12407,12408,4988,12409,12410,12411,12412,12413,12414,12415, #12368 +12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431, #12384 +12432,12433,12434,12435,12436,12437,12438,3554,12439,12440,12441,12442,12443,12444,12445,12446, #12400 +12447,12448,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462, #12416 +12463,12464,4989,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477, #12432 +12478,12479,12480,4990,12481,12482,12483,12484,12485,12486,12487,12488,12489,4498,12490,12491, #12448 +12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507, #12464 +12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523, #12480 +12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,12535,12536,12537,12538,12539, #12496 +12540,12541,12542,12543,12544,12545,12546,12547,12548,12549,12550,12551,4991,12552,12553,12554, #12512 +12555,12556,12557,12558,12559,12560,12561,12562,12563,12564,12565,12566,12567,12568,12569,12570, #12528 +12571,12572,12573,12574,12575,12576,12577,12578,3036,12579,12580,12581,12582,12583,3966,12584, #12544 +12585,12586,12587,12588,12589,12590,12591,12592,12593,12594,12595,12596,12597,12598,12599,12600, #12560 +12601,12602,12603,12604,12605,12606,12607,12608,12609,12610,12611,12612,12613,12614,12615,12616, #12576 +12617,12618,12619,12620,12621,12622,12623,12624,12625,12626,12627,12628,12629,12630,12631,12632, #12592 +12633,12634,12635,12636,12637,12638,12639,12640,12641,12642,12643,12644,12645,12646,4499,12647, #12608 +12648,12649,12650,12651,12652,12653,12654,12655,12656,12657,12658,12659,12660,12661,12662,12663, #12624 +12664,12665,12666,12667,12668,12669,12670,12671,12672,12673,12674,12675,12676,12677,12678,12679, #12640 +12680,12681,12682,12683,12684,12685,12686,12687,12688,12689,12690,12691,12692,12693,12694,12695, #12656 +12696,12697,12698,4992,12699,12700,12701,12702,12703,12704,12705,12706,12707,12708,12709,12710, #12672 +12711,12712,12713,12714,12715,12716,12717,12718,12719,12720,12721,12722,12723,12724,12725,12726, #12688 +12727,12728,12729,12730,12731,12732,12733,12734,12735,12736,12737,12738,12739,12740,12741,12742, #12704 +12743,12744,12745,12746,12747,12748,12749,12750,12751,12752,12753,12754,12755,12756,12757,12758, #12720 +12759,12760,12761,12762,12763,12764,12765,12766,12767,12768,12769,12770,12771,12772,12773,12774, #12736 +12775,12776,12777,12778,4993,2175,12779,12780,12781,12782,12783,12784,12785,12786,4500,12787, #12752 +12788,12789,12790,12791,12792,12793,12794,12795,12796,12797,12798,12799,12800,12801,12802,12803, #12768 +12804,12805,12806,12807,12808,12809,12810,12811,12812,12813,12814,12815,12816,12817,12818,12819, #12784 +12820,12821,12822,12823,12824,12825,12826,4198,3967,12827,12828,12829,12830,12831,12832,12833, #12800 +12834,12835,12836,12837,12838,12839,12840,12841,12842,12843,12844,12845,12846,12847,12848,12849, #12816 +12850,12851,12852,12853,12854,12855,12856,12857,12858,12859,12860,12861,4199,12862,12863,12864, #12832 +12865,12866,12867,12868,12869,12870,12871,12872,12873,12874,12875,12876,12877,12878,12879,12880, #12848 +12881,12882,12883,12884,12885,12886,12887,4501,12888,12889,12890,12891,12892,12893,12894,12895, #12864 +12896,12897,12898,12899,12900,12901,12902,12903,12904,12905,12906,12907,12908,12909,12910,12911, #12880 +12912,4994,12913,12914,12915,12916,12917,12918,12919,12920,12921,12922,12923,12924,12925,12926, #12896 +12927,12928,12929,12930,12931,12932,12933,12934,12935,12936,12937,12938,12939,12940,12941,12942, #12912 +12943,12944,12945,12946,12947,12948,12949,12950,12951,12952,12953,12954,12955,12956,1772,12957, #12928 +12958,12959,12960,12961,12962,12963,12964,12965,12966,12967,12968,12969,12970,12971,12972,12973, #12944 +12974,12975,12976,12977,12978,12979,12980,12981,12982,12983,12984,12985,12986,12987,12988,12989, #12960 +12990,12991,12992,12993,12994,12995,12996,12997,4502,12998,4503,12999,13000,13001,13002,13003, #12976 +4504,13004,13005,13006,13007,13008,13009,13010,13011,13012,13013,13014,13015,13016,13017,13018, #12992 +13019,13020,13021,13022,13023,13024,13025,13026,13027,13028,13029,3449,13030,13031,13032,13033, #13008 +13034,13035,13036,13037,13038,13039,13040,13041,13042,13043,13044,13045,13046,13047,13048,13049, #13024 +13050,13051,13052,13053,13054,13055,13056,13057,13058,13059,13060,13061,13062,13063,13064,13065, #13040 +13066,13067,13068,13069,13070,13071,13072,13073,13074,13075,13076,13077,13078,13079,13080,13081, #13056 +13082,13083,13084,13085,13086,13087,13088,13089,13090,13091,13092,13093,13094,13095,13096,13097, #13072 +13098,13099,13100,13101,13102,13103,13104,13105,13106,13107,13108,13109,13110,13111,13112,13113, #13088 +13114,13115,13116,13117,13118,3968,13119,4995,13120,13121,13122,13123,13124,13125,13126,13127, #13104 +4505,13128,13129,13130,13131,13132,13133,13134,4996,4506,13135,13136,13137,13138,13139,4997, #13120 +13140,13141,13142,13143,13144,13145,13146,13147,13148,13149,13150,13151,13152,13153,13154,13155, #13136 +13156,13157,13158,13159,4998,13160,13161,13162,13163,13164,13165,13166,13167,13168,13169,13170, #13152 +13171,13172,13173,13174,13175,13176,4999,13177,13178,13179,13180,13181,13182,13183,13184,13185, #13168 +13186,13187,13188,13189,13190,13191,13192,13193,13194,13195,13196,13197,13198,13199,13200,13201, #13184 +13202,13203,13204,13205,13206,5000,13207,13208,13209,13210,13211,13212,13213,13214,13215,13216, #13200 +13217,13218,13219,13220,13221,13222,13223,13224,13225,13226,13227,4200,5001,13228,13229,13230, #13216 +13231,13232,13233,13234,13235,13236,13237,13238,13239,13240,3969,13241,13242,13243,13244,3970, #13232 +13245,13246,13247,13248,13249,13250,13251,13252,13253,13254,13255,13256,13257,13258,13259,13260, #13248 +13261,13262,13263,13264,13265,13266,13267,13268,3450,13269,13270,13271,13272,13273,13274,13275, #13264 +13276,5002,13277,13278,13279,13280,13281,13282,13283,13284,13285,13286,13287,13288,13289,13290, #13280 +13291,13292,13293,13294,13295,13296,13297,13298,13299,13300,13301,13302,3813,13303,13304,13305, #13296 +13306,13307,13308,13309,13310,13311,13312,13313,13314,13315,13316,13317,13318,13319,13320,13321, #13312 +13322,13323,13324,13325,13326,13327,13328,4507,13329,13330,13331,13332,13333,13334,13335,13336, #13328 +13337,13338,13339,13340,13341,5003,13342,13343,13344,13345,13346,13347,13348,13349,13350,13351, #13344 +13352,13353,13354,13355,13356,13357,13358,13359,13360,13361,13362,13363,13364,13365,13366,13367, #13360 +5004,13368,13369,13370,13371,13372,13373,13374,13375,13376,13377,13378,13379,13380,13381,13382, #13376 +13383,13384,13385,13386,13387,13388,13389,13390,13391,13392,13393,13394,13395,13396,13397,13398, #13392 +13399,13400,13401,13402,13403,13404,13405,13406,13407,13408,13409,13410,13411,13412,13413,13414, #13408 +13415,13416,13417,13418,13419,13420,13421,13422,13423,13424,13425,13426,13427,13428,13429,13430, #13424 +13431,13432,4508,13433,13434,13435,4201,13436,13437,13438,13439,13440,13441,13442,13443,13444, #13440 +13445,13446,13447,13448,13449,13450,13451,13452,13453,13454,13455,13456,13457,5005,13458,13459, #13456 +13460,13461,13462,13463,13464,13465,13466,13467,13468,13469,13470,4509,13471,13472,13473,13474, #13472 +13475,13476,13477,13478,13479,13480,13481,13482,13483,13484,13485,13486,13487,13488,13489,13490, #13488 +13491,13492,13493,13494,13495,13496,13497,13498,13499,13500,13501,13502,13503,13504,13505,13506, #13504 +13507,13508,13509,13510,13511,13512,13513,13514,13515,13516,13517,13518,13519,13520,13521,13522, #13520 +13523,13524,13525,13526,13527,13528,13529,13530,13531,13532,13533,13534,13535,13536,13537,13538, #13536 +13539,13540,13541,13542,13543,13544,13545,13546,13547,13548,13549,13550,13551,13552,13553,13554, #13552 +13555,13556,13557,13558,13559,13560,13561,13562,13563,13564,13565,13566,13567,13568,13569,13570, #13568 +13571,13572,13573,13574,13575,13576,13577,13578,13579,13580,13581,13582,13583,13584,13585,13586, #13584 +13587,13588,13589,13590,13591,13592,13593,13594,13595,13596,13597,13598,13599,13600,13601,13602, #13600 +13603,13604,13605,13606,13607,13608,13609,13610,13611,13612,13613,13614,13615,13616,13617,13618, #13616 +13619,13620,13621,13622,13623,13624,13625,13626,13627,13628,13629,13630,13631,13632,13633,13634, #13632 +13635,13636,13637,13638,13639,13640,13641,13642,5006,13643,13644,13645,13646,13647,13648,13649, #13648 +13650,13651,5007,13652,13653,13654,13655,13656,13657,13658,13659,13660,13661,13662,13663,13664, #13664 +13665,13666,13667,13668,13669,13670,13671,13672,13673,13674,13675,13676,13677,13678,13679,13680, #13680 +13681,13682,13683,13684,13685,13686,13687,13688,13689,13690,13691,13692,13693,13694,13695,13696, #13696 +13697,13698,13699,13700,13701,13702,13703,13704,13705,13706,13707,13708,13709,13710,13711,13712, #13712 +13713,13714,13715,13716,13717,13718,13719,13720,13721,13722,13723,13724,13725,13726,13727,13728, #13728 +13729,13730,13731,13732,13733,13734,13735,13736,13737,13738,13739,13740,13741,13742,13743,13744, #13744 +13745,13746,13747,13748,13749,13750,13751,13752,13753,13754,13755,13756,13757,13758,13759,13760, #13760 +13761,13762,13763,13764,13765,13766,13767,13768,13769,13770,13771,13772,13773,13774,3273,13775, #13776 +13776,13777,13778,13779,13780,13781,13782,13783,13784,13785,13786,13787,13788,13789,13790,13791, #13792 +13792,13793,13794,13795,13796,13797,13798,13799,13800,13801,13802,13803,13804,13805,13806,13807, #13808 +13808,13809,13810,13811,13812,13813,13814,13815,13816,13817,13818,13819,13820,13821,13822,13823, #13824 +13824,13825,13826,13827,13828,13829,13830,13831,13832,13833,13834,13835,13836,13837,13838,13839, #13840 +13840,13841,13842,13843,13844,13845,13846,13847,13848,13849,13850,13851,13852,13853,13854,13855, #13856 +13856,13857,13858,13859,13860,13861,13862,13863,13864,13865,13866,13867,13868,13869,13870,13871, #13872 +13872,13873,13874,13875,13876,13877,13878,13879,13880,13881,13882,13883,13884,13885,13886,13887, #13888 +13888,13889,13890,13891,13892,13893,13894,13895,13896,13897,13898,13899,13900,13901,13902,13903, #13904 +13904,13905,13906,13907,13908,13909,13910,13911,13912,13913,13914,13915,13916,13917,13918,13919, #13920 +13920,13921,13922,13923,13924,13925,13926,13927,13928,13929,13930,13931,13932,13933,13934,13935, #13936 +13936,13937,13938,13939,13940,13941,13942,13943,13944,13945,13946,13947,13948,13949,13950,13951, #13952 +13952,13953,13954,13955,13956,13957,13958,13959,13960,13961,13962,13963,13964,13965,13966,13967, #13968 +13968,13969,13970,13971,13972) #13973 diff --git a/libs/requests/packages/chardet2/big5prober.py b/libs/requests/packages/chardet2/big5prober.py new file mode 100644 index 00000000..823dc8d7 --- /dev/null +++ b/libs/requests/packages/chardet2/big5prober.py @@ -0,0 +1,41 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import Big5DistributionAnalysis +from .mbcssm import Big5SMModel + +class Big5Prober(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(Big5SMModel) + self._mDistributionAnalyzer = Big5DistributionAnalysis() + self.reset() + + def get_charset_name(self): + return "Big5" diff --git a/libs/requests/packages/chardet2/chardistribution.py b/libs/requests/packages/chardet2/chardistribution.py new file mode 100644 index 00000000..1d8ab40f --- /dev/null +++ b/libs/requests/packages/chardet2/chardistribution.py @@ -0,0 +1,200 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants +from .euctwfreq import EUCTWCharToFreqOrder, EUCTW_TABLE_SIZE, EUCTW_TYPICAL_DISTRIBUTION_RATIO +from .euckrfreq import EUCKRCharToFreqOrder, EUCKR_TABLE_SIZE, EUCKR_TYPICAL_DISTRIBUTION_RATIO +from .gb2312freq import GB2312CharToFreqOrder, GB2312_TABLE_SIZE, GB2312_TYPICAL_DISTRIBUTION_RATIO +from .big5freq import Big5CharToFreqOrder, BIG5_TABLE_SIZE, BIG5_TYPICAL_DISTRIBUTION_RATIO +from .jisfreq import JISCharToFreqOrder, JIS_TABLE_SIZE, JIS_TYPICAL_DISTRIBUTION_RATIO + +ENOUGH_DATA_THRESHOLD = 1024 +SURE_YES = 0.99 +SURE_NO = 0.01 + +class CharDistributionAnalysis: + def __init__(self): + self._mCharToFreqOrder = None # Mapping table to get frequency order from char order (get from GetOrder()) + self._mTableSize = None # Size of above table + self._mTypicalDistributionRatio = None # This is a constant value which varies from language to language, used in calculating confidence. See http://www.mozilla.org/projects/intl/UniversalCharsetDetection.html for further detail. + self.reset() + + def reset(self): + """reset analyser, clear any state""" + self._mDone = False # If this flag is set to True, detection is done and conclusion has been made + self._mTotalChars = 0 # Total characters encountered + self._mFreqChars = 0 # The number of characters whose frequency order is less than 512 + + def feed(self, aBuf, aCharLen): + """feed a character with known length""" + if aCharLen == 2: + # we only care about 2-bytes character in our distribution analysis + order = self.get_order(aBuf) + else: + order = -1 + if order >= 0: + self._mTotalChars += 1 + # order is valid + if order < self._mTableSize: + if 512 > self._mCharToFreqOrder[order]: + self._mFreqChars += 1 + + def get_confidence(self): + """return confidence based on existing data""" + # if we didn't receive any character in our consideration range, return negative answer + if self._mTotalChars <= 0: + return SURE_NO + + if self._mTotalChars != self._mFreqChars: + r = self._mFreqChars / ((self._mTotalChars - self._mFreqChars) * self._mTypicalDistributionRatio) + if r < SURE_YES: + return r + + # normalize confidence (we don't want to be 100% sure) + return SURE_YES + + def got_enough_data(self): + # It is not necessary to receive all data to draw conclusion. For charset detection, + # certain amount of data is enough + return self._mTotalChars > ENOUGH_DATA_THRESHOLD + + def get_order(self, aBuf): + # We do not handle characters based on the original encoding string, but + # convert this encoding string to a number, here called order. + # This allows multiple encodings of a language to share one frequency table. + return -1 + +class EUCTWDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = EUCTWCharToFreqOrder + self._mTableSize = EUCTW_TABLE_SIZE + self._mTypicalDistributionRatio = EUCTW_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aBuf): + # for euc-TW encoding, we are interested + # first byte range: 0xc4 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + if aBuf[0] >= 0xC4: + return 94 * (aBuf[0] - 0xC4) + aBuf[1] - 0xA1 + else: + return -1 + +class EUCKRDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = EUCKRCharToFreqOrder + self._mTableSize = EUCKR_TABLE_SIZE + self._mTypicalDistributionRatio = EUCKR_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aBuf): + # for euc-KR encoding, we are interested + # first byte range: 0xb0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + if aBuf[0] >= 0xB0: + return 94 * (aBuf[0] - 0xB0) + aBuf[1] - 0xA1 + else: + return -1; + +class GB2312DistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = GB2312CharToFreqOrder + self._mTableSize = GB2312_TABLE_SIZE + self._mTypicalDistributionRatio = GB2312_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aBuf): + # for GB2312 encoding, we are interested + # first byte range: 0xb0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + if (aBuf[0] >= 0xB0) and (aBuf[1] >= 0xA1): + return 94 * (aBuf[0] - 0xB0) + aBuf[1] - 0xA1 + else: + return -1; + +class Big5DistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = Big5CharToFreqOrder + self._mTableSize = BIG5_TABLE_SIZE + self._mTypicalDistributionRatio = BIG5_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aBuf): + # for big5 encoding, we are interested + # first byte range: 0xa4 -- 0xfe + # second byte range: 0x40 -- 0x7e , 0xa1 -- 0xfe + # no validation needed here. State machine has done that + if aBuf[0] >= 0xA4: + if aBuf[1] >= 0xA1: + return 157 * (aBuf[0] - 0xA4) + aBuf[1] - 0xA1 + 63 + else: + return 157 * (aBuf[0] - 0xA4) + aBuf[1] - 0x40 + else: + return -1 + +class SJISDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = JISCharToFreqOrder + self._mTableSize = JIS_TABLE_SIZE + self._mTypicalDistributionRatio = JIS_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aBuf): + # for sjis encoding, we are interested + # first byte range: 0x81 -- 0x9f , 0xe0 -- 0xfe + # second byte range: 0x40 -- 0x7e, 0x81 -- oxfe + # no validation needed here. State machine has done that + if (aBuf[0] >= 0x81) and (aBuf[0] <= 0x9F): + order = 188 * (aBuf[0] - 0x81) + elif (aBuf[0] >= 0xE0) and (aBuf[0] <= 0xEF): + order = 188 * (aBuf[0] - 0xE0 + 31) + else: + return -1; + order = order + aBuf[1] - 0x40 + if aBuf[1] > 0x7F: + order =- 1 + return order + +class EUCJPDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + CharDistributionAnalysis.__init__(self) + self._mCharToFreqOrder = JISCharToFreqOrder + self._mTableSize = JIS_TABLE_SIZE + self._mTypicalDistributionRatio = JIS_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, aBuf): + # for euc-JP encoding, we are interested + # first byte range: 0xa0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + if aBuf[0] >= 0xA0: + return 94 * (aBuf[0] - 0xA1) + aBuf[1] - 0xa1 + else: + return -1 diff --git a/libs/requests/packages/chardet2/charsetgroupprober.py b/libs/requests/packages/chardet2/charsetgroupprober.py new file mode 100644 index 00000000..3514ae4d --- /dev/null +++ b/libs/requests/packages/chardet2/charsetgroupprober.py @@ -0,0 +1,97 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants +import sys +from .charsetprober import CharSetProber + +class CharSetGroupProber(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self._mActiveNum = 0 + self._mProbers = [] + self._mBestGuessProber = None + + def reset(self): + CharSetProber.reset(self) + self._mActiveNum = 0 + for prober in self._mProbers: + if prober: + prober.reset() + prober.active = True + self._mActiveNum += 1 + self._mBestGuessProber = None + + def get_charset_name(self): + if not self._mBestGuessProber: + self.get_confidence() + if not self._mBestGuessProber: return None +# self._mBestGuessProber = self._mProbers[0] + return self._mBestGuessProber.get_charset_name() + + def feed(self, aBuf): + for prober in self._mProbers: + if not prober: continue + if not prober.active: continue + st = prober.feed(aBuf) + if not st: continue + if st == constants.eFoundIt: + self._mBestGuessProber = prober + return self.get_state() + elif st == constants.eNotMe: + prober.active = False + self._mActiveNum -= 1 + if self._mActiveNum <= 0: + self._mState = constants.eNotMe + return self.get_state() + return self.get_state() + + def get_confidence(self): + st = self.get_state() + if st == constants.eFoundIt: + return 0.99 + elif st == constants.eNotMe: + return 0.01 + bestConf = 0.0 + self._mBestGuessProber = None + for prober in self._mProbers: + if not prober: continue + if not prober.active: + if constants._debug: + sys.stderr.write(prober.get_charset_name() + ' not active\n') + continue + cf = prober.get_confidence() + if constants._debug: + sys.stderr.write('%s confidence = %s\n' % (prober.get_charset_name(), cf)) + if bestConf < cf: + bestConf = cf + self._mBestGuessProber = prober + if not self._mBestGuessProber: return 0.0 + return bestConf +# else: +# self._mBestGuessProber = self._mProbers[0] +# return self._mBestGuessProber.get_confidence() diff --git a/libs/requests/packages/chardet2/charsetprober.py b/libs/requests/packages/chardet2/charsetprober.py new file mode 100644 index 00000000..450c95ed --- /dev/null +++ b/libs/requests/packages/chardet2/charsetprober.py @@ -0,0 +1,61 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants +import re + +class CharSetProber: + def __init__(self): + pass + + def reset(self): + self._mState = constants.eDetecting + + def get_charset_name(self): + return None + + def feed(self, aBuf): + pass + + def get_state(self): + return self._mState + + def get_confidence(self): + return 0.0 + + def filter_high_bit_only(self, aBuf): + aBuf = re.sub(b'([\x00-\x7F])+', b' ', aBuf) + return aBuf + + def filter_without_english_letters(self, aBuf): + aBuf = re.sub(b'([A-Za-z])+', b' ', aBuf) + return aBuf + + def filter_with_english_letters(self, aBuf): + # TODO + return aBuf diff --git a/libs/requests/packages/chardet2/codingstatemachine.py b/libs/requests/packages/chardet2/codingstatemachine.py new file mode 100644 index 00000000..1cfda5df --- /dev/null +++ b/libs/requests/packages/chardet2/codingstatemachine.py @@ -0,0 +1,57 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .constants import eStart, eError, eItsMe + +class CodingStateMachine: + def __init__(self, sm): + self._mModel = sm + self._mCurrentBytePos = 0 + self._mCurrentCharLen = 0 + self.reset() + + def reset(self): + self._mCurrentState = eStart + + def next_state(self, c): + # for each byte we get its class + # if it is first byte, we also get byte length + # PY3K: aBuf is a byte stream, so c is an int, not a byte + byteCls = self._mModel['classTable'][c] + if self._mCurrentState == eStart: + self._mCurrentBytePos = 0 + self._mCurrentCharLen = self._mModel['charLenTable'][byteCls] + # from byte's class and stateTable, we get its next state + self._mCurrentState = self._mModel['stateTable'][self._mCurrentState * self._mModel['classFactor'] + byteCls] + self._mCurrentBytePos += 1 + return self._mCurrentState + + def get_current_charlen(self): + return self._mCurrentCharLen + + def get_coding_state_machine(self): + return self._mModel['name'] diff --git a/libs/requests/packages/chardet2/constants.py b/libs/requests/packages/chardet2/constants.py new file mode 100644 index 00000000..e4d148b3 --- /dev/null +++ b/libs/requests/packages/chardet2/constants.py @@ -0,0 +1,39 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +_debug = 0 + +eDetecting = 0 +eFoundIt = 1 +eNotMe = 2 + +eStart = 0 +eError = 1 +eItsMe = 2 + +SHORTCUT_THRESHOLD = 0.95 diff --git a/libs/requests/packages/chardet2/escprober.py b/libs/requests/packages/chardet2/escprober.py new file mode 100644 index 00000000..9dd00e33 --- /dev/null +++ b/libs/requests/packages/chardet2/escprober.py @@ -0,0 +1,81 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants +import sys +from .escsm import HZSMModel, ISO2022CNSMModel, ISO2022JPSMModel, ISO2022KRSMModel +from .charsetprober import CharSetProber +from .codingstatemachine import CodingStateMachine + +class EscCharSetProber(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self._mCodingSM = [ \ + CodingStateMachine(HZSMModel), + CodingStateMachine(ISO2022CNSMModel), + CodingStateMachine(ISO2022JPSMModel), + CodingStateMachine(ISO2022KRSMModel) + ] + self.reset() + + def reset(self): + CharSetProber.reset(self) + for codingSM in self._mCodingSM: + if not codingSM: continue + codingSM.active = True + codingSM.reset() + self._mActiveSM = len(self._mCodingSM) + self._mDetectedCharset = None + + def get_charset_name(self): + return self._mDetectedCharset + + def get_confidence(self): + if self._mDetectedCharset: + return 0.99 + else: + return 0.00 + + def feed(self, aBuf): + for c in aBuf: + # PY3K: aBuf is a byte array, so c is an int, not a byte + for codingSM in self._mCodingSM: + if not codingSM: continue + if not codingSM.active: continue + codingState = codingSM.next_state(c) + if codingState == constants.eError: + codingSM.active = False + self._mActiveSM -= 1 + if self._mActiveSM <= 0: + self._mState = constants.eNotMe + return self.get_state() + elif codingState == constants.eItsMe: + self._mState = constants.eFoundIt + self._mDetectedCharset = codingSM.get_coding_state_machine() + return self.get_state() + + return self.get_state() diff --git a/libs/requests/packages/chardet2/escsm.py b/libs/requests/packages/chardet2/escsm.py new file mode 100644 index 00000000..b05fefa0 --- /dev/null +++ b/libs/requests/packages/chardet2/escsm.py @@ -0,0 +1,240 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .constants import eStart, eError, eItsMe + +HZ_cls = ( \ +1,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,0,0,0,0, # 20 - 27 +0,0,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,0,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,4,0,5,2,0, # 78 - 7f +1,1,1,1,1,1,1,1, # 80 - 87 +1,1,1,1,1,1,1,1, # 88 - 8f +1,1,1,1,1,1,1,1, # 90 - 97 +1,1,1,1,1,1,1,1, # 98 - 9f +1,1,1,1,1,1,1,1, # a0 - a7 +1,1,1,1,1,1,1,1, # a8 - af +1,1,1,1,1,1,1,1, # b0 - b7 +1,1,1,1,1,1,1,1, # b8 - bf +1,1,1,1,1,1,1,1, # c0 - c7 +1,1,1,1,1,1,1,1, # c8 - cf +1,1,1,1,1,1,1,1, # d0 - d7 +1,1,1,1,1,1,1,1, # d8 - df +1,1,1,1,1,1,1,1, # e0 - e7 +1,1,1,1,1,1,1,1, # e8 - ef +1,1,1,1,1,1,1,1, # f0 - f7 +1,1,1,1,1,1,1,1, # f8 - ff +) + +HZ_st = ( \ +eStart,eError, 3,eStart,eStart,eStart,eError,eError,# 00-07 +eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,# 08-0f +eItsMe,eItsMe,eError,eError,eStart,eStart, 4,eError,# 10-17 + 5,eError, 6,eError, 5, 5, 4,eError,# 18-1f + 4,eError, 4, 4, 4,eError, 4,eError,# 20-27 + 4,eItsMe,eStart,eStart,eStart,eStart,eStart,eStart,# 28-2f +) + +HZCharLenTable = (0, 0, 0, 0, 0, 0) + +HZSMModel = {'classTable': HZ_cls, + 'classFactor': 6, + 'stateTable': HZ_st, + 'charLenTable': HZCharLenTable, + 'name': "HZ-GB-2312"} + +ISO2022CN_cls = ( \ +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,0,0,0,0, # 20 - 27 +0,3,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,4,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022CN_st = ( \ +eStart, 3,eError,eStart,eStart,eStart,eStart,eStart,# 00-07 +eStart,eError,eError,eError,eError,eError,eError,eError,# 08-0f +eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,# 10-17 +eItsMe,eItsMe,eItsMe,eError,eError,eError, 4,eError,# 18-1f +eError,eError,eError,eItsMe,eError,eError,eError,eError,# 20-27 + 5, 6,eError,eError,eError,eError,eError,eError,# 28-2f +eError,eError,eError,eItsMe,eError,eError,eError,eError,# 30-37 +eError,eError,eError,eError,eError,eItsMe,eError,eStart,# 38-3f +) + +ISO2022CNCharLenTable = (0, 0, 0, 0, 0, 0, 0, 0, 0) + +ISO2022CNSMModel = {'classTable': ISO2022CN_cls, + 'classFactor': 9, + 'stateTable': ISO2022CN_st, + 'charLenTable': ISO2022CNCharLenTable, + 'name': "ISO-2022-CN"} + +ISO2022JP_cls = ( \ +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,2,2, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,7,0,0,0, # 20 - 27 +3,0,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +6,0,4,0,8,0,0,0, # 40 - 47 +0,9,5,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022JP_st = ( \ +eStart, 3,eError,eStart,eStart,eStart,eStart,eStart,# 00-07 +eStart,eStart,eError,eError,eError,eError,eError,eError,# 08-0f +eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,# 10-17 +eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eError,eError,# 18-1f +eError, 5,eError,eError,eError, 4,eError,eError,# 20-27 +eError,eError,eError, 6,eItsMe,eError,eItsMe,eError,# 28-2f +eError,eError,eError,eError,eError,eError,eItsMe,eItsMe,# 30-37 +eError,eError,eError,eItsMe,eError,eError,eError,eError,# 38-3f +eError,eError,eError,eError,eItsMe,eError,eStart,eStart,# 40-47 +) + +ISO2022JPCharLenTable = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + +ISO2022JPSMModel = {'classTable': ISO2022JP_cls, + 'classFactor': 10, + 'stateTable': ISO2022JP_st, + 'charLenTable': ISO2022JPCharLenTable, + 'name': "ISO-2022-JP"} + +ISO2022KR_cls = ( \ +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,3,0,0,0, # 20 - 27 +0,4,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,5,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022KR_st = ( \ +eStart, 3,eError,eStart,eStart,eStart,eError,eError,# 00-07 +eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,# 08-0f +eItsMe,eItsMe,eError,eError,eError, 4,eError,eError,# 10-17 +eError,eError,eError,eError, 5,eError,eError,eError,# 18-1f +eError,eError,eError,eItsMe,eStart,eStart,eStart,eStart,# 20-27 +) + +ISO2022KRCharLenTable = (0, 0, 0, 0, 0, 0) + +ISO2022KRSMModel = {'classTable': ISO2022KR_cls, + 'classFactor': 6, + 'stateTable': ISO2022KR_st, + 'charLenTable': ISO2022KRCharLenTable, + 'name': "ISO-2022-KR"} diff --git a/libs/requests/packages/chardet2/eucjpprober.py b/libs/requests/packages/chardet2/eucjpprober.py new file mode 100644 index 00000000..16935a9a --- /dev/null +++ b/libs/requests/packages/chardet2/eucjpprober.py @@ -0,0 +1,87 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants +import sys +from .constants import eStart, eError, eItsMe +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCJPDistributionAnalysis +from .jpcntx import EUCJPContextAnalysis +from .mbcssm import EUCJPSMModel + +class EUCJPProber(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(EUCJPSMModel) + self._mDistributionAnalyzer = EUCJPDistributionAnalysis() + self._mContextAnalyzer = EUCJPContextAnalysis() + self.reset() + + def reset(self): + MultiByteCharSetProber.reset(self) + self._mContextAnalyzer.reset() + + def get_charset_name(self): + return "EUC-JP" + + def feed(self, aBuf): + aLen = len(aBuf) + for i in range(0, aLen): + # PY3K: aBuf is a byte array, so aBuf[i] is an int, not a byte + codingState = self._mCodingSM.next_state(aBuf[i]) + if codingState == eError: + if constants._debug: + sys.stderr.write(self.get_charset_name() + ' prober hit error at byte ' + str(i) + '\n') + self._mState = constants.eNotMe + break + elif codingState == eItsMe: + self._mState = constants.eFoundIt + break + elif codingState == eStart: + charLen = self._mCodingSM.get_current_charlen() + if i == 0: + self._mLastChar[1] = aBuf[0] + self._mContextAnalyzer.feed(self._mLastChar, charLen) + self._mDistributionAnalyzer.feed(self._mLastChar, charLen) + else: + self._mContextAnalyzer.feed(aBuf[i-1:i+1], charLen) + self._mDistributionAnalyzer.feed(aBuf[i-1:i+1], charLen) + + self._mLastChar[0] = aBuf[aLen - 1] + + if self.get_state() == constants.eDetecting: + if self._mContextAnalyzer.got_enough_data() and \ + (self.get_confidence() > constants.SHORTCUT_THRESHOLD): + self._mState = constants.eFoundIt + + return self.get_state() + + def get_confidence(self): + contxtCf = self._mContextAnalyzer.get_confidence() + distribCf = self._mDistributionAnalyzer.get_confidence() + return max(contxtCf, distribCf) diff --git a/libs/requests/packages/chardet2/euckrfreq.py b/libs/requests/packages/chardet2/euckrfreq.py new file mode 100644 index 00000000..1463fa1d --- /dev/null +++ b/libs/requests/packages/chardet2/euckrfreq.py @@ -0,0 +1,594 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Sampling from about 20M text materials include literature and computer technology + +# 128 --> 0.79 +# 256 --> 0.92 +# 512 --> 0.986 +# 1024 --> 0.99944 +# 2048 --> 0.99999 +# +# Idea Distribution Ratio = 0.98653 / (1-0.98653) = 73.24 +# Random Distribution Ration = 512 / (2350-512) = 0.279. +# +# Typical Distribution Ratio + +EUCKR_TYPICAL_DISTRIBUTION_RATIO = 6.0 + +EUCKR_TABLE_SIZE = 2352 + +# Char to FreqOrder table , +EUCKRCharToFreqOrder = ( \ + 13, 130, 120,1396, 481,1719,1720, 328, 609, 212,1721, 707, 400, 299,1722, 87, +1397,1723, 104, 536,1117,1203,1724,1267, 685,1268, 508,1725,1726,1727,1728,1398, +1399,1729,1730,1731, 141, 621, 326,1057, 368,1732, 267, 488, 20,1733,1269,1734, + 945,1400,1735, 47, 904,1270,1736,1737, 773, 248,1738, 409, 313, 786, 429,1739, + 116, 987, 813,1401, 683, 75,1204, 145,1740,1741,1742,1743, 16, 847, 667, 622, + 708,1744,1745,1746, 966, 787, 304, 129,1747, 60, 820, 123, 676,1748,1749,1750, +1751, 617,1752, 626,1753,1754,1755,1756, 653,1757,1758,1759,1760,1761,1762, 856, + 344,1763,1764,1765,1766, 89, 401, 418, 806, 905, 848,1767,1768,1769, 946,1205, + 709,1770,1118,1771, 241,1772,1773,1774,1271,1775, 569,1776, 999,1777,1778,1779, +1780, 337, 751,1058, 28, 628, 254,1781, 177, 906, 270, 349, 891,1079,1782, 19, +1783, 379,1784, 315,1785, 629, 754,1402, 559,1786, 636, 203,1206,1787, 710, 567, +1788, 935, 814,1789,1790,1207, 766, 528,1791,1792,1208,1793,1794,1795,1796,1797, +1403,1798,1799, 533,1059,1404,1405,1156,1406, 936, 884,1080,1800, 351,1801,1802, +1803,1804,1805, 801,1806,1807,1808,1119,1809,1157, 714, 474,1407,1810, 298, 899, + 885,1811,1120, 802,1158,1812, 892,1813,1814,1408, 659,1815,1816,1121,1817,1818, +1819,1820,1821,1822, 319,1823, 594, 545,1824, 815, 937,1209,1825,1826, 573,1409, +1022,1827,1210,1828,1829,1830,1831,1832,1833, 556, 722, 807,1122,1060,1834, 697, +1835, 900, 557, 715,1836,1410, 540,1411, 752,1159, 294, 597,1211, 976, 803, 770, +1412,1837,1838, 39, 794,1413, 358,1839, 371, 925,1840, 453, 661, 788, 531, 723, + 544,1023,1081, 869, 91,1841, 392, 430, 790, 602,1414, 677,1082, 457,1415,1416, +1842,1843, 475, 327,1024,1417, 795, 121,1844, 733, 403,1418,1845,1846,1847, 300, + 119, 711,1212, 627,1848,1272, 207,1849,1850, 796,1213, 382,1851, 519,1852,1083, + 893,1853,1854,1855, 367, 809, 487, 671,1856, 663,1857,1858, 956, 471, 306, 857, +1859,1860,1160,1084,1861,1862,1863,1864,1865,1061,1866,1867,1868,1869,1870,1871, + 282, 96, 574,1872, 502,1085,1873,1214,1874, 907,1875,1876, 827, 977,1419,1420, +1421, 268,1877,1422,1878,1879,1880, 308,1881, 2, 537,1882,1883,1215,1884,1885, + 127, 791,1886,1273,1423,1887, 34, 336, 404, 643,1888, 571, 654, 894, 840,1889, + 0, 886,1274, 122, 575, 260, 908, 938,1890,1275, 410, 316,1891,1892, 100,1893, +1894,1123, 48,1161,1124,1025,1895, 633, 901,1276,1896,1897, 115, 816,1898, 317, +1899, 694,1900, 909, 734,1424, 572, 866,1425, 691, 85, 524,1010, 543, 394, 841, +1901,1902,1903,1026,1904,1905,1906,1907,1908,1909, 30, 451, 651, 988, 310,1910, +1911,1426, 810,1216, 93,1912,1913,1277,1217,1914, 858, 759, 45, 58, 181, 610, + 269,1915,1916, 131,1062, 551, 443,1000, 821,1427, 957, 895,1086,1917,1918, 375, +1919, 359,1920, 687,1921, 822,1922, 293,1923,1924, 40, 662, 118, 692, 29, 939, + 887, 640, 482, 174,1925, 69,1162, 728,1428, 910,1926,1278,1218,1279, 386, 870, + 217, 854,1163, 823,1927,1928,1929,1930, 834,1931, 78,1932, 859,1933,1063,1934, +1935,1936,1937, 438,1164, 208, 595,1938,1939,1940,1941,1219,1125,1942, 280, 888, +1429,1430,1220,1431,1943,1944,1945,1946,1947,1280, 150, 510,1432,1948,1949,1950, +1951,1952,1953,1954,1011,1087,1955,1433,1043,1956, 881,1957, 614, 958,1064,1065, +1221,1958, 638,1001, 860, 967, 896,1434, 989, 492, 553,1281,1165,1959,1282,1002, +1283,1222,1960,1961,1962,1963, 36, 383, 228, 753, 247, 454,1964, 876, 678,1965, +1966,1284, 126, 464, 490, 835, 136, 672, 529, 940,1088,1435, 473,1967,1968, 467, + 50, 390, 227, 587, 279, 378, 598, 792, 968, 240, 151, 160, 849, 882,1126,1285, + 639,1044, 133, 140, 288, 360, 811, 563,1027, 561, 142, 523,1969,1970,1971, 7, + 103, 296, 439, 407, 506, 634, 990,1972,1973,1974,1975, 645,1976,1977,1978,1979, +1980,1981, 236,1982,1436,1983,1984,1089, 192, 828, 618, 518,1166, 333,1127,1985, + 818,1223,1986,1987,1988,1989,1990,1991,1992,1993, 342,1128,1286, 746, 842,1994, +1995, 560, 223,1287, 98, 8, 189, 650, 978,1288,1996,1437,1997, 17, 345, 250, + 423, 277, 234, 512, 226, 97, 289, 42, 167,1998, 201,1999,2000, 843, 836, 824, + 532, 338, 783,1090, 182, 576, 436,1438,1439, 527, 500,2001, 947, 889,2002,2003, +2004,2005, 262, 600, 314, 447,2006, 547,2007, 693, 738,1129,2008, 71,1440, 745, + 619, 688,2009, 829,2010,2011, 147,2012, 33, 948,2013,2014, 74, 224,2015, 61, + 191, 918, 399, 637,2016,1028,1130, 257, 902,2017,2018,2019,2020,2021,2022,2023, +2024,2025,2026, 837,2027,2028,2029,2030, 179, 874, 591, 52, 724, 246,2031,2032, +2033,2034,1167, 969,2035,1289, 630, 605, 911,1091,1168,2036,2037,2038,1441, 912, +2039, 623,2040,2041, 253,1169,1290,2042,1442, 146, 620, 611, 577, 433,2043,1224, + 719,1170, 959, 440, 437, 534, 84, 388, 480,1131, 159, 220, 198, 679,2044,1012, + 819,1066,1443, 113,1225, 194, 318,1003,1029,2045,2046,2047,2048,1067,2049,2050, +2051,2052,2053, 59, 913, 112,2054, 632,2055, 455, 144, 739,1291,2056, 273, 681, + 499,2057, 448,2058,2059, 760,2060,2061, 970, 384, 169, 245,1132,2062,2063, 414, +1444,2064,2065, 41, 235,2066, 157, 252, 877, 568, 919, 789, 580,2067, 725,2068, +2069,1292,2070,2071,1445,2072,1446,2073,2074, 55, 588, 66,1447, 271,1092,2075, +1226,2076, 960,1013, 372,2077,2078,2079,2080,2081,1293,2082,2083,2084,2085, 850, +2086,2087,2088,2089,2090, 186,2091,1068, 180,2092,2093,2094, 109,1227, 522, 606, +2095, 867,1448,1093, 991,1171, 926, 353,1133,2096, 581,2097,2098,2099,1294,1449, +1450,2100, 596,1172,1014,1228,2101,1451,1295,1173,1229,2102,2103,1296,1134,1452, + 949,1135,2104,2105,1094,1453,1454,1455,2106,1095,2107,2108,2109,2110,2111,2112, +2113,2114,2115,2116,2117, 804,2118,2119,1230,1231, 805,1456, 405,1136,2120,2121, +2122,2123,2124, 720, 701,1297, 992,1457, 927,1004,2125,2126,2127,2128,2129,2130, + 22, 417,2131, 303,2132, 385,2133, 971, 520, 513,2134,1174, 73,1096, 231, 274, + 962,1458, 673,2135,1459,2136, 152,1137,2137,2138,2139,2140,1005,1138,1460,1139, +2141,2142,2143,2144, 11, 374, 844,2145, 154,1232, 46,1461,2146, 838, 830, 721, +1233, 106,2147, 90, 428, 462, 578, 566,1175, 352,2148,2149, 538,1234, 124,1298, +2150,1462, 761, 565,2151, 686,2152, 649,2153, 72, 173,2154, 460, 415,2155,1463, +2156,1235, 305,2157,2158,2159,2160,2161,2162, 579,2163,2164,2165,2166,2167, 747, +2168,2169,2170,2171,1464, 669,2172,2173,2174,2175,2176,1465,2177, 23, 530, 285, +2178, 335, 729,2179, 397,2180,2181,2182,1030,2183,2184, 698,2185,2186, 325,2187, +2188, 369,2189, 799,1097,1015, 348,2190,1069, 680,2191, 851,1466,2192,2193, 10, +2194, 613, 424,2195, 979, 108, 449, 589, 27, 172, 81,1031, 80, 774, 281, 350, +1032, 525, 301, 582,1176,2196, 674,1045,2197,2198,1467, 730, 762,2199,2200,2201, +2202,1468,2203, 993,2204,2205, 266,1070, 963,1140,2206,2207,2208, 664,1098, 972, +2209,2210,2211,1177,1469,1470, 871,2212,2213,2214,2215,2216,1471,2217,2218,2219, +2220,2221,2222,2223,2224,2225,2226,2227,1472,1236,2228,2229,2230,2231,2232,2233, +2234,2235,1299,2236,2237, 200,2238, 477, 373,2239,2240, 731, 825, 777,2241,2242, +2243, 521, 486, 548,2244,2245,2246,1473,1300, 53, 549, 137, 875, 76, 158,2247, +1301,1474, 469, 396,1016, 278, 712,2248, 321, 442, 503, 767, 744, 941,1237,1178, +1475,2249, 82, 178,1141,1179, 973,2250,1302,2251, 297,2252,2253, 570,2254,2255, +2256, 18, 450, 206,2257, 290, 292,1142,2258, 511, 162, 99, 346, 164, 735,2259, +1476,1477, 4, 554, 343, 798,1099,2260,1100,2261, 43, 171,1303, 139, 215,2262, +2263, 717, 775,2264,1033, 322, 216,2265, 831,2266, 149,2267,1304,2268,2269, 702, +1238, 135, 845, 347, 309,2270, 484,2271, 878, 655, 238,1006,1478,2272, 67,2273, + 295,2274,2275, 461,2276, 478, 942, 412,2277,1034,2278,2279,2280, 265,2281, 541, +2282,2283,2284,2285,2286, 70, 852,1071,2287,2288,2289,2290, 21, 56, 509, 117, + 432,2291,2292, 331, 980, 552,1101, 148, 284, 105, 393,1180,1239, 755,2293, 187, +2294,1046,1479,2295, 340,2296, 63,1047, 230,2297,2298,1305, 763,1306, 101, 800, + 808, 494,2299,2300,2301, 903,2302, 37,1072, 14, 5,2303, 79, 675,2304, 312, +2305,2306,2307,2308,2309,1480, 6,1307,2310,2311,2312, 1, 470, 35, 24, 229, +2313, 695, 210, 86, 778, 15, 784, 592, 779, 32, 77, 855, 964,2314, 259,2315, + 501, 380,2316,2317, 83, 981, 153, 689,1308,1481,1482,1483,2318,2319, 716,1484, +2320,2321,2322,2323,2324,2325,1485,2326,2327, 128, 57, 68, 261,1048, 211, 170, +1240, 31,2328, 51, 435, 742,2329,2330,2331, 635,2332, 264, 456,2333,2334,2335, + 425,2336,1486, 143, 507, 263, 943,2337, 363, 920,1487, 256,1488,1102, 243, 601, +1489,2338,2339,2340,2341,2342,2343,2344, 861,2345,2346,2347,2348,2349,2350, 395, +2351,1490,1491, 62, 535, 166, 225,2352,2353, 668, 419,1241, 138, 604, 928,2354, +1181,2355,1492,1493,2356,2357,2358,1143,2359, 696,2360, 387, 307,1309, 682, 476, +2361,2362, 332, 12, 222, 156,2363, 232,2364, 641, 276, 656, 517,1494,1495,1035, + 416, 736,1496,2365,1017, 586,2366,2367,2368,1497,2369, 242,2370,2371,2372,1498, +2373, 965, 713,2374,2375,2376,2377, 740, 982,1499, 944,1500,1007,2378,2379,1310, +1501,2380,2381,2382, 785, 329,2383,2384,1502,2385,2386,2387, 932,2388,1503,2389, +2390,2391,2392,1242,2393,2394,2395,2396,2397, 994, 950,2398,2399,2400,2401,1504, +1311,2402,2403,2404,2405,1049, 749,2406,2407, 853, 718,1144,1312,2408,1182,1505, +2409,2410, 255, 516, 479, 564, 550, 214,1506,1507,1313, 413, 239, 444, 339,1145, +1036,1508,1509,1314,1037,1510,1315,2411,1511,2412,2413,2414, 176, 703, 497, 624, + 593, 921, 302,2415, 341, 165,1103,1512,2416,1513,2417,2418,2419, 376,2420, 700, +2421,2422,2423, 258, 768,1316,2424,1183,2425, 995, 608,2426,2427,2428,2429, 221, +2430,2431,2432,2433,2434,2435,2436,2437, 195, 323, 726, 188, 897, 983,1317, 377, + 644,1050, 879,2438, 452,2439,2440,2441,2442,2443,2444, 914,2445,2446,2447,2448, + 915, 489,2449,1514,1184,2450,2451, 515, 64, 427, 495,2452, 583,2453, 483, 485, +1038, 562, 213,1515, 748, 666,2454,2455,2456,2457, 334,2458, 780, 996,1008, 705, +1243,2459,2460,2461,2462,2463, 114,2464, 493,1146, 366, 163,1516, 961,1104,2465, + 291,2466,1318,1105,2467,1517, 365,2468, 355, 951,1244,2469,1319,2470, 631,2471, +2472, 218,1320, 364, 320, 756,1518,1519,1321,1520,1322,2473,2474,2475,2476, 997, +2477,2478,2479,2480, 665,1185,2481, 916,1521,2482,2483,2484, 584, 684,2485,2486, + 797,2487,1051,1186,2488,2489,2490,1522,2491,2492, 370,2493,1039,1187, 65,2494, + 434, 205, 463,1188,2495, 125, 812, 391, 402, 826, 699, 286, 398, 155, 781, 771, + 585,2496, 590, 505,1073,2497, 599, 244, 219, 917,1018, 952, 646,1523,2498,1323, +2499,2500, 49, 984, 354, 741,2501, 625,2502,1324,2503,1019, 190, 357, 757, 491, + 95, 782, 868,2504,2505,2506,2507,2508,2509, 134,1524,1074, 422,1525, 898,2510, + 161,2511,2512,2513,2514, 769,2515,1526,2516,2517, 411,1325,2518, 472,1527,2519, +2520,2521,2522,2523,2524, 985,2525,2526,2527,2528,2529,2530, 764,2531,1245,2532, +2533, 25, 204, 311,2534, 496,2535,1052,2536,2537,2538,2539,2540,2541,2542, 199, + 704, 504, 468, 758, 657,1528, 196, 44, 839,1246, 272, 750,2543, 765, 862,2544, +2545,1326,2546, 132, 615, 933,2547, 732,2548,2549,2550,1189,1529,2551, 283,1247, +1053, 607, 929,2552,2553,2554, 930, 183, 872, 616,1040,1147,2555,1148,1020, 441, + 249,1075,2556,2557,2558, 466, 743,2559,2560,2561, 92, 514, 426, 420, 526,2562, +2563,2564,2565,2566,2567,2568, 185,2569,2570,2571,2572, 776,1530, 658,2573, 362, +2574, 361, 922,1076, 793,2575,2576,2577,2578,2579,2580,1531, 251,2581,2582,2583, +2584,1532, 54, 612, 237,1327,2585,2586, 275, 408, 647, 111,2587,1533,1106, 465, + 3, 458, 9, 38,2588, 107, 110, 890, 209, 26, 737, 498,2589,1534,2590, 431, + 202, 88,1535, 356, 287,1107, 660,1149,2591, 381,1536, 986,1150, 445,1248,1151, + 974,2592,2593, 846,2594, 446, 953, 184,1249,1250, 727,2595, 923, 193, 883,2596, +2597,2598, 102, 324, 539, 817,2599, 421,1041,2600, 832,2601, 94, 175, 197, 406, +2602, 459,2603,2604,2605,2606,2607, 330, 555,2608,2609,2610, 706,1108, 389,2611, +2612,2613,2614, 233,2615, 833, 558, 931, 954,1251,2616,2617,1537, 546,2618,2619, +1009,2620,2621,2622,1538, 690,1328,2623, 955,2624,1539,2625,2626, 772,2627,2628, +2629,2630,2631, 924, 648, 863, 603,2632,2633, 934,1540, 864, 865,2634, 642,1042, + 670,1190,2635,2636,2637,2638, 168,2639, 652, 873, 542,1054,1541,2640,2641,2642, # 512, 256 +#Everything below is of no interest for detection purpose +2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,2654,2655,2656,2657,2658, +2659,2660,2661,2662,2663,2664,2665,2666,2667,2668,2669,2670,2671,2672,2673,2674, +2675,2676,2677,2678,2679,2680,2681,2682,2683,2684,2685,2686,2687,2688,2689,2690, +2691,2692,2693,2694,2695,2696,2697,2698,2699,1542, 880,2700,2701,2702,2703,2704, +2705,2706,2707,2708,2709,2710,2711,2712,2713,2714,2715,2716,2717,2718,2719,2720, +2721,2722,2723,2724,2725,1543,2726,2727,2728,2729,2730,2731,2732,1544,2733,2734, +2735,2736,2737,2738,2739,2740,2741,2742,2743,2744,2745,2746,2747,2748,2749,2750, +2751,2752,2753,2754,1545,2755,2756,2757,2758,2759,2760,2761,2762,2763,2764,2765, +2766,1546,2767,1547,2768,2769,2770,2771,2772,2773,2774,2775,2776,2777,2778,2779, +2780,2781,2782,2783,2784,2785,2786,1548,2787,2788,2789,1109,2790,2791,2792,2793, +2794,2795,2796,2797,2798,2799,2800,2801,2802,2803,2804,2805,2806,2807,2808,2809, +2810,2811,2812,1329,2813,2814,2815,2816,2817,2818,2819,2820,2821,2822,2823,2824, +2825,2826,2827,2828,2829,2830,2831,2832,2833,2834,2835,2836,2837,2838,2839,2840, +2841,2842,2843,2844,2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856, +1549,2857,2858,2859,2860,1550,2861,2862,1551,2863,2864,2865,2866,2867,2868,2869, +2870,2871,2872,2873,2874,1110,1330,2875,2876,2877,2878,2879,2880,2881,2882,2883, +2884,2885,2886,2887,2888,2889,2890,2891,2892,2893,2894,2895,2896,2897,2898,2899, +2900,2901,2902,2903,2904,2905,2906,2907,2908,2909,2910,2911,2912,2913,2914,2915, +2916,2917,2918,2919,2920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2930,1331, +2931,2932,2933,2934,2935,2936,2937,2938,2939,2940,2941,2942,2943,1552,2944,2945, +2946,2947,2948,2949,2950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961, +2962,2963,2964,1252,2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2976, +2977,2978,2979,2980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992, +2993,2994,2995,2996,2997,2998,2999,3000,3001,3002,3003,3004,3005,3006,3007,3008, +3009,3010,3011,3012,1553,3013,3014,3015,3016,3017,1554,3018,1332,3019,3020,3021, +3022,3023,3024,3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037, +3038,3039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,1555,3051,3052, +3053,1556,1557,3054,3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066, +3067,1558,3068,3069,3070,3071,3072,3073,3074,3075,3076,1559,3077,3078,3079,3080, +3081,3082,3083,1253,3084,3085,3086,3087,3088,3089,3090,3091,3092,3093,3094,3095, +3096,3097,3098,3099,3100,3101,3102,3103,3104,3105,3106,3107,3108,1152,3109,3110, +3111,3112,3113,1560,3114,3115,3116,3117,1111,3118,3119,3120,3121,3122,3123,3124, +3125,3126,3127,3128,3129,3130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140, +3141,3142,3143,3144,3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156, +3157,3158,3159,3160,3161,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172, +3173,3174,3175,3176,1333,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187, +3188,3189,1561,3190,3191,1334,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201, +3202,3203,3204,3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217, +3218,3219,3220,3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233, +3234,1562,3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248, +3249,3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264, +3265,3266,3267,3268,3269,3270,3271,3272,3273,3274,3275,3276,3277,1563,3278,3279, +3280,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,3295, +3296,3297,3298,3299,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309,3310,3311, +3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,3325,3326,3327, +3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,3340,3341,3342,3343, +3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,3359, +3360,3361,3362,3363,3364,1335,3365,3366,3367,3368,3369,3370,3371,3372,3373,3374, +3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387,1336,3388,3389, +3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,3400,3401,3402,3403,3404,3405, +3406,3407,3408,3409,3410,3411,3412,3413,3414,1337,3415,3416,3417,3418,3419,1338, +3420,3421,3422,1564,1565,3423,3424,3425,3426,3427,3428,3429,3430,3431,1254,3432, +3433,3434,1339,3435,3436,3437,3438,3439,1566,3440,3441,3442,3443,3444,3445,3446, +3447,3448,3449,3450,3451,3452,3453,3454,1255,3455,3456,3457,3458,3459,1567,1191, +3460,1568,1569,3461,3462,3463,1570,3464,3465,3466,3467,3468,1571,3469,3470,3471, +3472,3473,1572,3474,3475,3476,3477,3478,3479,3480,3481,3482,3483,3484,3485,3486, +1340,3487,3488,3489,3490,3491,3492,1021,3493,3494,3495,3496,3497,3498,1573,3499, +1341,3500,3501,3502,3503,3504,3505,3506,3507,3508,3509,3510,3511,1342,3512,3513, +3514,3515,3516,1574,1343,3517,3518,3519,1575,3520,1576,3521,3522,3523,3524,3525, +3526,3527,3528,3529,3530,3531,3532,3533,3534,3535,3536,3537,3538,3539,3540,3541, +3542,3543,3544,3545,3546,3547,3548,3549,3550,3551,3552,3553,3554,3555,3556,3557, +3558,3559,3560,3561,3562,3563,3564,3565,3566,3567,3568,3569,3570,3571,3572,3573, +3574,3575,3576,3577,3578,3579,3580,1577,3581,3582,1578,3583,3584,3585,3586,3587, +3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603, +3604,1579,3605,3606,3607,3608,3609,3610,3611,3612,3613,3614,3615,3616,3617,3618, +3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,3629,1580,3630,3631,1581,3632, +3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,3643,3644,3645,3646,3647,3648, +3649,3650,3651,3652,3653,3654,3655,3656,1582,3657,3658,3659,3660,3661,3662,3663, +3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3674,3675,3676,3677,3678,3679, +3680,3681,3682,3683,3684,3685,3686,3687,3688,3689,3690,3691,3692,3693,3694,3695, +3696,3697,3698,3699,3700,1192,3701,3702,3703,3704,1256,3705,3706,3707,3708,1583, +1257,3709,3710,3711,3712,3713,3714,3715,3716,1584,3717,3718,3719,3720,3721,3722, +3723,3724,3725,3726,3727,3728,3729,3730,3731,3732,3733,3734,3735,3736,3737,3738, +3739,3740,3741,3742,3743,3744,3745,1344,3746,3747,3748,3749,3750,3751,3752,3753, +3754,3755,3756,1585,3757,3758,3759,3760,3761,3762,3763,3764,3765,3766,1586,3767, +3768,3769,3770,3771,3772,3773,3774,3775,3776,3777,3778,1345,3779,3780,3781,3782, +3783,3784,3785,3786,3787,3788,3789,3790,3791,3792,3793,3794,3795,1346,1587,3796, +3797,1588,3798,3799,3800,3801,3802,3803,3804,3805,3806,1347,3807,3808,3809,3810, +3811,1589,3812,3813,3814,3815,3816,3817,3818,3819,3820,3821,1590,3822,3823,1591, +1348,3824,3825,3826,3827,3828,3829,3830,1592,3831,3832,1593,3833,3834,3835,3836, +3837,3838,3839,3840,3841,3842,3843,3844,1349,3845,3846,3847,3848,3849,3850,3851, +3852,3853,3854,3855,3856,3857,3858,1594,3859,3860,3861,3862,3863,3864,3865,3866, +3867,3868,3869,1595,3870,3871,3872,3873,1596,3874,3875,3876,3877,3878,3879,3880, +3881,3882,3883,3884,3885,3886,1597,3887,3888,3889,3890,3891,3892,3893,3894,3895, +1598,3896,3897,3898,1599,1600,3899,1350,3900,1351,3901,3902,1352,3903,3904,3905, +3906,3907,3908,3909,3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921, +3922,3923,3924,1258,3925,3926,3927,3928,3929,3930,3931,1193,3932,1601,3933,3934, +3935,3936,3937,3938,3939,3940,3941,3942,3943,1602,3944,3945,3946,3947,3948,1603, +3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964, +3965,1604,3966,3967,3968,3969,3970,3971,3972,3973,3974,3975,3976,3977,1353,3978, +3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990,3991,1354,3992,3993, +3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009, +4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,1355,4024, +4025,4026,4027,4028,4029,4030,4031,4032,4033,4034,4035,4036,4037,4038,4039,4040, +1605,4041,4042,4043,4044,4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055, +4056,4057,4058,4059,4060,1606,4061,4062,4063,4064,1607,4065,4066,4067,4068,4069, +4070,4071,4072,4073,4074,4075,4076,1194,4077,4078,1608,4079,4080,4081,4082,4083, +4084,4085,4086,4087,1609,4088,4089,4090,4091,4092,4093,4094,4095,4096,4097,4098, +4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,1259,4109,4110,4111,4112,4113, +4114,4115,4116,4117,4118,4119,4120,4121,4122,4123,4124,1195,4125,4126,4127,1610, +4128,4129,4130,4131,4132,4133,4134,4135,4136,4137,1356,4138,4139,4140,4141,4142, +4143,4144,1611,4145,4146,4147,4148,4149,4150,4151,4152,4153,4154,4155,4156,4157, +4158,4159,4160,4161,4162,4163,4164,4165,4166,4167,4168,4169,4170,4171,4172,4173, +4174,4175,4176,4177,4178,4179,4180,4181,4182,4183,4184,4185,4186,4187,4188,4189, +4190,4191,4192,4193,4194,4195,4196,4197,4198,4199,4200,4201,4202,4203,4204,4205, +4206,4207,4208,4209,4210,4211,4212,4213,4214,4215,4216,4217,4218,4219,1612,4220, +4221,4222,4223,4224,4225,4226,4227,1357,4228,1613,4229,4230,4231,4232,4233,4234, +4235,4236,4237,4238,4239,4240,4241,4242,4243,1614,4244,4245,4246,4247,4248,4249, +4250,4251,4252,4253,4254,4255,4256,4257,4258,4259,4260,4261,4262,4263,4264,4265, +4266,4267,4268,4269,4270,1196,1358,4271,4272,4273,4274,4275,4276,4277,4278,4279, +4280,4281,4282,4283,4284,4285,4286,4287,1615,4288,4289,4290,4291,4292,4293,4294, +4295,4296,4297,4298,4299,4300,4301,4302,4303,4304,4305,4306,4307,4308,4309,4310, +4311,4312,4313,4314,4315,4316,4317,4318,4319,4320,4321,4322,4323,4324,4325,4326, +4327,4328,4329,4330,4331,4332,4333,4334,1616,4335,4336,4337,4338,4339,4340,4341, +4342,4343,4344,4345,4346,4347,4348,4349,4350,4351,4352,4353,4354,4355,4356,4357, +4358,4359,4360,1617,4361,4362,4363,4364,4365,1618,4366,4367,4368,4369,4370,4371, +4372,4373,4374,4375,4376,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387, +4388,4389,4390,4391,4392,4393,4394,4395,4396,4397,4398,4399,4400,4401,4402,4403, +4404,4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,1619,4417,4418, +4419,4420,4421,4422,4423,4424,4425,1112,4426,4427,4428,4429,4430,1620,4431,4432, +4433,4434,4435,4436,4437,4438,4439,4440,4441,4442,1260,1261,4443,4444,4445,4446, +4447,4448,4449,4450,4451,4452,4453,4454,4455,1359,4456,4457,4458,4459,4460,4461, +4462,4463,4464,4465,1621,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476, +4477,4478,4479,4480,4481,4482,4483,4484,4485,4486,4487,4488,4489,1055,4490,4491, +4492,4493,4494,4495,4496,4497,4498,4499,4500,4501,4502,4503,4504,4505,4506,4507, +4508,4509,4510,4511,4512,4513,4514,4515,4516,4517,4518,1622,4519,4520,4521,1623, +4522,4523,4524,4525,4526,4527,4528,4529,4530,4531,4532,4533,4534,4535,1360,4536, +4537,4538,4539,4540,4541,4542,4543, 975,4544,4545,4546,4547,4548,4549,4550,4551, +4552,4553,4554,4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,4567, +4568,4569,4570,4571,1624,4572,4573,4574,4575,4576,1625,4577,4578,4579,4580,4581, +4582,4583,4584,1626,4585,4586,4587,4588,4589,4590,4591,4592,4593,4594,4595,1627, +4596,4597,4598,4599,4600,4601,4602,4603,4604,4605,4606,4607,4608,4609,4610,4611, +4612,4613,4614,4615,1628,4616,4617,4618,4619,4620,4621,4622,4623,4624,4625,4626, +4627,4628,4629,4630,4631,4632,4633,4634,4635,4636,4637,4638,4639,4640,4641,4642, +4643,4644,4645,4646,4647,4648,4649,1361,4650,4651,4652,4653,4654,4655,4656,4657, +4658,4659,4660,4661,1362,4662,4663,4664,4665,4666,4667,4668,4669,4670,4671,4672, +4673,4674,4675,4676,4677,4678,4679,4680,4681,4682,1629,4683,4684,4685,4686,4687, +1630,4688,4689,4690,4691,1153,4692,4693,4694,1113,4695,4696,4697,4698,4699,4700, +4701,4702,4703,4704,4705,4706,4707,4708,4709,4710,4711,1197,4712,4713,4714,4715, +4716,4717,4718,4719,4720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731, +4732,4733,4734,4735,1631,4736,1632,4737,4738,4739,4740,4741,4742,4743,4744,1633, +4745,4746,4747,4748,4749,1262,4750,4751,4752,4753,4754,1363,4755,4756,4757,4758, +4759,4760,4761,4762,4763,4764,4765,4766,4767,4768,1634,4769,4770,4771,4772,4773, +4774,4775,4776,4777,4778,1635,4779,4780,4781,4782,4783,4784,4785,4786,4787,4788, +4789,1636,4790,4791,4792,4793,4794,4795,4796,4797,4798,4799,4800,4801,4802,4803, +4804,4805,4806,1637,4807,4808,4809,1638,4810,4811,4812,4813,4814,4815,4816,4817, +4818,1639,4819,4820,4821,4822,4823,4824,4825,4826,4827,4828,4829,4830,4831,4832, +4833,1077,4834,4835,4836,4837,4838,4839,4840,4841,4842,4843,4844,4845,4846,4847, +4848,4849,4850,4851,4852,4853,4854,4855,4856,4857,4858,4859,4860,4861,4862,4863, +4864,4865,4866,4867,4868,4869,4870,4871,4872,4873,4874,4875,4876,4877,4878,4879, +4880,4881,4882,4883,1640,4884,4885,1641,4886,4887,4888,4889,4890,4891,4892,4893, +4894,4895,4896,4897,4898,4899,4900,4901,4902,4903,4904,4905,4906,4907,4908,4909, +4910,4911,1642,4912,4913,4914,1364,4915,4916,4917,4918,4919,4920,4921,4922,4923, +4924,4925,4926,4927,4928,4929,4930,4931,1643,4932,4933,4934,4935,4936,4937,4938, +4939,4940,4941,4942,4943,4944,4945,4946,4947,4948,4949,4950,4951,4952,4953,4954, +4955,4956,4957,4958,4959,4960,4961,4962,4963,4964,4965,4966,4967,4968,4969,4970, +4971,4972,4973,4974,4975,4976,4977,4978,4979,4980,1644,4981,4982,4983,4984,1645, +4985,4986,1646,4987,4988,4989,4990,4991,4992,4993,4994,4995,4996,4997,4998,4999, +5000,5001,5002,5003,5004,5005,1647,5006,1648,5007,5008,5009,5010,5011,5012,1078, +5013,5014,5015,5016,5017,5018,5019,5020,5021,5022,5023,5024,5025,5026,5027,5028, +1365,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039,1649,5040,5041,5042, +5043,5044,5045,1366,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,1650,5056, +5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072, +5073,5074,5075,5076,5077,1651,5078,5079,5080,5081,5082,5083,5084,5085,5086,5087, +5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102,5103, +5104,5105,5106,5107,5108,5109,5110,1652,5111,5112,5113,5114,5115,5116,5117,5118, +1367,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,1653,5130,5131,5132, +5133,5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,5144,5145,5146,5147,5148, +5149,1368,5150,1654,5151,1369,5152,5153,5154,5155,5156,5157,5158,5159,5160,5161, +5162,5163,5164,5165,5166,5167,5168,5169,5170,5171,5172,5173,5174,5175,5176,5177, +5178,1370,5179,5180,5181,5182,5183,5184,5185,5186,5187,5188,5189,5190,5191,5192, +5193,5194,5195,5196,5197,5198,1655,5199,5200,5201,5202,1656,5203,5204,5205,5206, +1371,5207,1372,5208,5209,5210,5211,1373,5212,5213,1374,5214,5215,5216,5217,5218, +5219,5220,5221,5222,5223,5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,5234, +5235,5236,5237,5238,5239,5240,5241,5242,5243,5244,5245,5246,5247,1657,5248,5249, +5250,5251,1658,1263,5252,5253,5254,5255,5256,1375,5257,5258,5259,5260,5261,5262, +5263,5264,5265,5266,5267,5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278, +5279,5280,5281,5282,5283,1659,5284,5285,5286,5287,5288,5289,5290,5291,5292,5293, +5294,5295,5296,5297,5298,5299,5300,1660,5301,5302,5303,5304,5305,5306,5307,5308, +5309,5310,5311,5312,5313,5314,5315,5316,5317,5318,5319,5320,5321,1376,5322,5323, +5324,5325,5326,5327,5328,5329,5330,5331,5332,5333,1198,5334,5335,5336,5337,5338, +5339,5340,5341,5342,5343,1661,5344,5345,5346,5347,5348,5349,5350,5351,5352,5353, +5354,5355,5356,5357,5358,5359,5360,5361,5362,5363,5364,5365,5366,5367,5368,5369, +5370,5371,5372,5373,5374,5375,5376,5377,5378,5379,5380,5381,5382,5383,5384,5385, +5386,5387,5388,5389,5390,5391,5392,5393,5394,5395,5396,5397,5398,1264,5399,5400, +5401,5402,5403,5404,5405,5406,5407,5408,5409,5410,5411,5412,1662,5413,5414,5415, +5416,1663,5417,5418,5419,5420,5421,5422,5423,5424,5425,5426,5427,5428,5429,5430, +5431,5432,5433,5434,5435,5436,5437,5438,1664,5439,5440,5441,5442,5443,5444,5445, +5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456,5457,5458,5459,5460,5461, +5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472,5473,5474,5475,5476,5477, +5478,1154,5479,5480,5481,5482,5483,5484,5485,1665,5486,5487,5488,5489,5490,5491, +5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,5504,5505,5506,5507, +5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,5519,5520,5521,5522,5523, +5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,5534,5535,5536,5537,5538,5539, +5540,5541,5542,5543,5544,5545,5546,5547,5548,1377,5549,5550,5551,5552,5553,5554, +5555,5556,5557,5558,5559,5560,5561,5562,5563,5564,5565,5566,5567,5568,5569,5570, +1114,5571,5572,5573,5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584,5585, +5586,5587,5588,5589,5590,5591,5592,1378,5593,5594,5595,5596,5597,5598,5599,5600, +5601,5602,5603,5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,1379,5615, +5616,5617,5618,5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631, +5632,5633,5634,1380,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646, +5647,5648,5649,1381,1056,5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660, +1666,5661,5662,5663,5664,5665,5666,5667,5668,1667,5669,1668,5670,5671,5672,5673, +5674,5675,5676,5677,5678,1155,5679,5680,5681,5682,5683,5684,5685,5686,5687,5688, +5689,5690,5691,5692,5693,5694,5695,5696,5697,5698,1669,5699,5700,5701,5702,5703, +5704,5705,1670,5706,5707,5708,5709,5710,1671,5711,5712,5713,5714,1382,5715,5716, +5717,5718,5719,5720,5721,5722,5723,5724,5725,1672,5726,5727,1673,1674,5728,5729, +5730,5731,5732,5733,5734,5735,5736,1675,5737,5738,5739,5740,5741,5742,5743,5744, +1676,5745,5746,5747,5748,5749,5750,5751,1383,5752,5753,5754,5755,5756,5757,5758, +5759,5760,5761,5762,5763,5764,5765,5766,5767,5768,1677,5769,5770,5771,5772,5773, +1678,5774,5775,5776, 998,5777,5778,5779,5780,5781,5782,5783,5784,5785,1384,5786, +5787,5788,5789,5790,5791,5792,5793,5794,5795,5796,5797,5798,5799,5800,1679,5801, +5802,5803,1115,1116,5804,5805,5806,5807,5808,5809,5810,5811,5812,5813,5814,5815, +5816,5817,5818,5819,5820,5821,5822,5823,5824,5825,5826,5827,5828,5829,5830,5831, +5832,5833,5834,5835,5836,5837,5838,5839,5840,5841,5842,5843,5844,5845,5846,5847, +5848,5849,5850,5851,5852,5853,5854,5855,1680,5856,5857,5858,5859,5860,5861,5862, +5863,5864,1681,5865,5866,5867,1682,5868,5869,5870,5871,5872,5873,5874,5875,5876, +5877,5878,5879,1683,5880,1684,5881,5882,5883,5884,1685,5885,5886,5887,5888,5889, +5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904,5905, +5906,5907,1686,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920, +5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,1687, +5936,5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951, +5952,1688,1689,5953,1199,5954,5955,5956,5957,5958,5959,5960,5961,1690,5962,5963, +5964,5965,5966,5967,5968,5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979, +5980,5981,1385,5982,1386,5983,5984,5985,5986,5987,5988,5989,5990,5991,5992,5993, +5994,5995,5996,5997,5998,5999,6000,6001,6002,6003,6004,6005,6006,6007,6008,6009, +6010,6011,6012,6013,6014,6015,6016,6017,6018,6019,6020,6021,6022,6023,6024,6025, +6026,6027,1265,6028,6029,1691,6030,6031,6032,6033,6034,6035,6036,6037,6038,6039, +6040,6041,6042,6043,6044,6045,6046,6047,6048,6049,6050,6051,6052,6053,6054,6055, +6056,6057,6058,6059,6060,6061,6062,6063,6064,6065,6066,6067,6068,6069,6070,6071, +6072,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084,1692,6085,6086, +6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,6100,6101,6102, +6103,6104,6105,6106,6107,6108,6109,6110,6111,6112,6113,6114,6115,6116,6117,6118, +6119,6120,6121,6122,6123,6124,6125,6126,6127,6128,6129,6130,6131,1693,6132,6133, +6134,6135,6136,1694,6137,6138,6139,6140,6141,1695,6142,6143,6144,6145,6146,6147, +6148,6149,6150,6151,6152,6153,6154,6155,6156,6157,6158,6159,6160,6161,6162,6163, +6164,6165,6166,6167,6168,6169,6170,6171,6172,6173,6174,6175,6176,6177,6178,6179, +6180,6181,6182,6183,6184,6185,1696,6186,6187,6188,6189,6190,6191,6192,6193,6194, +6195,6196,6197,6198,6199,6200,6201,6202,6203,6204,6205,6206,6207,6208,6209,6210, +6211,6212,6213,6214,6215,6216,6217,6218,6219,1697,6220,6221,6222,6223,6224,6225, +6226,6227,6228,6229,6230,6231,6232,6233,6234,6235,6236,6237,6238,6239,6240,6241, +6242,6243,6244,6245,6246,6247,6248,6249,6250,6251,6252,6253,1698,6254,6255,6256, +6257,6258,6259,6260,6261,6262,6263,1200,6264,6265,6266,6267,6268,6269,6270,6271, #1024 +6272,6273,6274,6275,6276,6277,6278,6279,6280,6281,6282,6283,6284,6285,6286,6287, +6288,6289,6290,6291,6292,6293,6294,6295,6296,6297,6298,6299,6300,6301,6302,1699, +6303,6304,1700,6305,6306,6307,6308,6309,6310,6311,6312,6313,6314,6315,6316,6317, +6318,6319,6320,6321,6322,6323,6324,6325,6326,6327,6328,6329,6330,6331,6332,6333, +6334,6335,6336,6337,6338,6339,1701,6340,6341,6342,6343,6344,1387,6345,6346,6347, +6348,6349,6350,6351,6352,6353,6354,6355,6356,6357,6358,6359,6360,6361,6362,6363, +6364,6365,6366,6367,6368,6369,6370,6371,6372,6373,6374,6375,6376,6377,6378,6379, +6380,6381,6382,6383,6384,6385,6386,6387,6388,6389,6390,6391,6392,6393,6394,6395, +6396,6397,6398,6399,6400,6401,6402,6403,6404,6405,6406,6407,6408,6409,6410,6411, +6412,6413,1702,6414,6415,6416,6417,6418,6419,6420,6421,6422,1703,6423,6424,6425, +6426,6427,6428,6429,6430,6431,6432,6433,6434,6435,6436,6437,6438,1704,6439,6440, +6441,6442,6443,6444,6445,6446,6447,6448,6449,6450,6451,6452,6453,6454,6455,6456, +6457,6458,6459,6460,6461,6462,6463,6464,6465,6466,6467,6468,6469,6470,6471,6472, +6473,6474,6475,6476,6477,6478,6479,6480,6481,6482,6483,6484,6485,6486,6487,6488, +6489,6490,6491,6492,6493,6494,6495,6496,6497,6498,6499,6500,6501,6502,6503,1266, +6504,6505,6506,6507,6508,6509,6510,6511,6512,6513,6514,6515,6516,6517,6518,6519, +6520,6521,6522,6523,6524,6525,6526,6527,6528,6529,6530,6531,6532,6533,6534,6535, +6536,6537,6538,6539,6540,6541,6542,6543,6544,6545,6546,6547,6548,6549,6550,6551, +1705,1706,6552,6553,6554,6555,6556,6557,6558,6559,6560,6561,6562,6563,6564,6565, +6566,6567,6568,6569,6570,6571,6572,6573,6574,6575,6576,6577,6578,6579,6580,6581, +6582,6583,6584,6585,6586,6587,6588,6589,6590,6591,6592,6593,6594,6595,6596,6597, +6598,6599,6600,6601,6602,6603,6604,6605,6606,6607,6608,6609,6610,6611,6612,6613, +6614,6615,6616,6617,6618,6619,6620,6621,6622,6623,6624,6625,6626,6627,6628,6629, +6630,6631,6632,6633,6634,6635,6636,6637,1388,6638,6639,6640,6641,6642,6643,6644, +1707,6645,6646,6647,6648,6649,6650,6651,6652,6653,6654,6655,6656,6657,6658,6659, +6660,6661,6662,6663,1708,6664,6665,6666,6667,6668,6669,6670,6671,6672,6673,6674, +1201,6675,6676,6677,6678,6679,6680,6681,6682,6683,6684,6685,6686,6687,6688,6689, +6690,6691,6692,6693,6694,6695,6696,6697,6698,6699,6700,6701,6702,6703,6704,6705, +6706,6707,6708,6709,6710,6711,6712,6713,6714,6715,6716,6717,6718,6719,6720,6721, +6722,6723,6724,6725,1389,6726,6727,6728,6729,6730,6731,6732,6733,6734,6735,6736, +1390,1709,6737,6738,6739,6740,6741,6742,1710,6743,6744,6745,6746,1391,6747,6748, +6749,6750,6751,6752,6753,6754,6755,6756,6757,1392,6758,6759,6760,6761,6762,6763, +6764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,6775,6776,6777,6778,6779, +6780,1202,6781,6782,6783,6784,6785,6786,6787,6788,6789,6790,6791,6792,6793,6794, +6795,6796,6797,6798,6799,6800,6801,6802,6803,6804,6805,6806,6807,6808,6809,1711, +6810,6811,6812,6813,6814,6815,6816,6817,6818,6819,6820,6821,6822,6823,6824,6825, +6826,6827,6828,6829,6830,6831,6832,6833,6834,6835,6836,1393,6837,6838,6839,6840, +6841,6842,6843,6844,6845,6846,6847,6848,6849,6850,6851,6852,6853,6854,6855,6856, +6857,6858,6859,6860,6861,6862,6863,6864,6865,6866,6867,6868,6869,6870,6871,6872, +6873,6874,6875,6876,6877,6878,6879,6880,6881,6882,6883,6884,6885,6886,6887,6888, +6889,6890,6891,6892,6893,6894,6895,6896,6897,6898,6899,6900,6901,6902,1712,6903, +6904,6905,6906,6907,6908,6909,6910,1713,6911,6912,6913,6914,6915,6916,6917,6918, +6919,6920,6921,6922,6923,6924,6925,6926,6927,6928,6929,6930,6931,6932,6933,6934, +6935,6936,6937,6938,6939,6940,6941,6942,6943,6944,6945,6946,6947,6948,6949,6950, +6951,6952,6953,6954,6955,6956,6957,6958,6959,6960,6961,6962,6963,6964,6965,6966, +6967,6968,6969,6970,6971,6972,6973,6974,1714,6975,6976,6977,6978,6979,6980,6981, +6982,6983,6984,6985,6986,6987,6988,1394,6989,6990,6991,6992,6993,6994,6995,6996, +6997,6998,6999,7000,1715,7001,7002,7003,7004,7005,7006,7007,7008,7009,7010,7011, +7012,7013,7014,7015,7016,7017,7018,7019,7020,7021,7022,7023,7024,7025,7026,7027, +7028,1716,7029,7030,7031,7032,7033,7034,7035,7036,7037,7038,7039,7040,7041,7042, +7043,7044,7045,7046,7047,7048,7049,7050,7051,7052,7053,7054,7055,7056,7057,7058, +7059,7060,7061,7062,7063,7064,7065,7066,7067,7068,7069,7070,7071,7072,7073,7074, +7075,7076,7077,7078,7079,7080,7081,7082,7083,7084,7085,7086,7087,7088,7089,7090, +7091,7092,7093,7094,7095,7096,7097,7098,7099,7100,7101,7102,7103,7104,7105,7106, +7107,7108,7109,7110,7111,7112,7113,7114,7115,7116,7117,7118,7119,7120,7121,7122, +7123,7124,7125,7126,7127,7128,7129,7130,7131,7132,7133,7134,7135,7136,7137,7138, +7139,7140,7141,7142,7143,7144,7145,7146,7147,7148,7149,7150,7151,7152,7153,7154, +7155,7156,7157,7158,7159,7160,7161,7162,7163,7164,7165,7166,7167,7168,7169,7170, +7171,7172,7173,7174,7175,7176,7177,7178,7179,7180,7181,7182,7183,7184,7185,7186, +7187,7188,7189,7190,7191,7192,7193,7194,7195,7196,7197,7198,7199,7200,7201,7202, +7203,7204,7205,7206,7207,1395,7208,7209,7210,7211,7212,7213,1717,7214,7215,7216, +7217,7218,7219,7220,7221,7222,7223,7224,7225,7226,7227,7228,7229,7230,7231,7232, +7233,7234,7235,7236,7237,7238,7239,7240,7241,7242,7243,7244,7245,7246,7247,7248, +7249,7250,7251,7252,7253,7254,7255,7256,7257,7258,7259,7260,7261,7262,7263,7264, +7265,7266,7267,7268,7269,7270,7271,7272,7273,7274,7275,7276,7277,7278,7279,7280, +7281,7282,7283,7284,7285,7286,7287,7288,7289,7290,7291,7292,7293,7294,7295,7296, +7297,7298,7299,7300,7301,7302,7303,7304,7305,7306,7307,7308,7309,7310,7311,7312, +7313,1718,7314,7315,7316,7317,7318,7319,7320,7321,7322,7323,7324,7325,7326,7327, +7328,7329,7330,7331,7332,7333,7334,7335,7336,7337,7338,7339,7340,7341,7342,7343, +7344,7345,7346,7347,7348,7349,7350,7351,7352,7353,7354,7355,7356,7357,7358,7359, +7360,7361,7362,7363,7364,7365,7366,7367,7368,7369,7370,7371,7372,7373,7374,7375, +7376,7377,7378,7379,7380,7381,7382,7383,7384,7385,7386,7387,7388,7389,7390,7391, +7392,7393,7394,7395,7396,7397,7398,7399,7400,7401,7402,7403,7404,7405,7406,7407, +7408,7409,7410,7411,7412,7413,7414,7415,7416,7417,7418,7419,7420,7421,7422,7423, +7424,7425,7426,7427,7428,7429,7430,7431,7432,7433,7434,7435,7436,7437,7438,7439, +7440,7441,7442,7443,7444,7445,7446,7447,7448,7449,7450,7451,7452,7453,7454,7455, +7456,7457,7458,7459,7460,7461,7462,7463,7464,7465,7466,7467,7468,7469,7470,7471, +7472,7473,7474,7475,7476,7477,7478,7479,7480,7481,7482,7483,7484,7485,7486,7487, +7488,7489,7490,7491,7492,7493,7494,7495,7496,7497,7498,7499,7500,7501,7502,7503, +7504,7505,7506,7507,7508,7509,7510,7511,7512,7513,7514,7515,7516,7517,7518,7519, +7520,7521,7522,7523,7524,7525,7526,7527,7528,7529,7530,7531,7532,7533,7534,7535, +7536,7537,7538,7539,7540,7541,7542,7543,7544,7545,7546,7547,7548,7549,7550,7551, +7552,7553,7554,7555,7556,7557,7558,7559,7560,7561,7562,7563,7564,7565,7566,7567, +7568,7569,7570,7571,7572,7573,7574,7575,7576,7577,7578,7579,7580,7581,7582,7583, +7584,7585,7586,7587,7588,7589,7590,7591,7592,7593,7594,7595,7596,7597,7598,7599, +7600,7601,7602,7603,7604,7605,7606,7607,7608,7609,7610,7611,7612,7613,7614,7615, +7616,7617,7618,7619,7620,7621,7622,7623,7624,7625,7626,7627,7628,7629,7630,7631, +7632,7633,7634,7635,7636,7637,7638,7639,7640,7641,7642,7643,7644,7645,7646,7647, +7648,7649,7650,7651,7652,7653,7654,7655,7656,7657,7658,7659,7660,7661,7662,7663, +7664,7665,7666,7667,7668,7669,7670,7671,7672,7673,7674,7675,7676,7677,7678,7679, +7680,7681,7682,7683,7684,7685,7686,7687,7688,7689,7690,7691,7692,7693,7694,7695, +7696,7697,7698,7699,7700,7701,7702,7703,7704,7705,7706,7707,7708,7709,7710,7711, +7712,7713,7714,7715,7716,7717,7718,7719,7720,7721,7722,7723,7724,7725,7726,7727, +7728,7729,7730,7731,7732,7733,7734,7735,7736,7737,7738,7739,7740,7741,7742,7743, +7744,7745,7746,7747,7748,7749,7750,7751,7752,7753,7754,7755,7756,7757,7758,7759, +7760,7761,7762,7763,7764,7765,7766,7767,7768,7769,7770,7771,7772,7773,7774,7775, +7776,7777,7778,7779,7780,7781,7782,7783,7784,7785,7786,7787,7788,7789,7790,7791, +7792,7793,7794,7795,7796,7797,7798,7799,7800,7801,7802,7803,7804,7805,7806,7807, +7808,7809,7810,7811,7812,7813,7814,7815,7816,7817,7818,7819,7820,7821,7822,7823, +7824,7825,7826,7827,7828,7829,7830,7831,7832,7833,7834,7835,7836,7837,7838,7839, +7840,7841,7842,7843,7844,7845,7846,7847,7848,7849,7850,7851,7852,7853,7854,7855, +7856,7857,7858,7859,7860,7861,7862,7863,7864,7865,7866,7867,7868,7869,7870,7871, +7872,7873,7874,7875,7876,7877,7878,7879,7880,7881,7882,7883,7884,7885,7886,7887, +7888,7889,7890,7891,7892,7893,7894,7895,7896,7897,7898,7899,7900,7901,7902,7903, +7904,7905,7906,7907,7908,7909,7910,7911,7912,7913,7914,7915,7916,7917,7918,7919, +7920,7921,7922,7923,7924,7925,7926,7927,7928,7929,7930,7931,7932,7933,7934,7935, +7936,7937,7938,7939,7940,7941,7942,7943,7944,7945,7946,7947,7948,7949,7950,7951, +7952,7953,7954,7955,7956,7957,7958,7959,7960,7961,7962,7963,7964,7965,7966,7967, +7968,7969,7970,7971,7972,7973,7974,7975,7976,7977,7978,7979,7980,7981,7982,7983, +7984,7985,7986,7987,7988,7989,7990,7991,7992,7993,7994,7995,7996,7997,7998,7999, +8000,8001,8002,8003,8004,8005,8006,8007,8008,8009,8010,8011,8012,8013,8014,8015, +8016,8017,8018,8019,8020,8021,8022,8023,8024,8025,8026,8027,8028,8029,8030,8031, +8032,8033,8034,8035,8036,8037,8038,8039,8040,8041,8042,8043,8044,8045,8046,8047, +8048,8049,8050,8051,8052,8053,8054,8055,8056,8057,8058,8059,8060,8061,8062,8063, +8064,8065,8066,8067,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079, +8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095, +8096,8097,8098,8099,8100,8101,8102,8103,8104,8105,8106,8107,8108,8109,8110,8111, +8112,8113,8114,8115,8116,8117,8118,8119,8120,8121,8122,8123,8124,8125,8126,8127, +8128,8129,8130,8131,8132,8133,8134,8135,8136,8137,8138,8139,8140,8141,8142,8143, +8144,8145,8146,8147,8148,8149,8150,8151,8152,8153,8154,8155,8156,8157,8158,8159, +8160,8161,8162,8163,8164,8165,8166,8167,8168,8169,8170,8171,8172,8173,8174,8175, +8176,8177,8178,8179,8180,8181,8182,8183,8184,8185,8186,8187,8188,8189,8190,8191, +8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8203,8204,8205,8206,8207, +8208,8209,8210,8211,8212,8213,8214,8215,8216,8217,8218,8219,8220,8221,8222,8223, +8224,8225,8226,8227,8228,8229,8230,8231,8232,8233,8234,8235,8236,8237,8238,8239, +8240,8241,8242,8243,8244,8245,8246,8247,8248,8249,8250,8251,8252,8253,8254,8255, +8256,8257,8258,8259,8260,8261,8262,8263,8264,8265,8266,8267,8268,8269,8270,8271, +8272,8273,8274,8275,8276,8277,8278,8279,8280,8281,8282,8283,8284,8285,8286,8287, +8288,8289,8290,8291,8292,8293,8294,8295,8296,8297,8298,8299,8300,8301,8302,8303, +8304,8305,8306,8307,8308,8309,8310,8311,8312,8313,8314,8315,8316,8317,8318,8319, +8320,8321,8322,8323,8324,8325,8326,8327,8328,8329,8330,8331,8332,8333,8334,8335, +8336,8337,8338,8339,8340,8341,8342,8343,8344,8345,8346,8347,8348,8349,8350,8351, +8352,8353,8354,8355,8356,8357,8358,8359,8360,8361,8362,8363,8364,8365,8366,8367, +8368,8369,8370,8371,8372,8373,8374,8375,8376,8377,8378,8379,8380,8381,8382,8383, +8384,8385,8386,8387,8388,8389,8390,8391,8392,8393,8394,8395,8396,8397,8398,8399, +8400,8401,8402,8403,8404,8405,8406,8407,8408,8409,8410,8411,8412,8413,8414,8415, +8416,8417,8418,8419,8420,8421,8422,8423,8424,8425,8426,8427,8428,8429,8430,8431, +8432,8433,8434,8435,8436,8437,8438,8439,8440,8441,8442,8443,8444,8445,8446,8447, +8448,8449,8450,8451,8452,8453,8454,8455,8456,8457,8458,8459,8460,8461,8462,8463, +8464,8465,8466,8467,8468,8469,8470,8471,8472,8473,8474,8475,8476,8477,8478,8479, +8480,8481,8482,8483,8484,8485,8486,8487,8488,8489,8490,8491,8492,8493,8494,8495, +8496,8497,8498,8499,8500,8501,8502,8503,8504,8505,8506,8507,8508,8509,8510,8511, +8512,8513,8514,8515,8516,8517,8518,8519,8520,8521,8522,8523,8524,8525,8526,8527, +8528,8529,8530,8531,8532,8533,8534,8535,8536,8537,8538,8539,8540,8541,8542,8543, +8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,8556,8557,8558,8559, +8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,8570,8571,8572,8573,8574,8575, +8576,8577,8578,8579,8580,8581,8582,8583,8584,8585,8586,8587,8588,8589,8590,8591, +8592,8593,8594,8595,8596,8597,8598,8599,8600,8601,8602,8603,8604,8605,8606,8607, +8608,8609,8610,8611,8612,8613,8614,8615,8616,8617,8618,8619,8620,8621,8622,8623, +8624,8625,8626,8627,8628,8629,8630,8631,8632,8633,8634,8635,8636,8637,8638,8639, +8640,8641,8642,8643,8644,8645,8646,8647,8648,8649,8650,8651,8652,8653,8654,8655, +8656,8657,8658,8659,8660,8661,8662,8663,8664,8665,8666,8667,8668,8669,8670,8671, +8672,8673,8674,8675,8676,8677,8678,8679,8680,8681,8682,8683,8684,8685,8686,8687, +8688,8689,8690,8691,8692,8693,8694,8695,8696,8697,8698,8699,8700,8701,8702,8703, +8704,8705,8706,8707,8708,8709,8710,8711,8712,8713,8714,8715,8716,8717,8718,8719, +8720,8721,8722,8723,8724,8725,8726,8727,8728,8729,8730,8731,8732,8733,8734,8735, +8736,8737,8738,8739,8740,8741) diff --git a/libs/requests/packages/chardet2/euckrprober.py b/libs/requests/packages/chardet2/euckrprober.py new file mode 100644 index 00000000..c82c4ffd --- /dev/null +++ b/libs/requests/packages/chardet2/euckrprober.py @@ -0,0 +1,41 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCKRDistributionAnalysis +from .mbcssm import EUCKRSMModel + +class EUCKRProber(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(EUCKRSMModel) + self._mDistributionAnalyzer = EUCKRDistributionAnalysis() + self.reset() + + def get_charset_name(self): + return "EUC-KR" diff --git a/libs/requests/packages/chardet2/euctwfreq.py b/libs/requests/packages/chardet2/euctwfreq.py new file mode 100644 index 00000000..c0572095 --- /dev/null +++ b/libs/requests/packages/chardet2/euctwfreq.py @@ -0,0 +1,426 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# EUCTW frequency table +# Converted from big5 work +# by Taiwan's Mandarin Promotion Council +# + +# 128 --> 0.42261 +# 256 --> 0.57851 +# 512 --> 0.74851 +# 1024 --> 0.89384 +# 2048 --> 0.97583 +# +# Idea Distribution Ratio = 0.74851/(1-0.74851) =2.98 +# Random Distribution Ration = 512/(5401-512)=0.105 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR + +EUCTW_TYPICAL_DISTRIBUTION_RATIO = 0.75 + +# Char to FreqOrder table , +EUCTW_TABLE_SIZE = 8102 + +EUCTWCharToFreqOrder = ( \ + 1,1800,1506, 255,1431, 198, 9, 82, 6,7310, 177, 202,3615,1256,2808, 110, # 2742 +3735, 33,3241, 261, 76, 44,2113, 16,2931,2184,1176, 659,3868, 26,3404,2643, # 2758 +1198,3869,3313,4060, 410,2211, 302, 590, 361,1963, 8, 204, 58,4296,7311,1931, # 2774 + 63,7312,7313, 317,1614, 75, 222, 159,4061,2412,1480,7314,3500,3068, 224,2809, # 2790 +3616, 3, 10,3870,1471, 29,2774,1135,2852,1939, 873, 130,3242,1123, 312,7315, # 2806 +4297,2051, 507, 252, 682,7316, 142,1914, 124, 206,2932, 34,3501,3173, 64, 604, # 2822 +7317,2494,1976,1977, 155,1990, 645, 641,1606,7318,3405, 337, 72, 406,7319, 80, # 2838 + 630, 238,3174,1509, 263, 939,1092,2644, 756,1440,1094,3406, 449, 69,2969, 591, # 2854 + 179,2095, 471, 115,2034,1843, 60, 50,2970, 134, 806,1868, 734,2035,3407, 180, # 2870 + 995,1607, 156, 537,2893, 688,7320, 319,1305, 779,2144, 514,2374, 298,4298, 359, # 2886 +2495, 90,2707,1338, 663, 11, 906,1099,2545, 20,2436, 182, 532,1716,7321, 732, # 2902 +1376,4062,1311,1420,3175, 25,2312,1056, 113, 399, 382,1949, 242,3408,2467, 529, # 2918 +3243, 475,1447,3617,7322, 117, 21, 656, 810,1297,2295,2329,3502,7323, 126,4063, # 2934 + 706, 456, 150, 613,4299, 71,1118,2036,4064, 145,3069, 85, 835, 486,2114,1246, # 2950 +1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,7324,2127,2354, 347,3736, 221, # 2966 +3503,3110,7325,1955,1153,4065, 83, 296,1199,3070, 192, 624, 93,7326, 822,1897, # 2982 +2810,3111, 795,2064, 991,1554,1542,1592, 27, 43,2853, 859, 139,1456, 860,4300, # 2998 + 437, 712,3871, 164,2392,3112, 695, 211,3017,2096, 195,3872,1608,3504,3505,3618, # 3014 +3873, 234, 811,2971,2097,3874,2229,1441,3506,1615,2375, 668,2076,1638, 305, 228, # 3030 +1664,4301, 467, 415,7327, 262,2098,1593, 239, 108, 300, 200,1033, 512,1247,2077, # 3046 +7328,7329,2173,3176,3619,2673, 593, 845,1062,3244, 88,1723,2037,3875,1950, 212, # 3062 + 266, 152, 149, 468,1898,4066,4302, 77, 187,7330,3018, 37, 5,2972,7331,3876, # 3078 +7332,7333, 39,2517,4303,2894,3177,2078, 55, 148, 74,4304, 545, 483,1474,1029, # 3094 +1665, 217,1869,1531,3113,1104,2645,4067, 24, 172,3507, 900,3877,3508,3509,4305, # 3110 + 32,1408,2811,1312, 329, 487,2355,2247,2708, 784,2674, 4,3019,3314,1427,1788, # 3126 + 188, 109, 499,7334,3620,1717,1789, 888,1217,3020,4306,7335,3510,7336,3315,1520, # 3142 +3621,3878, 196,1034, 775,7337,7338, 929,1815, 249, 439, 38,7339,1063,7340, 794, # 3158 +3879,1435,2296, 46, 178,3245,2065,7341,2376,7342, 214,1709,4307, 804, 35, 707, # 3174 + 324,3622,1601,2546, 140, 459,4068,7343,7344,1365, 839, 272, 978,2257,2572,3409, # 3190 +2128,1363,3623,1423, 697, 100,3071, 48, 70,1231, 495,3114,2193,7345,1294,7346, # 3206 +2079, 462, 586,1042,3246, 853, 256, 988, 185,2377,3410,1698, 434,1084,7347,3411, # 3222 + 314,2615,2775,4308,2330,2331, 569,2280, 637,1816,2518, 757,1162,1878,1616,3412, # 3238 + 287,1577,2115, 768,4309,1671,2854,3511,2519,1321,3737, 909,2413,7348,4069, 933, # 3254 +3738,7349,2052,2356,1222,4310, 765,2414,1322, 786,4311,7350,1919,1462,1677,2895, # 3270 +1699,7351,4312,1424,2437,3115,3624,2590,3316,1774,1940,3413,3880,4070, 309,1369, # 3286 +1130,2812, 364,2230,1653,1299,3881,3512,3882,3883,2646, 525,1085,3021, 902,2000, # 3302 +1475, 964,4313, 421,1844,1415,1057,2281, 940,1364,3116, 376,4314,4315,1381, 7, # 3318 +2520, 983,2378, 336,1710,2675,1845, 321,3414, 559,1131,3022,2742,1808,1132,1313, # 3334 + 265,1481,1857,7352, 352,1203,2813,3247, 167,1089, 420,2814, 776, 792,1724,3513, # 3350 +4071,2438,3248,7353,4072,7354, 446, 229, 333,2743, 901,3739,1200,1557,4316,2647, # 3366 +1920, 395,2744,2676,3740,4073,1835, 125, 916,3178,2616,4317,7355,7356,3741,7357, # 3382 +7358,7359,4318,3117,3625,1133,2547,1757,3415,1510,2313,1409,3514,7360,2145, 438, # 3398 +2591,2896,2379,3317,1068, 958,3023, 461, 311,2855,2677,4074,1915,3179,4075,1978, # 3414 + 383, 750,2745,2617,4076, 274, 539, 385,1278,1442,7361,1154,1964, 384, 561, 210, # 3430 + 98,1295,2548,3515,7362,1711,2415,1482,3416,3884,2897,1257, 129,7363,3742, 642, # 3446 + 523,2776,2777,2648,7364, 141,2231,1333, 68, 176, 441, 876, 907,4077, 603,2592, # 3462 + 710, 171,3417, 404, 549, 18,3118,2393,1410,3626,1666,7365,3516,4319,2898,4320, # 3478 +7366,2973, 368,7367, 146, 366, 99, 871,3627,1543, 748, 807,1586,1185, 22,2258, # 3494 + 379,3743,3180,7368,3181, 505,1941,2618,1991,1382,2314,7369, 380,2357, 218, 702, # 3510 +1817,1248,3418,3024,3517,3318,3249,7370,2974,3628, 930,3250,3744,7371, 59,7372, # 3526 + 585, 601,4078, 497,3419,1112,1314,4321,1801,7373,1223,1472,2174,7374, 749,1836, # 3542 + 690,1899,3745,1772,3885,1476, 429,1043,1790,2232,2116, 917,4079, 447,1086,1629, # 3558 +7375, 556,7376,7377,2020,1654, 844,1090, 105, 550, 966,1758,2815,1008,1782, 686, # 3574 +1095,7378,2282, 793,1602,7379,3518,2593,4322,4080,2933,2297,4323,3746, 980,2496, # 3590 + 544, 353, 527,4324, 908,2678,2899,7380, 381,2619,1942,1348,7381,1341,1252, 560, # 3606 +3072,7382,3420,2856,7383,2053, 973, 886,2080, 143,4325,7384,7385, 157,3886, 496, # 3622 +4081, 57, 840, 540,2038,4326,4327,3421,2117,1445, 970,2259,1748,1965,2081,4082, # 3638 +3119,1234,1775,3251,2816,3629, 773,1206,2129,1066,2039,1326,3887,1738,1725,4083, # 3654 + 279,3120, 51,1544,2594, 423,1578,2130,2066, 173,4328,1879,7386,7387,1583, 264, # 3670 + 610,3630,4329,2439, 280, 154,7388,7389,7390,1739, 338,1282,3073, 693,2857,1411, # 3686 +1074,3747,2440,7391,4330,7392,7393,1240, 952,2394,7394,2900,1538,2679, 685,1483, # 3702 +4084,2468,1436, 953,4085,2054,4331, 671,2395, 79,4086,2441,3252, 608, 567,2680, # 3718 +3422,4087,4088,1691, 393,1261,1791,2396,7395,4332,7396,7397,7398,7399,1383,1672, # 3734 +3748,3182,1464, 522,1119, 661,1150, 216, 675,4333,3888,1432,3519, 609,4334,2681, # 3750 +2397,7400,7401,7402,4089,3025, 0,7403,2469, 315, 231,2442, 301,3319,4335,2380, # 3766 +7404, 233,4090,3631,1818,4336,4337,7405, 96,1776,1315,2082,7406, 257,7407,1809, # 3782 +3632,2709,1139,1819,4091,2021,1124,2163,2778,1777,2649,7408,3074, 363,1655,3183, # 3798 +7409,2975,7410,7411,7412,3889,1567,3890, 718, 103,3184, 849,1443, 341,3320,2934, # 3814 +1484,7413,1712, 127, 67, 339,4092,2398, 679,1412, 821,7414,7415, 834, 738, 351, # 3830 +2976,2146, 846, 235,1497,1880, 418,1992,3749,2710, 186,1100,2147,2746,3520,1545, # 3846 +1355,2935,2858,1377, 583,3891,4093,2573,2977,7416,1298,3633,1078,2549,3634,2358, # 3862 + 78,3750,3751, 267,1289,2099,2001,1594,4094, 348, 369,1274,2194,2175,1837,4338, # 3878 +1820,2817,3635,2747,2283,2002,4339,2936,2748, 144,3321, 882,4340,3892,2749,3423, # 3894 +4341,2901,7417,4095,1726, 320,7418,3893,3026, 788,2978,7419,2818,1773,1327,2859, # 3910 +3894,2819,7420,1306,4342,2003,1700,3752,3521,2359,2650, 787,2022, 506, 824,3636, # 3926 + 534, 323,4343,1044,3322,2023,1900, 946,3424,7421,1778,1500,1678,7422,1881,4344, # 3942 + 165, 243,4345,3637,2521, 123, 683,4096, 764,4346, 36,3895,1792, 589,2902, 816, # 3958 + 626,1667,3027,2233,1639,1555,1622,3753,3896,7423,3897,2860,1370,1228,1932, 891, # 3974 +2083,2903, 304,4097,7424, 292,2979,2711,3522, 691,2100,4098,1115,4347, 118, 662, # 3990 +7425, 611,1156, 854,2381,1316,2861, 2, 386, 515,2904,7426,7427,3253, 868,2234, # 4006 +1486, 855,2651, 785,2212,3028,7428,1040,3185,3523,7429,3121, 448,7430,1525,7431, # 4022 +2164,4348,7432,3754,7433,4099,2820,3524,3122, 503, 818,3898,3123,1568, 814, 676, # 4038 +1444, 306,1749,7434,3755,1416,1030, 197,1428, 805,2821,1501,4349,7435,7436,7437, # 4054 +1993,7438,4350,7439,7440,2195, 13,2779,3638,2980,3124,1229,1916,7441,3756,2131, # 4070 +7442,4100,4351,2399,3525,7443,2213,1511,1727,1120,7444,7445, 646,3757,2443, 307, # 4086 +7446,7447,1595,3186,7448,7449,7450,3639,1113,1356,3899,1465,2522,2523,7451, 519, # 4102 +7452, 128,2132, 92,2284,1979,7453,3900,1512, 342,3125,2196,7454,2780,2214,1980, # 4118 +3323,7455, 290,1656,1317, 789, 827,2360,7456,3758,4352, 562, 581,3901,7457, 401, # 4134 +4353,2248, 94,4354,1399,2781,7458,1463,2024,4355,3187,1943,7459, 828,1105,4101, # 4150 +1262,1394,7460,4102, 605,4356,7461,1783,2862,7462,2822, 819,2101, 578,2197,2937, # 4166 +7463,1502, 436,3254,4103,3255,2823,3902,2905,3425,3426,7464,2712,2315,7465,7466, # 4182 +2332,2067, 23,4357, 193, 826,3759,2102, 699,1630,4104,3075, 390,1793,1064,3526, # 4198 +7467,1579,3076,3077,1400,7468,4105,1838,1640,2863,7469,4358,4359, 137,4106, 598, # 4214 +3078,1966, 780, 104, 974,2938,7470, 278, 899, 253, 402, 572, 504, 493,1339,7471, # 4230 +3903,1275,4360,2574,2550,7472,3640,3029,3079,2249, 565,1334,2713, 863, 41,7473, # 4246 +7474,4361,7475,1657,2333, 19, 463,2750,4107, 606,7476,2981,3256,1087,2084,1323, # 4262 +2652,2982,7477,1631,1623,1750,4108,2682,7478,2864, 791,2714,2653,2334, 232,2416, # 4278 +7479,2983,1498,7480,2654,2620, 755,1366,3641,3257,3126,2025,1609, 119,1917,3427, # 4294 + 862,1026,4109,7481,3904,3760,4362,3905,4363,2260,1951,2470,7482,1125, 817,4110, # 4310 +4111,3906,1513,1766,2040,1487,4112,3030,3258,2824,3761,3127,7483,7484,1507,7485, # 4326 +2683, 733, 40,1632,1106,2865, 345,4113, 841,2524, 230,4364,2984,1846,3259,3428, # 4342 +7486,1263, 986,3429,7487, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562,3907, # 4358 +3908,2939, 967,2751,2655,1349, 592,2133,1692,3324,2985,1994,4114,1679,3909,1901, # 4374 +2185,7488, 739,3642,2715,1296,1290,7489,4115,2198,2199,1921,1563,2595,2551,1870, # 4390 +2752,2986,7490, 435,7491, 343,1108, 596, 17,1751,4365,2235,3430,3643,7492,4366, # 4406 + 294,3527,2940,1693, 477, 979, 281,2041,3528, 643,2042,3644,2621,2782,2261,1031, # 4422 +2335,2134,2298,3529,4367, 367,1249,2552,7493,3530,7494,4368,1283,3325,2004, 240, # 4438 +1762,3326,4369,4370, 836,1069,3128, 474,7495,2148,2525, 268,3531,7496,3188,1521, # 4454 +1284,7497,1658,1546,4116,7498,3532,3533,7499,4117,3327,2684,1685,4118, 961,1673, # 4470 +2622, 190,2005,2200,3762,4371,4372,7500, 570,2497,3645,1490,7501,4373,2623,3260, # 4486 +1956,4374, 584,1514, 396,1045,1944,7502,4375,1967,2444,7503,7504,4376,3910, 619, # 4502 +7505,3129,3261, 215,2006,2783,2553,3189,4377,3190,4378, 763,4119,3763,4379,7506, # 4518 +7507,1957,1767,2941,3328,3646,1174, 452,1477,4380,3329,3130,7508,2825,1253,2382, # 4534 +2186,1091,2285,4120, 492,7509, 638,1169,1824,2135,1752,3911, 648, 926,1021,1324, # 4550 +4381, 520,4382, 997, 847,1007, 892,4383,3764,2262,1871,3647,7510,2400,1784,4384, # 4566 +1952,2942,3080,3191,1728,4121,2043,3648,4385,2007,1701,3131,1551, 30,2263,4122, # 4582 +7511,2026,4386,3534,7512, 501,7513,4123, 594,3431,2165,1821,3535,3432,3536,3192, # 4598 + 829,2826,4124,7514,1680,3132,1225,4125,7515,3262,4387,4126,3133,2336,7516,4388, # 4614 +4127,7517,3912,3913,7518,1847,2383,2596,3330,7519,4389, 374,3914, 652,4128,4129, # 4630 + 375,1140, 798,7520,7521,7522,2361,4390,2264, 546,1659, 138,3031,2445,4391,7523, # 4646 +2250, 612,1848, 910, 796,3765,1740,1371, 825,3766,3767,7524,2906,2554,7525, 692, # 4662 + 444,3032,2624, 801,4392,4130,7526,1491, 244,1053,3033,4131,4132, 340,7527,3915, # 4678 +1041,2987, 293,1168, 87,1357,7528,1539, 959,7529,2236, 721, 694,4133,3768, 219, # 4694 +1478, 644,1417,3331,2656,1413,1401,1335,1389,3916,7530,7531,2988,2362,3134,1825, # 4710 + 730,1515, 184,2827, 66,4393,7532,1660,2943, 246,3332, 378,1457, 226,3433, 975, # 4726 +3917,2944,1264,3537, 674, 696,7533, 163,7534,1141,2417,2166, 713,3538,3333,4394, # 4742 +3918,7535,7536,1186, 15,7537,1079,1070,7538,1522,3193,3539, 276,1050,2716, 758, # 4758 +1126, 653,2945,3263,7539,2337, 889,3540,3919,3081,2989, 903,1250,4395,3920,3434, # 4774 +3541,1342,1681,1718, 766,3264, 286, 89,2946,3649,7540,1713,7541,2597,3334,2990, # 4790 +7542,2947,2215,3194,2866,7543,4396,2498,2526, 181, 387,1075,3921, 731,2187,3335, # 4806 +7544,3265, 310, 313,3435,2299, 770,4134, 54,3034, 189,4397,3082,3769,3922,7545, # 4822 +1230,1617,1849, 355,3542,4135,4398,3336, 111,4136,3650,1350,3135,3436,3035,4137, # 4838 +2149,3266,3543,7546,2784,3923,3924,2991, 722,2008,7547,1071, 247,1207,2338,2471, # 4854 +1378,4399,2009, 864,1437,1214,4400, 373,3770,1142,2216, 667,4401, 442,2753,2555, # 4870 +3771,3925,1968,4138,3267,1839, 837, 170,1107, 934,1336,1882,7548,7549,2118,4139, # 4886 +2828, 743,1569,7550,4402,4140, 582,2384,1418,3437,7551,1802,7552, 357,1395,1729, # 4902 +3651,3268,2418,1564,2237,7553,3083,3772,1633,4403,1114,2085,4141,1532,7554, 482, # 4918 +2446,4404,7555,7556,1492, 833,1466,7557,2717,3544,1641,2829,7558,1526,1272,3652, # 4934 +4142,1686,1794, 416,2556,1902,1953,1803,7559,3773,2785,3774,1159,2316,7560,2867, # 4950 +4405,1610,1584,3036,2419,2754, 443,3269,1163,3136,7561,7562,3926,7563,4143,2499, # 4966 +3037,4406,3927,3137,2103,1647,3545,2010,1872,4144,7564,4145, 431,3438,7565, 250, # 4982 + 97, 81,4146,7566,1648,1850,1558, 160, 848,7567, 866, 740,1694,7568,2201,2830, # 4998 +3195,4147,4407,3653,1687, 950,2472, 426, 469,3196,3654,3655,3928,7569,7570,1188, # 5014 + 424,1995, 861,3546,4148,3775,2202,2685, 168,1235,3547,4149,7571,2086,1674,4408, # 5030 +3337,3270, 220,2557,1009,7572,3776, 670,2992, 332,1208, 717,7573,7574,3548,2447, # 5046 +3929,3338,7575, 513,7576,1209,2868,3339,3138,4409,1080,7577,7578,7579,7580,2527, # 5062 +3656,3549, 815,1587,3930,3931,7581,3550,3439,3777,1254,4410,1328,3038,1390,3932, # 5078 +1741,3933,3778,3934,7582, 236,3779,2448,3271,7583,7584,3657,3780,1273,3781,4411, # 5094 +7585, 308,7586,4412, 245,4413,1851,2473,1307,2575, 430, 715,2136,2449,7587, 270, # 5110 + 199,2869,3935,7588,3551,2718,1753, 761,1754, 725,1661,1840,4414,3440,3658,7589, # 5126 +7590, 587, 14,3272, 227,2598, 326, 480,2265, 943,2755,3552, 291, 650,1883,7591, # 5142 +1702,1226, 102,1547, 62,3441, 904,4415,3442,1164,4150,7592,7593,1224,1548,2756, # 5158 + 391, 498,1493,7594,1386,1419,7595,2055,1177,4416, 813, 880,1081,2363, 566,1145, # 5174 +4417,2286,1001,1035,2558,2599,2238, 394,1286,7596,7597,2068,7598, 86,1494,1730, # 5190 +3936, 491,1588, 745, 897,2948, 843,3340,3937,2757,2870,3273,1768, 998,2217,2069, # 5206 + 397,1826,1195,1969,3659,2993,3341, 284,7599,3782,2500,2137,2119,1903,7600,3938, # 5222 +2150,3939,4151,1036,3443,1904, 114,2559,4152, 209,1527,7601,7602,2949,2831,2625, # 5238 +2385,2719,3139, 812,2560,7603,3274,7604,1559, 737,1884,3660,1210, 885, 28,2686, # 5254 +3553,3783,7605,4153,1004,1779,4418,7606, 346,1981,2218,2687,4419,3784,1742, 797, # 5270 +1642,3940,1933,1072,1384,2151, 896,3941,3275,3661,3197,2871,3554,7607,2561,1958, # 5286 +4420,2450,1785,7608,7609,7610,3942,4154,1005,1308,3662,4155,2720,4421,4422,1528, # 5302 +2600, 161,1178,4156,1982, 987,4423,1101,4157, 631,3943,1157,3198,2420,1343,1241, # 5318 +1016,2239,2562, 372, 877,2339,2501,1160, 555,1934, 911,3944,7611, 466,1170, 169, # 5334 +1051,2907,2688,3663,2474,2994,1182,2011,2563,1251,2626,7612, 992,2340,3444,1540, # 5350 +2721,1201,2070,2401,1996,2475,7613,4424, 528,1922,2188,1503,1873,1570,2364,3342, # 5366 +3276,7614, 557,1073,7615,1827,3445,2087,2266,3140,3039,3084, 767,3085,2786,4425, # 5382 +1006,4158,4426,2341,1267,2176,3664,3199, 778,3945,3200,2722,1597,2657,7616,4427, # 5398 +7617,3446,7618,7619,7620,3277,2689,1433,3278, 131, 95,1504,3946, 723,4159,3141, # 5414 +1841,3555,2758,2189,3947,2027,2104,3665,7621,2995,3948,1218,7622,3343,3201,3949, # 5430 +4160,2576, 248,1634,3785, 912,7623,2832,3666,3040,3786, 654, 53,7624,2996,7625, # 5446 +1688,4428, 777,3447,1032,3950,1425,7626, 191, 820,2120,2833, 971,4429, 931,3202, # 5462 + 135, 664, 783,3787,1997, 772,2908,1935,3951,3788,4430,2909,3203, 282,2723, 640, # 5478 +1372,3448,1127, 922, 325,3344,7627,7628, 711,2044,7629,7630,3952,2219,2787,1936, # 5494 +3953,3345,2220,2251,3789,2300,7631,4431,3790,1258,3279,3954,3204,2138,2950,3955, # 5510 +3956,7632,2221, 258,3205,4432, 101,1227,7633,3280,1755,7634,1391,3281,7635,2910, # 5526 +2056, 893,7636,7637,7638,1402,4161,2342,7639,7640,3206,3556,7641,7642, 878,1325, # 5542 +1780,2788,4433, 259,1385,2577, 744,1183,2267,4434,7643,3957,2502,7644, 684,1024, # 5558 +4162,7645, 472,3557,3449,1165,3282,3958,3959, 322,2152, 881, 455,1695,1152,1340, # 5574 + 660, 554,2153,4435,1058,4436,4163, 830,1065,3346,3960,4437,1923,7646,1703,1918, # 5590 +7647, 932,2268, 122,7648,4438, 947, 677,7649,3791,2627, 297,1905,1924,2269,4439, # 5606 +2317,3283,7650,7651,4164,7652,4165, 84,4166, 112, 989,7653, 547,1059,3961, 701, # 5622 +3558,1019,7654,4167,7655,3450, 942, 639, 457,2301,2451, 993,2951, 407, 851, 494, # 5638 +4440,3347, 927,7656,1237,7657,2421,3348, 573,4168, 680, 921,2911,1279,1874, 285, # 5654 + 790,1448,1983, 719,2167,7658,7659,4441,3962,3963,1649,7660,1541, 563,7661,1077, # 5670 +7662,3349,3041,3451, 511,2997,3964,3965,3667,3966,1268,2564,3350,3207,4442,4443, # 5686 +7663, 535,1048,1276,1189,2912,2028,3142,1438,1373,2834,2952,1134,2012,7664,4169, # 5702 +1238,2578,3086,1259,7665, 700,7666,2953,3143,3668,4170,7667,4171,1146,1875,1906, # 5718 +4444,2601,3967, 781,2422, 132,1589, 203, 147, 273,2789,2402, 898,1786,2154,3968, # 5734 +3969,7668,3792,2790,7669,7670,4445,4446,7671,3208,7672,1635,3793, 965,7673,1804, # 5750 +2690,1516,3559,1121,1082,1329,3284,3970,1449,3794, 65,1128,2835,2913,2759,1590, # 5766 +3795,7674,7675, 12,2658, 45, 976,2579,3144,4447, 517,2528,1013,1037,3209,7676, # 5782 +3796,2836,7677,3797,7678,3452,7679,2602, 614,1998,2318,3798,3087,2724,2628,7680, # 5798 +2580,4172, 599,1269,7681,1810,3669,7682,2691,3088, 759,1060, 489,1805,3351,3285, # 5814 +1358,7683,7684,2386,1387,1215,2629,2252, 490,7685,7686,4173,1759,2387,2343,7687, # 5830 +4448,3799,1907,3971,2630,1806,3210,4449,3453,3286,2760,2344, 874,7688,7689,3454, # 5846 +3670,1858, 91,2914,3671,3042,3800,4450,7690,3145,3972,2659,7691,3455,1202,1403, # 5862 +3801,2954,2529,1517,2503,4451,3456,2504,7692,4452,7693,2692,1885,1495,1731,3973, # 5878 +2365,4453,7694,2029,7695,7696,3974,2693,1216, 237,2581,4174,2319,3975,3802,4454, # 5894 +4455,2694,3560,3457, 445,4456,7697,7698,7699,7700,2761, 61,3976,3672,1822,3977, # 5910 +7701, 687,2045, 935, 925, 405,2660, 703,1096,1859,2725,4457,3978,1876,1367,2695, # 5926 +3352, 918,2105,1781,2476, 334,3287,1611,1093,4458, 564,3146,3458,3673,3353, 945, # 5942 +2631,2057,4459,7702,1925, 872,4175,7703,3459,2696,3089, 349,4176,3674,3979,4460, # 5958 +3803,4177,3675,2155,3980,4461,4462,4178,4463,2403,2046, 782,3981, 400, 251,4179, # 5974 +1624,7704,7705, 277,3676, 299,1265, 476,1191,3804,2121,4180,4181,1109, 205,7706, # 5990 +2582,1000,2156,3561,1860,7707,7708,7709,4464,7710,4465,2565, 107,2477,2157,3982, # 6006 +3460,3147,7711,1533, 541,1301, 158, 753,4182,2872,3562,7712,1696, 370,1088,4183, # 6022 +4466,3563, 579, 327, 440, 162,2240, 269,1937,1374,3461, 968,3043, 56,1396,3090, # 6038 +2106,3288,3354,7713,1926,2158,4467,2998,7714,3564,7715,7716,3677,4468,2478,7717, # 6054 +2791,7718,1650,4469,7719,2603,7720,7721,3983,2661,3355,1149,3356,3984,3805,3985, # 6070 +7722,1076, 49,7723, 951,3211,3289,3290, 450,2837, 920,7724,1811,2792,2366,4184, # 6086 +1908,1138,2367,3806,3462,7725,3212,4470,1909,1147,1518,2423,4471,3807,7726,4472, # 6102 +2388,2604, 260,1795,3213,7727,7728,3808,3291, 708,7729,3565,1704,7730,3566,1351, # 6118 +1618,3357,2999,1886, 944,4185,3358,4186,3044,3359,4187,7731,3678, 422, 413,1714, # 6134 +3292, 500,2058,2345,4188,2479,7732,1344,1910, 954,7733,1668,7734,7735,3986,2404, # 6150 +4189,3567,3809,4190,7736,2302,1318,2505,3091, 133,3092,2873,4473, 629, 31,2838, # 6166 +2697,3810,4474, 850, 949,4475,3987,2955,1732,2088,4191,1496,1852,7737,3988, 620, # 6182 +3214, 981,1242,3679,3360,1619,3680,1643,3293,2139,2452,1970,1719,3463,2168,7738, # 6198 +3215,7739,7740,3361,1828,7741,1277,4476,1565,2047,7742,1636,3568,3093,7743, 869, # 6214 +2839, 655,3811,3812,3094,3989,3000,3813,1310,3569,4477,7744,7745,7746,1733, 558, # 6230 +4478,3681, 335,1549,3045,1756,4192,3682,1945,3464,1829,1291,1192, 470,2726,2107, # 6246 +2793, 913,1054,3990,7747,1027,7748,3046,3991,4479, 982,2662,3362,3148,3465,3216, # 6262 +3217,1946,2794,7749, 571,4480,7750,1830,7751,3570,2583,1523,2424,7752,2089, 984, # 6278 +4481,3683,1959,7753,3684, 852, 923,2795,3466,3685, 969,1519, 999,2048,2320,1705, # 6294 +7754,3095, 615,1662, 151, 597,3992,2405,2321,1049, 275,4482,3686,4193, 568,3687, # 6310 +3571,2480,4194,3688,7755,2425,2270, 409,3218,7756,1566,2874,3467,1002, 769,2840, # 6326 + 194,2090,3149,3689,2222,3294,4195, 628,1505,7757,7758,1763,2177,3001,3993, 521, # 6342 +1161,2584,1787,2203,2406,4483,3994,1625,4196,4197, 412, 42,3096, 464,7759,2632, # 6358 +4484,3363,1760,1571,2875,3468,2530,1219,2204,3814,2633,2140,2368,4485,4486,3295, # 6374 +1651,3364,3572,7760,7761,3573,2481,3469,7762,3690,7763,7764,2271,2091, 460,7765, # 6390 +4487,7766,3002, 962, 588,3574, 289,3219,2634,1116, 52,7767,3047,1796,7768,7769, # 6406 +7770,1467,7771,1598,1143,3691,4198,1984,1734,1067,4488,1280,3365, 465,4489,1572, # 6422 + 510,7772,1927,2241,1812,1644,3575,7773,4490,3692,7774,7775,2663,1573,1534,7776, # 6438 +7777,4199, 536,1807,1761,3470,3815,3150,2635,7778,7779,7780,4491,3471,2915,1911, # 6454 +2796,7781,3296,1122, 377,3220,7782, 360,7783,7784,4200,1529, 551,7785,2059,3693, # 6470 +1769,2426,7786,2916,4201,3297,3097,2322,2108,2030,4492,1404, 136,1468,1479, 672, # 6486 +1171,3221,2303, 271,3151,7787,2762,7788,2049, 678,2727, 865,1947,4493,7789,2013, # 6502 +3995,2956,7790,2728,2223,1397,3048,3694,4494,4495,1735,2917,3366,3576,7791,3816, # 6518 + 509,2841,2453,2876,3817,7792,7793,3152,3153,4496,4202,2531,4497,2304,1166,1010, # 6534 + 552, 681,1887,7794,7795,2957,2958,3996,1287,1596,1861,3154, 358, 453, 736, 175, # 6550 + 478,1117, 905,1167,1097,7796,1853,1530,7797,1706,7798,2178,3472,2287,3695,3473, # 6566 +3577,4203,2092,4204,7799,3367,1193,2482,4205,1458,2190,2205,1862,1888,1421,3298, # 6582 +2918,3049,2179,3474, 595,2122,7800,3997,7801,7802,4206,1707,2636, 223,3696,1359, # 6598 + 751,3098, 183,3475,7803,2797,3003, 419,2369, 633, 704,3818,2389, 241,7804,7805, # 6614 +7806, 838,3004,3697,2272,2763,2454,3819,1938,2050,3998,1309,3099,2242,1181,7807, # 6630 +1136,2206,3820,2370,1446,4207,2305,4498,7808,7809,4208,1055,2605, 484,3698,7810, # 6646 +3999, 625,4209,2273,3368,1499,4210,4000,7811,4001,4211,3222,2274,2275,3476,7812, # 6662 +7813,2764, 808,2606,3699,3369,4002,4212,3100,2532, 526,3370,3821,4213, 955,7814, # 6678 +1620,4214,2637,2427,7815,1429,3700,1669,1831, 994, 928,7816,3578,1260,7817,7818, # 6694 +7819,1948,2288, 741,2919,1626,4215,2729,2455, 867,1184, 362,3371,1392,7820,7821, # 6710 +4003,4216,1770,1736,3223,2920,4499,4500,1928,2698,1459,1158,7822,3050,3372,2877, # 6726 +1292,1929,2506,2842,3701,1985,1187,2071,2014,2607,4217,7823,2566,2507,2169,3702, # 6742 +2483,3299,7824,3703,4501,7825,7826, 666,1003,3005,1022,3579,4218,7827,4502,1813, # 6758 +2253, 574,3822,1603, 295,1535, 705,3823,4219, 283, 858, 417,7828,7829,3224,4503, # 6774 +4504,3051,1220,1889,1046,2276,2456,4004,1393,1599, 689,2567, 388,4220,7830,2484, # 6790 + 802,7831,2798,3824,2060,1405,2254,7832,4505,3825,2109,1052,1345,3225,1585,7833, # 6806 + 809,7834,7835,7836, 575,2730,3477, 956,1552,1469,1144,2323,7837,2324,1560,2457, # 6822 +3580,3226,4005, 616,2207,3155,2180,2289,7838,1832,7839,3478,4506,7840,1319,3704, # 6838 +3705,1211,3581,1023,3227,1293,2799,7841,7842,7843,3826, 607,2306,3827, 762,2878, # 6854 +1439,4221,1360,7844,1485,3052,7845,4507,1038,4222,1450,2061,2638,4223,1379,4508, # 6870 +2585,7846,7847,4224,1352,1414,2325,2921,1172,7848,7849,3828,3829,7850,1797,1451, # 6886 +7851,7852,7853,7854,2922,4006,4007,2485,2346, 411,4008,4009,3582,3300,3101,4509, # 6902 +1561,2664,1452,4010,1375,7855,7856, 47,2959, 316,7857,1406,1591,2923,3156,7858, # 6918 +1025,2141,3102,3157, 354,2731, 884,2224,4225,2407, 508,3706, 726,3583, 996,2428, # 6934 +3584, 729,7859, 392,2191,1453,4011,4510,3707,7860,7861,2458,3585,2608,1675,2800, # 6950 + 919,2347,2960,2348,1270,4511,4012, 73,7862,7863, 647,7864,3228,2843,2255,1550, # 6966 +1346,3006,7865,1332, 883,3479,7866,7867,7868,7869,3301,2765,7870,1212, 831,1347, # 6982 +4226,4512,2326,3830,1863,3053, 720,3831,4513,4514,3832,7871,4227,7872,7873,4515, # 6998 +7874,7875,1798,4516,3708,2609,4517,3586,1645,2371,7876,7877,2924, 669,2208,2665, # 7014 +2429,7878,2879,7879,7880,1028,3229,7881,4228,2408,7882,2256,1353,7883,7884,4518, # 7030 +3158, 518,7885,4013,7886,4229,1960,7887,2142,4230,7888,7889,3007,2349,2350,3833, # 7046 + 516,1833,1454,4014,2699,4231,4519,2225,2610,1971,1129,3587,7890,2766,7891,2961, # 7062 +1422, 577,1470,3008,1524,3373,7892,7893, 432,4232,3054,3480,7894,2586,1455,2508, # 7078 +2226,1972,1175,7895,1020,2732,4015,3481,4520,7896,2733,7897,1743,1361,3055,3482, # 7094 +2639,4016,4233,4521,2290, 895, 924,4234,2170, 331,2243,3056, 166,1627,3057,1098, # 7110 +7898,1232,2880,2227,3374,4522, 657, 403,1196,2372, 542,3709,3375,1600,4235,3483, # 7126 +7899,4523,2767,3230, 576, 530,1362,7900,4524,2533,2666,3710,4017,7901, 842,3834, # 7142 +7902,2801,2031,1014,4018, 213,2700,3376, 665, 621,4236,7903,3711,2925,2430,7904, # 7158 +2431,3302,3588,3377,7905,4237,2534,4238,4525,3589,1682,4239,3484,1380,7906, 724, # 7174 +2277, 600,1670,7907,1337,1233,4526,3103,2244,7908,1621,4527,7909, 651,4240,7910, # 7190 +1612,4241,2611,7911,2844,7912,2734,2307,3058,7913, 716,2459,3059, 174,1255,2701, # 7206 +4019,3590, 548,1320,1398, 728,4020,1574,7914,1890,1197,3060,4021,7915,3061,3062, # 7222 +3712,3591,3713, 747,7916, 635,4242,4528,7917,7918,7919,4243,7920,7921,4529,7922, # 7238 +3378,4530,2432, 451,7923,3714,2535,2072,4244,2735,4245,4022,7924,1764,4531,7925, # 7254 +4246, 350,7926,2278,2390,2486,7927,4247,4023,2245,1434,4024, 488,4532, 458,4248, # 7270 +4025,3715, 771,1330,2391,3835,2568,3159,2159,2409,1553,2667,3160,4249,7928,2487, # 7286 +2881,2612,1720,2702,4250,3379,4533,7929,2536,4251,7930,3231,4252,2768,7931,2015, # 7302 +2736,7932,1155,1017,3716,3836,7933,3303,2308, 201,1864,4253,1430,7934,4026,7935, # 7318 +7936,7937,7938,7939,4254,1604,7940, 414,1865, 371,2587,4534,4535,3485,2016,3104, # 7334 +4536,1708, 960,4255, 887, 389,2171,1536,1663,1721,7941,2228,4027,2351,2926,1580, # 7350 +7942,7943,7944,1744,7945,2537,4537,4538,7946,4539,7947,2073,7948,7949,3592,3380, # 7366 +2882,4256,7950,4257,2640,3381,2802, 673,2703,2460, 709,3486,4028,3593,4258,7951, # 7382 +1148, 502, 634,7952,7953,1204,4540,3594,1575,4541,2613,3717,7954,3718,3105, 948, # 7398 +3232, 121,1745,3837,1110,7955,4259,3063,2509,3009,4029,3719,1151,1771,3838,1488, # 7414 +4030,1986,7956,2433,3487,7957,7958,2093,7959,4260,3839,1213,1407,2803, 531,2737, # 7430 +2538,3233,1011,1537,7960,2769,4261,3106,1061,7961,3720,3721,1866,2883,7962,2017, # 7446 + 120,4262,4263,2062,3595,3234,2309,3840,2668,3382,1954,4542,7963,7964,3488,1047, # 7462 +2704,1266,7965,1368,4543,2845, 649,3383,3841,2539,2738,1102,2846,2669,7966,7967, # 7478 +1999,7968,1111,3596,2962,7969,2488,3842,3597,2804,1854,3384,3722,7970,7971,3385, # 7494 +2410,2884,3304,3235,3598,7972,2569,7973,3599,2805,4031,1460, 856,7974,3600,7975, # 7510 +2885,2963,7976,2886,3843,7977,4264, 632,2510, 875,3844,1697,3845,2291,7978,7979, # 7526 +4544,3010,1239, 580,4545,4265,7980, 914, 936,2074,1190,4032,1039,2123,7981,7982, # 7542 +7983,3386,1473,7984,1354,4266,3846,7985,2172,3064,4033, 915,3305,4267,4268,3306, # 7558 +1605,1834,7986,2739, 398,3601,4269,3847,4034, 328,1912,2847,4035,3848,1331,4270, # 7574 +3011, 937,4271,7987,3602,4036,4037,3387,2160,4546,3388, 524, 742, 538,3065,1012, # 7590 +7988,7989,3849,2461,7990, 658,1103, 225,3850,7991,7992,4547,7993,4548,7994,3236, # 7606 +1243,7995,4038, 963,2246,4549,7996,2705,3603,3161,7997,7998,2588,2327,7999,4550, # 7622 +8000,8001,8002,3489,3307, 957,3389,2540,2032,1930,2927,2462, 870,2018,3604,1746, # 7638 +2770,2771,2434,2463,8003,3851,8004,3723,3107,3724,3490,3390,3725,8005,1179,3066, # 7654 +8006,3162,2373,4272,3726,2541,3163,3108,2740,4039,8007,3391,1556,2542,2292, 977, # 7670 +2887,2033,4040,1205,3392,8008,1765,3393,3164,2124,1271,1689, 714,4551,3491,8009, # 7686 +2328,3852, 533,4273,3605,2181, 617,8010,2464,3308,3492,2310,8011,8012,3165,8013, # 7702 +8014,3853,1987, 618, 427,2641,3493,3394,8015,8016,1244,1690,8017,2806,4274,4552, # 7718 +8018,3494,8019,8020,2279,1576, 473,3606,4275,3395, 972,8021,3607,8022,3067,8023, # 7734 +8024,4553,4554,8025,3727,4041,4042,8026, 153,4555, 356,8027,1891,2888,4276,2143, # 7750 + 408, 803,2352,8028,3854,8029,4277,1646,2570,2511,4556,4557,3855,8030,3856,4278, # 7766 +8031,2411,3396, 752,8032,8033,1961,2964,8034, 746,3012,2465,8035,4279,3728, 698, # 7782 +4558,1892,4280,3608,2543,4559,3609,3857,8036,3166,3397,8037,1823,1302,4043,2706, # 7798 +3858,1973,4281,8038,4282,3167, 823,1303,1288,1236,2848,3495,4044,3398, 774,3859, # 7814 +8039,1581,4560,1304,2849,3860,4561,8040,2435,2161,1083,3237,4283,4045,4284, 344, # 7830 +1173, 288,2311, 454,1683,8041,8042,1461,4562,4046,2589,8043,8044,4563, 985, 894, # 7846 +8045,3399,3168,8046,1913,2928,3729,1988,8047,2110,1974,8048,4047,8049,2571,1194, # 7862 + 425,8050,4564,3169,1245,3730,4285,8051,8052,2850,8053, 636,4565,1855,3861, 760, # 7878 +1799,8054,4286,2209,1508,4566,4048,1893,1684,2293,8055,8056,8057,4287,4288,2210, # 7894 + 479,8058,8059, 832,8060,4049,2489,8061,2965,2490,3731, 990,3109, 627,1814,2642, # 7910 +4289,1582,4290,2125,2111,3496,4567,8062, 799,4291,3170,8063,4568,2112,1737,3013, # 7926 +1018, 543, 754,4292,3309,1676,4569,4570,4050,8064,1489,8065,3497,8066,2614,2889, # 7942 +4051,8067,8068,2966,8069,8070,8071,8072,3171,4571,4572,2182,1722,8073,3238,3239, # 7958 +1842,3610,1715, 481, 365,1975,1856,8074,8075,1962,2491,4573,8076,2126,3611,3240, # 7974 + 433,1894,2063,2075,8077, 602,2741,8078,8079,8080,8081,8082,3014,1628,3400,8083, # 7990 +3172,4574,4052,2890,4575,2512,8084,2544,2772,8085,8086,8087,3310,4576,2891,8088, # 8006 +4577,8089,2851,4578,4579,1221,2967,4053,2513,8090,8091,8092,1867,1989,8093,8094, # 8022 +8095,1895,8096,8097,4580,1896,4054, 318,8098,2094,4055,4293,8099,8100, 485,8101, # 8038 + 938,3862, 553,2670, 116,8102,3863,3612,8103,3498,2671,2773,3401,3311,2807,8104, # 8054 +3613,2929,4056,1747,2930,2968,8105,8106, 207,8107,8108,2672,4581,2514,8109,3015, # 8070 + 890,3614,3864,8110,1877,3732,3402,8111,2183,2353,3403,1652,8112,8113,8114, 941, # 8086 +2294, 208,3499,4057,2019, 330,4294,3865,2892,2492,3733,4295,8115,8116,8117,8118, # 8102 +#Everything below is of no interest for detection purpose +2515,1613,4582,8119,3312,3866,2516,8120,4058,8121,1637,4059,2466,4583,3867,8122, # 8118 +2493,3016,3734,8123,8124,2192,8125,8126,2162,8127,8128,8129,8130,8131,8132,8133, # 8134 +8134,8135,8136,8137,8138,8139,8140,8141,8142,8143,8144,8145,8146,8147,8148,8149, # 8150 +8150,8151,8152,8153,8154,8155,8156,8157,8158,8159,8160,8161,8162,8163,8164,8165, # 8166 +8166,8167,8168,8169,8170,8171,8172,8173,8174,8175,8176,8177,8178,8179,8180,8181, # 8182 +8182,8183,8184,8185,8186,8187,8188,8189,8190,8191,8192,8193,8194,8195,8196,8197, # 8198 +8198,8199,8200,8201,8202,8203,8204,8205,8206,8207,8208,8209,8210,8211,8212,8213, # 8214 +8214,8215,8216,8217,8218,8219,8220,8221,8222,8223,8224,8225,8226,8227,8228,8229, # 8230 +8230,8231,8232,8233,8234,8235,8236,8237,8238,8239,8240,8241,8242,8243,8244,8245, # 8246 +8246,8247,8248,8249,8250,8251,8252,8253,8254,8255,8256,8257,8258,8259,8260,8261, # 8262 +8262,8263,8264,8265,8266,8267,8268,8269,8270,8271,8272,8273,8274,8275,8276,8277, # 8278 +8278,8279,8280,8281,8282,8283,8284,8285,8286,8287,8288,8289,8290,8291,8292,8293, # 8294 +8294,8295,8296,8297,8298,8299,8300,8301,8302,8303,8304,8305,8306,8307,8308,8309, # 8310 +8310,8311,8312,8313,8314,8315,8316,8317,8318,8319,8320,8321,8322,8323,8324,8325, # 8326 +8326,8327,8328,8329,8330,8331,8332,8333,8334,8335,8336,8337,8338,8339,8340,8341, # 8342 +8342,8343,8344,8345,8346,8347,8348,8349,8350,8351,8352,8353,8354,8355,8356,8357, # 8358 +8358,8359,8360,8361,8362,8363,8364,8365,8366,8367,8368,8369,8370,8371,8372,8373, # 8374 +8374,8375,8376,8377,8378,8379,8380,8381,8382,8383,8384,8385,8386,8387,8388,8389, # 8390 +8390,8391,8392,8393,8394,8395,8396,8397,8398,8399,8400,8401,8402,8403,8404,8405, # 8406 +8406,8407,8408,8409,8410,8411,8412,8413,8414,8415,8416,8417,8418,8419,8420,8421, # 8422 +8422,8423,8424,8425,8426,8427,8428,8429,8430,8431,8432,8433,8434,8435,8436,8437, # 8438 +8438,8439,8440,8441,8442,8443,8444,8445,8446,8447,8448,8449,8450,8451,8452,8453, # 8454 +8454,8455,8456,8457,8458,8459,8460,8461,8462,8463,8464,8465,8466,8467,8468,8469, # 8470 +8470,8471,8472,8473,8474,8475,8476,8477,8478,8479,8480,8481,8482,8483,8484,8485, # 8486 +8486,8487,8488,8489,8490,8491,8492,8493,8494,8495,8496,8497,8498,8499,8500,8501, # 8502 +8502,8503,8504,8505,8506,8507,8508,8509,8510,8511,8512,8513,8514,8515,8516,8517, # 8518 +8518,8519,8520,8521,8522,8523,8524,8525,8526,8527,8528,8529,8530,8531,8532,8533, # 8534 +8534,8535,8536,8537,8538,8539,8540,8541,8542,8543,8544,8545,8546,8547,8548,8549, # 8550 +8550,8551,8552,8553,8554,8555,8556,8557,8558,8559,8560,8561,8562,8563,8564,8565, # 8566 +8566,8567,8568,8569,8570,8571,8572,8573,8574,8575,8576,8577,8578,8579,8580,8581, # 8582 +8582,8583,8584,8585,8586,8587,8588,8589,8590,8591,8592,8593,8594,8595,8596,8597, # 8598 +8598,8599,8600,8601,8602,8603,8604,8605,8606,8607,8608,8609,8610,8611,8612,8613, # 8614 +8614,8615,8616,8617,8618,8619,8620,8621,8622,8623,8624,8625,8626,8627,8628,8629, # 8630 +8630,8631,8632,8633,8634,8635,8636,8637,8638,8639,8640,8641,8642,8643,8644,8645, # 8646 +8646,8647,8648,8649,8650,8651,8652,8653,8654,8655,8656,8657,8658,8659,8660,8661, # 8662 +8662,8663,8664,8665,8666,8667,8668,8669,8670,8671,8672,8673,8674,8675,8676,8677, # 8678 +8678,8679,8680,8681,8682,8683,8684,8685,8686,8687,8688,8689,8690,8691,8692,8693, # 8694 +8694,8695,8696,8697,8698,8699,8700,8701,8702,8703,8704,8705,8706,8707,8708,8709, # 8710 +8710,8711,8712,8713,8714,8715,8716,8717,8718,8719,8720,8721,8722,8723,8724,8725, # 8726 +8726,8727,8728,8729,8730,8731,8732,8733,8734,8735,8736,8737,8738,8739,8740,8741) # 8742 diff --git a/libs/requests/packages/chardet2/euctwprober.py b/libs/requests/packages/chardet2/euctwprober.py new file mode 100644 index 00000000..fe652fe3 --- /dev/null +++ b/libs/requests/packages/chardet2/euctwprober.py @@ -0,0 +1,41 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCTWDistributionAnalysis +from .mbcssm import EUCTWSMModel + +class EUCTWProber(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(EUCTWSMModel) + self._mDistributionAnalyzer = EUCTWDistributionAnalysis() + self.reset() + + def get_charset_name(self): + return "EUC-TW" diff --git a/libs/requests/packages/chardet2/gb2312freq.py b/libs/requests/packages/chardet2/gb2312freq.py new file mode 100644 index 00000000..7a4d5a1b --- /dev/null +++ b/libs/requests/packages/chardet2/gb2312freq.py @@ -0,0 +1,471 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# GB2312 most frequently used character table +# +# Char to FreqOrder table , from hz6763 + +# 512 --> 0.79 -- 0.79 +# 1024 --> 0.92 -- 0.13 +# 2048 --> 0.98 -- 0.06 +# 6768 --> 1.00 -- 0.02 +# +# Ideal Distribution Ratio = 0.79135/(1-0.79135) = 3.79 +# Random Distribution Ration = 512 / (3755 - 512) = 0.157 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher that RDR + +GB2312_TYPICAL_DISTRIBUTION_RATIO = 0.9 + +GB2312_TABLE_SIZE = 3760 + +GB2312CharToFreqOrder = ( \ +1671, 749,1443,2364,3924,3807,2330,3921,1704,3463,2691,1511,1515, 572,3191,2205, +2361, 224,2558, 479,1711, 963,3162, 440,4060,1905,2966,2947,3580,2647,3961,3842, +2204, 869,4207, 970,2678,5626,2944,2956,1479,4048, 514,3595, 588,1346,2820,3409, + 249,4088,1746,1873,2047,1774, 581,1813, 358,1174,3590,1014,1561,4844,2245, 670, +1636,3112, 889,1286, 953, 556,2327,3060,1290,3141, 613, 185,3477,1367, 850,3820, +1715,2428,2642,2303,2732,3041,2562,2648,3566,3946,1349, 388,3098,2091,1360,3585, + 152,1687,1539, 738,1559, 59,1232,2925,2267,1388,1249,1741,1679,2960, 151,1566, +1125,1352,4271, 924,4296, 385,3166,4459, 310,1245,2850, 70,3285,2729,3534,3575, +2398,3298,3466,1960,2265, 217,3647, 864,1909,2084,4401,2773,1010,3269,5152, 853, +3051,3121,1244,4251,1895, 364,1499,1540,2313,1180,3655,2268, 562, 715,2417,3061, + 544, 336,3768,2380,1752,4075, 950, 280,2425,4382, 183,2759,3272, 333,4297,2155, +1688,2356,1444,1039,4540, 736,1177,3349,2443,2368,2144,2225, 565, 196,1482,3406, + 927,1335,4147, 692, 878,1311,1653,3911,3622,1378,4200,1840,2969,3149,2126,1816, +2534,1546,2393,2760, 737,2494, 13, 447, 245,2747, 38,2765,2129,2589,1079, 606, + 360, 471,3755,2890, 404, 848, 699,1785,1236, 370,2221,1023,3746,2074,2026,2023, +2388,1581,2119, 812,1141,3091,2536,1519, 804,2053, 406,1596,1090, 784, 548,4414, +1806,2264,2936,1100, 343,4114,5096, 622,3358, 743,3668,1510,1626,5020,3567,2513, +3195,4115,5627,2489,2991, 24,2065,2697,1087,2719, 48,1634, 315, 68, 985,2052, + 198,2239,1347,1107,1439, 597,2366,2172, 871,3307, 919,2487,2790,1867, 236,2570, +1413,3794, 906,3365,3381,1701,1982,1818,1524,2924,1205, 616,2586,2072,2004, 575, + 253,3099, 32,1365,1182, 197,1714,2454,1201, 554,3388,3224,2748, 756,2587, 250, +2567,1507,1517,3529,1922,2761,2337,3416,1961,1677,2452,2238,3153, 615, 911,1506, +1474,2495,1265,1906,2749,3756,3280,2161, 898,2714,1759,3450,2243,2444, 563, 26, +3286,2266,3769,3344,2707,3677, 611,1402, 531,1028,2871,4548,1375, 261,2948, 835, +1190,4134, 353, 840,2684,1900,3082,1435,2109,1207,1674, 329,1872,2781,4055,2686, +2104, 608,3318,2423,2957,2768,1108,3739,3512,3271,3985,2203,1771,3520,1418,2054, +1681,1153, 225,1627,2929, 162,2050,2511,3687,1954, 124,1859,2431,1684,3032,2894, + 585,4805,3969,2869,2704,2088,2032,2095,3656,2635,4362,2209, 256, 518,2042,2105, +3777,3657, 643,2298,1148,1779, 190, 989,3544, 414, 11,2135,2063,2979,1471, 403, +3678, 126, 770,1563, 671,2499,3216,2877, 600,1179, 307,2805,4937,1268,1297,2694, + 252,4032,1448,1494,1331,1394, 127,2256, 222,1647,1035,1481,3056,1915,1048, 873, +3651, 210, 33,1608,2516, 200,1520, 415, 102, 0,3389,1287, 817, 91,3299,2940, + 836,1814, 549,2197,1396,1669,2987,3582,2297,2848,4528,1070, 687, 20,1819, 121, +1552,1364,1461,1968,2617,3540,2824,2083, 177, 948,4938,2291, 110,4549,2066, 648, +3359,1755,2110,2114,4642,4845,1693,3937,3308,1257,1869,2123, 208,1804,3159,2992, +2531,2549,3361,2418,1350,2347,2800,2568,1291,2036,2680, 72, 842,1990, 212,1233, +1154,1586, 75,2027,3410,4900,1823,1337,2710,2676, 728,2810,1522,3026,4995, 157, + 755,1050,4022, 710, 785,1936,2194,2085,1406,2777,2400, 150,1250,4049,1206, 807, +1910, 534, 529,3309,1721,1660, 274, 39,2827, 661,2670,1578, 925,3248,3815,1094, +4278,4901,4252, 41,1150,3747,2572,2227,4501,3658,4902,3813,3357,3617,2884,2258, + 887, 538,4187,3199,1294,2439,3042,2329,2343,2497,1255, 107, 543,1527, 521,3478, +3568, 194,5062, 15, 961,3870,1241,1192,2664, 66,5215,3260,2111,1295,1127,2152, +3805,4135, 901,1164,1976, 398,1278, 530,1460, 748, 904,1054,1966,1426, 53,2909, + 509, 523,2279,1534, 536,1019, 239,1685, 460,2353, 673,1065,2401,3600,4298,2272, +1272,2363, 284,1753,3679,4064,1695, 81, 815,2677,2757,2731,1386, 859, 500,4221, +2190,2566, 757,1006,2519,2068,1166,1455, 337,2654,3203,1863,1682,1914,3025,1252, +1409,1366, 847, 714,2834,2038,3209, 964,2970,1901, 885,2553,1078,1756,3049, 301, +1572,3326, 688,2130,1996,2429,1805,1648,2930,3421,2750,3652,3088, 262,1158,1254, + 389,1641,1812, 526,1719, 923,2073,1073,1902, 468, 489,4625,1140, 857,2375,3070, +3319,2863, 380, 116,1328,2693,1161,2244, 273,1212,1884,2769,3011,1775,1142, 461, +3066,1200,2147,2212, 790, 702,2695,4222,1601,1058, 434,2338,5153,3640, 67,2360, +4099,2502, 618,3472,1329, 416,1132, 830,2782,1807,2653,3211,3510,1662, 192,2124, + 296,3979,1739,1611,3684, 23, 118, 324, 446,1239,1225, 293,2520,3814,3795,2535, +3116, 17,1074, 467,2692,2201, 387,2922, 45,1326,3055,1645,3659,2817, 958, 243, +1903,2320,1339,2825,1784,3289, 356, 576, 865,2315,2381,3377,3916,1088,3122,1713, +1655, 935, 628,4689,1034,1327, 441, 800, 720, 894,1979,2183,1528,5289,2702,1071, +4046,3572,2399,1571,3281, 79, 761,1103, 327, 134, 758,1899,1371,1615, 879, 442, + 215,2605,2579, 173,2048,2485,1057,2975,3317,1097,2253,3801,4263,1403,1650,2946, + 814,4968,3487,1548,2644,1567,1285, 2, 295,2636, 97, 946,3576, 832, 141,4257, +3273, 760,3821,3521,3156,2607, 949,1024,1733,1516,1803,1920,2125,2283,2665,3180, +1501,2064,3560,2171,1592, 803,3518,1416, 732,3897,4258,1363,1362,2458, 119,1427, + 602,1525,2608,1605,1639,3175, 694,3064, 10, 465, 76,2000,4846,4208, 444,3781, +1619,3353,2206,1273,3796, 740,2483, 320,1723,2377,3660,2619,1359,1137,1762,1724, +2345,2842,1850,1862, 912, 821,1866, 612,2625,1735,2573,3369,1093, 844, 89, 937, + 930,1424,3564,2413,2972,1004,3046,3019,2011, 711,3171,1452,4178, 428, 801,1943, + 432, 445,2811, 206,4136,1472, 730, 349, 73, 397,2802,2547, 998,1637,1167, 789, + 396,3217, 154,1218, 716,1120,1780,2819,4826,1931,3334,3762,2139,1215,2627, 552, +3664,3628,3232,1405,2383,3111,1356,2652,3577,3320,3101,1703, 640,1045,1370,1246, +4996, 371,1575,2436,1621,2210, 984,4033,1734,2638, 16,4529, 663,2755,3255,1451, +3917,2257,1253,1955,2234,1263,2951, 214,1229, 617, 485, 359,1831,1969, 473,2310, + 750,2058, 165, 80,2864,2419, 361,4344,2416,2479,1134, 796,3726,1266,2943, 860, +2715, 938, 390,2734,1313,1384, 248, 202, 877,1064,2854, 522,3907, 279,1602, 297, +2357, 395,3740, 137,2075, 944,4089,2584,1267,3802, 62,1533,2285, 178, 176, 780, +2440, 201,3707, 590, 478,1560,4354,2117,1075, 30, 74,4643,4004,1635,1441,2745, + 776,2596, 238,1077,1692,1912,2844, 605, 499,1742,3947, 241,3053, 980,1749, 936, +2640,4511,2582, 515,1543,2162,5322,2892,2993, 890,2148,1924, 665,1827,3581,1032, + 968,3163, 339,1044,1896, 270, 583,1791,1720,4367,1194,3488,3669, 43,2523,1657, + 163,2167, 290,1209,1622,3378, 550, 634,2508,2510, 695,2634,2384,2512,1476,1414, + 220,1469,2341,2138,2852,3183,2900,4939,2865,3502,1211,3680, 854,3227,1299,2976, +3172, 186,2998,1459, 443,1067,3251,1495, 321,1932,3054, 909, 753,1410,1828, 436, +2441,1119,1587,3164,2186,1258, 227, 231,1425,1890,3200,3942, 247, 959, 725,5254, +2741, 577,2158,2079, 929, 120, 174, 838,2813, 591,1115, 417,2024, 40,3240,1536, +1037, 291,4151,2354, 632,1298,2406,2500,3535,1825,1846,3451, 205,1171, 345,4238, + 18,1163, 811, 685,2208,1217, 425,1312,1508,1175,4308,2552,1033, 587,1381,3059, +2984,3482, 340,1316,4023,3972, 792,3176, 519, 777,4690, 918, 933,4130,2981,3741, + 90,3360,2911,2200,5184,4550, 609,3079,2030, 272,3379,2736, 363,3881,1130,1447, + 286, 779, 357,1169,3350,3137,1630,1220,2687,2391, 747,1277,3688,2618,2682,2601, +1156,3196,5290,4034,3102,1689,3596,3128, 874, 219,2783, 798, 508,1843,2461, 269, +1658,1776,1392,1913,2983,3287,2866,2159,2372, 829,4076, 46,4253,2873,1889,1894, + 915,1834,1631,2181,2318, 298, 664,2818,3555,2735, 954,3228,3117, 527,3511,2173, + 681,2712,3033,2247,2346,3467,1652, 155,2164,3382, 113,1994, 450, 899, 494, 994, +1237,2958,1875,2336,1926,3727, 545,1577,1550, 633,3473, 204,1305,3072,2410,1956, +2471, 707,2134, 841,2195,2196,2663,3843,1026,4940, 990,3252,4997, 368,1092, 437, +3212,3258,1933,1829, 675,2977,2893, 412, 943,3723,4644,3294,3283,2230,2373,5154, +2389,2241,2661,2323,1404,2524, 593, 787, 677,3008,1275,2059, 438,2709,2609,2240, +2269,2246,1446, 36,1568,1373,3892,1574,2301,1456,3962, 693,2276,5216,2035,1143, +2720,1919,1797,1811,2763,4137,2597,1830,1699,1488,1198,2090, 424,1694, 312,3634, +3390,4179,3335,2252,1214, 561,1059,3243,2295,2561, 975,5155,2321,2751,3772, 472, +1537,3282,3398,1047,2077,2348,2878,1323,3340,3076, 690,2906, 51, 369, 170,3541, +1060,2187,2688,3670,2541,1083,1683, 928,3918, 459, 109,4427, 599,3744,4286, 143, +2101,2730,2490, 82,1588,3036,2121, 281,1860, 477,4035,1238,2812,3020,2716,3312, +1530,2188,2055,1317, 843, 636,1808,1173,3495, 649, 181,1002, 147,3641,1159,2414, +3750,2289,2795, 813,3123,2610,1136,4368, 5,3391,4541,2174, 420, 429,1728, 754, +1228,2115,2219, 347,2223,2733, 735,1518,3003,2355,3134,1764,3948,3329,1888,2424, +1001,1234,1972,3321,3363,1672,1021,1450,1584, 226, 765, 655,2526,3404,3244,2302, +3665, 731, 594,2184, 319,1576, 621, 658,2656,4299,2099,3864,1279,2071,2598,2739, + 795,3086,3699,3908,1707,2352,2402,1382,3136,2475,1465,4847,3496,3865,1085,3004, +2591,1084, 213,2287,1963,3565,2250, 822, 793,4574,3187,1772,1789,3050, 595,1484, +1959,2770,1080,2650, 456, 422,2996, 940,3322,4328,4345,3092,2742, 965,2784, 739, +4124, 952,1358,2498,2949,2565, 332,2698,2378, 660,2260,2473,4194,3856,2919, 535, +1260,2651,1208,1428,1300,1949,1303,2942, 433,2455,2450,1251,1946, 614,1269, 641, +1306,1810,2737,3078,2912, 564,2365,1419,1415,1497,4460,2367,2185,1379,3005,1307, +3218,2175,1897,3063, 682,1157,4040,4005,1712,1160,1941,1399, 394, 402,2952,1573, +1151,2986,2404, 862, 299,2033,1489,3006, 346, 171,2886,3401,1726,2932, 168,2533, + 47,2507,1030,3735,1145,3370,1395,1318,1579,3609,4560,2857,4116,1457,2529,1965, + 504,1036,2690,2988,2405, 745,5871, 849,2397,2056,3081, 863,2359,3857,2096, 99, +1397,1769,2300,4428,1643,3455,1978,1757,3718,1440, 35,4879,3742,1296,4228,2280, + 160,5063,1599,2013, 166, 520,3479,1646,3345,3012, 490,1937,1545,1264,2182,2505, +1096,1188,1369,1436,2421,1667,2792,2460,1270,2122, 727,3167,2143, 806,1706,1012, +1800,3037, 960,2218,1882, 805, 139,2456,1139,1521, 851,1052,3093,3089, 342,2039, + 744,5097,1468,1502,1585,2087, 223, 939, 326,2140,2577, 892,2481,1623,4077, 982, +3708, 135,2131, 87,2503,3114,2326,1106, 876,1616, 547,2997,2831,2093,3441,4530, +4314, 9,3256,4229,4148, 659,1462,1986,1710,2046,2913,2231,4090,4880,5255,3392, +3274,1368,3689,4645,1477, 705,3384,3635,1068,1529,2941,1458,3782,1509, 100,1656, +2548, 718,2339, 408,1590,2780,3548,1838,4117,3719,1345,3530, 717,3442,2778,3220, +2898,1892,4590,3614,3371,2043,1998,1224,3483, 891, 635, 584,2559,3355, 733,1766, +1729,1172,3789,1891,2307, 781,2982,2271,1957,1580,5773,2633,2005,4195,3097,1535, +3213,1189,1934,5693,3262, 586,3118,1324,1598, 517,1564,2217,1868,1893,4445,3728, +2703,3139,1526,1787,1992,3882,2875,1549,1199,1056,2224,1904,2711,5098,4287, 338, +1993,3129,3489,2689,1809,2815,1997, 957,1855,3898,2550,3275,3057,1105,1319, 627, +1505,1911,1883,3526, 698,3629,3456,1833,1431, 746, 77,1261,2017,2296,1977,1885, + 125,1334,1600, 525,1798,1109,2222,1470,1945, 559,2236,1186,3443,2476,1929,1411, +2411,3135,1777,3372,2621,1841,1613,3229, 668,1430,1839,2643,2916, 195,1989,2671, +2358,1387, 629,3205,2293,5256,4439, 123,1310, 888,1879,4300,3021,3605,1003,1162, +3192,2910,2010, 140,2395,2859, 55,1082,2012,2901, 662, 419,2081,1438, 680,2774, +4654,3912,1620,1731,1625,5035,4065,2328, 512,1344, 802,5443,2163,2311,2537, 524, +3399, 98,1155,2103,1918,2606,3925,2816,1393,2465,1504,3773,2177,3963,1478,4346, + 180,1113,4655,3461,2028,1698, 833,2696,1235,1322,1594,4408,3623,3013,3225,2040, +3022, 541,2881, 607,3632,2029,1665,1219, 639,1385,1686,1099,2803,3231,1938,3188, +2858, 427, 676,2772,1168,2025, 454,3253,2486,3556, 230,1950, 580, 791,1991,1280, +1086,1974,2034, 630, 257,3338,2788,4903,1017, 86,4790, 966,2789,1995,1696,1131, + 259,3095,4188,1308, 179,1463,5257, 289,4107,1248, 42,3413,1725,2288, 896,1947, + 774,4474,4254, 604,3430,4264, 392,2514,2588, 452, 237,1408,3018, 988,4531,1970, +3034,3310, 540,2370,1562,1288,2990, 502,4765,1147, 4,1853,2708, 207, 294,2814, +4078,2902,2509, 684, 34,3105,3532,2551, 644, 709,2801,2344, 573,1727,3573,3557, +2021,1081,3100,4315,2100,3681, 199,2263,1837,2385, 146,3484,1195,2776,3949, 997, +1939,3973,1008,1091,1202,1962,1847,1149,4209,5444,1076, 493, 117,5400,2521, 972, +1490,2934,1796,4542,2374,1512,2933,2657, 413,2888,1135,2762,2314,2156,1355,2369, + 766,2007,2527,2170,3124,2491,2593,2632,4757,2437, 234,3125,3591,1898,1750,1376, +1942,3468,3138, 570,2127,2145,3276,4131, 962, 132,1445,4196, 19, 941,3624,3480, +3366,1973,1374,4461,3431,2629, 283,2415,2275, 808,2887,3620,2112,2563,1353,3610, + 955,1089,3103,1053, 96, 88,4097, 823,3808,1583, 399, 292,4091,3313, 421,1128, + 642,4006, 903,2539,1877,2082, 596, 29,4066,1790, 722,2157, 130, 995,1569, 769, +1485, 464, 513,2213, 288,1923,1101,2453,4316, 133, 486,2445, 50, 625, 487,2207, + 57, 423, 481,2962, 159,3729,1558, 491, 303, 482, 501, 240,2837, 112,3648,2392, +1783, 362, 8,3433,3422, 610,2793,3277,1390,1284,1654, 21,3823, 734, 367, 623, + 193, 287, 374,1009,1483, 816, 476, 313,2255,2340,1262,2150,2899,1146,2581, 782, +2116,1659,2018,1880, 255,3586,3314,1110,2867,2137,2564, 986,2767,5185,2006, 650, + 158, 926, 762, 881,3157,2717,2362,3587, 306,3690,3245,1542,3077,2427,1691,2478, +2118,2985,3490,2438, 539,2305, 983, 129,1754, 355,4201,2386, 827,2923, 104,1773, +2838,2771, 411,2905,3919, 376, 767, 122,1114, 828,2422,1817,3506, 266,3460,1007, +1609,4998, 945,2612,4429,2274, 726,1247,1964,2914,2199,2070,4002,4108, 657,3323, +1422, 579, 455,2764,4737,1222,2895,1670, 824,1223,1487,2525, 558, 861,3080, 598, +2659,2515,1967, 752,2583,2376,2214,4180, 977, 704,2464,4999,2622,4109,1210,2961, + 819,1541, 142,2284, 44, 418, 457,1126,3730,4347,4626,1644,1876,3671,1864, 302, +1063,5694, 624, 723,1984,3745,1314,1676,2488,1610,1449,3558,3569,2166,2098, 409, +1011,2325,3704,2306, 818,1732,1383,1824,1844,3757, 999,2705,3497,1216,1423,2683, +2426,2954,2501,2726,2229,1475,2554,5064,1971,1794,1666,2014,1343, 783, 724, 191, +2434,1354,2220,5065,1763,2752,2472,4152, 131, 175,2885,3434, 92,1466,4920,2616, +3871,3872,3866, 128,1551,1632, 669,1854,3682,4691,4125,1230, 188,2973,3290,1302, +1213, 560,3266, 917, 763,3909,3249,1760, 868,1958, 764,1782,2097, 145,2277,3774, +4462, 64,1491,3062, 971,2132,3606,2442, 221,1226,1617, 218, 323,1185,3207,3147, + 571, 619,1473,1005,1744,2281, 449,1887,2396,3685, 275, 375,3816,1743,3844,3731, + 845,1983,2350,4210,1377, 773, 967,3499,3052,3743,2725,4007,1697,1022,3943,1464, +3264,2855,2722,1952,1029,2839,2467, 84,4383,2215, 820,1391,2015,2448,3672, 377, +1948,2168, 797,2545,3536,2578,2645, 94,2874,1678, 405,1259,3071, 771, 546,1315, + 470,1243,3083, 895,2468, 981, 969,2037, 846,4181, 653,1276,2928, 14,2594, 557, +3007,2474, 156, 902,1338,1740,2574, 537,2518, 973,2282,2216,2433,1928, 138,2903, +1293,2631,1612, 646,3457, 839,2935, 111, 496,2191,2847, 589,3186, 149,3994,2060, +4031,2641,4067,3145,1870, 37,3597,2136,1025,2051,3009,3383,3549,1121,1016,3261, +1301, 251,2446,2599,2153, 872,3246, 637, 334,3705, 831, 884, 921,3065,3140,4092, +2198,1944, 246,2964, 108,2045,1152,1921,2308,1031, 203,3173,4170,1907,3890, 810, +1401,2003,1690, 506, 647,1242,2828,1761,1649,3208,2249,1589,3709,2931,5156,1708, + 498, 666,2613, 834,3817,1231, 184,2851,1124, 883,3197,2261,3710,1765,1553,2658, +1178,2639,2351, 93,1193, 942,2538,2141,4402, 235,1821, 870,1591,2192,1709,1871, +3341,1618,4126,2595,2334, 603, 651, 69, 701, 268,2662,3411,2555,1380,1606, 503, + 448, 254,2371,2646, 574,1187,2309,1770, 322,2235,1292,1801, 305, 566,1133, 229, +2067,2057, 706, 167, 483,2002,2672,3295,1820,3561,3067, 316, 378,2746,3452,1112, + 136,1981, 507,1651,2917,1117, 285,4591, 182,2580,3522,1304, 335,3303,1835,2504, +1795,1792,2248, 674,1018,2106,2449,1857,2292,2845, 976,3047,1781,2600,2727,1389, +1281, 52,3152, 153, 265,3950, 672,3485,3951,4463, 430,1183, 365, 278,2169, 27, +1407,1336,2304, 209,1340,1730,2202,1852,2403,2883, 979,1737,1062, 631,2829,2542, +3876,2592, 825,2086,2226,3048,3625, 352,1417,3724, 542, 991, 431,1351,3938,1861, +2294, 826,1361,2927,3142,3503,1738, 463,2462,2723, 582,1916,1595,2808, 400,3845, +3891,2868,3621,2254, 58,2492,1123, 910,2160,2614,1372,1603,1196,1072,3385,1700, +3267,1980, 696, 480,2430, 920, 799,1570,2920,1951,2041,4047,2540,1321,4223,2469, +3562,2228,1271,2602, 401,2833,3351,2575,5157, 907,2312,1256, 410, 263,3507,1582, + 996, 678,1849,2316,1480, 908,3545,2237, 703,2322, 667,1826,2849,1531,2604,2999, +2407,3146,2151,2630,1786,3711, 469,3542, 497,3899,2409, 858, 837,4446,3393,1274, + 786, 620,1845,2001,3311, 484, 308,3367,1204,1815,3691,2332,1532,2557,1842,2020, +2724,1927,2333,4440, 567, 22,1673,2728,4475,1987,1858,1144,1597, 101,1832,3601, + 12, 974,3783,4391, 951,1412, 1,3720, 453,4608,4041, 528,1041,1027,3230,2628, +1129, 875,1051,3291,1203,2262,1069,2860,2799,2149,2615,3278, 144,1758,3040, 31, + 475,1680, 366,2685,3184, 311,1642,4008,2466,5036,1593,1493,2809, 216,1420,1668, + 233, 304,2128,3284, 232,1429,1768,1040,2008,3407,2740,2967,2543, 242,2133, 778, +1565,2022,2620, 505,2189,2756,1098,2273, 372,1614, 708, 553,2846,2094,2278, 169, +3626,2835,4161, 228,2674,3165, 809,1454,1309, 466,1705,1095, 900,3423, 880,2667, +3751,5258,2317,3109,2571,4317,2766,1503,1342, 866,4447,1118, 63,2076, 314,1881, +1348,1061, 172, 978,3515,1747, 532, 511,3970, 6, 601, 905,2699,3300,1751, 276, +1467,3725,2668, 65,4239,2544,2779,2556,1604, 578,2451,1802, 992,2331,2624,1320, +3446, 713,1513,1013, 103,2786,2447,1661, 886,1702, 916, 654,3574,2031,1556, 751, +2178,2821,2179,1498,1538,2176, 271, 914,2251,2080,1325, 638,1953,2937,3877,2432, +2754, 95,3265,1716, 260,1227,4083, 775, 106,1357,3254, 426,1607, 555,2480, 772, +1985, 244,2546, 474, 495,1046,2611,1851,2061, 71,2089,1675,2590, 742,3758,2843, +3222,1433, 267,2180,2576,2826,2233,2092,3913,2435, 956,1745,3075, 856,2113,1116, + 451, 3,1988,2896,1398, 993,2463,1878,2049,1341,2718,2721,2870,2108, 712,2904, +4363,2753,2324, 277,2872,2349,2649, 384, 987, 435, 691,3000, 922, 164,3939, 652, +1500,1184,4153,2482,3373,2165,4848,2335,3775,3508,3154,2806,2830,1554,2102,1664, +2530,1434,2408, 893,1547,2623,3447,2832,2242,2532,3169,2856,3223,2078, 49,3770, +3469, 462, 318, 656,2259,3250,3069, 679,1629,2758, 344,1138,1104,3120,1836,1283, +3115,2154,1437,4448, 934, 759,1999, 794,2862,1038, 533,2560,1722,2342, 855,2626, +1197,1663,4476,3127, 85,4240,2528, 25,1111,1181,3673, 407,3470,4561,2679,2713, + 768,1925,2841,3986,1544,1165, 932, 373,1240,2146,1930,2673, 721,4766, 354,4333, + 391,2963, 187, 61,3364,1442,1102, 330,1940,1767, 341,3809,4118, 393,2496,2062, +2211, 105, 331, 300, 439, 913,1332, 626, 379,3304,1557, 328, 689,3952, 309,1555, + 931, 317,2517,3027, 325, 569, 686,2107,3084, 60,1042,1333,2794, 264,3177,4014, +1628, 258,3712, 7,4464,1176,1043,1778, 683, 114,1975, 78,1492, 383,1886, 510, + 386, 645,5291,2891,2069,3305,4138,3867,2939,2603,2493,1935,1066,1848,3588,1015, +1282,1289,4609, 697,1453,3044,2666,3611,1856,2412, 54, 719,1330, 568,3778,2459, +1748, 788, 492, 551,1191,1000, 488,3394,3763, 282,1799, 348,2016,1523,3155,2390, +1049, 382,2019,1788,1170, 729,2968,3523, 897,3926,2785,2938,3292, 350,2319,3238, +1718,1717,2655,3453,3143,4465, 161,2889,2980,2009,1421, 56,1908,1640,2387,2232, +1917,1874,2477,4921, 148, 83,3438, 592,4245,2882,1822,1055, 741, 115,1496,1624, + 381,1638,4592,1020, 516,3214, 458, 947,4575,1432, 211,1514,2926,1865,2142, 189, + 852,1221,1400,1486, 882,2299,4036, 351, 28,1122, 700,6479,6480,6481,6482,6483, # last 512 +#Everything below is of no interest for detection purpose +5508,6484,3900,3414,3974,4441,4024,3537,4037,5628,5099,3633,6485,3148,6486,3636, +5509,3257,5510,5973,5445,5872,4941,4403,3174,4627,5873,6276,2286,4230,5446,5874, +5122,6102,6103,4162,5447,5123,5323,4849,6277,3980,3851,5066,4246,5774,5067,6278, +3001,2807,5695,3346,5775,5974,5158,5448,6487,5975,5976,5776,3598,6279,5696,4806, +4211,4154,6280,6488,6489,6490,6281,4212,5037,3374,4171,6491,4562,4807,4722,4827, +5977,6104,4532,4079,5159,5324,5160,4404,3858,5359,5875,3975,4288,4610,3486,4512, +5325,3893,5360,6282,6283,5560,2522,4231,5978,5186,5449,2569,3878,6284,5401,3578, +4415,6285,4656,5124,5979,2506,4247,4449,3219,3417,4334,4969,4329,6492,4576,4828, +4172,4416,4829,5402,6286,3927,3852,5361,4369,4830,4477,4867,5876,4173,6493,6105, +4657,6287,6106,5877,5450,6494,4155,4868,5451,3700,5629,4384,6288,6289,5878,3189, +4881,6107,6290,6495,4513,6496,4692,4515,4723,5100,3356,6497,6291,3810,4080,5561, +3570,4430,5980,6498,4355,5697,6499,4724,6108,6109,3764,4050,5038,5879,4093,3226, +6292,5068,5217,4693,3342,5630,3504,4831,4377,4466,4309,5698,4431,5777,6293,5778, +4272,3706,6110,5326,3752,4676,5327,4273,5403,4767,5631,6500,5699,5880,3475,5039, +6294,5562,5125,4348,4301,4482,4068,5126,4593,5700,3380,3462,5981,5563,3824,5404, +4970,5511,3825,4738,6295,6501,5452,4516,6111,5881,5564,6502,6296,5982,6503,4213, +4163,3454,6504,6112,4009,4450,6113,4658,6297,6114,3035,6505,6115,3995,4904,4739, +4563,4942,4110,5040,3661,3928,5362,3674,6506,5292,3612,4791,5565,4149,5983,5328, +5259,5021,4725,4577,4564,4517,4364,6298,5405,4578,5260,4594,4156,4157,5453,3592, +3491,6507,5127,5512,4709,4922,5984,5701,4726,4289,6508,4015,6116,5128,4628,3424, +4241,5779,6299,4905,6509,6510,5454,5702,5780,6300,4365,4923,3971,6511,5161,3270, +3158,5985,4100, 867,5129,5703,6117,5363,3695,3301,5513,4467,6118,6512,5455,4232, +4242,4629,6513,3959,4478,6514,5514,5329,5986,4850,5162,5566,3846,4694,6119,5456, +4869,5781,3779,6301,5704,5987,5515,4710,6302,5882,6120,4392,5364,5705,6515,6121, +6516,6517,3736,5988,5457,5989,4695,2457,5883,4551,5782,6303,6304,6305,5130,4971, +6122,5163,6123,4870,3263,5365,3150,4871,6518,6306,5783,5069,5706,3513,3498,4409, +5330,5632,5366,5458,5459,3991,5990,4502,3324,5991,5784,3696,4518,5633,4119,6519, +4630,5634,4417,5707,4832,5992,3418,6124,5993,5567,4768,5218,6520,4595,3458,5367, +6125,5635,6126,4202,6521,4740,4924,6307,3981,4069,4385,6308,3883,2675,4051,3834, +4302,4483,5568,5994,4972,4101,5368,6309,5164,5884,3922,6127,6522,6523,5261,5460, +5187,4164,5219,3538,5516,4111,3524,5995,6310,6311,5369,3181,3386,2484,5188,3464, +5569,3627,5708,6524,5406,5165,4677,4492,6312,4872,4851,5885,4468,5996,6313,5709, +5710,6128,2470,5886,6314,5293,4882,5785,3325,5461,5101,6129,5711,5786,6525,4906, +6526,6527,4418,5887,5712,4808,2907,3701,5713,5888,6528,3765,5636,5331,6529,6530, +3593,5889,3637,4943,3692,5714,5787,4925,6315,6130,5462,4405,6131,6132,6316,5262, +6531,6532,5715,3859,5716,5070,4696,5102,3929,5788,3987,4792,5997,6533,6534,3920, +4809,5000,5998,6535,2974,5370,6317,5189,5263,5717,3826,6536,3953,5001,4883,3190, +5463,5890,4973,5999,4741,6133,6134,3607,5570,6000,4711,3362,3630,4552,5041,6318, +6001,2950,2953,5637,4646,5371,4944,6002,2044,4120,3429,6319,6537,5103,4833,6538, +6539,4884,4647,3884,6003,6004,4758,3835,5220,5789,4565,5407,6540,6135,5294,4697, +4852,6320,6321,3206,4907,6541,6322,4945,6542,6136,6543,6323,6005,4631,3519,6544, +5891,6545,5464,3784,5221,6546,5571,4659,6547,6324,6137,5190,6548,3853,6549,4016, +4834,3954,6138,5332,3827,4017,3210,3546,4469,5408,5718,3505,4648,5790,5131,5638, +5791,5465,4727,4318,6325,6326,5792,4553,4010,4698,3439,4974,3638,4335,3085,6006, +5104,5042,5166,5892,5572,6327,4356,4519,5222,5573,5333,5793,5043,6550,5639,5071, +4503,6328,6139,6551,6140,3914,3901,5372,6007,5640,4728,4793,3976,3836,4885,6552, +4127,6553,4451,4102,5002,6554,3686,5105,6555,5191,5072,5295,4611,5794,5296,6556, +5893,5264,5894,4975,5466,5265,4699,4976,4370,4056,3492,5044,4886,6557,5795,4432, +4769,4357,5467,3940,4660,4290,6141,4484,4770,4661,3992,6329,4025,4662,5022,4632, +4835,4070,5297,4663,4596,5574,5132,5409,5895,6142,4504,5192,4664,5796,5896,3885, +5575,5797,5023,4810,5798,3732,5223,4712,5298,4084,5334,5468,6143,4052,4053,4336, +4977,4794,6558,5335,4908,5576,5224,4233,5024,4128,5469,5225,4873,6008,5045,4729, +4742,4633,3675,4597,6559,5897,5133,5577,5003,5641,5719,6330,6560,3017,2382,3854, +4406,4811,6331,4393,3964,4946,6561,2420,3722,6562,4926,4378,3247,1736,4442,6332, +5134,6333,5226,3996,2918,5470,4319,4003,4598,4743,4744,4485,3785,3902,5167,5004, +5373,4394,5898,6144,4874,1793,3997,6334,4085,4214,5106,5642,4909,5799,6009,4419, +4189,3330,5899,4165,4420,5299,5720,5227,3347,6145,4081,6335,2876,3930,6146,3293, +3786,3910,3998,5900,5300,5578,2840,6563,5901,5579,6147,3531,5374,6564,6565,5580, +4759,5375,6566,6148,3559,5643,6336,6010,5517,6337,6338,5721,5902,3873,6011,6339, +6567,5518,3868,3649,5722,6568,4771,4947,6569,6149,4812,6570,2853,5471,6340,6341, +5644,4795,6342,6012,5723,6343,5724,6013,4349,6344,3160,6150,5193,4599,4514,4493, +5168,4320,6345,4927,3666,4745,5169,5903,5005,4928,6346,5725,6014,4730,4203,5046, +4948,3395,5170,6015,4150,6016,5726,5519,6347,5047,3550,6151,6348,4197,4310,5904, +6571,5581,2965,6152,4978,3960,4291,5135,6572,5301,5727,4129,4026,5905,4853,5728, +5472,6153,6349,4533,2700,4505,5336,4678,3583,5073,2994,4486,3043,4554,5520,6350, +6017,5800,4487,6351,3931,4103,5376,6352,4011,4321,4311,4190,5136,6018,3988,3233, +4350,5906,5645,4198,6573,5107,3432,4191,3435,5582,6574,4139,5410,6353,5411,3944, +5583,5074,3198,6575,6354,4358,6576,5302,4600,5584,5194,5412,6577,6578,5585,5413, +5303,4248,5414,3879,4433,6579,4479,5025,4854,5415,6355,4760,4772,3683,2978,4700, +3797,4452,3965,3932,3721,4910,5801,6580,5195,3551,5907,3221,3471,3029,6019,3999, +5908,5909,5266,5267,3444,3023,3828,3170,4796,5646,4979,4259,6356,5647,5337,3694, +6357,5648,5338,4520,4322,5802,3031,3759,4071,6020,5586,4836,4386,5048,6581,3571, +4679,4174,4949,6154,4813,3787,3402,3822,3958,3215,3552,5268,4387,3933,4950,4359, +6021,5910,5075,3579,6358,4234,4566,5521,6359,3613,5049,6022,5911,3375,3702,3178, +4911,5339,4521,6582,6583,4395,3087,3811,5377,6023,6360,6155,4027,5171,5649,4421, +4249,2804,6584,2270,6585,4000,4235,3045,6156,5137,5729,4140,4312,3886,6361,4330, +6157,4215,6158,3500,3676,4929,4331,3713,4930,5912,4265,3776,3368,5587,4470,4855, +3038,4980,3631,6159,6160,4132,4680,6161,6362,3923,4379,5588,4255,6586,4121,6587, +6363,4649,6364,3288,4773,4774,6162,6024,6365,3543,6588,4274,3107,3737,5050,5803, +4797,4522,5589,5051,5730,3714,4887,5378,4001,4523,6163,5026,5522,4701,4175,2791, +3760,6589,5473,4224,4133,3847,4814,4815,4775,3259,5416,6590,2738,6164,6025,5304, +3733,5076,5650,4816,5590,6591,6165,6592,3934,5269,6593,3396,5340,6594,5804,3445, +3602,4042,4488,5731,5732,3525,5591,4601,5196,6166,6026,5172,3642,4612,3202,4506, +4798,6366,3818,5108,4303,5138,5139,4776,3332,4304,2915,3415,4434,5077,5109,4856, +2879,5305,4817,6595,5913,3104,3144,3903,4634,5341,3133,5110,5651,5805,6167,4057, +5592,2945,4371,5593,6596,3474,4182,6367,6597,6168,4507,4279,6598,2822,6599,4777, +4713,5594,3829,6169,3887,5417,6170,3653,5474,6368,4216,2971,5228,3790,4579,6369, +5733,6600,6601,4951,4746,4555,6602,5418,5475,6027,3400,4665,5806,6171,4799,6028, +5052,6172,3343,4800,4747,5006,6370,4556,4217,5476,4396,5229,5379,5477,3839,5914, +5652,5807,4714,3068,4635,5808,6173,5342,4192,5078,5419,5523,5734,6174,4557,6175, +4602,6371,6176,6603,5809,6372,5735,4260,3869,5111,5230,6029,5112,6177,3126,4681, +5524,5915,2706,3563,4748,3130,6178,4018,5525,6604,6605,5478,4012,4837,6606,4534, +4193,5810,4857,3615,5479,6030,4082,3697,3539,4086,5270,3662,4508,4931,5916,4912, +5811,5027,3888,6607,4397,3527,3302,3798,2775,2921,2637,3966,4122,4388,4028,4054, +1633,4858,5079,3024,5007,3982,3412,5736,6608,3426,3236,5595,3030,6179,3427,3336, +3279,3110,6373,3874,3039,5080,5917,5140,4489,3119,6374,5812,3405,4494,6031,4666, +4141,6180,4166,6032,5813,4981,6609,5081,4422,4982,4112,3915,5653,3296,3983,6375, +4266,4410,5654,6610,6181,3436,5082,6611,5380,6033,3819,5596,4535,5231,5306,5113, +6612,4952,5918,4275,3113,6613,6376,6182,6183,5814,3073,4731,4838,5008,3831,6614, +4888,3090,3848,4280,5526,5232,3014,5655,5009,5737,5420,5527,6615,5815,5343,5173, +5381,4818,6616,3151,4953,6617,5738,2796,3204,4360,2989,4281,5739,5174,5421,5197, +3132,5141,3849,5142,5528,5083,3799,3904,4839,5480,2880,4495,3448,6377,6184,5271, +5919,3771,3193,6034,6035,5920,5010,6036,5597,6037,6378,6038,3106,5422,6618,5423, +5424,4142,6619,4889,5084,4890,4313,5740,6620,3437,5175,5307,5816,4199,5198,5529, +5817,5199,5656,4913,5028,5344,3850,6185,2955,5272,5011,5818,4567,4580,5029,5921, +3616,5233,6621,6622,6186,4176,6039,6379,6380,3352,5200,5273,2908,5598,5234,3837, +5308,6623,6624,5819,4496,4323,5309,5201,6625,6626,4983,3194,3838,4167,5530,5922, +5274,6381,6382,3860,3861,5599,3333,4292,4509,6383,3553,5481,5820,5531,4778,6187, +3955,3956,4324,4389,4218,3945,4325,3397,2681,5923,4779,5085,4019,5482,4891,5382, +5383,6040,4682,3425,5275,4094,6627,5310,3015,5483,5657,4398,5924,3168,4819,6628, +5925,6629,5532,4932,4613,6041,6630,4636,6384,4780,4204,5658,4423,5821,3989,4683, +5822,6385,4954,6631,5345,6188,5425,5012,5384,3894,6386,4490,4104,6632,5741,5053, +6633,5823,5926,5659,5660,5927,6634,5235,5742,5824,4840,4933,4820,6387,4859,5928, +4955,6388,4143,3584,5825,5346,5013,6635,5661,6389,5014,5484,5743,4337,5176,5662, +6390,2836,6391,3268,6392,6636,6042,5236,6637,4158,6638,5744,5663,4471,5347,3663, +4123,5143,4293,3895,6639,6640,5311,5929,5826,3800,6189,6393,6190,5664,5348,3554, +3594,4749,4603,6641,5385,4801,6043,5827,4183,6642,5312,5426,4761,6394,5665,6191, +4715,2669,6643,6644,5533,3185,5427,5086,5930,5931,5386,6192,6044,6645,4781,4013, +5745,4282,4435,5534,4390,4267,6045,5746,4984,6046,2743,6193,3501,4087,5485,5932, +5428,4184,4095,5747,4061,5054,3058,3862,5933,5600,6646,5144,3618,6395,3131,5055, +5313,6396,4650,4956,3855,6194,3896,5202,4985,4029,4225,6195,6647,5828,5486,5829, +3589,3002,6648,6397,4782,5276,6649,6196,6650,4105,3803,4043,5237,5830,6398,4096, +3643,6399,3528,6651,4453,3315,4637,6652,3984,6197,5535,3182,3339,6653,3096,2660, +6400,6654,3449,5934,4250,4236,6047,6401,5831,6655,5487,3753,4062,5832,6198,6199, +6656,3766,6657,3403,4667,6048,6658,4338,2897,5833,3880,2797,3780,4326,6659,5748, +5015,6660,5387,4351,5601,4411,6661,3654,4424,5935,4339,4072,5277,4568,5536,6402, +6662,5238,6663,5349,5203,6200,5204,6201,5145,4536,5016,5056,4762,5834,4399,4957, +6202,6403,5666,5749,6664,4340,6665,5936,5177,5667,6666,6667,3459,4668,6404,6668, +6669,4543,6203,6670,4276,6405,4480,5537,6671,4614,5205,5668,6672,3348,2193,4763, +6406,6204,5937,5602,4177,5669,3419,6673,4020,6205,4443,4569,5388,3715,3639,6407, +6049,4058,6206,6674,5938,4544,6050,4185,4294,4841,4651,4615,5488,6207,6408,6051, +5178,3241,3509,5835,6208,4958,5836,4341,5489,5278,6209,2823,5538,5350,5206,5429, +6675,4638,4875,4073,3516,4684,4914,4860,5939,5603,5389,6052,5057,3237,5490,3791, +6676,6409,6677,4821,4915,4106,5351,5058,4243,5539,4244,5604,4842,4916,5239,3028, +3716,5837,5114,5605,5390,5940,5430,6210,4332,6678,5540,4732,3667,3840,6053,4305, +3408,5670,5541,6410,2744,5240,5750,6679,3234,5606,6680,5607,5671,3608,4283,4159, +4400,5352,4783,6681,6411,6682,4491,4802,6211,6412,5941,6413,6414,5542,5751,6683, +4669,3734,5942,6684,6415,5943,5059,3328,4670,4144,4268,6685,6686,6687,6688,4372, +3603,6689,5944,5491,4373,3440,6416,5543,4784,4822,5608,3792,4616,5838,5672,3514, +5391,6417,4892,6690,4639,6691,6054,5673,5839,6055,6692,6056,5392,6212,4038,5544, +5674,4497,6057,6693,5840,4284,5675,4021,4545,5609,6418,4454,6419,6213,4113,4472, +5314,3738,5087,5279,4074,5610,4959,4063,3179,4750,6058,6420,6214,3476,4498,4716, +5431,4960,4685,6215,5241,6694,6421,6216,6695,5841,5945,6422,3748,5946,5179,3905, +5752,5545,5947,4374,6217,4455,6423,4412,6218,4803,5353,6696,3832,5280,6219,4327, +4702,6220,6221,6059,4652,5432,6424,3749,4751,6425,5753,4986,5393,4917,5948,5030, +5754,4861,4733,6426,4703,6697,6222,4671,5949,4546,4961,5180,6223,5031,3316,5281, +6698,4862,4295,4934,5207,3644,6427,5842,5950,6428,6429,4570,5843,5282,6430,6224, +5088,3239,6060,6699,5844,5755,6061,6431,2701,5546,6432,5115,5676,4039,3993,3327, +4752,4425,5315,6433,3941,6434,5677,4617,4604,3074,4581,6225,5433,6435,6226,6062, +4823,5756,5116,6227,3717,5678,4717,5845,6436,5679,5846,6063,5847,6064,3977,3354, +6437,3863,5117,6228,5547,5394,4499,4524,6229,4605,6230,4306,4500,6700,5951,6065, +3693,5952,5089,4366,4918,6701,6231,5548,6232,6702,6438,4704,5434,6703,6704,5953, +4168,6705,5680,3420,6706,5242,4407,6066,3812,5757,5090,5954,4672,4525,3481,5681, +4618,5395,5354,5316,5955,6439,4962,6707,4526,6440,3465,4673,6067,6441,5682,6708, +5435,5492,5758,5683,4619,4571,4674,4804,4893,4686,5493,4753,6233,6068,4269,6442, +6234,5032,4705,5146,5243,5208,5848,6235,6443,4963,5033,4640,4226,6236,5849,3387, +6444,6445,4436,4437,5850,4843,5494,4785,4894,6709,4361,6710,5091,5956,3331,6237, +4987,5549,6069,6711,4342,3517,4473,5317,6070,6712,6071,4706,6446,5017,5355,6713, +6714,4988,5436,6447,4734,5759,6715,4735,4547,4456,4754,6448,5851,6449,6450,3547, +5852,5318,6451,6452,5092,4205,6716,6238,4620,4219,5611,6239,6072,4481,5760,5957, +5958,4059,6240,6453,4227,4537,6241,5761,4030,4186,5244,5209,3761,4457,4876,3337, +5495,5181,6242,5959,5319,5612,5684,5853,3493,5854,6073,4169,5613,5147,4895,6074, +5210,6717,5182,6718,3830,6243,2798,3841,6075,6244,5855,5614,3604,4606,5496,5685, +5118,5356,6719,6454,5960,5357,5961,6720,4145,3935,4621,5119,5962,4261,6721,6455, +4786,5963,4375,4582,6245,6246,6247,6076,5437,4877,5856,3376,4380,6248,4160,6722, +5148,6456,5211,6457,6723,4718,6458,6724,6249,5358,4044,3297,6459,6250,5857,5615, +5497,5245,6460,5498,6725,6251,6252,5550,3793,5499,2959,5396,6461,6462,4572,5093, +5500,5964,3806,4146,6463,4426,5762,5858,6077,6253,4755,3967,4220,5965,6254,4989, +5501,6464,4352,6726,6078,4764,2290,5246,3906,5438,5283,3767,4964,2861,5763,5094, +6255,6256,4622,5616,5859,5860,4707,6727,4285,4708,4824,5617,6257,5551,4787,5212, +4965,4935,4687,6465,6728,6466,5686,6079,3494,4413,2995,5247,5966,5618,6729,5967, +5764,5765,5687,5502,6730,6731,6080,5397,6467,4990,6258,6732,4538,5060,5619,6733, +4719,5688,5439,5018,5149,5284,5503,6734,6081,4607,6259,5120,3645,5861,4583,6260, +4584,4675,5620,4098,5440,6261,4863,2379,3306,4585,5552,5689,4586,5285,6735,4864, +6736,5286,6082,6737,4623,3010,4788,4381,4558,5621,4587,4896,3698,3161,5248,4353, +4045,6262,3754,5183,4588,6738,6263,6739,6740,5622,3936,6741,6468,6742,6264,5095, +6469,4991,5968,6743,4992,6744,6083,4897,6745,4256,5766,4307,3108,3968,4444,5287, +3889,4343,6084,4510,6085,4559,6086,4898,5969,6746,5623,5061,4919,5249,5250,5504, +5441,6265,5320,4878,3242,5862,5251,3428,6087,6747,4237,5624,5442,6266,5553,4539, +6748,2585,3533,5398,4262,6088,5150,4736,4438,6089,6267,5505,4966,6749,6268,6750, +6269,5288,5554,3650,6090,6091,4624,6092,5690,6751,5863,4270,5691,4277,5555,5864, +6752,5692,4720,4865,6470,5151,4688,4825,6753,3094,6754,6471,3235,4653,6755,5213, +5399,6756,3201,4589,5865,4967,6472,5866,6473,5019,3016,6757,5321,4756,3957,4573, +6093,4993,5767,4721,6474,6758,5625,6759,4458,6475,6270,6760,5556,4994,5214,5252, +6271,3875,5768,6094,5034,5506,4376,5769,6761,2120,6476,5253,5770,6762,5771,5970, +3990,5971,5557,5558,5772,6477,6095,2787,4641,5972,5121,6096,6097,6272,6763,3703, +5867,5507,6273,4206,6274,4789,6098,6764,3619,3646,3833,3804,2394,3788,4936,3978, +4866,4899,6099,6100,5559,6478,6765,3599,5868,6101,5869,5870,6275,6766,4527,6767) + diff --git a/libs/requests/packages/chardet2/gb2312prober.py b/libs/requests/packages/chardet2/gb2312prober.py new file mode 100644 index 00000000..0325a2d8 --- /dev/null +++ b/libs/requests/packages/chardet2/gb2312prober.py @@ -0,0 +1,41 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import GB2312DistributionAnalysis +from .mbcssm import GB2312SMModel + +class GB2312Prober(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(GB2312SMModel) + self._mDistributionAnalyzer = GB2312DistributionAnalysis() + self.reset() + + def get_charset_name(self): + return "GB2312" diff --git a/libs/requests/packages/chardet2/hebrewprober.py b/libs/requests/packages/chardet2/hebrewprober.py new file mode 100644 index 00000000..6727d76b --- /dev/null +++ b/libs/requests/packages/chardet2/hebrewprober.py @@ -0,0 +1,269 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Shy Shalom +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from . import constants + +# This prober doesn't actually recognize a language or a charset. +# It is a helper prober for the use of the Hebrew model probers + +### General ideas of the Hebrew charset recognition ### +# +# Four main charsets exist in Hebrew: +# "ISO-8859-8" - Visual Hebrew +# "windows-1255" - Logical Hebrew +# "ISO-8859-8-I" - Logical Hebrew +# "x-mac-hebrew" - ?? Logical Hebrew ?? +# +# Both "ISO" charsets use a completely identical set of code points, whereas +# "windows-1255" and "x-mac-hebrew" are two different proper supersets of +# these code points. windows-1255 defines additional characters in the range +# 0x80-0x9F as some misc punctuation marks as well as some Hebrew-specific +# diacritics and additional 'Yiddish' ligature letters in the range 0xc0-0xd6. +# x-mac-hebrew defines similar additional code points but with a different +# mapping. +# +# As far as an average Hebrew text with no diacritics is concerned, all four +# charsets are identical with respect to code points. Meaning that for the +# main Hebrew alphabet, all four map the same values to all 27 Hebrew letters +# (including final letters). +# +# The dominant difference between these charsets is their directionality. +# "Visual" directionality means that the text is ordered as if the renderer is +# not aware of a BIDI rendering algorithm. The renderer sees the text and +# draws it from left to right. The text itself when ordered naturally is read +# backwards. A buffer of Visual Hebrew generally looks like so: +# "[last word of first line spelled backwards] [whole line ordered backwards +# and spelled backwards] [first word of first line spelled backwards] +# [end of line] [last word of second line] ... etc' " +# adding punctuation marks, numbers and English text to visual text is +# naturally also "visual" and from left to right. +# +# "Logical" directionality means the text is ordered "naturally" according to +# the order it is read. It is the responsibility of the renderer to display +# the text from right to left. A BIDI algorithm is used to place general +# punctuation marks, numbers and English text in the text. +# +# Texts in x-mac-hebrew are almost impossible to find on the Internet. From +# what little evidence I could find, it seems that its general directionality +# is Logical. +# +# To sum up all of the above, the Hebrew probing mechanism knows about two +# charsets: +# Visual Hebrew - "ISO-8859-8" - backwards text - Words and sentences are +# backwards while line order is natural. For charset recognition purposes +# the line order is unimportant (In fact, for this implementation, even +# word order is unimportant). +# Logical Hebrew - "windows-1255" - normal, naturally ordered text. +# +# "ISO-8859-8-I" is a subset of windows-1255 and doesn't need to be +# specifically identified. +# "x-mac-hebrew" is also identified as windows-1255. A text in x-mac-hebrew +# that contain special punctuation marks or diacritics is displayed with +# some unconverted characters showing as question marks. This problem might +# be corrected using another model prober for x-mac-hebrew. Due to the fact +# that x-mac-hebrew texts are so rare, writing another model prober isn't +# worth the effort and performance hit. +# +#### The Prober #### +# +# The prober is divided between two SBCharSetProbers and a HebrewProber, +# all of which are managed, created, fed data, inquired and deleted by the +# SBCSGroupProber. The two SBCharSetProbers identify that the text is in +# fact some kind of Hebrew, Logical or Visual. The final decision about which +# one is it is made by the HebrewProber by combining final-letter scores +# with the scores of the two SBCharSetProbers to produce a final answer. +# +# The SBCSGroupProber is responsible for stripping the original text of HTML +# tags, English characters, numbers, low-ASCII punctuation characters, spaces +# and new lines. It reduces any sequence of such characters to a single space. +# The buffer fed to each prober in the SBCS group prober is pure text in +# high-ASCII. +# The two SBCharSetProbers (model probers) share the same language model: +# Win1255Model. +# The first SBCharSetProber uses the model normally as any other +# SBCharSetProber does, to recognize windows-1255, upon which this model was +# built. The second SBCharSetProber is told to make the pair-of-letter +# lookup in the language model backwards. This in practice exactly simulates +# a visual Hebrew model using the windows-1255 logical Hebrew model. +# +# The HebrewProber is not using any language model. All it does is look for +# final-letter evidence suggesting the text is either logical Hebrew or visual +# Hebrew. Disjointed from the model probers, the results of the HebrewProber +# alone are meaningless. HebrewProber always returns 0.00 as confidence +# since it never identifies a charset by itself. Instead, the pointer to the +# HebrewProber is passed to the model probers as a helper "Name Prober". +# When the Group prober receives a positive identification from any prober, +# it asks for the name of the charset identified. If the prober queried is a +# Hebrew model prober, the model prober forwards the call to the +# HebrewProber to make the final decision. In the HebrewProber, the +# decision is made according to the final-letters scores maintained and Both +# model probers scores. The answer is returned in the form of the name of the +# charset identified, either "windows-1255" or "ISO-8859-8". + +# windows-1255 / ISO-8859-8 code points of interest +FINAL_KAF = '\xea' +NORMAL_KAF = '\xeb' +FINAL_MEM = '\xed' +NORMAL_MEM = '\xee' +FINAL_NUN = '\xef' +NORMAL_NUN = '\xf0' +FINAL_PE = '\xf3' +NORMAL_PE = '\xf4' +FINAL_TSADI = '\xf5' +NORMAL_TSADI = '\xf6' + +# Minimum Visual vs Logical final letter score difference. +# If the difference is below this, don't rely solely on the final letter score distance. +MIN_FINAL_CHAR_DISTANCE = 5 + +# Minimum Visual vs Logical model score difference. +# If the difference is below this, don't rely at all on the model score distance. +MIN_MODEL_DISTANCE = 0.01 + +VISUAL_HEBREW_NAME = "ISO-8859-8" +LOGICAL_HEBREW_NAME = "windows-1255" + +class HebrewProber(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self._mLogicalProber = None + self._mVisualProber = None + self.reset() + + def reset(self): + self._mFinalCharLogicalScore = 0 + self._mFinalCharVisualScore = 0 + # The two last characters seen in the previous buffer, + # mPrev and mBeforePrev are initialized to space in order to simulate a word + # delimiter at the beginning of the data + self._mPrev = ' ' + self._mBeforePrev = ' ' + # These probers are owned by the group prober. + + def set_model_probers(self, logicalProber, visualProber): + self._mLogicalProber = logicalProber + self._mVisualProber = visualProber + + def is_final(self, c): + return c in [FINAL_KAF, FINAL_MEM, FINAL_NUN, FINAL_PE, FINAL_TSADI] + + def is_non_final(self, c): + # The normal Tsadi is not a good Non-Final letter due to words like + # 'lechotet' (to chat) containing an apostrophe after the tsadi. This + # apostrophe is converted to a space in FilterWithoutEnglishLetters causing + # the Non-Final tsadi to appear at an end of a word even though this is not + # the case in the original text. + # The letters Pe and Kaf rarely display a related behavior of not being a + # good Non-Final letter. Words like 'Pop', 'Winamp' and 'Mubarak' for + # example legally end with a Non-Final Pe or Kaf. However, the benefit of + # these letters as Non-Final letters outweighs the damage since these words + # are quite rare. + return c in [NORMAL_KAF, NORMAL_MEM, NORMAL_NUN, NORMAL_PE] + + def feed(self, aBuf): + # Final letter analysis for logical-visual decision. + # Look for evidence that the received buffer is either logical Hebrew or + # visual Hebrew. + # The following cases are checked: + # 1) A word longer than 1 letter, ending with a final letter. This is an + # indication that the text is laid out "naturally" since the final letter + # really appears at the end. +1 for logical score. + # 2) A word longer than 1 letter, ending with a Non-Final letter. In normal + # Hebrew, words ending with Kaf, Mem, Nun, Pe or Tsadi, should not end with + # the Non-Final form of that letter. Exceptions to this rule are mentioned + # above in isNonFinal(). This is an indication that the text is laid out + # backwards. +1 for visual score + # 3) A word longer than 1 letter, starting with a final letter. Final letters + # should not appear at the beginning of a word. This is an indication that + # the text is laid out backwards. +1 for visual score. + # + # The visual score and logical score are accumulated throughout the text and + # are finally checked against each other in GetCharSetName(). + # No checking for final letters in the middle of words is done since that case + # is not an indication for either Logical or Visual text. + # + # We automatically filter out all 7-bit characters (replace them with spaces) + # so the word boundary detection works properly. [MAP] + + if self.get_state() == constants.eNotMe: + # Both model probers say it's not them. No reason to continue. + return constants.eNotMe + + aBuf = self.filter_high_bit_only(aBuf) + + for cur in aBuf: + if cur == ' ': + # We stand on a space - a word just ended + if self._mBeforePrev != ' ': + # next-to-last char was not a space so self._mPrev is not a 1 letter word + if self.is_final(self._mPrev): + # case (1) [-2:not space][-1:final letter][cur:space] + self._mFinalCharLogicalScore += 1 + elif self.is_non_final(self._mPrev): + # case (2) [-2:not space][-1:Non-Final letter][cur:space] + self._mFinalCharVisualScore += 1 + else: + # Not standing on a space + if (self._mBeforePrev == ' ') and (self.is_final(self._mPrev)) and (cur != ' '): + # case (3) [-2:space][-1:final letter][cur:not space] + self._mFinalCharVisualScore += 1 + self._mBeforePrev = self._mPrev + self._mPrev = cur + + # Forever detecting, till the end or until both model probers return eNotMe (handled above) + return constants.eDetecting + + def get_charset_name(self): + # Make the decision: is it Logical or Visual? + # If the final letter score distance is dominant enough, rely on it. + finalsub = self._mFinalCharLogicalScore - self._mFinalCharVisualScore + if finalsub >= MIN_FINAL_CHAR_DISTANCE: + return LOGICAL_HEBREW_NAME + if finalsub <= -MIN_FINAL_CHAR_DISTANCE: + return VISUAL_HEBREW_NAME + + # It's not dominant enough, try to rely on the model scores instead. + modelsub = self._mLogicalProber.get_confidence() - self._mVisualProber.get_confidence() + if modelsub > MIN_MODEL_DISTANCE: + return LOGICAL_HEBREW_NAME + if modelsub < -MIN_MODEL_DISTANCE: + return VISUAL_HEBREW_NAME + + # Still no good, back to final letter distance, maybe it'll save the day. + if finalsub < 0.0: + return VISUAL_HEBREW_NAME + + # (finalsub > 0 - Logical) or (don't know what to do) default to Logical. + return LOGICAL_HEBREW_NAME + + def get_state(self): + # Remain active as long as any of the model probers are active. + if (self._mLogicalProber.get_state() == constants.eNotMe) and \ + (self._mVisualProber.get_state() == constants.eNotMe): + return constants.eNotMe + return constants.eDetecting diff --git a/libs/requests/packages/chardet2/jisfreq.py b/libs/requests/packages/chardet2/jisfreq.py new file mode 100644 index 00000000..5fe4a5c3 --- /dev/null +++ b/libs/requests/packages/chardet2/jisfreq.py @@ -0,0 +1,567 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Sampling from about 20M text materials include literature and computer technology +# +# Japanese frequency table, applied to both S-JIS and EUC-JP +# They are sorted in order. + +# 128 --> 0.77094 +# 256 --> 0.85710 +# 512 --> 0.92635 +# 1024 --> 0.97130 +# 2048 --> 0.99431 +# +# Ideal Distribution Ratio = 0.92635 / (1-0.92635) = 12.58 +# Random Distribution Ration = 512 / (2965+62+83+86-512) = 0.191 +# +# Typical Distribution Ratio, 25% of IDR + +JIS_TYPICAL_DISTRIBUTION_RATIO = 3.0 + +# Char to FreqOrder table , +JIS_TABLE_SIZE = 4368 + +JISCharToFreqOrder = ( \ + 40, 1, 6, 182, 152, 180, 295,2127, 285, 381,3295,4304,3068,4606,3165,3510, # 16 +3511,1822,2785,4607,1193,2226,5070,4608, 171,2996,1247, 18, 179,5071, 856,1661, # 32 +1262,5072, 619, 127,3431,3512,3230,1899,1700, 232, 228,1294,1298, 284, 283,2041, # 48 +2042,1061,1062, 48, 49, 44, 45, 433, 434,1040,1041, 996, 787,2997,1255,4305, # 64 +2108,4609,1684,1648,5073,5074,5075,5076,5077,5078,3687,5079,4610,5080,3927,3928, # 80 +5081,3296,3432, 290,2285,1471,2187,5082,2580,2825,1303,2140,1739,1445,2691,3375, # 96 +1691,3297,4306,4307,4611, 452,3376,1182,2713,3688,3069,4308,5083,5084,5085,5086, # 112 +5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102, # 128 +5103,5104,5105,5106,5107,5108,5109,5110,5111,5112,4097,5113,5114,5115,5116,5117, # 144 +5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,5130,5131,5132,5133, # 160 +5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,5144,5145,5146,5147,5148,5149, # 176 +5150,5151,5152,4612,5153,5154,5155,5156,5157,5158,5159,5160,5161,5162,5163,5164, # 192 +5165,5166,5167,5168,5169,5170,5171,5172,5173,5174,5175,1472, 598, 618, 820,1205, # 208 +1309,1412,1858,1307,1692,5176,5177,5178,5179,5180,5181,5182,1142,1452,1234,1172, # 224 +1875,2043,2149,1793,1382,2973, 925,2404,1067,1241, 960,1377,2935,1491, 919,1217, # 240 +1865,2030,1406,1499,2749,4098,5183,5184,5185,5186,5187,5188,2561,4099,3117,1804, # 256 +2049,3689,4309,3513,1663,5189,3166,3118,3298,1587,1561,3433,5190,3119,1625,2998, # 272 +3299,4613,1766,3690,2786,4614,5191,5192,5193,5194,2161, 26,3377, 2,3929, 20, # 288 +3691, 47,4100, 50, 17, 16, 35, 268, 27, 243, 42, 155, 24, 154, 29, 184, # 304 + 4, 91, 14, 92, 53, 396, 33, 289, 9, 37, 64, 620, 21, 39, 321, 5, # 320 + 12, 11, 52, 13, 3, 208, 138, 0, 7, 60, 526, 141, 151,1069, 181, 275, # 336 +1591, 83, 132,1475, 126, 331, 829, 15, 69, 160, 59, 22, 157, 55,1079, 312, # 352 + 109, 38, 23, 25, 10, 19, 79,5195, 61, 382,1124, 8, 30,5196,5197,5198, # 368 +5199,5200,5201,5202,5203,5204,5205,5206, 89, 62, 74, 34,2416, 112, 139, 196, # 384 + 271, 149, 84, 607, 131, 765, 46, 88, 153, 683, 76, 874, 101, 258, 57, 80, # 400 + 32, 364, 121,1508, 169,1547, 68, 235, 145,2999, 41, 360,3027, 70, 63, 31, # 416 + 43, 259, 262,1383, 99, 533, 194, 66, 93, 846, 217, 192, 56, 106, 58, 565, # 432 + 280, 272, 311, 256, 146, 82, 308, 71, 100, 128, 214, 655, 110, 261, 104,1140, # 448 + 54, 51, 36, 87, 67,3070, 185,2618,2936,2020, 28,1066,2390,2059,5207,5208, # 464 +5209,5210,5211,5212,5213,5214,5215,5216,4615,5217,5218,5219,5220,5221,5222,5223, # 480 +5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,5234,5235,5236,3514,5237,5238, # 496 +5239,5240,5241,5242,5243,5244,2297,2031,4616,4310,3692,5245,3071,5246,3598,5247, # 512 +4617,3231,3515,5248,4101,4311,4618,3808,4312,4102,5249,4103,4104,3599,5250,5251, # 528 +5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,5264,5265,5266,5267, # 544 +5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,5279,5280,5281,5282,5283, # 560 +5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,5294,5295,5296,5297,5298,5299, # 576 +5300,5301,5302,5303,5304,5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315, # 592 +5316,5317,5318,5319,5320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331, # 608 +5332,5333,5334,5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347, # 624 +5348,5349,5350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363, # 640 +5364,5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379, # 656 +5380,5381, 363, 642,2787,2878,2788,2789,2316,3232,2317,3434,2011, 165,1942,3930, # 672 +3931,3932,3933,5382,4619,5383,4620,5384,5385,5386,5387,5388,5389,5390,5391,5392, # 688 +5393,5394,5395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,5408, # 704 +5409,5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424, # 720 +5425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,5440, # 736 +5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456, # 752 +5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472, # 768 +5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488, # 784 +5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,5504, # 800 +5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,5519,5520, # 816 +5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,5534,5535,5536, # 832 +5537,5538,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,5549,5550,5551,5552, # 848 +5553,5554,5555,5556,5557,5558,5559,5560,5561,5562,5563,5564,5565,5566,5567,5568, # 864 +5569,5570,5571,5572,5573,5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584, # 880 +5585,5586,5587,5588,5589,5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600, # 896 +5601,5602,5603,5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616, # 912 +5617,5618,5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632, # 928 +5633,5634,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648, # 944 +5649,5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664, # 960 +5665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,5680, # 976 +5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,5695,5696, # 992 +5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,5710,5711,5712, # 1008 +5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,5725,5726,5727,5728, # 1024 +5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5741,5742,5743,5744, # 1040 +5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,5755,5756,5757,5758,5759,5760, # 1056 +5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,5771,5772,5773,5774,5775,5776, # 1072 +5777,5778,5779,5780,5781,5782,5783,5784,5785,5786,5787,5788,5789,5790,5791,5792, # 1088 +5793,5794,5795,5796,5797,5798,5799,5800,5801,5802,5803,5804,5805,5806,5807,5808, # 1104 +5809,5810,5811,5812,5813,5814,5815,5816,5817,5818,5819,5820,5821,5822,5823,5824, # 1120 +5825,5826,5827,5828,5829,5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840, # 1136 +5841,5842,5843,5844,5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856, # 1152 +5857,5858,5859,5860,5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872, # 1168 +5873,5874,5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888, # 1184 +5889,5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904, # 1200 +5905,5906,5907,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920, # 1216 +5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936, # 1232 +5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951,5952, # 1248 +5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968, # 1264 +5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,5984, # 1280 +5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,5999,6000, # 1296 +6001,6002,6003,6004,6005,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,6016, # 1312 +6017,6018,6019,6020,6021,6022,6023,6024,6025,6026,6027,6028,6029,6030,6031,6032, # 1328 +6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,6044,6045,6046,6047,6048, # 1344 +6049,6050,6051,6052,6053,6054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064, # 1360 +6065,6066,6067,6068,6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080, # 1376 +6081,6082,6083,6084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096, # 1392 +6097,6098,6099,6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112, # 1408 +6113,6114,2044,2060,4621, 997,1235, 473,1186,4622, 920,3378,6115,6116, 379,1108, # 1424 +4313,2657,2735,3934,6117,3809, 636,3233, 573,1026,3693,3435,2974,3300,2298,4105, # 1440 + 854,2937,2463, 393,2581,2417, 539, 752,1280,2750,2480, 140,1161, 440, 708,1569, # 1456 + 665,2497,1746,1291,1523,3000, 164,1603, 847,1331, 537,1997, 486, 508,1693,2418, # 1472 +1970,2227, 878,1220, 299,1030, 969, 652,2751, 624,1137,3301,2619, 65,3302,2045, # 1488 +1761,1859,3120,1930,3694,3516, 663,1767, 852, 835,3695, 269, 767,2826,2339,1305, # 1504 + 896,1150, 770,1616,6118, 506,1502,2075,1012,2519, 775,2520,2975,2340,2938,4314, # 1520 +3028,2086,1224,1943,2286,6119,3072,4315,2240,1273,1987,3935,1557, 175, 597, 985, # 1536 +3517,2419,2521,1416,3029, 585, 938,1931,1007,1052,1932,1685,6120,3379,4316,4623, # 1552 + 804, 599,3121,1333,2128,2539,1159,1554,2032,3810, 687,2033,2904, 952, 675,1467, # 1568 +3436,6121,2241,1096,1786,2440,1543,1924, 980,1813,2228, 781,2692,1879, 728,1918, # 1584 +3696,4624, 548,1950,4625,1809,1088,1356,3303,2522,1944, 502, 972, 373, 513,2827, # 1600 + 586,2377,2391,1003,1976,1631,6122,2464,1084, 648,1776,4626,2141, 324, 962,2012, # 1616 +2177,2076,1384, 742,2178,1448,1173,1810, 222, 102, 301, 445, 125,2420, 662,2498, # 1632 + 277, 200,1476,1165,1068, 224,2562,1378,1446, 450,1880, 659, 791, 582,4627,2939, # 1648 +3936,1516,1274, 555,2099,3697,1020,1389,1526,3380,1762,1723,1787,2229, 412,2114, # 1664 +1900,2392,3518, 512,2597, 427,1925,2341,3122,1653,1686,2465,2499, 697, 330, 273, # 1680 + 380,2162, 951, 832, 780, 991,1301,3073, 965,2270,3519, 668,2523,2636,1286, 535, # 1696 +1407, 518, 671, 957,2658,2378, 267, 611,2197,3030,6123, 248,2299, 967,1799,2356, # 1712 + 850,1418,3437,1876,1256,1480,2828,1718,6124,6125,1755,1664,2405,6126,4628,2879, # 1728 +2829, 499,2179, 676,4629, 557,2329,2214,2090, 325,3234, 464, 811,3001, 992,2342, # 1744 +2481,1232,1469, 303,2242, 466,1070,2163, 603,1777,2091,4630,2752,4631,2714, 322, # 1760 +2659,1964,1768, 481,2188,1463,2330,2857,3600,2092,3031,2421,4632,2318,2070,1849, # 1776 +2598,4633,1302,2254,1668,1701,2422,3811,2905,3032,3123,2046,4106,1763,1694,4634, # 1792 +1604, 943,1724,1454, 917, 868,2215,1169,2940, 552,1145,1800,1228,1823,1955, 316, # 1808 +1080,2510, 361,1807,2830,4107,2660,3381,1346,1423,1134,4108,6127, 541,1263,1229, # 1824 +1148,2540, 545, 465,1833,2880,3438,1901,3074,2482, 816,3937, 713,1788,2500, 122, # 1840 +1575, 195,1451,2501,1111,6128, 859, 374,1225,2243,2483,4317, 390,1033,3439,3075, # 1856 +2524,1687, 266, 793,1440,2599, 946, 779, 802, 507, 897,1081, 528,2189,1292, 711, # 1872 +1866,1725,1167,1640, 753, 398,2661,1053, 246, 348,4318, 137,1024,3440,1600,2077, # 1888 +2129, 825,4319, 698, 238, 521, 187,2300,1157,2423,1641,1605,1464,1610,1097,2541, # 1904 +1260,1436, 759,2255,1814,2150, 705,3235, 409,2563,3304, 561,3033,2005,2564, 726, # 1920 +1956,2343,3698,4109, 949,3812,3813,3520,1669, 653,1379,2525, 881,2198, 632,2256, # 1936 +1027, 778,1074, 733,1957, 514,1481,2466, 554,2180, 702,3938,1606,1017,1398,6129, # 1952 +1380,3521, 921, 993,1313, 594, 449,1489,1617,1166, 768,1426,1360, 495,1794,3601, # 1968 +1177,3602,1170,4320,2344, 476, 425,3167,4635,3168,1424, 401,2662,1171,3382,1998, # 1984 +1089,4110, 477,3169, 474,6130,1909, 596,2831,1842, 494, 693,1051,1028,1207,3076, # 2000 + 606,2115, 727,2790,1473,1115, 743,3522, 630, 805,1532,4321,2021, 366,1057, 838, # 2016 + 684,1114,2142,4322,2050,1492,1892,1808,2271,3814,2424,1971,1447,1373,3305,1090, # 2032 +1536,3939,3523,3306,1455,2199, 336, 369,2331,1035, 584,2393, 902, 718,2600,6131, # 2048 +2753, 463,2151,1149,1611,2467, 715,1308,3124,1268, 343,1413,3236,1517,1347,2663, # 2064 +2093,3940,2022,1131,1553,2100,2941,1427,3441,2942,1323,2484,6132,1980, 872,2368, # 2080 +2441,2943, 320,2369,2116,1082, 679,1933,3941,2791,3815, 625,1143,2023, 422,2200, # 2096 +3816,6133, 730,1695, 356,2257,1626,2301,2858,2637,1627,1778, 937, 883,2906,2693, # 2112 +3002,1769,1086, 400,1063,1325,3307,2792,4111,3077, 456,2345,1046, 747,6134,1524, # 2128 + 884,1094,3383,1474,2164,1059, 974,1688,2181,2258,1047, 345,1665,1187, 358, 875, # 2144 +3170, 305, 660,3524,2190,1334,1135,3171,1540,1649,2542,1527, 927, 968,2793, 885, # 2160 +1972,1850, 482, 500,2638,1218,1109,1085,2543,1654,2034, 876, 78,2287,1482,1277, # 2176 + 861,1675,1083,1779, 724,2754, 454, 397,1132,1612,2332, 893, 672,1237, 257,2259, # 2192 +2370, 135,3384, 337,2244, 547, 352, 340, 709,2485,1400, 788,1138,2511, 540, 772, # 2208 +1682,2260,2272,2544,2013,1843,1902,4636,1999,1562,2288,4637,2201,1403,1533, 407, # 2224 + 576,3308,1254,2071, 978,3385, 170, 136,1201,3125,2664,3172,2394, 213, 912, 873, # 2240 +3603,1713,2202, 699,3604,3699, 813,3442, 493, 531,1054, 468,2907,1483, 304, 281, # 2256 +4112,1726,1252,2094, 339,2319,2130,2639, 756,1563,2944, 748, 571,2976,1588,2425, # 2272 +2715,1851,1460,2426,1528,1392,1973,3237, 288,3309, 685,3386, 296, 892,2716,2216, # 2288 +1570,2245, 722,1747,2217, 905,3238,1103,6135,1893,1441,1965, 251,1805,2371,3700, # 2304 +2601,1919,1078, 75,2182,1509,1592,1270,2640,4638,2152,6136,3310,3817, 524, 706, # 2320 +1075, 292,3818,1756,2602, 317, 98,3173,3605,3525,1844,2218,3819,2502, 814, 567, # 2336 + 385,2908,1534,6137, 534,1642,3239, 797,6138,1670,1529, 953,4323, 188,1071, 538, # 2352 + 178, 729,3240,2109,1226,1374,2000,2357,2977, 731,2468,1116,2014,2051,6139,1261, # 2368 +1593, 803,2859,2736,3443, 556, 682, 823,1541,6140,1369,2289,1706,2794, 845, 462, # 2384 +2603,2665,1361, 387, 162,2358,1740, 739,1770,1720,1304,1401,3241,1049, 627,1571, # 2400 +2427,3526,1877,3942,1852,1500, 431,1910,1503, 677, 297,2795, 286,1433,1038,1198, # 2416 +2290,1133,1596,4113,4639,2469,1510,1484,3943,6141,2442, 108, 712,4640,2372, 866, # 2432 +3701,2755,3242,1348, 834,1945,1408,3527,2395,3243,1811, 824, 994,1179,2110,1548, # 2448 +1453, 790,3003, 690,4324,4325,2832,2909,3820,1860,3821, 225,1748, 310, 346,1780, # 2464 +2470, 821,1993,2717,2796, 828, 877,3528,2860,2471,1702,2165,2910,2486,1789, 453, # 2480 + 359,2291,1676, 73,1164,1461,1127,3311, 421, 604, 314,1037, 589, 116,2487, 737, # 2496 + 837,1180, 111, 244, 735,6142,2261,1861,1362, 986, 523, 418, 581,2666,3822, 103, # 2512 + 855, 503,1414,1867,2488,1091, 657,1597, 979, 605,1316,4641,1021,2443,2078,2001, # 2528 +1209, 96, 587,2166,1032, 260,1072,2153, 173, 94, 226,3244, 819,2006,4642,4114, # 2544 +2203, 231,1744, 782, 97,2667, 786,3387, 887, 391, 442,2219,4326,1425,6143,2694, # 2560 + 633,1544,1202, 483,2015, 592,2052,1958,2472,1655, 419, 129,4327,3444,3312,1714, # 2576 +1257,3078,4328,1518,1098, 865,1310,1019,1885,1512,1734, 469,2444, 148, 773, 436, # 2592 +1815,1868,1128,1055,4329,1245,2756,3445,2154,1934,1039,4643, 579,1238, 932,2320, # 2608 + 353, 205, 801, 115,2428, 944,2321,1881, 399,2565,1211, 678, 766,3944, 335,2101, # 2624 +1459,1781,1402,3945,2737,2131,1010, 844, 981,1326,1013, 550,1816,1545,2620,1335, # 2640 +1008, 371,2881, 936,1419,1613,3529,1456,1395,2273,1834,2604,1317,2738,2503, 416, # 2656 +1643,4330, 806,1126, 229, 591,3946,1314,1981,1576,1837,1666, 347,1790, 977,3313, # 2672 + 764,2861,1853, 688,2429,1920,1462, 77, 595, 415,2002,3034, 798,1192,4115,6144, # 2688 +2978,4331,3035,2695,2582,2072,2566, 430,2430,1727, 842,1396,3947,3702, 613, 377, # 2704 + 278, 236,1417,3388,3314,3174, 757,1869, 107,3530,6145,1194, 623,2262, 207,1253, # 2720 +2167,3446,3948, 492,1117,1935, 536,1838,2757,1246,4332, 696,2095,2406,1393,1572, # 2736 +3175,1782, 583, 190, 253,1390,2230, 830,3126,3389, 934,3245,1703,1749,2979,1870, # 2752 +2545,1656,2204, 869,2346,4116,3176,1817, 496,1764,4644, 942,1504, 404,1903,1122, # 2768 +1580,3606,2945,1022, 515, 372,1735, 955,2431,3036,6146,2797,1110,2302,2798, 617, # 2784 +6147, 441, 762,1771,3447,3607,3608,1904, 840,3037, 86, 939,1385, 572,1370,2445, # 2800 +1336, 114,3703, 898, 294, 203,3315, 703,1583,2274, 429, 961,4333,1854,1951,3390, # 2816 +2373,3704,4334,1318,1381, 966,1911,2322,1006,1155, 309, 989, 458,2718,1795,1372, # 2832 +1203, 252,1689,1363,3177, 517,1936, 168,1490, 562, 193,3823,1042,4117,1835, 551, # 2848 + 470,4645, 395, 489,3448,1871,1465,2583,2641, 417,1493, 279,1295, 511,1236,1119, # 2864 + 72,1231,1982,1812,3004, 871,1564, 984,3449,1667,2696,2096,4646,2347,2833,1673, # 2880 +3609, 695,3246,2668, 807,1183,4647, 890, 388,2333,1801,1457,2911,1765,1477,1031, # 2896 +3316,3317,1278,3391,2799,2292,2526, 163,3450,4335,2669,1404,1802,6148,2323,2407, # 2912 +1584,1728,1494,1824,1269, 298, 909,3318,1034,1632, 375, 776,1683,2061, 291, 210, # 2928 +1123, 809,1249,1002,2642,3038, 206,1011,2132, 144, 975, 882,1565, 342, 667, 754, # 2944 +1442,2143,1299,2303,2062, 447, 626,2205,1221,2739,2912,1144,1214,2206,2584, 760, # 2960 +1715, 614, 950,1281,2670,2621, 810, 577,1287,2546,4648, 242,2168, 250,2643, 691, # 2976 + 123,2644, 647, 313,1029, 689,1357,2946,1650, 216, 771,1339,1306, 808,2063, 549, # 2992 + 913,1371,2913,2914,6149,1466,1092,1174,1196,1311,2605,2396,1783,1796,3079, 406, # 3008 +2671,2117,3949,4649, 487,1825,2220,6150,2915, 448,2348,1073,6151,2397,1707, 130, # 3024 + 900,1598, 329, 176,1959,2527,1620,6152,2275,4336,3319,1983,2191,3705,3610,2155, # 3040 +3706,1912,1513,1614,6153,1988, 646, 392,2304,1589,3320,3039,1826,1239,1352,1340, # 3056 +2916, 505,2567,1709,1437,2408,2547, 906,6154,2672, 384,1458,1594,1100,1329, 710, # 3072 + 423,3531,2064,2231,2622,1989,2673,1087,1882, 333, 841,3005,1296,2882,2379, 580, # 3088 +1937,1827,1293,2585, 601, 574, 249,1772,4118,2079,1120, 645, 901,1176,1690, 795, # 3104 +2207, 478,1434, 516,1190,1530, 761,2080, 930,1264, 355, 435,1552, 644,1791, 987, # 3120 + 220,1364,1163,1121,1538, 306,2169,1327,1222, 546,2645, 218, 241, 610,1704,3321, # 3136 +1984,1839,1966,2528, 451,6155,2586,3707,2568, 907,3178, 254,2947, 186,1845,4650, # 3152 + 745, 432,1757, 428,1633, 888,2246,2221,2489,3611,2118,1258,1265, 956,3127,1784, # 3168 +4337,2490, 319, 510, 119, 457,3612, 274,2035,2007,4651,1409,3128, 970,2758, 590, # 3184 +2800, 661,2247,4652,2008,3950,1420,1549,3080,3322,3951,1651,1375,2111, 485,2491, # 3200 +1429,1156,6156,2548,2183,1495, 831,1840,2529,2446, 501,1657, 307,1894,3247,1341, # 3216 + 666, 899,2156,1539,2549,1559, 886, 349,2208,3081,2305,1736,3824,2170,2759,1014, # 3232 +1913,1386, 542,1397,2948, 490, 368, 716, 362, 159, 282,2569,1129,1658,1288,1750, # 3248 +2674, 276, 649,2016, 751,1496, 658,1818,1284,1862,2209,2087,2512,3451, 622,2834, # 3264 + 376, 117,1060,2053,1208,1721,1101,1443, 247,1250,3179,1792,3952,2760,2398,3953, # 3280 +6157,2144,3708, 446,2432,1151,2570,3452,2447,2761,2835,1210,2448,3082, 424,2222, # 3296 +1251,2449,2119,2836, 504,1581,4338, 602, 817, 857,3825,2349,2306, 357,3826,1470, # 3312 +1883,2883, 255, 958, 929,2917,3248, 302,4653,1050,1271,1751,2307,1952,1430,2697, # 3328 +2719,2359, 354,3180, 777, 158,2036,4339,1659,4340,4654,2308,2949,2248,1146,2232, # 3344 +3532,2720,1696,2623,3827,6158,3129,1550,2698,1485,1297,1428, 637, 931,2721,2145, # 3360 + 914,2550,2587, 81,2450, 612, 827,2646,1242,4655,1118,2884, 472,1855,3181,3533, # 3376 +3534, 569,1353,2699,1244,1758,2588,4119,2009,2762,2171,3709,1312,1531,6159,1152, # 3392 +1938, 134,1830, 471,3710,2276,1112,1535,3323,3453,3535, 982,1337,2950, 488, 826, # 3408 + 674,1058,1628,4120,2017, 522,2399, 211, 568,1367,3454, 350, 293,1872,1139,3249, # 3424 +1399,1946,3006,1300,2360,3324, 588, 736,6160,2606, 744, 669,3536,3828,6161,1358, # 3440 + 199, 723, 848, 933, 851,1939,1505,1514,1338,1618,1831,4656,1634,3613, 443,2740, # 3456 +3829, 717,1947, 491,1914,6162,2551,1542,4121,1025,6163,1099,1223, 198,3040,2722, # 3472 + 370, 410,1905,2589, 998,1248,3182,2380, 519,1449,4122,1710, 947, 928,1153,4341, # 3488 +2277, 344,2624,1511, 615, 105, 161,1212,1076,1960,3130,2054,1926,1175,1906,2473, # 3504 + 414,1873,2801,6164,2309, 315,1319,3325, 318,2018,2146,2157, 963, 631, 223,4342, # 3520 +4343,2675, 479,3711,1197,2625,3712,2676,2361,6165,4344,4123,6166,2451,3183,1886, # 3536 +2184,1674,1330,1711,1635,1506, 799, 219,3250,3083,3954,1677,3713,3326,2081,3614, # 3552 +1652,2073,4657,1147,3041,1752, 643,1961, 147,1974,3955,6167,1716,2037, 918,3007, # 3568 +1994, 120,1537, 118, 609,3184,4345, 740,3455,1219, 332,1615,3830,6168,1621,2980, # 3584 +1582, 783, 212, 553,2350,3714,1349,2433,2082,4124, 889,6169,2310,1275,1410, 973, # 3600 + 166,1320,3456,1797,1215,3185,2885,1846,2590,2763,4658, 629, 822,3008, 763, 940, # 3616 +1990,2862, 439,2409,1566,1240,1622, 926,1282,1907,2764, 654,2210,1607, 327,1130, # 3632 +3956,1678,1623,6170,2434,2192, 686, 608,3831,3715, 903,3957,3042,6171,2741,1522, # 3648 +1915,1105,1555,2552,1359, 323,3251,4346,3457, 738,1354,2553,2311,2334,1828,2003, # 3664 +3832,1753,2351,1227,6172,1887,4125,1478,6173,2410,1874,1712,1847, 520,1204,2607, # 3680 + 264,4659, 836,2677,2102, 600,4660,3833,2278,3084,6174,4347,3615,1342, 640, 532, # 3696 + 543,2608,1888,2400,2591,1009,4348,1497, 341,1737,3616,2723,1394, 529,3252,1321, # 3712 + 983,4661,1515,2120, 971,2592, 924, 287,1662,3186,4349,2700,4350,1519, 908,1948, # 3728 +2452, 156, 796,1629,1486,2223,2055, 694,4126,1259,1036,3392,1213,2249,2742,1889, # 3744 +1230,3958,1015, 910, 408, 559,3617,4662, 746, 725, 935,4663,3959,3009,1289, 563, # 3760 + 867,4664,3960,1567,2981,2038,2626, 988,2263,2381,4351, 143,2374, 704,1895,6175, # 3776 +1188,3716,2088, 673,3085,2362,4352, 484,1608,1921,2765,2918, 215, 904,3618,3537, # 3792 + 894, 509, 976,3043,2701,3961,4353,2837,2982, 498,6176,6177,1102,3538,1332,3393, # 3808 +1487,1636,1637, 233, 245,3962, 383, 650, 995,3044, 460,1520,1206,2352, 749,3327, # 3824 + 530, 700, 389,1438,1560,1773,3963,2264, 719,2951,2724,3834, 870,1832,1644,1000, # 3840 + 839,2474,3717, 197,1630,3394, 365,2886,3964,1285,2133, 734, 922, 818,1106, 732, # 3856 + 480,2083,1774,3458, 923,2279,1350, 221,3086, 85,2233,2234,3835,1585,3010,2147, # 3872 +1387,1705,2382,1619,2475, 133, 239,2802,1991,1016,2084,2383, 411,2838,1113, 651, # 3888 +1985,1160,3328, 990,1863,3087,1048,1276,2647, 265,2627,1599,3253,2056, 150, 638, # 3904 +2019, 656, 853, 326,1479, 680,1439,4354,1001,1759, 413,3459,3395,2492,1431, 459, # 3920 +4355,1125,3329,2265,1953,1450,2065,2863, 849, 351,2678,3131,3254,3255,1104,1577, # 3936 + 227,1351,1645,2453,2193,1421,2887, 812,2121, 634, 95,2435, 201,2312,4665,1646, # 3952 +1671,2743,1601,2554,2702,2648,2280,1315,1366,2089,3132,1573,3718,3965,1729,1189, # 3968 + 328,2679,1077,1940,1136, 558,1283, 964,1195, 621,2074,1199,1743,3460,3619,1896, # 3984 +1916,1890,3836,2952,1154,2112,1064, 862, 378,3011,2066,2113,2803,1568,2839,6178, # 4000 +3088,2919,1941,1660,2004,1992,2194, 142, 707,1590,1708,1624,1922,1023,1836,1233, # 4016 +1004,2313, 789, 741,3620,6179,1609,2411,1200,4127,3719,3720,4666,2057,3721, 593, # 4032 +2840, 367,2920,1878,6180,3461,1521, 628,1168, 692,2211,2649, 300, 720,2067,2571, # 4048 +2953,3396, 959,2504,3966,3539,3462,1977, 701,6181, 954,1043, 800, 681, 183,3722, # 4064 +1803,1730,3540,4128,2103, 815,2314, 174, 467, 230,2454,1093,2134, 755,3541,3397, # 4080 +1141,1162,6182,1738,2039, 270,3256,2513,1005,1647,2185,3837, 858,1679,1897,1719, # 4096 +2954,2324,1806, 402, 670, 167,4129,1498,2158,2104, 750,6183, 915, 189,1680,1551, # 4112 + 455,4356,1501,2455, 405,1095,2955, 338,1586,1266,1819, 570, 641,1324, 237,1556, # 4128 +2650,1388,3723,6184,1368,2384,1343,1978,3089,2436, 879,3724, 792,1191, 758,3012, # 4144 +1411,2135,1322,4357, 240,4667,1848,3725,1574,6185, 420,3045,1546,1391, 714,4358, # 4160 +1967, 941,1864, 863, 664, 426, 560,1731,2680,1785,2864,1949,2363, 403,3330,1415, # 4176 +1279,2136,1697,2335, 204, 721,2097,3838, 90,6186,2085,2505, 191,3967, 124,2148, # 4192 +1376,1798,1178,1107,1898,1405, 860,4359,1243,1272,2375,2983,1558,2456,1638, 113, # 4208 +3621, 578,1923,2609, 880, 386,4130, 784,2186,2266,1422,2956,2172,1722, 497, 263, # 4224 +2514,1267,2412,2610, 177,2703,3542, 774,1927,1344, 616,1432,1595,1018, 172,4360, # 4240 +2325, 911,4361, 438,1468,3622, 794,3968,2024,2173,1681,1829,2957, 945, 895,3090, # 4256 + 575,2212,2476, 475,2401,2681, 785,2744,1745,2293,2555,1975,3133,2865, 394,4668, # 4272 +3839, 635,4131, 639, 202,1507,2195,2766,1345,1435,2572,3726,1908,1184,1181,2457, # 4288 +3727,3134,4362, 843,2611, 437, 916,4669, 234, 769,1884,3046,3047,3623, 833,6187, # 4304 +1639,2250,2402,1355,1185,2010,2047, 999, 525,1732,1290,1488,2612, 948,1578,3728, # 4320 +2413,2477,1216,2725,2159, 334,3840,1328,3624,2921,1525,4132, 564,1056, 891,4363, # 4336 +1444,1698,2385,2251,3729,1365,2281,2235,1717,6188, 864,3841,2515, 444, 527,2767, # 4352 +2922,3625, 544, 461,6189, 566, 209,2437,3398,2098,1065,2068,3331,3626,3257,2137, # 4368 #last 512 +#Everything below is of no interest for detection purpose +2138,2122,3730,2888,1995,1820,1044,6190,6191,6192,6193,6194,6195,6196,6197,6198, # 4384 +6199,6200,6201,6202,6203,6204,6205,4670,6206,6207,6208,6209,6210,6211,6212,6213, # 4400 +6214,6215,6216,6217,6218,6219,6220,6221,6222,6223,6224,6225,6226,6227,6228,6229, # 4416 +6230,6231,6232,6233,6234,6235,6236,6237,3187,6238,6239,3969,6240,6241,6242,6243, # 4432 +6244,4671,6245,6246,4672,6247,6248,4133,6249,6250,4364,6251,2923,2556,2613,4673, # 4448 +4365,3970,6252,6253,6254,6255,4674,6256,6257,6258,2768,2353,4366,4675,4676,3188, # 4464 +4367,3463,6259,4134,4677,4678,6260,2267,6261,3842,3332,4368,3543,6262,6263,6264, # 4480 +3013,1954,1928,4135,4679,6265,6266,2478,3091,6267,4680,4369,6268,6269,1699,6270, # 4496 +3544,4136,4681,6271,4137,6272,4370,2804,6273,6274,2593,3971,3972,4682,6275,2236, # 4512 +4683,6276,6277,4684,6278,6279,4138,3973,4685,6280,6281,3258,6282,6283,6284,6285, # 4528 +3974,4686,2841,3975,6286,6287,3545,6288,6289,4139,4687,4140,6290,4141,6291,4142, # 4544 +6292,6293,3333,6294,6295,6296,4371,6297,3399,6298,6299,4372,3976,6300,6301,6302, # 4560 +4373,6303,6304,3843,3731,6305,4688,4374,6306,6307,3259,2294,6308,3732,2530,4143, # 4576 +6309,4689,6310,6311,6312,3048,6313,6314,4690,3733,2237,6315,6316,2282,3334,6317, # 4592 +6318,3844,6319,6320,4691,6321,3400,4692,6322,4693,6323,3049,6324,4375,6325,3977, # 4608 +6326,6327,6328,3546,6329,4694,3335,6330,4695,4696,6331,6332,6333,6334,4376,3978, # 4624 +6335,4697,3979,4144,6336,3980,4698,6337,6338,6339,6340,6341,4699,4700,4701,6342, # 4640 +6343,4702,6344,6345,4703,6346,6347,4704,6348,4705,4706,3135,6349,4707,6350,4708, # 4656 +6351,4377,6352,4709,3734,4145,6353,2506,4710,3189,6354,3050,4711,3981,6355,3547, # 4672 +3014,4146,4378,3735,2651,3845,3260,3136,2224,1986,6356,3401,6357,4712,2594,3627, # 4688 +3137,2573,3736,3982,4713,3628,4714,4715,2682,3629,4716,6358,3630,4379,3631,6359, # 4704 +6360,6361,3983,6362,6363,6364,6365,4147,3846,4717,6366,6367,3737,2842,6368,4718, # 4720 +2628,6369,3261,6370,2386,6371,6372,3738,3984,4719,3464,4720,3402,6373,2924,3336, # 4736 +4148,2866,6374,2805,3262,4380,2704,2069,2531,3138,2806,2984,6375,2769,6376,4721, # 4752 +4722,3403,6377,6378,3548,6379,6380,2705,3092,1979,4149,2629,3337,2889,6381,3338, # 4768 +4150,2557,3339,4381,6382,3190,3263,3739,6383,4151,4723,4152,2558,2574,3404,3191, # 4784 +6384,6385,4153,6386,4724,4382,6387,6388,4383,6389,6390,4154,6391,4725,3985,6392, # 4800 +3847,4155,6393,6394,6395,6396,6397,3465,6398,4384,6399,6400,6401,6402,6403,6404, # 4816 +4156,6405,6406,6407,6408,2123,6409,6410,2326,3192,4726,6411,6412,6413,6414,4385, # 4832 +4157,6415,6416,4158,6417,3093,3848,6418,3986,6419,6420,3849,6421,6422,6423,4159, # 4848 +6424,6425,4160,6426,3740,6427,6428,6429,6430,3987,6431,4727,6432,2238,6433,6434, # 4864 +4386,3988,6435,6436,3632,6437,6438,2843,6439,6440,6441,6442,3633,6443,2958,6444, # 4880 +6445,3466,6446,2364,4387,3850,6447,4388,2959,3340,6448,3851,6449,4728,6450,6451, # 4896 +3264,4729,6452,3193,6453,4389,4390,2706,3341,4730,6454,3139,6455,3194,6456,3051, # 4912 +2124,3852,1602,4391,4161,3853,1158,3854,4162,3989,4392,3990,4731,4732,4393,2040, # 4928 +4163,4394,3265,6457,2807,3467,3855,6458,6459,6460,3991,3468,4733,4734,6461,3140, # 4944 +2960,6462,4735,6463,6464,6465,6466,4736,4737,4738,4739,6467,6468,4164,2403,3856, # 4960 +6469,6470,2770,2844,6471,4740,6472,6473,6474,6475,6476,6477,6478,3195,6479,4741, # 4976 +4395,6480,2867,6481,4742,2808,6482,2493,4165,6483,6484,6485,6486,2295,4743,6487, # 4992 +6488,6489,3634,6490,6491,6492,6493,6494,6495,6496,2985,4744,6497,6498,4745,6499, # 5008 +6500,2925,3141,4166,6501,6502,4746,6503,6504,4747,6505,6506,6507,2890,6508,6509, # 5024 +6510,6511,6512,6513,6514,6515,6516,6517,6518,6519,3469,4167,6520,6521,6522,4748, # 5040 +4396,3741,4397,4749,4398,3342,2125,4750,6523,4751,4752,4753,3052,6524,2961,4168, # 5056 +6525,4754,6526,4755,4399,2926,4169,6527,3857,6528,4400,4170,6529,4171,6530,6531, # 5072 +2595,6532,6533,6534,6535,3635,6536,6537,6538,6539,6540,6541,6542,4756,6543,6544, # 5088 +6545,6546,6547,6548,4401,6549,6550,6551,6552,4402,3405,4757,4403,6553,6554,6555, # 5104 +4172,3742,6556,6557,6558,3992,3636,6559,6560,3053,2726,6561,3549,4173,3054,4404, # 5120 +6562,6563,3993,4405,3266,3550,2809,4406,6564,6565,6566,4758,4759,6567,3743,6568, # 5136 +4760,3744,4761,3470,6569,6570,6571,4407,6572,3745,4174,6573,4175,2810,4176,3196, # 5152 +4762,6574,4177,6575,6576,2494,2891,3551,6577,6578,3471,6579,4408,6580,3015,3197, # 5168 +6581,3343,2532,3994,3858,6582,3094,3406,4409,6583,2892,4178,4763,4410,3016,4411, # 5184 +6584,3995,3142,3017,2683,6585,4179,6586,6587,4764,4412,6588,6589,4413,6590,2986, # 5200 +6591,2962,3552,6592,2963,3472,6593,6594,4180,4765,6595,6596,2225,3267,4414,6597, # 5216 +3407,3637,4766,6598,6599,3198,6600,4415,6601,3859,3199,6602,3473,4767,2811,4416, # 5232 +1856,3268,3200,2575,3996,3997,3201,4417,6603,3095,2927,6604,3143,6605,2268,6606, # 5248 +3998,3860,3096,2771,6607,6608,3638,2495,4768,6609,3861,6610,3269,2745,4769,4181, # 5264 +3553,6611,2845,3270,6612,6613,6614,3862,6615,6616,4770,4771,6617,3474,3999,4418, # 5280 +4419,6618,3639,3344,6619,4772,4182,6620,2126,6621,6622,6623,4420,4773,6624,3018, # 5296 +6625,4774,3554,6626,4183,2025,3746,6627,4184,2707,6628,4421,4422,3097,1775,4185, # 5312 +3555,6629,6630,2868,6631,6632,4423,6633,6634,4424,2414,2533,2928,6635,4186,2387, # 5328 +6636,4775,6637,4187,6638,1891,4425,3202,3203,6639,6640,4776,6641,3345,6642,6643, # 5344 +3640,6644,3475,3346,3641,4000,6645,3144,6646,3098,2812,4188,3642,3204,6647,3863, # 5360 +3476,6648,3864,6649,4426,4001,6650,6651,6652,2576,6653,4189,4777,6654,6655,6656, # 5376 +2846,6657,3477,3205,4002,6658,4003,6659,3347,2252,6660,6661,6662,4778,6663,6664, # 5392 +6665,6666,6667,6668,6669,4779,4780,2048,6670,3478,3099,6671,3556,3747,4004,6672, # 5408 +6673,6674,3145,4005,3748,6675,6676,6677,6678,6679,3408,6680,6681,6682,6683,3206, # 5424 +3207,6684,6685,4781,4427,6686,4782,4783,4784,6687,6688,6689,4190,6690,6691,3479, # 5440 +6692,2746,6693,4428,6694,6695,6696,6697,6698,6699,4785,6700,6701,3208,2727,6702, # 5456 +3146,6703,6704,3409,2196,6705,4429,6706,6707,6708,2534,1996,6709,6710,6711,2747, # 5472 +6712,6713,6714,4786,3643,6715,4430,4431,6716,3557,6717,4432,4433,6718,6719,6720, # 5488 +6721,3749,6722,4006,4787,6723,6724,3644,4788,4434,6725,6726,4789,2772,6727,6728, # 5504 +6729,6730,6731,2708,3865,2813,4435,6732,6733,4790,4791,3480,6734,6735,6736,6737, # 5520 +4436,3348,6738,3410,4007,6739,6740,4008,6741,6742,4792,3411,4191,6743,6744,6745, # 5536 +6746,6747,3866,6748,3750,6749,6750,6751,6752,6753,6754,6755,3867,6756,4009,6757, # 5552 +4793,4794,6758,2814,2987,6759,6760,6761,4437,6762,6763,6764,6765,3645,6766,6767, # 5568 +3481,4192,6768,3751,6769,6770,2174,6771,3868,3752,6772,6773,6774,4193,4795,4438, # 5584 +3558,4796,4439,6775,4797,6776,6777,4798,6778,4799,3559,4800,6779,6780,6781,3482, # 5600 +6782,2893,6783,6784,4194,4801,4010,6785,6786,4440,6787,4011,6788,6789,6790,6791, # 5616 +6792,6793,4802,6794,6795,6796,4012,6797,6798,6799,6800,3349,4803,3483,6801,4804, # 5632 +4195,6802,4013,6803,6804,4196,6805,4014,4015,6806,2847,3271,2848,6807,3484,6808, # 5648 +6809,6810,4441,6811,4442,4197,4443,3272,4805,6812,3412,4016,1579,6813,6814,4017, # 5664 +6815,3869,6816,2964,6817,4806,6818,6819,4018,3646,6820,6821,4807,4019,4020,6822, # 5680 +6823,3560,6824,6825,4021,4444,6826,4198,6827,6828,4445,6829,6830,4199,4808,6831, # 5696 +6832,6833,3870,3019,2458,6834,3753,3413,3350,6835,4809,3871,4810,3561,4446,6836, # 5712 +6837,4447,4811,4812,6838,2459,4448,6839,4449,6840,6841,4022,3872,6842,4813,4814, # 5728 +6843,6844,4815,4200,4201,4202,6845,4023,6846,6847,4450,3562,3873,6848,6849,4816, # 5744 +4817,6850,4451,4818,2139,6851,3563,6852,6853,3351,6854,6855,3352,4024,2709,3414, # 5760 +4203,4452,6856,4204,6857,6858,3874,3875,6859,6860,4819,6861,6862,6863,6864,4453, # 5776 +3647,6865,6866,4820,6867,6868,6869,6870,4454,6871,2869,6872,6873,4821,6874,3754, # 5792 +6875,4822,4205,6876,6877,6878,3648,4206,4455,6879,4823,6880,4824,3876,6881,3055, # 5808 +4207,6882,3415,6883,6884,6885,4208,4209,6886,4210,3353,6887,3354,3564,3209,3485, # 5824 +2652,6888,2728,6889,3210,3755,6890,4025,4456,6891,4825,6892,6893,6894,6895,4211, # 5840 +6896,6897,6898,4826,6899,6900,4212,6901,4827,6902,2773,3565,6903,4828,6904,6905, # 5856 +6906,6907,3649,3650,6908,2849,3566,6909,3567,3100,6910,6911,6912,6913,6914,6915, # 5872 +4026,6916,3355,4829,3056,4457,3756,6917,3651,6918,4213,3652,2870,6919,4458,6920, # 5888 +2438,6921,6922,3757,2774,4830,6923,3356,4831,4832,6924,4833,4459,3653,2507,6925, # 5904 +4834,2535,6926,6927,3273,4027,3147,6928,3568,6929,6930,6931,4460,6932,3877,4461, # 5920 +2729,3654,6933,6934,6935,6936,2175,4835,2630,4214,4028,4462,4836,4215,6937,3148, # 5936 +4216,4463,4837,4838,4217,6938,6939,2850,4839,6940,4464,6941,6942,6943,4840,6944, # 5952 +4218,3274,4465,6945,6946,2710,6947,4841,4466,6948,6949,2894,6950,6951,4842,6952, # 5968 +4219,3057,2871,6953,6954,6955,6956,4467,6957,2711,6958,6959,6960,3275,3101,4843, # 5984 +6961,3357,3569,6962,4844,6963,6964,4468,4845,3570,6965,3102,4846,3758,6966,4847, # 6000 +3878,4848,4849,4029,6967,2929,3879,4850,4851,6968,6969,1733,6970,4220,6971,6972, # 6016 +6973,6974,6975,6976,4852,6977,6978,6979,6980,6981,6982,3759,6983,6984,6985,3486, # 6032 +3487,6986,3488,3416,6987,6988,6989,6990,6991,6992,6993,6994,6995,6996,6997,4853, # 6048 +6998,6999,4030,7000,7001,3211,7002,7003,4221,7004,7005,3571,4031,7006,3572,7007, # 6064 +2614,4854,2577,7008,7009,2965,3655,3656,4855,2775,3489,3880,4222,4856,3881,4032, # 6080 +3882,3657,2730,3490,4857,7010,3149,7011,4469,4858,2496,3491,4859,2283,7012,7013, # 6096 +7014,2365,4860,4470,7015,7016,3760,7017,7018,4223,1917,7019,7020,7021,4471,7022, # 6112 +2776,4472,7023,7024,7025,7026,4033,7027,3573,4224,4861,4034,4862,7028,7029,1929, # 6128 +3883,4035,7030,4473,3058,7031,2536,3761,3884,7032,4036,7033,2966,2895,1968,4474, # 6144 +3276,4225,3417,3492,4226,2105,7034,7035,1754,2596,3762,4227,4863,4475,3763,4864, # 6160 +3764,2615,2777,3103,3765,3658,3418,4865,2296,3766,2815,7036,7037,7038,3574,2872, # 6176 +3277,4476,7039,4037,4477,7040,7041,4038,7042,7043,7044,7045,7046,7047,2537,7048, # 6192 +7049,7050,7051,7052,7053,7054,4478,7055,7056,3767,3659,4228,3575,7057,7058,4229, # 6208 +7059,7060,7061,3660,7062,3212,7063,3885,4039,2460,7064,7065,7066,7067,7068,7069, # 6224 +7070,7071,7072,7073,7074,4866,3768,4867,7075,7076,7077,7078,4868,3358,3278,2653, # 6240 +7079,7080,4479,3886,7081,7082,4869,7083,7084,7085,7086,7087,7088,2538,7089,7090, # 6256 +7091,4040,3150,3769,4870,4041,2896,3359,4230,2930,7092,3279,7093,2967,4480,3213, # 6272 +4481,3661,7094,7095,7096,7097,7098,7099,7100,7101,7102,2461,3770,7103,7104,4231, # 6288 +3151,7105,7106,7107,4042,3662,7108,7109,4871,3663,4872,4043,3059,7110,7111,7112, # 6304 +3493,2988,7113,4873,7114,7115,7116,3771,4874,7117,7118,4232,4875,7119,3576,2336, # 6320 +4876,7120,4233,3419,4044,4877,4878,4482,4483,4879,4484,4234,7121,3772,4880,1045, # 6336 +3280,3664,4881,4882,7122,7123,7124,7125,4883,7126,2778,7127,4485,4486,7128,4884, # 6352 +3214,3887,7129,7130,3215,7131,4885,4045,7132,7133,4046,7134,7135,7136,7137,7138, # 6368 +7139,7140,7141,7142,7143,4235,7144,4886,7145,7146,7147,4887,7148,7149,7150,4487, # 6384 +4047,4488,7151,7152,4888,4048,2989,3888,7153,3665,7154,4049,7155,7156,7157,7158, # 6400 +7159,7160,2931,4889,4890,4489,7161,2631,3889,4236,2779,7162,7163,4891,7164,3060, # 6416 +7165,1672,4892,7166,4893,4237,3281,4894,7167,7168,3666,7169,3494,7170,7171,4050, # 6432 +7172,7173,3104,3360,3420,4490,4051,2684,4052,7174,4053,7175,7176,7177,2253,4054, # 6448 +7178,7179,4895,7180,3152,3890,3153,4491,3216,7181,7182,7183,2968,4238,4492,4055, # 6464 +7184,2990,7185,2479,7186,7187,4493,7188,7189,7190,7191,7192,4896,7193,4897,2969, # 6480 +4494,4898,7194,3495,7195,7196,4899,4495,7197,3105,2731,7198,4900,7199,7200,7201, # 6496 +4056,7202,3361,7203,7204,4496,4901,4902,7205,4497,7206,7207,2315,4903,7208,4904, # 6512 +7209,4905,2851,7210,7211,3577,7212,3578,4906,7213,4057,3667,4907,7214,4058,2354, # 6528 +3891,2376,3217,3773,7215,7216,7217,7218,7219,4498,7220,4908,3282,2685,7221,3496, # 6544 +4909,2632,3154,4910,7222,2337,7223,4911,7224,7225,7226,4912,4913,3283,4239,4499, # 6560 +7227,2816,7228,7229,7230,7231,7232,7233,7234,4914,4500,4501,7235,7236,7237,2686, # 6576 +7238,4915,7239,2897,4502,7240,4503,7241,2516,7242,4504,3362,3218,7243,7244,7245, # 6592 +4916,7246,7247,4505,3363,7248,7249,7250,7251,3774,4506,7252,7253,4917,7254,7255, # 6608 +3284,2991,4918,4919,3219,3892,4920,3106,3497,4921,7256,7257,7258,4922,7259,4923, # 6624 +3364,4507,4508,4059,7260,4240,3498,7261,7262,4924,7263,2992,3893,4060,3220,7264, # 6640 +7265,7266,7267,7268,7269,4509,3775,7270,2817,7271,4061,4925,4510,3776,7272,4241, # 6656 +4511,3285,7273,7274,3499,7275,7276,7277,4062,4512,4926,7278,3107,3894,7279,7280, # 6672 +4927,7281,4513,7282,7283,3668,7284,7285,4242,4514,4243,7286,2058,4515,4928,4929, # 6688 +4516,7287,3286,4244,7288,4517,7289,7290,7291,3669,7292,7293,4930,4931,4932,2355, # 6704 +4933,7294,2633,4518,7295,4245,7296,7297,4519,7298,7299,4520,4521,4934,7300,4246, # 6720 +4522,7301,7302,7303,3579,7304,4247,4935,7305,4936,7306,7307,7308,7309,3777,7310, # 6736 +4523,7311,7312,7313,4248,3580,7314,4524,3778,4249,7315,3581,7316,3287,7317,3221, # 6752 +7318,4937,7319,7320,7321,7322,7323,7324,4938,4939,7325,4525,7326,7327,7328,4063, # 6768 +7329,7330,4940,7331,7332,4941,7333,4526,7334,3500,2780,1741,4942,2026,1742,7335, # 6784 +7336,3582,4527,2388,7337,7338,7339,4528,7340,4250,4943,7341,7342,7343,4944,7344, # 6800 +7345,7346,3020,7347,4945,7348,7349,7350,7351,3895,7352,3896,4064,3897,7353,7354, # 6816 +7355,4251,7356,7357,3898,7358,3779,7359,3780,3288,7360,7361,4529,7362,4946,4530, # 6832 +2027,7363,3899,4531,4947,3222,3583,7364,4948,7365,7366,7367,7368,4949,3501,4950, # 6848 +3781,4951,4532,7369,2517,4952,4252,4953,3155,7370,4954,4955,4253,2518,4533,7371, # 6864 +7372,2712,4254,7373,7374,7375,3670,4956,3671,7376,2389,3502,4065,7377,2338,7378, # 6880 +7379,7380,7381,3061,7382,4957,7383,7384,7385,7386,4958,4534,7387,7388,2993,7389, # 6896 +3062,7390,4959,7391,7392,7393,4960,3108,4961,7394,4535,7395,4962,3421,4536,7396, # 6912 +4963,7397,4964,1857,7398,4965,7399,7400,2176,3584,4966,7401,7402,3422,4537,3900, # 6928 +3585,7403,3782,7404,2852,7405,7406,7407,4538,3783,2654,3423,4967,4539,7408,3784, # 6944 +3586,2853,4540,4541,7409,3901,7410,3902,7411,7412,3785,3109,2327,3903,7413,7414, # 6960 +2970,4066,2932,7415,7416,7417,3904,3672,3424,7418,4542,4543,4544,7419,4968,7420, # 6976 +7421,4255,7422,7423,7424,7425,7426,4067,7427,3673,3365,4545,7428,3110,2559,3674, # 6992 +7429,7430,3156,7431,7432,3503,7433,3425,4546,7434,3063,2873,7435,3223,4969,4547, # 7008 +4548,2898,4256,4068,7436,4069,3587,3786,2933,3787,4257,4970,4971,3788,7437,4972, # 7024 +3064,7438,4549,7439,7440,7441,7442,7443,4973,3905,7444,2874,7445,7446,7447,7448, # 7040 +3021,7449,4550,3906,3588,4974,7450,7451,3789,3675,7452,2578,7453,4070,7454,7455, # 7056 +7456,4258,3676,7457,4975,7458,4976,4259,3790,3504,2634,4977,3677,4551,4260,7459, # 7072 +7460,7461,7462,3907,4261,4978,7463,7464,7465,7466,4979,4980,7467,7468,2213,4262, # 7088 +7469,7470,7471,3678,4981,7472,2439,7473,4263,3224,3289,7474,3908,2415,4982,7475, # 7104 +4264,7476,4983,2655,7477,7478,2732,4552,2854,2875,7479,7480,4265,7481,4553,4984, # 7120 +7482,7483,4266,7484,3679,3366,3680,2818,2781,2782,3367,3589,4554,3065,7485,4071, # 7136 +2899,7486,7487,3157,2462,4072,4555,4073,4985,4986,3111,4267,2687,3368,4556,4074, # 7152 +3791,4268,7488,3909,2783,7489,2656,1962,3158,4557,4987,1963,3159,3160,7490,3112, # 7168 +4988,4989,3022,4990,4991,3792,2855,7491,7492,2971,4558,7493,7494,4992,7495,7496, # 7184 +7497,7498,4993,7499,3426,4559,4994,7500,3681,4560,4269,4270,3910,7501,4075,4995, # 7200 +4271,7502,7503,4076,7504,4996,7505,3225,4997,4272,4077,2819,3023,7506,7507,2733, # 7216 +4561,7508,4562,7509,3369,3793,7510,3590,2508,7511,7512,4273,3113,2994,2616,7513, # 7232 +7514,7515,7516,7517,7518,2820,3911,4078,2748,7519,7520,4563,4998,7521,7522,7523, # 7248 +7524,4999,4274,7525,4564,3682,2239,4079,4565,7526,7527,7528,7529,5000,7530,7531, # 7264 +5001,4275,3794,7532,7533,7534,3066,5002,4566,3161,7535,7536,4080,7537,3162,7538, # 7280 +7539,4567,7540,7541,7542,7543,7544,7545,5003,7546,4568,7547,7548,7549,7550,7551, # 7296 +7552,7553,7554,7555,7556,5004,7557,7558,7559,5005,7560,3795,7561,4569,7562,7563, # 7312 +7564,2821,3796,4276,4277,4081,7565,2876,7566,5006,7567,7568,2900,7569,3797,3912, # 7328 +7570,7571,7572,4278,7573,7574,7575,5007,7576,7577,5008,7578,7579,4279,2934,7580, # 7344 +7581,5009,7582,4570,7583,4280,7584,7585,7586,4571,4572,3913,7587,4573,3505,7588, # 7360 +5010,7589,7590,7591,7592,3798,4574,7593,7594,5011,7595,4281,7596,7597,7598,4282, # 7376 +5012,7599,7600,5013,3163,7601,5014,7602,3914,7603,7604,2734,4575,4576,4577,7605, # 7392 +7606,7607,7608,7609,3506,5015,4578,7610,4082,7611,2822,2901,2579,3683,3024,4579, # 7408 +3507,7612,4580,7613,3226,3799,5016,7614,7615,7616,7617,7618,7619,7620,2995,3290, # 7424 +7621,4083,7622,5017,7623,7624,7625,7626,7627,4581,3915,7628,3291,7629,5018,7630, # 7440 +7631,7632,7633,4084,7634,7635,3427,3800,7636,7637,4582,7638,5019,4583,5020,7639, # 7456 +3916,7640,3801,5021,4584,4283,7641,7642,3428,3591,2269,7643,2617,7644,4585,3592, # 7472 +7645,4586,2902,7646,7647,3227,5022,7648,4587,7649,4284,7650,7651,7652,4588,2284, # 7488 +7653,5023,7654,7655,7656,4589,5024,3802,7657,7658,5025,3508,4590,7659,7660,7661, # 7504 +1969,5026,7662,7663,3684,1821,2688,7664,2028,2509,4285,7665,2823,1841,7666,2689, # 7520 +3114,7667,3917,4085,2160,5027,5028,2972,7668,5029,7669,7670,7671,3593,4086,7672, # 7536 +4591,4087,5030,3803,7673,7674,7675,7676,7677,7678,7679,4286,2366,4592,4593,3067, # 7552 +2328,7680,7681,4594,3594,3918,2029,4287,7682,5031,3919,3370,4288,4595,2856,7683, # 7568 +3509,7684,7685,5032,5033,7686,7687,3804,2784,7688,7689,7690,7691,3371,7692,7693, # 7584 +2877,5034,7694,7695,3920,4289,4088,7696,7697,7698,5035,7699,5036,4290,5037,5038, # 7600 +5039,7700,7701,7702,5040,5041,3228,7703,1760,7704,5042,3229,4596,2106,4089,7705, # 7616 +4597,2824,5043,2107,3372,7706,4291,4090,5044,7707,4091,7708,5045,3025,3805,4598, # 7632 +4292,4293,4294,3373,7709,4599,7710,5046,7711,7712,5047,5048,3806,7713,7714,7715, # 7648 +5049,7716,7717,7718,7719,4600,5050,7720,7721,7722,5051,7723,4295,3429,7724,7725, # 7664 +7726,7727,3921,7728,3292,5052,4092,7729,7730,7731,7732,7733,7734,7735,5053,5054, # 7680 +7736,7737,7738,7739,3922,3685,7740,7741,7742,7743,2635,5055,7744,5056,4601,7745, # 7696 +7746,2560,7747,7748,7749,7750,3923,7751,7752,7753,7754,7755,4296,2903,7756,7757, # 7712 +7758,7759,7760,3924,7761,5057,4297,7762,7763,5058,4298,7764,4093,7765,7766,5059, # 7728 +3925,7767,7768,7769,7770,7771,7772,7773,7774,7775,7776,3595,7777,4299,5060,4094, # 7744 +7778,3293,5061,7779,7780,4300,7781,7782,4602,7783,3596,7784,7785,3430,2367,7786, # 7760 +3164,5062,5063,4301,7787,7788,4095,5064,5065,7789,3374,3115,7790,7791,7792,7793, # 7776 +7794,7795,7796,3597,4603,7797,7798,3686,3116,3807,5066,7799,7800,5067,7801,7802, # 7792 +4604,4302,5068,4303,4096,7803,7804,3294,7805,7806,5069,4605,2690,7807,3026,7808, # 7808 +7809,7810,7811,7812,7813,7814,7815,7816,7817,7818,7819,7820,7821,7822,7823,7824, # 7824 +7825,7826,7827,7828,7829,7830,7831,7832,7833,7834,7835,7836,7837,7838,7839,7840, # 7840 +7841,7842,7843,7844,7845,7846,7847,7848,7849,7850,7851,7852,7853,7854,7855,7856, # 7856 +7857,7858,7859,7860,7861,7862,7863,7864,7865,7866,7867,7868,7869,7870,7871,7872, # 7872 +7873,7874,7875,7876,7877,7878,7879,7880,7881,7882,7883,7884,7885,7886,7887,7888, # 7888 +7889,7890,7891,7892,7893,7894,7895,7896,7897,7898,7899,7900,7901,7902,7903,7904, # 7904 +7905,7906,7907,7908,7909,7910,7911,7912,7913,7914,7915,7916,7917,7918,7919,7920, # 7920 +7921,7922,7923,7924,3926,7925,7926,7927,7928,7929,7930,7931,7932,7933,7934,7935, # 7936 +7936,7937,7938,7939,7940,7941,7942,7943,7944,7945,7946,7947,7948,7949,7950,7951, # 7952 +7952,7953,7954,7955,7956,7957,7958,7959,7960,7961,7962,7963,7964,7965,7966,7967, # 7968 +7968,7969,7970,7971,7972,7973,7974,7975,7976,7977,7978,7979,7980,7981,7982,7983, # 7984 +7984,7985,7986,7987,7988,7989,7990,7991,7992,7993,7994,7995,7996,7997,7998,7999, # 8000 +8000,8001,8002,8003,8004,8005,8006,8007,8008,8009,8010,8011,8012,8013,8014,8015, # 8016 +8016,8017,8018,8019,8020,8021,8022,8023,8024,8025,8026,8027,8028,8029,8030,8031, # 8032 +8032,8033,8034,8035,8036,8037,8038,8039,8040,8041,8042,8043,8044,8045,8046,8047, # 8048 +8048,8049,8050,8051,8052,8053,8054,8055,8056,8057,8058,8059,8060,8061,8062,8063, # 8064 +8064,8065,8066,8067,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079, # 8080 +8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095, # 8096 +8096,8097,8098,8099,8100,8101,8102,8103,8104,8105,8106,8107,8108,8109,8110,8111, # 8112 +8112,8113,8114,8115,8116,8117,8118,8119,8120,8121,8122,8123,8124,8125,8126,8127, # 8128 +8128,8129,8130,8131,8132,8133,8134,8135,8136,8137,8138,8139,8140,8141,8142,8143, # 8144 +8144,8145,8146,8147,8148,8149,8150,8151,8152,8153,8154,8155,8156,8157,8158,8159, # 8160 +8160,8161,8162,8163,8164,8165,8166,8167,8168,8169,8170,8171,8172,8173,8174,8175, # 8176 +8176,8177,8178,8179,8180,8181,8182,8183,8184,8185,8186,8187,8188,8189,8190,8191, # 8192 +8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8203,8204,8205,8206,8207, # 8208 +8208,8209,8210,8211,8212,8213,8214,8215,8216,8217,8218,8219,8220,8221,8222,8223, # 8224 +8224,8225,8226,8227,8228,8229,8230,8231,8232,8233,8234,8235,8236,8237,8238,8239, # 8240 +8240,8241,8242,8243,8244,8245,8246,8247,8248,8249,8250,8251,8252,8253,8254,8255, # 8256 +8256,8257,8258,8259,8260,8261,8262,8263,8264,8265,8266,8267,8268,8269,8270,8271) # 8272 diff --git a/libs/requests/packages/chardet2/jpcntx.py b/libs/requests/packages/chardet2/jpcntx.py new file mode 100644 index 00000000..ec3303d6 --- /dev/null +++ b/libs/requests/packages/chardet2/jpcntx.py @@ -0,0 +1,210 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants + +NUM_OF_CATEGORY = 6 +DONT_KNOW = -1 +ENOUGH_REL_THRESHOLD = 100 +MAX_REL_THRESHOLD = 1000 +MINIMUM_DATA_THRESHOLD = 4 + +# This is hiragana 2-char sequence table, the number in each cell represents its frequency category +jp2CharContext = ( \ +(0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1), +(2,4,0,4,0,3,0,4,0,3,4,4,4,2,4,3,3,4,3,2,3,3,4,2,3,3,3,2,4,1,4,3,3,1,5,4,3,4,3,4,3,5,3,0,3,5,4,2,0,3,1,0,3,3,0,3,3,0,1,1,0,4,3,0,3,3,0,4,0,2,0,3,5,5,5,5,4,0,4,1,0,3,4), +(0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2), +(0,4,0,5,0,5,0,4,0,4,5,4,4,3,5,3,5,1,5,3,4,3,4,4,3,4,3,3,4,3,5,4,4,3,5,5,3,5,5,5,3,5,5,3,4,5,5,3,1,3,2,0,3,4,0,4,2,0,4,2,1,5,3,2,3,5,0,4,0,2,0,5,4,4,5,4,5,0,4,0,0,4,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,4,0,3,0,3,0,4,5,4,3,3,3,3,4,3,5,4,4,3,5,4,4,3,4,3,4,4,4,4,5,3,4,4,3,4,5,5,4,5,5,1,4,5,4,3,0,3,3,1,3,3,0,4,4,0,3,3,1,5,3,3,3,5,0,4,0,3,0,4,4,3,4,3,3,0,4,1,1,3,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,4,0,3,0,3,0,4,0,3,4,4,3,2,2,1,2,1,3,1,3,3,3,3,3,4,3,1,3,3,5,3,3,0,4,3,0,5,4,3,3,5,4,4,3,4,4,5,0,1,2,0,1,2,0,2,2,0,1,0,0,5,2,2,1,4,0,3,0,1,0,4,4,3,5,4,3,0,2,1,0,4,3), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,5,0,4,0,2,1,4,4,2,4,1,4,2,4,2,4,3,3,3,4,3,3,3,3,1,4,2,3,3,3,1,4,4,1,1,1,4,3,3,2,0,2,4,3,2,0,3,3,0,3,1,1,0,0,0,3,3,0,4,2,2,3,4,0,4,0,3,0,4,4,5,3,4,4,0,3,0,0,1,4), +(1,4,0,4,0,4,0,4,0,3,5,4,4,3,4,3,5,4,3,3,4,3,5,4,4,4,4,3,4,2,4,3,3,1,5,4,3,2,4,5,4,5,5,4,4,5,4,4,0,3,2,2,3,3,0,4,3,1,3,2,1,4,3,3,4,5,0,3,0,2,0,4,5,5,4,5,4,0,4,0,0,5,4), +(0,5,0,5,0,4,0,3,0,4,4,3,4,3,3,3,4,0,4,4,4,3,4,3,4,3,3,1,4,2,4,3,4,0,5,4,1,4,5,4,4,5,3,2,4,3,4,3,2,4,1,3,3,3,2,3,2,0,4,3,3,4,3,3,3,4,0,4,0,3,0,4,5,4,4,4,3,0,4,1,0,1,3), +(0,3,1,4,0,3,0,2,0,3,4,4,3,1,4,2,3,3,4,3,4,3,4,3,4,4,3,2,3,1,5,4,4,1,4,4,3,5,4,4,3,5,5,4,3,4,4,3,1,2,3,1,2,2,0,3,2,0,3,1,0,5,3,3,3,4,3,3,3,3,4,4,4,4,5,4,2,0,3,3,2,4,3), +(0,2,0,3,0,1,0,1,0,0,3,2,0,0,2,0,1,0,2,1,3,3,3,1,2,3,1,0,1,0,4,2,1,1,3,3,0,4,3,3,1,4,3,3,0,3,3,2,0,0,0,0,1,0,0,2,0,0,0,0,0,4,1,0,2,3,2,2,2,1,3,3,3,4,4,3,2,0,3,1,0,3,3), +(0,4,0,4,0,3,0,3,0,4,4,4,3,3,3,3,3,3,4,3,4,2,4,3,4,3,3,2,4,3,4,5,4,1,4,5,3,5,4,5,3,5,4,0,3,5,5,3,1,3,3,2,2,3,0,3,4,1,3,3,2,4,3,3,3,4,0,4,0,3,0,4,5,4,4,5,3,0,4,1,0,3,4), +(0,2,0,3,0,3,0,0,0,2,2,2,1,0,1,0,0,0,3,0,3,0,3,0,1,3,1,0,3,1,3,3,3,1,3,3,3,0,1,3,1,3,4,0,0,3,1,1,0,3,2,0,0,0,0,1,3,0,1,0,0,3,3,2,0,3,0,0,0,0,0,3,4,3,4,3,3,0,3,0,0,2,3), +(2,3,0,3,0,2,0,1,0,3,3,4,3,1,3,1,1,1,3,1,4,3,4,3,3,3,0,0,3,1,5,4,3,1,4,3,2,5,5,4,4,4,4,3,3,4,4,4,0,2,1,1,3,2,0,1,2,0,0,1,0,4,1,3,3,3,0,3,0,1,0,4,4,4,5,5,3,0,2,0,0,4,4), +(0,2,0,1,0,3,1,3,0,2,3,3,3,0,3,1,0,0,3,0,3,2,3,1,3,2,1,1,0,0,4,2,1,0,2,3,1,4,3,2,0,4,4,3,1,3,1,3,0,1,0,0,1,0,0,0,1,0,0,0,0,4,1,1,1,2,0,3,0,0,0,3,4,2,4,3,2,0,1,0,0,3,3), +(0,1,0,4,0,5,0,4,0,2,4,4,2,3,3,2,3,3,5,3,3,3,4,3,4,2,3,0,4,3,3,3,4,1,4,3,2,1,5,5,3,4,5,1,3,5,4,2,0,3,3,0,1,3,0,4,2,0,1,3,1,4,3,3,3,3,0,3,0,1,0,3,4,4,4,5,5,0,3,0,1,4,5), +(0,2,0,3,0,3,0,0,0,2,3,1,3,0,4,0,1,1,3,0,3,4,3,2,3,1,0,3,3,2,3,1,3,0,2,3,0,2,1,4,1,2,2,0,0,3,3,0,0,2,0,0,0,1,0,0,0,0,2,2,0,3,2,1,3,3,0,2,0,2,0,0,3,3,1,2,4,0,3,0,2,2,3), +(2,4,0,5,0,4,0,4,0,2,4,4,4,3,4,3,3,3,1,2,4,3,4,3,4,4,5,0,3,3,3,3,2,0,4,3,1,4,3,4,1,4,4,3,3,4,4,3,1,2,3,0,4,2,0,4,1,0,3,3,0,4,3,3,3,4,0,4,0,2,0,3,5,3,4,5,2,0,3,0,0,4,5), +(0,3,0,4,0,1,0,1,0,1,3,2,2,1,3,0,3,0,2,0,2,0,3,0,2,0,0,0,1,0,1,1,0,0,3,1,0,0,0,4,0,3,1,0,2,1,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,4,2,2,3,1,0,3,0,0,0,1,4,4,4,3,0,0,4,0,0,1,4), +(1,4,1,5,0,3,0,3,0,4,5,4,4,3,5,3,3,4,4,3,4,1,3,3,3,3,2,1,4,1,5,4,3,1,4,4,3,5,4,4,3,5,4,3,3,4,4,4,0,3,3,1,2,3,0,3,1,0,3,3,0,5,4,4,4,4,4,4,3,3,5,4,4,3,3,5,4,0,3,2,0,4,4), +(0,2,0,3,0,1,0,0,0,1,3,3,3,2,4,1,3,0,3,1,3,0,2,2,1,1,0,0,2,0,4,3,1,0,4,3,0,4,4,4,1,4,3,1,1,3,3,1,0,2,0,0,1,3,0,0,0,0,2,0,0,4,3,2,4,3,5,4,3,3,3,4,3,3,4,3,3,0,2,1,0,3,3), +(0,2,0,4,0,3,0,2,0,2,5,5,3,4,4,4,4,1,4,3,3,0,4,3,4,3,1,3,3,2,4,3,0,3,4,3,0,3,4,4,2,4,4,0,4,5,3,3,2,2,1,1,1,2,0,1,5,0,3,3,2,4,3,3,3,4,0,3,0,2,0,4,4,3,5,5,0,0,3,0,2,3,3), +(0,3,0,4,0,3,0,1,0,3,4,3,3,1,3,3,3,0,3,1,3,0,4,3,3,1,1,0,3,0,3,3,0,0,4,4,0,1,5,4,3,3,5,0,3,3,4,3,0,2,0,1,1,1,0,1,3,0,1,2,1,3,3,2,3,3,0,3,0,1,0,1,3,3,4,4,1,0,1,2,2,1,3), +(0,1,0,4,0,4,0,3,0,1,3,3,3,2,3,1,1,0,3,0,3,3,4,3,2,4,2,0,1,0,4,3,2,0,4,3,0,5,3,3,2,4,4,4,3,3,3,4,0,1,3,0,0,1,0,0,1,0,0,0,0,4,2,3,3,3,0,3,0,0,0,4,4,4,5,3,2,0,3,3,0,3,5), +(0,2,0,3,0,0,0,3,0,1,3,0,2,0,0,0,1,0,3,1,1,3,3,0,0,3,0,0,3,0,2,3,1,0,3,1,0,3,3,2,0,4,2,2,0,2,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,2,1,2,0,1,0,1,0,0,0,1,3,1,2,0,0,0,1,0,0,1,4), +(0,3,0,3,0,5,0,1,0,2,4,3,1,3,3,2,1,1,5,2,1,0,5,1,2,0,0,0,3,3,2,2,3,2,4,3,0,0,3,3,1,3,3,0,2,5,3,4,0,3,3,0,1,2,0,2,2,0,3,2,0,2,2,3,3,3,0,2,0,1,0,3,4,4,2,5,4,0,3,0,0,3,5), +(0,3,0,3,0,3,0,1,0,3,3,3,3,0,3,0,2,0,2,1,1,0,2,0,1,0,0,0,2,1,0,0,1,0,3,2,0,0,3,3,1,2,3,1,0,3,3,0,0,1,0,0,0,0,0,2,0,0,0,0,0,2,3,1,2,3,0,3,0,1,0,3,2,1,0,4,3,0,1,1,0,3,3), +(0,4,0,5,0,3,0,3,0,4,5,5,4,3,5,3,4,3,5,3,3,2,5,3,4,4,4,3,4,3,4,5,5,3,4,4,3,4,4,5,4,4,4,3,4,5,5,4,2,3,4,2,3,4,0,3,3,1,4,3,2,4,3,3,5,5,0,3,0,3,0,5,5,5,5,4,4,0,4,0,1,4,4), +(0,4,0,4,0,3,0,3,0,3,5,4,4,2,3,2,5,1,3,2,5,1,4,2,3,2,3,3,4,3,3,3,3,2,5,4,1,3,3,5,3,4,4,0,4,4,3,1,1,3,1,0,2,3,0,2,3,0,3,0,0,4,3,1,3,4,0,3,0,2,0,4,4,4,3,4,5,0,4,0,0,3,4), +(0,3,0,3,0,3,1,2,0,3,4,4,3,3,3,0,2,2,4,3,3,1,3,3,3,1,1,0,3,1,4,3,2,3,4,4,2,4,4,4,3,4,4,3,2,4,4,3,1,3,3,1,3,3,0,4,1,0,2,2,1,4,3,2,3,3,5,4,3,3,5,4,4,3,3,0,4,0,3,2,2,4,4), +(0,2,0,1,0,0,0,0,0,1,2,1,3,0,0,0,0,0,2,0,1,2,1,0,0,1,0,0,0,0,3,0,0,1,0,1,1,3,1,0,0,0,1,1,0,1,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,1,2,2,0,3,4,0,0,0,1,1,0,0,1,0,0,0,0,0,1,1), +(0,1,0,0,0,1,0,0,0,0,4,0,4,1,4,0,3,0,4,0,3,0,4,0,3,0,3,0,4,1,5,1,4,0,0,3,0,5,0,5,2,0,1,0,0,0,2,1,4,0,1,3,0,0,3,0,0,3,1,1,4,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0), +(1,4,0,5,0,3,0,2,0,3,5,4,4,3,4,3,5,3,4,3,3,0,4,3,3,3,3,3,3,2,4,4,3,1,3,4,4,5,4,4,3,4,4,1,3,5,4,3,3,3,1,2,2,3,3,1,3,1,3,3,3,5,3,3,4,5,0,3,0,3,0,3,4,3,4,4,3,0,3,0,2,4,3), +(0,1,0,4,0,0,0,0,0,1,4,0,4,1,4,2,4,0,3,0,1,0,1,0,0,0,0,0,2,0,3,1,1,1,0,3,0,0,0,1,2,1,0,0,1,1,1,1,0,1,0,0,0,1,0,0,3,0,0,0,0,3,2,0,2,2,0,1,0,0,0,2,3,2,3,3,0,0,0,0,2,1,0), +(0,5,1,5,0,3,0,3,0,5,4,4,5,1,5,3,3,0,4,3,4,3,5,3,4,3,3,2,4,3,4,3,3,0,3,3,1,4,4,3,4,4,4,3,4,5,5,3,2,3,1,1,3,3,1,3,1,1,3,3,2,4,5,3,3,5,0,4,0,3,0,4,4,3,5,3,3,0,3,4,0,4,3), +(0,5,0,5,0,3,0,2,0,4,4,3,5,2,4,3,3,3,4,4,4,3,5,3,5,3,3,1,4,0,4,3,3,0,3,3,0,4,4,4,4,5,4,3,3,5,5,3,2,3,1,2,3,2,0,1,0,0,3,2,2,4,4,3,1,5,0,4,0,3,0,4,3,1,3,2,1,0,3,3,0,3,3), +(0,4,0,5,0,5,0,4,0,4,5,5,5,3,4,3,3,2,5,4,4,3,5,3,5,3,4,0,4,3,4,4,3,2,4,4,3,4,5,4,4,5,5,0,3,5,5,4,1,3,3,2,3,3,1,3,1,0,4,3,1,4,4,3,4,5,0,4,0,2,0,4,3,4,4,3,3,0,4,0,0,5,5), +(0,4,0,4,0,5,0,1,1,3,3,4,4,3,4,1,3,0,5,1,3,0,3,1,3,1,1,0,3,0,3,3,4,0,4,3,0,4,4,4,3,4,4,0,3,5,4,1,0,3,0,0,2,3,0,3,1,0,3,1,0,3,2,1,3,5,0,3,0,1,0,3,2,3,3,4,4,0,2,2,0,4,4), +(2,4,0,5,0,4,0,3,0,4,5,5,4,3,5,3,5,3,5,3,5,2,5,3,4,3,3,4,3,4,5,3,2,1,5,4,3,2,3,4,5,3,4,1,2,5,4,3,0,3,3,0,3,2,0,2,3,0,4,1,0,3,4,3,3,5,0,3,0,1,0,4,5,5,5,4,3,0,4,2,0,3,5), +(0,5,0,4,0,4,0,2,0,5,4,3,4,3,4,3,3,3,4,3,4,2,5,3,5,3,4,1,4,3,4,4,4,0,3,5,0,4,4,4,4,5,3,1,3,4,5,3,3,3,3,3,3,3,0,2,2,0,3,3,2,4,3,3,3,5,3,4,1,3,3,5,3,2,0,0,0,0,4,3,1,3,3), +(0,1,0,3,0,3,0,1,0,1,3,3,3,2,3,3,3,0,3,0,0,0,3,1,3,0,0,0,2,2,2,3,0,0,3,2,0,1,2,4,1,3,3,0,0,3,3,3,0,1,0,0,2,1,0,0,3,0,3,1,0,3,0,0,1,3,0,2,0,1,0,3,3,1,3,3,0,0,1,1,0,3,3), +(0,2,0,3,0,2,1,4,0,2,2,3,1,1,3,1,1,0,2,0,3,1,2,3,1,3,0,0,1,0,4,3,2,3,3,3,1,4,2,3,3,3,3,1,0,3,1,4,0,1,1,0,1,2,0,1,1,0,1,1,0,3,1,3,2,2,0,1,0,0,0,2,3,3,3,1,0,0,0,0,0,2,3), +(0,5,0,4,0,5,0,2,0,4,5,5,3,3,4,3,3,1,5,4,4,2,4,4,4,3,4,2,4,3,5,5,4,3,3,4,3,3,5,5,4,5,5,1,3,4,5,3,1,4,3,1,3,3,0,3,3,1,4,3,1,4,5,3,3,5,0,4,0,3,0,5,3,3,1,4,3,0,4,0,1,5,3), +(0,5,0,5,0,4,0,2,0,4,4,3,4,3,3,3,3,3,5,4,4,4,4,4,4,5,3,3,5,2,4,4,4,3,4,4,3,3,4,4,5,5,3,3,4,3,4,3,3,4,3,3,3,3,1,2,2,1,4,3,3,5,4,4,3,4,0,4,0,3,0,4,4,4,4,4,1,0,4,2,0,2,4), +(0,4,0,4,0,3,0,1,0,3,5,2,3,0,3,0,2,1,4,2,3,3,4,1,4,3,3,2,4,1,3,3,3,0,3,3,0,0,3,3,3,5,3,3,3,3,3,2,0,2,0,0,2,0,0,2,0,0,1,0,0,3,1,2,2,3,0,3,0,2,0,4,4,3,3,4,1,0,3,0,0,2,4), +(0,0,0,4,0,0,0,0,0,0,1,0,1,0,2,0,0,0,0,0,1,0,2,0,1,0,0,0,0,0,3,1,3,0,3,2,0,0,0,1,0,3,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,4,0,2,0,0,0,0,0,0,2), +(0,2,1,3,0,2,0,2,0,3,3,3,3,1,3,1,3,3,3,3,3,3,4,2,2,1,2,1,4,0,4,3,1,3,3,3,2,4,3,5,4,3,3,3,3,3,3,3,0,1,3,0,2,0,0,1,0,0,1,0,0,4,2,0,2,3,0,3,3,0,3,3,4,2,3,1,4,0,1,2,0,2,3), +(0,3,0,3,0,1,0,3,0,2,3,3,3,0,3,1,2,0,3,3,2,3,3,2,3,2,3,1,3,0,4,3,2,0,3,3,1,4,3,3,2,3,4,3,1,3,3,1,1,0,1,1,0,1,0,1,0,1,0,0,0,4,1,1,0,3,0,3,1,0,2,3,3,3,3,3,1,0,0,2,0,3,3), +(0,0,0,0,0,0,0,0,0,0,3,0,2,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,3,0,3,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,2,0,2,3,0,0,0,0,0,0,0,0,3), +(0,2,0,3,1,3,0,3,0,2,3,3,3,1,3,1,3,1,3,1,3,3,3,1,3,0,2,3,1,1,4,3,3,2,3,3,1,2,2,4,1,3,3,0,1,4,2,3,0,1,3,0,3,0,0,1,3,0,2,0,0,3,3,2,1,3,0,3,0,2,0,3,4,4,4,3,1,0,3,0,0,3,3), +(0,2,0,1,0,2,0,0,0,1,3,2,2,1,3,0,1,1,3,0,3,2,3,1,2,0,2,0,1,1,3,3,3,0,3,3,1,1,2,3,2,3,3,1,2,3,2,0,0,1,0,0,0,0,0,0,3,0,1,0,0,2,1,2,1,3,0,3,0,0,0,3,4,4,4,3,2,0,2,0,0,2,4), +(0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,3,1,0,0,0,0,0,0,0,3), +(0,3,0,3,0,2,0,3,0,3,3,3,2,3,2,2,2,0,3,1,3,3,3,2,3,3,0,0,3,0,3,2,2,0,2,3,1,4,3,4,3,3,2,3,1,5,4,4,0,3,1,2,1,3,0,3,1,1,2,0,2,3,1,3,1,3,0,3,0,1,0,3,3,4,4,2,1,0,2,1,0,2,4), +(0,1,0,3,0,1,0,2,0,1,4,2,5,1,4,0,2,0,2,1,3,1,4,0,2,1,0,0,2,1,4,1,1,0,3,3,0,5,1,3,2,3,3,1,0,3,2,3,0,1,0,0,0,0,0,0,1,0,0,0,0,4,0,1,0,3,0,2,0,1,0,3,3,3,4,3,3,0,0,0,0,2,3), +(0,0,0,1,0,0,0,0,0,0,2,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,1,0,0,0,0,0,3), +(0,1,0,3,0,4,0,3,0,2,4,3,1,0,3,2,2,1,3,1,2,2,3,1,1,1,2,1,3,0,1,2,0,1,3,2,1,3,0,5,5,1,0,0,1,3,2,1,0,3,0,0,1,0,0,0,0,0,3,4,0,1,1,1,3,2,0,2,0,1,0,2,3,3,1,2,3,0,1,0,1,0,4), +(0,0,0,1,0,3,0,3,0,2,2,1,0,0,4,0,3,0,3,1,3,0,3,0,3,0,1,0,3,0,3,1,3,0,3,3,0,0,1,2,1,1,1,0,1,2,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,2,2,1,2,0,0,2,0,0,0,0,2,3,3,3,3,0,0,0,0,1,4), +(0,0,0,3,0,3,0,0,0,0,3,1,1,0,3,0,1,0,2,0,1,0,0,0,0,0,0,0,1,0,3,0,2,0,2,3,0,0,2,2,3,1,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,2,3), +(2,4,0,5,0,5,0,4,0,3,4,3,3,3,4,3,3,3,4,3,4,4,5,4,5,5,5,2,3,0,5,5,4,1,5,4,3,1,5,4,3,4,4,3,3,4,3,3,0,3,2,0,2,3,0,3,0,0,3,3,0,5,3,2,3,3,0,3,0,3,0,3,4,5,4,5,3,0,4,3,0,3,4), +(0,3,0,3,0,3,0,3,0,3,3,4,3,2,3,2,3,0,4,3,3,3,3,3,3,3,3,0,3,2,4,3,3,1,3,4,3,4,4,4,3,4,4,3,2,4,4,1,0,2,0,0,1,1,0,2,0,0,3,1,0,5,3,2,1,3,0,3,0,1,2,4,3,2,4,3,3,0,3,2,0,4,4), +(0,3,0,3,0,1,0,0,0,1,4,3,3,2,3,1,3,1,4,2,3,2,4,2,3,4,3,0,2,2,3,3,3,0,3,3,3,0,3,4,1,3,3,0,3,4,3,3,0,1,1,0,1,0,0,0,4,0,3,0,0,3,1,2,1,3,0,4,0,1,0,4,3,3,4,3,3,0,2,0,0,3,3), +(0,3,0,4,0,1,0,3,0,3,4,3,3,0,3,3,3,1,3,1,3,3,4,3,3,3,0,0,3,1,5,3,3,1,3,3,2,5,4,3,3,4,5,3,2,5,3,4,0,1,0,0,0,0,0,2,0,0,1,1,0,4,2,2,1,3,0,3,0,2,0,4,4,3,5,3,2,0,1,1,0,3,4), +(0,5,0,4,0,5,0,2,0,4,4,3,3,2,3,3,3,1,4,3,4,1,5,3,4,3,4,0,4,2,4,3,4,1,5,4,0,4,4,4,4,5,4,1,3,5,4,2,1,4,1,1,3,2,0,3,1,0,3,2,1,4,3,3,3,4,0,4,0,3,0,4,4,4,3,3,3,0,4,2,0,3,4), +(1,4,0,4,0,3,0,1,0,3,3,3,1,1,3,3,2,2,3,3,1,0,3,2,2,1,2,0,3,1,2,1,2,0,3,2,0,2,2,3,3,4,3,0,3,3,1,2,0,1,1,3,1,2,0,0,3,0,1,1,0,3,2,2,3,3,0,3,0,0,0,2,3,3,4,3,3,0,1,0,0,1,4), +(0,4,0,4,0,4,0,0,0,3,4,4,3,1,4,2,3,2,3,3,3,1,4,3,4,0,3,0,4,2,3,3,2,2,5,4,2,1,3,4,3,4,3,1,3,3,4,2,0,2,1,0,3,3,0,0,2,0,3,1,0,4,4,3,4,3,0,4,0,1,0,2,4,4,4,4,4,0,3,2,0,3,3), +(0,0,0,1,0,4,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,3,2,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,2), +(0,2,0,3,0,4,0,4,0,1,3,3,3,0,4,0,2,1,2,1,1,1,2,0,3,1,1,0,1,0,3,1,0,0,3,3,2,0,1,1,0,0,0,0,0,1,0,2,0,2,2,0,3,1,0,0,1,0,1,1,0,1,2,0,3,0,0,0,0,1,0,0,3,3,4,3,1,0,1,0,3,0,2), +(0,0,0,3,0,5,0,0,0,0,1,0,2,0,3,1,0,1,3,0,0,0,2,0,0,0,1,0,0,0,1,1,0,0,4,0,0,0,2,3,0,1,4,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,1,0,0,0,0,0,0,0,2,0,0,3,0,0,0,0,0,3), +(0,2,0,5,0,5,0,1,0,2,4,3,3,2,5,1,3,2,3,3,3,0,4,1,2,0,3,0,4,0,2,2,1,1,5,3,0,0,1,4,2,3,2,0,3,3,3,2,0,2,4,1,1,2,0,1,1,0,3,1,0,1,3,1,2,3,0,2,0,0,0,1,3,5,4,4,4,0,3,0,0,1,3), +(0,4,0,5,0,4,0,4,0,4,5,4,3,3,4,3,3,3,4,3,4,4,5,3,4,5,4,2,4,2,3,4,3,1,4,4,1,3,5,4,4,5,5,4,4,5,5,5,2,3,3,1,4,3,1,3,3,0,3,3,1,4,3,4,4,4,0,3,0,4,0,3,3,4,4,5,0,0,4,3,0,4,5), +(0,4,0,4,0,3,0,3,0,3,4,4,4,3,3,2,4,3,4,3,4,3,5,3,4,3,2,1,4,2,4,4,3,1,3,4,2,4,5,5,3,4,5,4,1,5,4,3,0,3,2,2,3,2,1,3,1,0,3,3,3,5,3,3,3,5,4,4,2,3,3,4,3,3,3,2,1,0,3,2,1,4,3), +(0,4,0,5,0,4,0,3,0,3,5,5,3,2,4,3,4,0,5,4,4,1,4,4,4,3,3,3,4,3,5,5,2,3,3,4,1,2,5,5,3,5,5,2,3,5,5,4,0,3,2,0,3,3,1,1,5,1,4,1,0,4,3,2,3,5,0,4,0,3,0,5,4,3,4,3,0,0,4,1,0,4,4), +(1,3,0,4,0,2,0,2,0,2,5,5,3,3,3,3,3,0,4,2,3,4,4,4,3,4,0,0,3,4,5,4,3,3,3,3,2,5,5,4,5,5,5,4,3,5,5,5,1,3,1,0,1,0,0,3,2,0,4,2,0,5,2,3,2,4,1,3,0,3,0,4,5,4,5,4,3,0,4,2,0,5,4), +(0,3,0,4,0,5,0,3,0,3,4,4,3,2,3,2,3,3,3,3,3,2,4,3,3,2,2,0,3,3,3,3,3,1,3,3,3,0,4,4,3,4,4,1,1,4,4,2,0,3,1,0,1,1,0,4,1,0,2,3,1,3,3,1,3,4,0,3,0,1,0,3,1,3,0,0,1,0,2,0,0,4,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,3,0,2,0,3,0,1,5,4,3,3,3,1,4,2,1,2,3,4,4,2,4,4,5,0,3,1,4,3,4,0,4,3,3,3,2,3,2,5,3,4,3,2,2,3,0,0,3,0,2,1,0,1,2,0,0,0,0,2,1,1,3,1,0,2,0,4,0,3,4,4,4,5,2,0,2,0,0,1,3), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,1,1,0,0,0,4,2,1,1,0,1,0,3,2,0,0,3,1,1,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,1,0,0,0,2,0,0,0,1,4,0,4,2,1,0,0,0,0,0,1), +(0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,3,1,0,0,0,2,0,2,1,0,0,1,2,1,0,1,1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,1,3,1,0,0,0,0,0,1,0,0,2,1,0,0,0,0,0,0,0,0,2), +(0,4,0,4,0,4,0,3,0,4,4,3,4,2,4,3,2,0,4,4,4,3,5,3,5,3,3,2,4,2,4,3,4,3,1,4,0,2,3,4,4,4,3,3,3,4,4,4,3,4,1,3,4,3,2,1,2,1,3,3,3,4,4,3,3,5,0,4,0,3,0,4,3,3,3,2,1,0,3,0,0,3,3), +(0,4,0,3,0,3,0,3,0,3,5,5,3,3,3,3,4,3,4,3,3,3,4,4,4,3,3,3,3,4,3,5,3,3,1,3,2,4,5,5,5,5,4,3,4,5,5,3,2,2,3,3,3,3,2,3,3,1,2,3,2,4,3,3,3,4,0,4,0,2,0,4,3,2,2,1,2,0,3,0,0,4,1), +) + +class JapaneseContextAnalysis: + def __init__(self): + self.reset() + + def reset(self): + self._mTotalRel = 0 # total sequence received + self._mRelSample = [0] * NUM_OF_CATEGORY # category counters, each interger counts sequence in its category + self._mNeedToSkipCharNum = 0 # if last byte in current buffer is not the last byte of a character, we need to know how many bytes to skip in next buffer + self._mLastCharOrder = -1 # The order of previous char + self._mDone = False # If this flag is set to True, detection is done and conclusion has been made + + def feed(self, aBuf, aLen): + if self._mDone: return + + # The buffer we got is byte oriented, and a character may span in more than one + # buffers. In case the last one or two byte in last buffer is not complete, we + # record how many byte needed to complete that character and skip these bytes here. + # We can choose to record those bytes as well and analyse the character once it + # is complete, but since a character will not make much difference, by simply skipping + # this character will simply our logic and improve performance. + i = self._mNeedToSkipCharNum + while i < aLen: + order, charLen = self.get_order(aBuf[i:i+2]) + i += charLen + if i > aLen: + self._mNeedToSkipCharNum = i - aLen + self._mLastCharOrder = -1 + else: + if (order != -1) and (self._mLastCharOrder != -1): + self._mTotalRel += 1 + if self._mTotalRel > MAX_REL_THRESHOLD: + self._mDone = True + break + self._mRelSample[jp2CharContext[self._mLastCharOrder][order]] += 1 + self._mLastCharOrder = order + + def got_enough_data(self): + return self._mTotalRel > ENOUGH_REL_THRESHOLD + + def get_confidence(self): + # This is just one way to calculate confidence. It works well for me. + if self._mTotalRel > MINIMUM_DATA_THRESHOLD: + return (self._mTotalRel - self._mRelSample[0]) / self._mTotalRel + else: + return DONT_KNOW + + def get_order(self, aBuf): + return -1, 1 + +class SJISContextAnalysis(JapaneseContextAnalysis): + def get_order(self, aBuf): + if not aBuf: return -1, 1 + # find out current char's byte length + if ((aBuf[0] >= 0x81) and (aBuf[0] <= 0x9F)) or \ + ((aBuf[0] >= 0xE0) and (aBuf[0] <= 0xFC)): + charLen = 2 + else: + charLen = 1 + + # return its order if it is hiragana + if len(aBuf) > 1: + if (aBuf[0] == 202) and \ + (aBuf[1] >= 0x9F) and \ + (aBuf[1] <= 0xF1): + return aBuf[1] - 0x9F, charLen + + return -1, charLen + +class EUCJPContextAnalysis(JapaneseContextAnalysis): + def get_order(self, aBuf): + if not aBuf: return -1, 1 + # find out current char's byte length + if (aBuf[0] == 0x8E) or \ + ((aBuf[0] >= 0xA1) and (aBuf[0] <= 0xFE)): + charLen = 2 + elif aBuf[0] == 0x8F: + charLen = 3 + else: + charLen = 1 + + # return its order if it is hiragana + if len(aBuf) > 1: + if (aBuf[0] == 0xA4) and \ + (aBuf[1] >= 0xA1) and \ + (aBuf[1] <= 0xF3): + return aBuf[1] - 0xA1, charLen + + return -1, charLen diff --git a/libs/requests/packages/chardet2/langbulgarianmodel.py b/libs/requests/packages/chardet2/langbulgarianmodel.py new file mode 100644 index 00000000..bf57925b --- /dev/null +++ b/libs/requests/packages/chardet2/langbulgarianmodel.py @@ -0,0 +1,228 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +# this table is modified base on win1251BulgarianCharToOrderMap, so +# only number <64 is sure valid + +Latin5_BulgarianCharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 77, 90, 99,100, 72,109,107,101, 79,185, 81,102, 76, 94, 82, # 40 +110,186,108, 91, 74,119, 84, 96,111,187,115,253,253,253,253,253, # 50 +253, 65, 69, 70, 66, 63, 68,112,103, 92,194,104, 95, 86, 87, 71, # 60 +116,195, 85, 93, 97,113,196,197,198,199,200,253,253,253,253,253, # 70 +194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209, # 80 +210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225, # 90 + 81,226,227,228,229,230,105,231,232,233,234,235,236, 45,237,238, # a0 + 31, 32, 35, 43, 37, 44, 55, 47, 40, 59, 33, 46, 38, 36, 41, 30, # b0 + 39, 28, 34, 51, 48, 49, 53, 50, 54, 57, 61,239, 67,240, 60, 56, # c0 + 1, 18, 9, 20, 11, 3, 23, 15, 2, 26, 12, 10, 14, 6, 4, 13, # d0 + 7, 8, 5, 19, 29, 25, 22, 21, 27, 24, 17, 75, 52,241, 42, 16, # e0 + 62,242,243,244, 58,245, 98,246,247,248,249,250,251, 91,252,253, # f0 +) + +win1251BulgarianCharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 77, 90, 99,100, 72,109,107,101, 79,185, 81,102, 76, 94, 82, # 40 +110,186,108, 91, 74,119, 84, 96,111,187,115,253,253,253,253,253, # 50 +253, 65, 69, 70, 66, 63, 68,112,103, 92,194,104, 95, 86, 87, 71, # 60 +116,195, 85, 93, 97,113,196,197,198,199,200,253,253,253,253,253, # 70 +206,207,208,209,210,211,212,213,120,214,215,216,217,218,219,220, # 80 +221, 78, 64, 83,121, 98,117,105,222,223,224,225,226,227,228,229, # 90 + 88,230,231,232,233,122, 89,106,234,235,236,237,238, 45,239,240, # a0 + 73, 80,118,114,241,242,243,244,245, 62, 58,246,247,248,249,250, # b0 + 31, 32, 35, 43, 37, 44, 55, 47, 40, 59, 33, 46, 38, 36, 41, 30, # c0 + 39, 28, 34, 51, 48, 49, 53, 50, 54, 57, 61,251, 67,252, 60, 56, # d0 + 1, 18, 9, 20, 11, 3, 23, 15, 2, 26, 12, 10, 14, 6, 4, 13, # e0 + 7, 8, 5, 19, 29, 25, 22, 21, 27, 24, 17, 75, 52,253, 42, 16, # f0 +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 96.9392% +# first 1024 sequences:3.0618% +# rest sequences: 0.2992% +# negative sequences: 0.0020% +BulgarianLangModel = ( \ +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,2,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,2,2,3,2,2,1,2,2, +3,1,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,3,3,3,3,3,3,3,0,3,0,1, +0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,3,3,0,3,1,0, +0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,2,3,3,3,3,3,3,3,3,0,3,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,1,3,2,3,3,3,3,3,3,3,3,0,3,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,2,2,1,3,3,3,3,2,2,2,1,1,2,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,2,3,2,2,3,3,1,1,2,3,3,2,3,3,3,3,2,1,2,0,2,0,3,0,0, +0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,1,3,3,3,3,3,2,3,2,3,3,3,3,3,2,3,3,1,3,0,3,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,1,3,3,2,3,3,3,1,3,3,2,3,2,2,2,0,0,2,0,2,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,0,3,3,3,2,2,3,3,3,1,2,2,3,2,1,1,2,0,2,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,2,3,3,1,2,3,2,2,2,3,3,3,3,3,2,2,3,1,2,0,2,1,2,0,0, +0,0,0,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,1,3,3,3,3,3,2,3,3,3,2,3,3,2,3,2,2,2,3,1,2,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,1,1,1,2,2,1,3,1,3,2,2,3,0,0,1,0,1,0,1,0,0, +0,0,0,1,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,2,2,3,2,2,3,1,2,1,1,1,2,3,1,3,1,2,2,0,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,1,3,2,2,3,3,1,2,3,1,1,3,3,3,3,1,2,2,1,1,1,0,2,0,2,0,1, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,2,2,3,3,3,2,2,1,1,2,0,2,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,0,1,2,1,3,3,2,3,3,3,3,3,2,3,2,1,0,3,1,2,1,2,1,2,3,2,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,2,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,1,3,3,2,3,3,2,2,2,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,0,3,3,3,3,3,2,1,1,2,1,3,3,0,3,1,1,1,1,3,2,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,2,2,2,3,3,3,3,3,3,3,3,3,3,3,1,1,3,1,3,3,2,3,2,2,2,3,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,3,2,2,3,2,1,1,1,1,1,3,1,3,1,1,0,0,0,1,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,2,0,3,2,0,3,0,2,0,0,2,1,3,1,0,0,1,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,2,1,1,1,1,2,1,1,2,1,1,1,2,2,1,2,1,1,1,0,1,1,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,2,1,3,1,1,2,1,3,2,1,1,0,1,2,3,2,1,1,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,2,2,1,0,1,0,0,1,0,0,0,2,1,0,3,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,2,3,2,3,3,1,3,2,1,1,1,2,1,1,2,1,3,0,1,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,2,2,3,3,2,3,2,2,2,3,1,2,2,1,1,2,1,1,2,2,0,1,1,0,1,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,3,1,0,2,2,1,3,2,1,0,0,2,0,2,0,1,0,0,0,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,1,2,0,2,3,1,2,3,2,0,1,3,1,2,1,1,1,0,0,1,0,0,2,2,2,3, +2,2,2,2,1,2,1,1,2,2,1,1,2,0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,1, +3,3,3,3,3,2,1,2,2,1,2,0,2,0,1,0,1,2,1,2,1,1,0,0,0,1,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,2,3,3,1,1,3,1,0,3,2,1,0,0,0,1,2,0,2,0,1,0,0,0,1,0,1,2,1,2,2, +1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,0,1,2,1,1,1,0,0,0,0,0,1,1,0,0, +3,1,0,1,0,2,3,2,2,2,3,2,2,2,2,2,1,0,2,1,2,1,1,1,0,1,2,1,2,2,2,1, +1,1,2,2,2,2,1,2,1,1,0,1,2,1,2,2,2,1,1,1,0,1,1,1,1,2,0,1,0,0,0,0, +2,3,2,3,3,0,0,2,1,0,2,1,0,0,0,0,2,3,0,2,0,0,0,0,0,1,0,0,2,0,1,2, +2,1,2,1,2,2,1,1,1,2,1,1,1,0,1,2,2,1,1,1,1,1,0,1,1,1,0,0,1,2,0,0, +3,3,2,2,3,0,2,3,1,1,2,0,0,0,1,0,0,2,0,2,0,0,0,1,0,1,0,1,2,0,2,2, +1,1,1,1,2,1,0,1,2,2,2,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,1,1,0,0, +2,3,2,3,3,0,0,3,0,1,1,0,1,0,0,0,2,2,1,2,0,0,0,0,0,0,0,0,2,0,1,2, +2,2,1,1,1,1,1,2,2,2,1,0,2,0,1,0,1,0,0,1,0,1,0,0,1,0,0,0,0,1,0,0, +3,3,3,3,2,2,2,2,2,0,2,1,1,1,1,2,1,2,1,1,0,2,0,1,0,1,0,0,2,0,1,2, +1,1,1,1,1,1,1,2,2,1,1,0,2,0,1,0,2,0,0,1,1,1,0,0,2,0,0,0,1,1,0,0, +2,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,0,0,0,0,0,0,1,2,0,1,2, +2,2,2,1,1,2,1,1,2,2,2,1,2,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,0,0, +2,3,3,3,3,0,2,2,0,2,1,0,0,0,1,1,1,2,0,2,0,0,0,3,0,0,0,0,2,0,2,2, +1,1,1,2,1,2,1,1,2,2,2,1,2,0,1,1,1,0,1,1,1,1,0,2,1,0,0,0,1,1,0,0, +2,3,3,3,3,0,2,1,0,0,2,0,0,0,0,0,1,2,0,2,0,0,0,0,0,0,0,0,2,0,1,2, +1,1,1,2,1,1,1,1,2,2,2,0,1,0,1,1,1,0,0,1,1,1,0,0,1,0,0,0,0,1,0,0, +3,3,2,2,3,0,1,0,1,0,0,0,0,0,0,0,1,1,0,3,0,0,0,0,0,0,0,0,1,0,2,2, +1,1,1,1,1,2,1,1,2,2,1,2,2,1,0,1,1,1,1,1,0,1,0,0,1,0,0,0,1,1,0,0, +3,1,0,1,0,2,2,2,2,3,2,1,1,1,2,3,0,0,1,0,2,1,1,0,1,1,1,1,2,1,1,1, +1,2,2,1,2,1,2,2,1,1,0,1,2,1,2,2,1,1,1,0,0,1,1,1,2,1,0,1,0,0,0,0, +2,1,0,1,0,3,1,2,2,2,2,1,2,2,1,1,1,0,2,1,2,2,1,1,2,1,1,0,2,1,1,1, +1,2,2,2,2,2,2,2,1,2,0,1,1,0,2,1,1,1,1,1,0,0,1,1,1,1,0,1,0,0,0,0, +2,1,1,1,1,2,2,2,2,1,2,2,2,1,2,2,1,1,2,1,2,3,2,2,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,3,2,0,1,2,0,1,2,1,1,0,1,0,1,2,1,2,0,0,0,1,1,0,0,0,1,0,0,2, +1,1,0,0,1,1,0,1,1,1,1,0,2,0,1,1,1,0,0,1,1,0,0,0,0,1,0,0,0,1,0,0, +2,0,0,0,0,1,2,2,2,2,2,2,2,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,2,1,1,1, +1,2,2,2,2,1,1,2,1,2,1,1,1,0,2,1,2,1,1,1,0,2,1,1,1,1,0,1,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, +1,1,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,3,2,0,0,0,0,1,0,0,0,0,0,0,1,1,0,2,0,0,0,0,0,0,0,0,1,0,1,2, +1,1,1,1,1,1,0,0,2,2,2,2,2,0,1,1,0,1,1,1,1,1,0,0,1,0,0,0,1,1,0,1, +2,3,1,2,1,0,1,1,0,2,2,2,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,0,1,2, +1,1,1,1,2,1,1,1,1,1,1,1,1,0,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,1,0,0, +2,2,2,2,2,0,0,2,0,0,2,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,0,2,2, +1,1,1,1,1,0,0,1,2,1,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,2,0,1,1,0,0,0,1,0,0,2,0,2,0,0,0,0,0,0,0,0,0,0,1,1, +0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,3,2,0,0,1,0,0,1,0,0,0,0,0,0,1,0,2,0,0,0,1,0,0,0,0,0,0,0,2, +1,1,0,0,1,0,0,0,1,1,0,0,1,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,1,2,2,2,1,2,1,2,2,1,1,2,1,1,1,0,1,1,1,1,2,0,1,0,1,1,1,1,0,1,1, +1,1,2,1,1,1,1,1,1,0,0,1,2,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0, +1,0,0,1,3,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,1,0,0,1,0,2,0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,0,2,0,0,1, +0,2,0,1,0,0,1,1,2,0,1,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,1,1,0,2,1,0,1,1,1,0,0,1,0,2,0,1,0,0,0,0,0,0,0,0,0,1, +0,1,0,0,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,2,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1, +0,1,0,1,1,1,0,0,1,1,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,0,1,2,1,1,1,1,1,1,2,2,1,0,0,1,0,1,0,0,0,0,1,1,1,1,0,0,0, +1,1,2,1,1,1,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,1,2,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +0,1,1,0,1,1,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0, +1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,2,0,0,2,0,1,0,0,1,0,0,1, +1,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, +1,1,1,1,1,1,1,2,0,0,0,0,0,0,2,1,0,1,1,0,0,1,1,1,0,1,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +) + +Latin5BulgarianModel = { \ + 'charToOrderMap': Latin5_BulgarianCharToOrderMap, + 'precedenceMatrix': BulgarianLangModel, + 'mTypicalPositiveRatio': 0.969392, + 'keepEnglishLetter': False, + 'charsetName': "ISO-8859-5" +} + +Win1251BulgarianModel = { \ + 'charToOrderMap': win1251BulgarianCharToOrderMap, + 'precedenceMatrix': BulgarianLangModel, + 'mTypicalPositiveRatio': 0.969392, + 'keepEnglishLetter': False, + 'charsetName': "windows-1251" +} diff --git a/libs/requests/packages/chardet2/langcyrillicmodel.py b/libs/requests/packages/chardet2/langcyrillicmodel.py new file mode 100644 index 00000000..7b73f74b --- /dev/null +++ b/libs/requests/packages/chardet2/langcyrillicmodel.py @@ -0,0 +1,329 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants + +# KOI8-R language model +# Character Mapping Table: +KOI8R_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, # 80 +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, # 90 +223,224,225, 68,226,227,228,229,230,231,232,233,234,235,236,237, # a0 +238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253, # b0 + 27, 3, 21, 28, 13, 2, 39, 19, 26, 4, 23, 11, 8, 12, 5, 1, # c0 + 15, 16, 9, 7, 6, 14, 24, 10, 17, 18, 20, 25, 30, 29, 22, 54, # d0 + 59, 37, 44, 58, 41, 48, 53, 46, 55, 42, 60, 36, 49, 38, 31, 34, # e0 + 35, 43, 45, 32, 40, 52, 56, 33, 61, 62, 51, 57, 47, 63, 50, 70, # f0 +) + +win1251_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, +239,240,241,242,243,244,245,246, 68,247,248,249,250,251,252,253, + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +) + +latin5_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255, +) + +macCyrillic_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, +239,240,241,242,243,244,245,246,247,248,249,250,251,252, 68, 16, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27,255, +) + +IBM855_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194, 68,195,196,197,198,199,200,201,202,203,204,205, +206,207,208,209,210,211,212,213,214,215,216,217, 27, 59, 54, 70, + 3, 37, 21, 44, 28, 58, 13, 41, 2, 48, 39, 53, 19, 46,218,219, +220,221,222,223,224, 26, 55, 4, 42,225,226,227,228, 23, 60,229, +230,231,232,233,234,235, 11, 36,236,237,238,239,240,241,242,243, + 8, 49, 12, 38, 5, 31, 1, 34, 15,244,245,246,247, 35, 16,248, + 43, 9, 45, 7, 32, 6, 40, 14, 52, 24, 56, 10, 33, 17, 61,249, +250, 18, 62, 20, 51, 25, 57, 30, 47, 29, 63, 22, 50,251,252,255, +) + +IBM866_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 97.6601% +# first 1024 sequences: 2.3389% +# rest sequences: 0.1237% +# negative sequences: 0.0009% +RussianLangModel = ( \ +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,1,3,3,3,2,3,2,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,2,2,2,2,2,0,0,2, +3,3,3,2,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,2,3,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,2,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,2,3,3,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1, +0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1, +0,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,2,2,2,3,1,3,3,1,3,3,3,3,2,2,3,0,2,2,2,3,3,2,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,3,3,2,2,3,2,3,3,3,2,1,2,2,0,1,2,2,2,2,2,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,3,0,2,2,3,3,2,1,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,1,2,3,2,2,3,2,3,3,3,3,2,2,3,0,3,2,2,3,1,1,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,3,3,3,3,2,2,2,0,3,3,3,2,2,2,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,2,3,2,2,0,1,3,2,1,2,2,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,2,1,1,3,0,1,1,1,1,2,1,1,0,2,2,2,1,2,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,2,2,2,2,1,3,2,3,2,3,2,1,2,2,0,1,1,2,1,2,1,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,2,3,3,3,2,2,2,2,0,2,2,2,2,3,1,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,2,3,2,2,3,3,3,3,3,3,3,3,3,1,3,2,0,0,3,3,3,3,2,3,3,3,3,2,3,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,3,2,2,3,3,0,2,1,0,3,2,3,2,3,0,0,1,2,0,0,1,0,1,2,1,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,3,0,2,3,3,3,3,2,3,3,3,3,1,2,2,0,0,2,3,2,2,2,3,2,3,2,2,3,0,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,0,2,3,2,3,0,1,2,3,3,2,0,2,3,0,0,2,3,2,2,0,1,3,1,3,2,2,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,3,0,2,3,3,3,3,3,3,3,3,2,1,3,2,0,0,2,2,3,3,3,2,3,3,0,2,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,2,2,2,3,3,0,0,1,1,1,1,1,2,0,0,1,1,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,3,3,3,3,3,0,3,2,3,3,2,3,2,0,2,1,0,1,1,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,2,2,2,2,3,1,3,2,3,1,1,2,1,0,2,2,2,2,1,3,1,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +2,2,3,3,3,3,3,1,2,2,1,3,1,0,3,0,0,3,0,0,0,1,1,0,1,2,1,0,0,0,0,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,2,1,1,3,3,3,2,2,1,2,2,3,1,1,2,0,0,2,2,1,3,0,0,2,1,1,2,1,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,3,3,3,1,2,2,2,1,2,1,3,3,1,1,2,1,2,1,2,2,0,2,0,0,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,3,2,1,3,2,2,3,2,0,3,2,0,3,0,1,0,1,1,0,0,1,1,1,1,0,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,3,3,3,2,2,2,3,3,1,2,1,2,1,0,1,0,1,1,0,1,0,0,2,1,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,1,1,2,1,2,3,3,2,2,1,2,2,3,0,2,1,0,0,2,2,3,2,1,2,2,2,2,2,3,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,1,1,0,1,1,2,2,1,1,3,0,0,1,3,1,1,1,0,0,0,1,0,1,1,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,3,3,3,2,0,0,0,2,1,0,1,0,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,0,2,3,2,2,2,1,2,2,2,1,2,1,0,0,1,1,1,0,2,0,1,1,1,0,0,1,1, +1,0,0,0,0,0,1,2,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,0,0,0,0,1,0,0,0,0,3,0,1,2,1,0,0,0,0,0,0,0,1,1,0,0,1,1, +1,0,1,0,1,2,0,0,1,1,2,1,0,1,1,1,1,0,1,1,1,1,0,1,0,0,1,0,0,1,1,0, +2,2,3,2,2,2,3,1,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,0,1,0,1,1,1,0,2,1, +1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,0,1,1,0, +3,3,3,2,2,2,2,3,2,2,1,1,2,2,2,2,1,1,3,1,2,1,2,0,0,1,1,0,1,0,2,1, +1,1,1,1,1,2,1,0,1,1,1,1,0,1,0,0,1,1,0,0,1,0,1,0,0,1,0,0,0,1,1,0, +2,0,0,1,0,3,2,2,2,2,1,2,1,2,1,2,0,0,0,2,1,2,2,1,1,2,2,0,1,1,0,2, +1,1,1,1,1,0,1,1,1,2,1,1,1,2,1,0,1,2,1,1,1,1,0,1,1,1,0,0,1,0,0,1, +1,3,2,2,2,1,1,1,2,3,0,0,0,0,2,0,2,2,1,0,0,0,0,0,0,1,0,0,0,0,1,1, +1,0,1,1,0,1,0,1,1,0,1,1,0,2,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0, +2,3,2,3,2,1,2,2,2,2,1,0,0,0,2,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,2,1, +1,1,2,1,0,2,0,0,1,0,1,0,0,1,0,0,1,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0, +3,0,0,1,0,2,2,2,3,2,2,2,2,2,2,2,0,0,0,2,1,2,1,1,1,2,2,0,0,0,1,2, +1,1,1,1,1,0,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1, +2,3,2,3,3,2,0,1,1,1,0,0,1,0,2,0,1,1,3,1,0,0,0,0,0,0,0,1,0,0,2,1, +1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,0,0,1,1,0,1,0,0,0,0,0,0,1,0, +2,3,3,3,3,1,2,2,2,2,0,1,1,0,2,1,1,1,2,1,0,1,1,0,0,1,0,1,0,0,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,2,0,0,1,1,2,2,1,0,0,2,0,1,1,3,0,0,1,0,0,0,0,0,1,0,1,2,1, +1,1,2,0,1,1,1,0,1,0,1,1,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,1,0,1,1,0, +1,3,2,3,2,1,0,0,2,2,2,0,1,0,2,0,1,1,1,0,1,0,0,0,3,0,1,1,0,0,2,1, +1,1,1,0,1,1,0,0,0,0,1,1,0,1,0,0,2,1,1,0,1,0,0,0,1,0,1,0,0,1,1,0, +3,1,2,1,1,2,2,2,2,2,2,1,2,2,1,1,0,0,0,2,2,2,0,0,0,1,2,1,0,1,0,1, +2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,2,1,1,1,0,1,0,1,1,0,1,1,1,0,0,1, +3,0,0,0,0,2,0,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,0,1,0,1,1,0,0,1,0,1, +1,1,0,0,1,0,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1, +1,3,3,2,2,0,0,0,2,2,0,0,0,1,2,0,1,1,2,0,0,0,0,0,0,0,0,1,0,0,2,1, +0,1,1,0,0,1,1,0,0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +2,3,2,3,2,0,0,0,0,1,1,0,0,0,2,0,2,0,2,0,0,0,0,0,1,0,0,1,0,0,1,1, +1,1,2,0,1,2,1,0,1,1,2,1,1,1,1,1,2,1,1,0,1,0,0,1,1,1,1,1,0,1,1,0, +1,3,2,2,2,1,0,0,2,2,1,0,1,2,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,1, +0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,0,2,3,1,2,2,2,2,2,2,1,1,0,0,0,1,0,1,0,2,1,1,1,0,0,0,0,1, +1,1,0,1,1,0,1,1,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +2,0,2,0,0,1,0,3,2,1,2,1,2,2,0,1,0,0,0,2,1,0,0,2,1,1,1,1,0,2,0,2, +2,1,1,1,1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,0,0,0,1,1,1,1,0,1,0,0,1, +1,2,2,2,2,1,0,0,1,0,0,0,0,0,2,0,1,1,1,1,0,0,0,0,1,0,1,2,0,0,2,0, +1,0,1,1,1,2,1,0,1,0,1,1,0,0,1,0,1,1,1,0,1,0,0,0,1,0,0,1,0,1,1,0, +2,1,2,2,2,0,3,0,1,1,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,0,1,1,1,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0, +1,2,2,3,2,2,0,0,1,1,2,0,1,2,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1, +0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0, +2,2,1,1,2,1,2,2,2,2,2,1,2,2,0,1,0,0,0,1,2,2,2,1,2,1,1,1,1,1,2,1, +1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,0,1, +1,2,2,2,2,0,1,0,2,2,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0, +0,0,1,0,0,1,0,0,0,0,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,0,2,2,2,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1, +0,1,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,0,0,1,0,0,1,1,2,0,0,0,0,1,0,1,0,0,1,0,0,2,0,0,0,1, +0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,1,1,2,0,2,1,1,1,1,0,2,2,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1, +0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,0,2,1,2,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0, +0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +1,0,0,0,0,2,0,1,2,1,0,1,1,1,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1, +0,0,0,0,0,1,0,0,1,1,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1, +2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,1,0,1,0,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,0,1,1,0,1,0,1,0,0,0,0,1,1,0,1,1,0,0,0,0,0,1,0,1,1,0,1,0,0,0, +0,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, +) + +Koi8rModel = { \ + 'charToOrderMap': KOI8R_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': False, + 'charsetName': "KOI8-R" +} + +Win1251CyrillicModel = { \ + 'charToOrderMap': win1251_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': False, + 'charsetName': "windows-1251" +} + +Latin5CyrillicModel = { \ + 'charToOrderMap': latin5_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': False, + 'charsetName': "ISO-8859-5" +} + +MacCyrillicModel = { \ + 'charToOrderMap': macCyrillic_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': False, + 'charsetName': "MacCyrillic" +}; + +Ibm866Model = { \ + 'charToOrderMap': IBM866_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': False, + 'charsetName': "IBM866" +} + +Ibm855Model = { \ + 'charToOrderMap': IBM855_CharToOrderMap, + 'precedenceMatrix': RussianLangModel, + 'mTypicalPositiveRatio': 0.976601, + 'keepEnglishLetter': False, + 'charsetName': "IBM855" +} diff --git a/libs/requests/packages/chardet2/langgreekmodel.py b/libs/requests/packages/chardet2/langgreekmodel.py new file mode 100644 index 00000000..506451de --- /dev/null +++ b/libs/requests/packages/chardet2/langgreekmodel.py @@ -0,0 +1,225 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin7_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 82,100,104, 94, 98,101,116,102,111,187,117, 92, 88,113, 85, # 40 + 79,118,105, 83, 67,114,119, 95, 99,109,188,253,253,253,253,253, # 50 +253, 72, 70, 80, 81, 60, 96, 93, 89, 68,120, 97, 77, 86, 69, 55, # 60 + 78,115, 65, 66, 58, 76,106,103, 87,107,112,253,253,253,253,253, # 70 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 80 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 90 +253,233, 90,253,253,253,253,253,253,253,253,253,253, 74,253,253, # a0 +253,253,253,253,247,248, 61, 36, 46, 71, 73,253, 54,253,108,123, # b0 +110, 31, 51, 43, 41, 34, 91, 40, 52, 47, 44, 53, 38, 49, 59, 39, # c0 + 35, 48,250, 37, 33, 45, 56, 50, 84, 57,120,121, 17, 18, 22, 15, # d0 +124, 1, 29, 20, 21, 3, 32, 13, 25, 5, 11, 16, 10, 6, 30, 4, # e0 + 9, 8, 14, 7, 2, 12, 28, 23, 42, 24, 64, 75, 19, 26, 27,253, # f0 +) + +win1253_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 82,100,104, 94, 98,101,116,102,111,187,117, 92, 88,113, 85, # 40 + 79,118,105, 83, 67,114,119, 95, 99,109,188,253,253,253,253,253, # 50 +253, 72, 70, 80, 81, 60, 96, 93, 89, 68,120, 97, 77, 86, 69, 55, # 60 + 78,115, 65, 66, 58, 76,106,103, 87,107,112,253,253,253,253,253, # 70 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 80 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 90 +253,233, 61,253,253,253,253,253,253,253,253,253,253, 74,253,253, # a0 +253,253,253,253,247,253,253, 36, 46, 71, 73,253, 54,253,108,123, # b0 +110, 31, 51, 43, 41, 34, 91, 40, 52, 47, 44, 53, 38, 49, 59, 39, # c0 + 35, 48,250, 37, 33, 45, 56, 50, 84, 57,120,121, 17, 18, 22, 15, # d0 +124, 1, 29, 20, 21, 3, 32, 13, 25, 5, 11, 16, 10, 6, 30, 4, # e0 + 9, 8, 14, 7, 2, 12, 28, 23, 42, 24, 64, 75, 19, 26, 27,253, # f0 +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 98.2851% +# first 1024 sequences:1.7001% +# rest sequences: 0.0359% +# negative sequences: 0.0148% +GreekLangModel = ( \ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,2,2,3,3,3,3,3,3,3,3,1,3,3,3,0,2,2,3,3,0,3,0,3,2,0,3,3,3,0, +3,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,0,3,3,0,3,2,3,3,0,3,2,3,3,3,0,0,3,0,3,0,3,3,2,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,2,3,2,2,3,3,3,3,3,3,3,3,0,3,3,3,3,0,2,3,3,0,3,3,3,3,2,3,3,3,0, +2,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,0,2,1,3,3,3,3,2,3,3,2,3,3,2,0, +0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,3,3,0,3,3,3,3,3,3,3,3,3,3,0,3,2,3,3,0, +2,0,1,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,3,0,0,0,0,3,3,0,3,1,3,3,3,0,3,3,0,3,3,3,3,0,0,0,0, +2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,0,3,0,3,3,3,3,3,0,3,2,2,2,3,0,2,3,3,3,3,3,2,3,3,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,3,2,2,2,3,3,3,3,0,3,1,3,3,3,3,2,3,3,3,3,3,3,3,2,2,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,3,0,0,0,3,3,2,3,3,3,3,3,0,0,3,2,3,0,2,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,3,0,0,3,3,0,2,3,0,3,0,3,3,3,0,0,3,0,3,0,2,2,3,3,0,0, +0,0,1,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,3,2,3,3,3,3,0,3,3,3,3,3,0,3,3,2,3,2,3,3,2,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,2,3,2,3,3,3,3,3,3,0,2,3,2,3,2,2,2,3,2,3,3,2,3,0,2,2,2,3,0, +2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,0,3,3,3,2,3,3,0,0,3,0,3,0,0,0,3,2,0,3,0,3,0,0,2,0,2,0, +0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,3,3,0,3,0,0,0,3,3,0,3,3,3,0,0,1,2,3,0, +3,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,0,3,2,2,3,3,0,3,3,3,3,3,2,1,3,0,3,2,3,3,2,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,3,0,2,3,3,3,3,3,3,0,0,3,0,3,0,0,0,3,3,0,3,2,3,0,0,3,3,3,0, +3,0,0,0,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,0,3,0,3,0,0,0,3,2,0,3,2,3,0,0,3,2,3,0, +2,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,1,2,2,3,3,3,3,3,3,0,2,3,0,3,0,0,0,3,3,0,3,0,2,0,0,2,3,1,0, +2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,3,0,3,0,3,3,2,3,0,3,3,3,3,3,3,0,3,3,3,0,2,3,0,0,3,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,0,0,3,0,0,0,3,3,0,3,0,2,3,3,0,0,3,0,3,0,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,0,3,3,3,3,3,3,0,0,3,0,2,0,0,0,3,3,0,3,0,3,0,0,2,0,2,0, +0,0,0,0,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,3,0,3,0,2,0,3,2,0,3,2,3,2,3,0,0,3,2,3,2,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,2,3,3,3,3,3,0,0,0,3,0,2,1,0,0,3,2,2,2,0,3,0,0,2,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,2,0,3,0,3,0,3,3,0,2,1,2,3,3,0,0,3,0,3,0,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,3,0,3,3,3,3,3,3,0,2,3,0,3,0,0,0,2,1,0,2,2,3,0,0,2,2,2,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,2,3,3,3,2,3,0,0,1,3,0,2,0,0,0,0,3,0,1,0,2,0,0,1,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,1,0,3,0,0,0,3,2,0,3,2,3,3,3,0,0,3,0,3,2,2,2,1,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,0,0,3,0,0,0,0,2,0,2,3,3,2,2,2,2,3,0,2,0,2,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,2,0,0,0,0,0,0,2,3,0,2,0,2,3,2,0,0,3,0,3,0,3,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,3,2,3,3,2,2,3,0,2,0,3,0,0,0,2,0,0,0,0,1,2,0,2,0,2,0, +0,2,0,2,0,2,2,0,0,1,0,2,2,2,0,2,2,2,0,2,2,2,0,0,2,0,0,1,0,0,0,0, +0,2,0,3,3,2,0,0,0,0,0,0,1,3,0,2,0,2,2,2,0,0,2,0,3,0,0,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,2,3,2,0,2,2,0,2,0,2,2,0,2,0,2,2,2,0,0,0,0,0,0,2,3,0,0,0,2, +0,1,2,0,0,0,0,2,2,0,0,0,2,1,0,2,2,0,0,0,0,0,0,1,0,2,0,0,0,0,0,0, +0,0,2,1,0,2,3,2,2,3,2,3,2,0,0,3,3,3,0,0,3,2,0,0,0,1,1,0,2,0,2,2, +0,2,0,2,0,2,2,0,0,2,0,2,2,2,0,2,2,2,2,0,0,2,0,0,0,2,0,1,0,0,0,0, +0,3,0,3,3,2,2,0,3,0,0,0,2,2,0,2,2,2,1,2,0,0,1,2,2,0,0,3,0,0,0,2, +0,1,2,0,0,0,1,2,0,0,0,0,0,0,0,2,2,0,1,0,0,2,0,0,0,2,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,2,2,0,0,0,2,0,2,3,3,0,2,0,0,0,0,0,0,2,2,2,0,2,2,0,2,0,2, +0,2,2,0,0,2,2,2,2,1,0,0,2,2,0,2,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0, +0,2,0,3,2,3,0,0,0,3,0,0,2,2,0,2,0,2,2,2,0,0,2,0,0,0,0,0,0,0,0,2, +0,0,2,2,0,0,2,2,2,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,3,2,0,2,2,2,2,2,0,0,0,2,0,0,0,0,2,0,1,0,0,2,0,1,0,0,0, +0,2,2,2,0,2,2,0,1,2,0,2,2,2,0,2,2,2,2,1,2,2,0,0,2,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,2,0,2,0,2,2,0,0,0,0,1,2,1,0,0,2,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,3,2,3,0,0,2,0,0,0,2,2,0,2,0,0,0,1,0,0,2,0,2,0,2,2,0,0,0,0, +0,0,2,0,0,0,0,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0, +0,2,2,3,2,2,0,0,0,0,0,0,1,3,0,2,0,2,2,0,0,0,1,0,2,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,0,2,0,3,2,0,2,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,2,0,0,0,0,1,1,0,0,2,1,2,0,2,2,0,1,0,0,1,0,0,0,2,0,0,0,0,0,0, +0,3,0,2,2,2,0,0,2,0,0,0,2,0,0,0,2,3,0,2,0,0,0,0,0,0,2,2,0,0,0,2, +0,1,2,0,0,0,1,2,2,1,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,1,2,0,2,2,0,2,0,0,2,0,0,0,0,1,2,1,0,2,1,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,3,1,2,2,0,2,0,0,0,0,2,0,0,0,2,0,0,3,0,0,0,0,2,2,2,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,1,0,2,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,2, +0,2,2,0,0,2,2,2,2,2,0,1,2,0,0,0,2,2,0,1,0,2,0,0,2,2,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,0,0,0,0,2,0,2,0,0,0,0,2, +0,1,2,0,0,0,0,2,2,1,0,1,0,1,0,2,2,2,1,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,2,0,1,2,0,0,0,0,0,0,0,0,0,0,2,0,0,2,2,0,0,0,0,1,0,0,0,0,0,0,2, +0,2,2,0,0,0,0,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0, +0,2,2,2,2,0,0,0,3,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0,1, +0,0,2,0,0,0,0,1,2,0,0,0,0,0,0,2,2,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,2,0,2,2,2,0,0,2,0,0,0,0,0,0,0,2,2,2,0,0,0,2,0,0,0,0,0,0,0,0,2, +0,0,1,0,0,0,0,2,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,3,0,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,2, +0,0,2,0,0,0,0,2,2,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,0,2,2,1,0,0,0,0,0,0,2,0,0,2,0,2,2,2,0,0,0,0,0,0,2,0,0,0,0,2, +0,0,2,0,0,2,0,2,2,0,0,0,0,2,0,2,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0, +0,0,3,0,0,0,2,2,0,2,2,0,0,0,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0, +0,2,2,2,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1, +0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,2,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,2,0,0,0,2,0,0,0,0,0,1,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,2,0,0,0, +0,2,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,2,0,2,0,0,0, +0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,2,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +Latin7GreekModel = { \ + 'charToOrderMap': Latin7_CharToOrderMap, + 'precedenceMatrix': GreekLangModel, + 'mTypicalPositiveRatio': 0.982851, + 'keepEnglishLetter': False, + 'charsetName': "ISO-8859-7" +} + +Win1253GreekModel = { \ + 'charToOrderMap': win1253_CharToOrderMap, + 'precedenceMatrix': GreekLangModel, + 'mTypicalPositiveRatio': 0.982851, + 'keepEnglishLetter': False, + 'charsetName': "windows-1253" +} diff --git a/libs/requests/packages/chardet2/langhebrewmodel.py b/libs/requests/packages/chardet2/langhebrewmodel.py new file mode 100644 index 00000000..126cf073 --- /dev/null +++ b/libs/requests/packages/chardet2/langhebrewmodel.py @@ -0,0 +1,201 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Simon Montagu +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Shoshannah Forbes - original C code (?) +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Windows-1255 language model +# Character Mapping Table: +win1255_CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 69, 91, 79, 80, 92, 89, 97, 90, 68,111,112, 82, 73, 95, 85, # 40 + 78,121, 86, 71, 67,102,107, 84,114,103,115,253,253,253,253,253, # 50 +253, 50, 74, 60, 61, 42, 76, 70, 64, 53,105, 93, 56, 65, 54, 49, # 60 + 66,110, 51, 43, 44, 63, 81, 77, 98, 75,108,253,253,253,253,253, # 70 +124,202,203,204,205, 40, 58,206,207,208,209,210,211,212,213,214, +215, 83, 52, 47, 46, 72, 32, 94,216,113,217,109,218,219,220,221, + 34,116,222,118,100,223,224,117,119,104,125,225,226, 87, 99,227, +106,122,123,228, 55,229,230,101,231,232,120,233, 48, 39, 57,234, + 30, 59, 41, 88, 33, 37, 36, 31, 29, 35,235, 62, 28,236,126,237, +238, 38, 45,239,240,241,242,243,127,244,245,246,247,248,249,250, + 9, 8, 20, 16, 3, 2, 24, 14, 22, 1, 25, 15, 4, 11, 6, 23, + 12, 19, 13, 26, 18, 27, 21, 17, 7, 10, 5,251,252,128, 96,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 98.4004% +# first 1024 sequences: 1.5981% +# rest sequences: 0.087% +# negative sequences: 0.0015% +HebrewLangModel = ( \ +0,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,2,3,2,1,2,0,1,0,0, +3,0,3,1,0,0,1,3,2,0,1,1,2,0,2,2,2,1,1,1,1,2,1,1,1,2,0,0,2,2,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2, +1,2,1,2,1,2,0,0,2,0,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2, +1,2,1,3,1,1,0,0,2,0,0,0,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,0,1,2,2,1,3, +1,2,1,1,2,2,0,0,2,2,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,1,0,1,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,2,2,2,2,3,2, +1,2,1,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,2,3,2,2,3,2,2,2,1,2,2,2,2, +1,2,1,1,2,2,0,1,2,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,2,2,2,2,2, +0,2,0,2,2,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,0,2,2,2, +0,2,1,2,2,2,0,0,2,1,0,0,0,0,1,0,1,0,0,0,0,0,0,2,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,2,1,2,3,2,2,2, +1,2,1,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,1,0,2,0,2, +0,2,1,2,2,2,0,0,1,2,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,2,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,2,3,2,2,3,2,1,2,1,1,1, +0,1,1,1,1,1,3,0,1,0,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,0,0,1,0,0,0,0, +0,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,2,1,2,3,3,2,3,3,3,3,2,3,2,1,2,0,2,1,2, +0,2,0,2,2,2,0,0,1,2,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,1,2,2,3,3,2,3,2,3,2,2,3,1,2,2,0,2,2,2, +0,2,1,2,2,2,0,0,1,2,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,2,2,2,3,3,3,3,1,3,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,3,3,2,3,2,2,2,1,2,2,0,2,2,2,2, +0,2,0,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,1,3,2,3,3,2,3,3,2,2,1,2,2,2,2,2,2, +0,2,1,2,1,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,2,3,3,2,3,3,3,3,2,3,2,3,3,3,3,3,2,2,2,2,2,2,2,1, +0,2,0,1,2,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,1,2,3,3,3,3,3,3,3,2,3,2,3,2,1,2,3,0,2,1,2,2, +0,2,1,1,2,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,2,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,3,2,1,3,1,2,2,2,1,2,3,3,1,2,1,2,2,2,2, +0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,0,2,3,3,3,1,3,3,3,1,2,2,2,2,1,1,2,2,2,2,2,2, +0,2,0,1,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,2,2,3,3,3,2,1,2,3,2,3,2,2,2,2,1,2,1,1,1,2,2, +0,2,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1,0,0,0,0,0, +1,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,3,2,3,1,2,2,2,2,3,2,3,1,1,2,2,1,2,2,1,1,0,2,2,2,2, +0,1,0,1,2,2,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,0,0,1,1,0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,0,1,0,1,1,0,1,1,0,0,0,1,1,0,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +3,2,2,1,2,2,2,2,2,2,2,1,2,2,1,2,2,1,1,1,1,1,1,1,1,2,1,1,0,3,3,3, +0,3,0,2,2,2,2,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +2,2,2,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,1,2,2,2,1,1,1,2,0,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,0,0,0,0, +0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,0,2,1,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,3,1,1,2,2,2,2,2,1,2,2,2,1,1,2,2,2,2,2,2,2,1,2,2,1,0,1,1,1,1,0, +0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,1,1,1,1,2,1,1,2,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,0,0, +2,1,1,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,1,2,1,2,1,1,1,1,0,0,0,0, +0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,1,2,1,1,2,1,1,1,2,1,2,1,2,0,1,0,1, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,1,2,2,2,1,2,2,2,2,2,2,2,2,1,2,1,1,1,1,1,1,2,1,2,1,1,0,1,0,1, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,1,1,1,1,1,1,0,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,1,1,1,0,1,0,0,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0, +0,1,1,1,2,1,2,2,2,0,2,0,2,0,1,1,2,1,1,1,1,2,1,0,1,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,1,0,0,0,0,0,1,0,1,2,2,0,1,0,0,1,1,2,2,1,2,0,2,0,0,0,1,2,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,2,1,2,0,2,0,0,1,1,1,1,1,1,0,1,0,0,0,1,0,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,1,0,2,1,1,0,1,0,0,1,1,1,2,2,0,0,1,0,0,0,1,0,0,1, +1,1,2,1,0,1,1,1,0,1,0,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,2,1, +0,2,0,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,0,0,1,0,1,1,1,1,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,1,0,0,0,1,1,0,1, +2,0,1,0,1,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,0,1,1,2,1,1,2,0,1,0,0,0,1,1,0,1, +1,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,0,0,2,1,1,2,0,2,0,0,0,1,1,0,1, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,2,1,1,0,1,0,0,2,2,1,2,1,1,0,1,0,0,0,1,1,0,1, +2,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,1,0,1, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,2,1,1,1,0,2,1,1,0,0,0,2,1,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,1,1,0,2,1,1,0,1,0,0,0,1,1,0,1, +2,2,1,1,1,0,1,1,0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,2,1,1,0,1,0,0,1,1,0,1,2,1,0,2,0,0,0,1,1,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0, +0,1,0,0,2,0,2,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,1,1,1,0,1,0,0,1,0,0,0,1,0,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,1,0,1,1,0,0,1,0,0,2,1,1,1,1,1,0,1,0,0,0,0,1,0,1, +0,1,1,1,2,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,1,0,0,0,0,0,1,1,1,1,1,0,1,0,0,0,1,1,0,0, +) + +Win1255HebrewModel = { \ + 'charToOrderMap': win1255_CharToOrderMap, + 'precedenceMatrix': HebrewLangModel, + 'mTypicalPositiveRatio': 0.984004, + 'keepEnglishLetter': False, + 'charsetName': "windows-1255" +} diff --git a/libs/requests/packages/chardet2/langhungarianmodel.py b/libs/requests/packages/chardet2/langhungarianmodel.py new file mode 100644 index 00000000..76c21404 --- /dev/null +++ b/libs/requests/packages/chardet2/langhungarianmodel.py @@ -0,0 +1,225 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin2_HungarianCharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 28, 40, 54, 45, 32, 50, 49, 38, 39, 53, 36, 41, 34, 35, 47, + 46, 71, 43, 33, 37, 57, 48, 64, 68, 55, 52,253,253,253,253,253, +253, 2, 18, 26, 17, 1, 27, 12, 20, 9, 22, 7, 6, 13, 4, 8, + 23, 67, 10, 5, 3, 21, 19, 65, 62, 16, 11,253,253,253,253,253, +159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174, +175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190, +191,192,193,194,195,196,197, 75,198,199,200,201,202,203,204,205, + 79,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, +221, 51, 81,222, 78,223,224,225,226, 44,227,228,229, 61,230,231, +232,233,234, 58,235, 66, 59,236,237,238, 60, 69, 63,239,240,241, + 82, 14, 74,242, 70, 80,243, 72,244, 15, 83, 77, 84, 30, 76, 85, +245,246,247, 25, 73, 42, 24,248,249,250, 31, 56, 29,251,252,253, +) + +win1250HungarianCharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 28, 40, 54, 45, 32, 50, 49, 38, 39, 53, 36, 41, 34, 35, 47, + 46, 72, 43, 33, 37, 57, 48, 64, 68, 55, 52,253,253,253,253,253, +253, 2, 18, 26, 17, 1, 27, 12, 20, 9, 22, 7, 6, 13, 4, 8, + 23, 67, 10, 5, 3, 21, 19, 65, 62, 16, 11,253,253,253,253,253, +161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176, +177,178,179,180, 78,181, 69,182,183,184,185,186,187,188,189,190, +191,192,193,194,195,196,197, 76,198,199,200,201,202,203,204,205, + 81,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, +221, 51, 83,222, 80,223,224,225,226, 44,227,228,229, 61,230,231, +232,233,234, 58,235, 66, 59,236,237,238, 60, 70, 63,239,240,241, + 84, 14, 75,242, 71, 82,243, 73,244, 15, 85, 79, 86, 30, 77, 87, +245,246,247, 25, 74, 42, 24,248,249,250, 31, 56, 29,251,252,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 94.7368% +# first 1024 sequences:5.2623% +# rest sequences: 0.8894% +# negative sequences: 0.0009% +HungarianLangModel = ( \ +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,2,2,3,3,1,1,2,2,2,2,2,1,2, +3,2,2,3,3,3,3,3,2,3,3,3,3,3,3,1,2,3,3,3,3,2,3,3,1,1,3,3,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0, +3,2,1,3,3,3,3,3,2,3,3,3,3,3,1,1,2,3,3,3,3,3,3,3,1,1,3,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,1,1,2,3,3,3,1,3,3,3,3,3,1,3,3,2,2,0,3,2,3, +0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,2,3,3,2,3,3,3,3,3,2,3,3,2,2,3,2,3,2,0,3,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,3,3,2,3,3,3,1,2,3,2,2,3,1,2,3,3,2,2,0,3,3,3, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,3,2,3,3,3,3,2,3,3,3,3,0,2,3,2, +0,0,0,1,1,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,1,1,1,3,3,2,1,3,2,2,3,2,1,3,2,2,1,0,3,3,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,2,2,3,3,3,3,3,1,2,3,3,3,3,1,2,1,3,3,3,3,2,2,3,1,1,3,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,1,3,3,3,3,3,2,2,1,3,3,3,0,1,1,2, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,2,3,3,3,2,0,3,2,3, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,2,3,2,3,3,3,1,3,2,2,2,3,1,1,3,3,1,1,0,3,3,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,2,3,3,3,2,3,2,3,3,3,2,3,3,3,3,3,1,2,3,2,2,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,1,3,3,2,2,1,3,3,3,1,1,3,1,2,3,2,3,2,2,2,1,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,1,1,3,3,3,3,3,1,2,3,3,3,3,1,2,1,3,3,3,2,2,3,2,1,0,3,2,0,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,3,3,3,3,3,1,2,3,3,3,3,1,1,0,3,3,3,3,0,2,3,0,0,2,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,2,2,2,2,3,3,0,1,2,3,2,3,2,2,3,2,1,2,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,3,3,3,3,3,1,2,3,3,3,2,1,2,3,3,2,2,2,3,2,3,3,1,3,3,1,1,0,2,3,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,1,2,2,2,2,3,3,3,1,1,1,3,3,1,1,3,1,1,3,2,1,2,3,1,1,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,1,2,1,1,3,3,1,1,1,1,3,3,1,1,2,2,1,2,1,1,2,2,1,1,0,2,2,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,1,1,2,1,1,3,3,1,0,1,1,3,3,2,0,1,1,2,3,1,0,2,2,1,0,0,1,3,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,2,1,3,3,3,3,3,1,2,3,2,3,3,2,1,1,3,2,3,2,1,2,2,0,1,2,1,0,0,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,2,2,2,2,3,1,2,2,1,1,3,3,0,3,2,1,2,3,2,1,3,3,1,1,0,2,1,3, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,2,3,3,3,2,1,1,3,3,1,1,1,2,2,3,2,3,2,2,2,1,0,2,2,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +1,0,0,3,3,3,3,3,0,0,3,3,2,3,0,0,0,2,3,3,1,0,1,2,0,0,1,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,2,3,3,3,3,3,1,2,3,3,2,2,1,1,0,3,3,2,2,1,2,2,1,0,2,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,2,1,3,1,2,3,3,2,2,1,1,2,2,1,1,1,1,3,2,1,1,1,1,2,1,0,1,2,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +2,3,3,1,1,1,1,1,3,3,3,0,1,1,3,3,1,1,1,1,1,2,2,0,3,1,1,2,0,2,1,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,1,0,1,2,1,2,2,0,1,2,3,1,2,0,0,0,2,1,1,1,1,1,2,0,0,1,1,0,0,0,0, +1,2,1,2,2,2,1,2,1,2,0,2,0,2,2,1,1,2,1,1,2,1,1,1,0,1,0,0,0,1,1,0, +1,1,1,2,3,2,3,3,0,1,2,2,3,1,0,1,0,2,1,2,2,0,1,1,0,0,1,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,3,3,2,2,1,0,0,3,2,3,2,0,0,0,1,1,3,0,0,1,1,0,0,2,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,2,2,3,3,1,0,1,3,2,3,1,1,1,0,1,1,1,1,1,3,1,0,0,2,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,1,2,2,2,1,0,1,2,3,3,2,0,0,0,2,1,1,1,2,1,1,1,0,1,1,1,0,0,0, +1,2,2,2,2,2,1,1,1,2,0,2,1,1,1,1,1,2,1,1,1,1,1,1,0,1,1,1,0,0,1,1, +3,2,2,1,0,0,1,1,2,2,0,3,0,1,2,1,1,0,0,1,1,1,0,1,1,1,1,0,2,1,1,1, +2,2,1,1,1,2,1,2,1,1,1,1,1,1,1,2,1,1,1,2,3,1,1,1,1,1,1,1,1,1,0,1, +2,3,3,0,1,0,0,0,3,3,1,0,0,1,2,2,1,0,0,0,0,2,0,0,1,1,1,0,2,1,1,1, +2,1,1,1,1,1,1,2,1,1,0,1,1,0,1,1,1,0,1,2,1,1,0,1,1,1,1,1,1,1,0,1, +2,3,3,0,1,0,0,0,2,2,0,0,0,0,1,2,2,0,0,0,0,1,0,0,1,1,0,0,2,0,1,0, +2,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,2,0,1,1,1,1,1,0,1, +3,2,2,0,1,0,1,0,2,3,2,0,0,1,2,2,1,0,0,1,1,1,0,0,2,1,0,1,2,2,1,1, +2,1,1,1,1,1,1,2,1,1,1,1,1,1,0,2,1,0,1,1,0,1,1,1,0,1,1,2,1,1,0,1, +2,2,2,0,0,1,0,0,2,2,1,1,0,0,2,1,1,0,0,0,1,2,0,0,2,1,0,0,2,1,1,1, +2,1,1,1,1,2,1,2,1,1,1,2,2,1,1,2,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1, +1,2,3,0,0,0,1,0,3,2,1,0,0,1,2,1,1,0,0,0,0,2,1,0,1,1,0,0,2,1,2,1, +1,1,0,0,0,1,0,1,1,1,1,1,2,0,0,1,0,0,0,2,0,0,1,1,1,1,1,1,1,1,0,1, +3,0,0,2,1,2,2,1,0,0,2,1,2,2,0,0,0,2,1,1,1,0,1,1,0,0,1,1,2,0,0,0, +1,2,1,2,2,1,1,2,1,2,0,1,1,1,1,1,1,1,1,1,2,1,1,0,0,1,1,1,1,0,0,1, +1,3,2,0,0,0,1,0,2,2,2,0,0,0,2,2,1,0,0,0,0,3,1,1,1,1,0,0,2,1,1,1, +2,1,0,1,1,1,0,1,1,1,1,1,1,1,0,2,1,0,0,1,0,1,1,0,1,1,1,1,1,1,0,1, +2,3,2,0,0,0,1,0,2,2,0,0,0,0,2,1,1,0,0,0,0,2,1,0,1,1,0,0,2,1,1,0, +2,1,1,1,1,2,1,2,1,2,0,1,1,1,0,2,1,1,1,2,1,1,1,1,0,1,1,1,1,1,0,1, +3,1,1,2,2,2,3,2,1,1,2,2,1,1,0,1,0,2,2,1,1,1,1,1,0,0,1,1,0,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,0,0,0,0,0,2,2,0,0,0,0,2,2,1,0,0,0,1,1,0,0,1,2,0,0,2,1,1,1, +2,2,1,1,1,2,1,2,1,1,0,1,1,1,1,2,1,1,1,2,1,1,1,1,0,1,2,1,1,1,0,1, +1,0,0,1,2,3,2,1,0,0,2,0,1,1,0,0,0,1,1,1,1,0,1,1,0,0,1,0,0,0,0,0, +1,2,1,2,1,2,1,1,1,2,0,2,1,1,1,0,1,2,0,0,1,1,1,0,0,0,0,0,0,0,0,0, +2,3,2,0,0,0,0,0,1,1,2,1,0,0,1,1,1,0,0,0,0,2,0,0,1,1,0,0,2,1,1,1, +2,1,1,1,1,1,1,2,1,0,1,1,1,1,0,2,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1, +1,2,2,0,1,1,1,0,2,2,2,0,0,0,3,2,1,0,0,0,1,1,0,0,1,1,0,1,1,1,0,0, +1,1,0,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,0,0,1,1,1,0,1,0,1, +2,1,0,2,1,1,2,2,1,1,2,1,1,1,0,0,0,1,1,0,1,1,1,1,0,0,1,1,1,0,0,0, +1,2,2,2,2,2,1,1,1,2,0,2,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,1,0, +1,2,3,0,0,0,1,0,2,2,0,0,0,0,2,2,0,0,0,0,0,1,0,0,1,0,0,0,2,0,1,0, +2,1,1,1,1,1,0,2,0,0,0,1,2,1,1,1,1,0,1,2,0,1,0,1,0,1,1,1,0,1,0,1, +2,2,2,0,0,0,1,0,2,1,2,0,0,0,1,1,2,0,0,0,0,1,0,0,1,1,0,0,2,1,0,1, +2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,0,1,1,1,1,1,0,1, +1,2,2,0,0,0,1,0,2,2,2,0,0,0,1,1,0,0,0,0,0,1,1,0,2,0,0,1,1,1,0,1, +1,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,0,0,1,1,0,1,0,1,1,1,1,1,0,0,0,1, +1,0,0,1,0,1,2,1,0,0,1,1,1,2,0,0,0,1,1,0,1,0,1,1,0,0,1,0,0,0,0,0, +0,2,1,2,1,1,1,1,1,2,0,2,0,1,1,0,1,2,1,0,1,1,1,0,0,0,0,0,0,1,0,0, +2,1,1,0,1,2,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,2,1,0,1, +2,2,1,1,1,1,1,2,1,1,0,1,1,1,1,2,1,1,1,2,1,1,0,1,0,1,1,1,1,1,0,1, +1,2,2,0,0,0,0,0,1,1,0,0,0,0,2,1,0,0,0,0,0,2,0,0,2,2,0,0,2,0,0,1, +2,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,0,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1, +1,1,2,0,0,3,1,0,2,1,1,1,0,0,1,1,1,0,0,0,1,1,0,0,0,1,0,0,1,0,1,0, +1,2,1,0,1,1,1,2,1,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,1,0,0,0,1,0,0, +2,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,2,0,0,0, +2,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,2,1,1,0,0,1,1,1,1,1,0,1, +2,1,1,1,2,1,1,1,0,1,1,2,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,0,1,1,1,1,1,0,0,1,1,2,1,0,0,0,1,1,0,0,0,1,1,0,0,1,0,1,0,0,0, +1,2,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,1,0,0, +2,0,0,0,1,1,1,1,0,0,1,1,0,0,0,0,0,1,1,1,2,0,0,1,0,0,1,0,1,0,0,0, +0,1,1,1,1,1,1,1,1,2,0,1,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,1,0,0,2,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0, +0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,0,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +0,1,1,1,1,1,0,0,1,1,0,1,0,1,0,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +0,0,0,1,0,0,0,0,0,0,1,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,1,1,0,1,0,0,1,1,0,1,0,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +2,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0,1,0,1,0,1,1,1,0,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,1,1,1,1,1,0,1,1,0,1,0,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +) + +Latin2HungarianModel = { \ + 'charToOrderMap': Latin2_HungarianCharToOrderMap, + 'precedenceMatrix': HungarianLangModel, + 'mTypicalPositiveRatio': 0.947368, + 'keepEnglishLetter': True, + 'charsetName': "ISO-8859-2" +} + +Win1250HungarianModel = { \ + 'charToOrderMap': win1250HungarianCharToOrderMap, + 'precedenceMatrix': HungarianLangModel, + 'mTypicalPositiveRatio': 0.947368, + 'keepEnglishLetter': True, + 'charsetName': "windows-1250" +} diff --git a/libs/requests/packages/chardet2/langthaimodel.py b/libs/requests/packages/chardet2/langthaimodel.py new file mode 100644 index 00000000..cfa8ca11 --- /dev/null +++ b/libs/requests/packages/chardet2/langthaimodel.py @@ -0,0 +1,200 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# The following result for thai was collected from a limited sample (1M). + +# Character Mapping Table: +TIS620CharToOrderMap = ( \ +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,182,106,107,100,183,184,185,101, 94,186,187,108,109,110,111, # 40 +188,189,190, 89, 95,112,113,191,192,193,194,253,253,253,253,253, # 50 +253, 64, 72, 73,114, 74,115,116,102, 81,201,117, 90,103, 78, 82, # 60 + 96,202, 91, 79, 84,104,105, 97, 98, 92,203,253,253,253,253,253, # 70 +209,210,211,212,213, 88,214,215,216,217,218,219,220,118,221,222, +223,224, 99, 85, 83,225,226,227,228,229,230,231,232,233,234,235, +236, 5, 30,237, 24,238, 75, 8, 26, 52, 34, 51,119, 47, 58, 57, + 49, 53, 55, 43, 20, 19, 44, 14, 48, 3, 17, 25, 39, 62, 31, 54, + 45, 9, 16, 2, 61, 15,239, 12, 42, 46, 18, 21, 76, 4, 66, 63, + 22, 10, 1, 36, 23, 13, 40, 27, 32, 35, 86,240,241,242,243,244, + 11, 28, 41, 29, 33,245, 50, 37, 6, 7, 67, 77, 38, 93,246,247, + 68, 56, 59, 65, 69, 60, 70, 80, 71, 87,248,249,250,251,252,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 92.6386% +# first 1024 sequences:7.3177% +# rest sequences: 1.0230% +# negative sequences: 0.0436% +ThaiLangModel = ( \ +0,1,3,3,3,3,0,0,3,3,0,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3,3,0,3,3,3,3, +0,3,3,0,0,0,1,3,0,3,3,2,3,3,0,1,2,3,3,3,3,0,2,0,2,0,0,3,2,1,2,2, +3,0,3,3,2,3,0,0,3,3,0,3,3,0,3,3,3,3,3,3,3,3,3,0,3,2,3,0,2,2,2,3, +0,2,3,0,0,0,0,1,0,1,2,3,1,1,3,2,2,0,1,1,0,0,1,0,0,0,0,0,0,0,1,1, +3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,3,3,2,3,2,3,3,2,2,2, +3,1,2,3,0,3,3,2,2,1,2,3,3,1,2,0,1,3,0,1,0,0,1,0,0,0,0,0,0,0,1,1, +3,3,2,2,3,3,3,3,1,2,3,3,3,3,3,2,2,2,2,3,3,2,2,3,3,2,2,3,2,3,2,2, +3,3,1,2,3,1,2,2,3,3,1,0,2,1,0,0,3,1,2,1,0,0,1,0,0,0,0,0,0,1,0,1, +3,3,3,3,3,3,2,2,3,3,3,3,2,3,2,2,3,3,2,2,3,2,2,2,2,1,1,3,1,2,1,1, +3,2,1,0,2,1,0,1,0,1,1,0,1,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,3,2,3,2,3,3,2,2,3,2,3,3,2,3,1,1,2,3,2,2,2,3,2,2,2,2,2,1,2,1, +2,2,1,1,3,3,2,1,0,1,2,2,0,1,3,0,0,0,1,1,0,0,0,0,0,2,3,0,0,2,1,1, +3,3,2,3,3,2,0,0,3,3,0,3,3,0,2,2,3,1,2,2,1,1,1,0,2,2,2,0,2,2,1,1, +0,2,1,0,2,0,0,2,0,1,0,0,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,2,3,3,2,0,0,3,3,0,2,3,0,2,1,2,2,2,2,1,2,0,0,2,2,2,0,2,2,1,1, +0,2,1,0,2,0,0,2,0,1,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,2,3,2,3,2,0,2,2,1,3,2,1,3,2,1,2,3,2,2,3,0,2,3,2,2,1,2,2,2,2, +1,2,2,0,0,0,0,2,0,1,2,0,1,1,1,0,1,0,3,1,1,0,0,0,0,0,0,0,0,0,1,0, +3,3,2,3,3,2,3,2,2,2,3,2,2,3,2,2,1,2,3,2,2,3,1,3,2,2,2,3,2,2,2,3, +3,2,1,3,0,1,1,1,0,2,1,1,1,1,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,2,0,0, +1,0,0,3,0,3,3,3,3,3,0,0,3,0,2,2,3,3,3,3,3,0,0,0,1,1,3,0,0,0,0,2, +0,0,1,0,0,0,0,0,0,0,2,3,0,0,0,3,0,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +2,0,3,3,3,3,0,0,2,3,0,0,3,0,3,3,2,3,3,3,3,3,0,0,3,3,3,0,0,0,3,3, +0,0,3,0,0,0,0,2,0,0,2,1,1,3,0,0,1,0,0,2,3,0,1,0,0,0,0,0,0,0,1,0, +3,3,3,3,2,3,3,3,3,3,3,3,1,2,1,3,3,2,2,1,2,2,2,3,1,1,2,0,2,1,2,1, +2,2,1,0,0,0,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0, +3,0,2,1,2,3,3,3,0,2,0,2,2,0,2,1,3,2,2,1,2,1,0,0,2,2,1,0,2,1,2,2, +0,1,1,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,3,3,1,1,3,0,2,3,1,1,3,2,1,1,2,0,2,2,3,2,1,1,1,1,1,2, +3,0,0,1,3,1,2,1,2,0,3,0,0,0,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, +3,3,1,1,3,2,3,3,3,1,3,2,1,3,2,1,3,2,2,2,2,1,3,3,1,2,1,3,1,2,3,0, +2,1,1,3,2,2,2,1,2,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2, +3,3,2,3,2,3,3,2,3,2,3,2,3,3,2,1,0,3,2,2,2,1,2,2,2,1,2,2,1,2,1,1, +2,2,2,3,0,1,3,1,1,1,1,0,1,1,0,2,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,3,2,2,1,1,3,2,3,2,3,2,0,3,2,2,1,2,0,2,2,2,1,2,2,2,2,1, +3,2,1,2,2,1,0,2,0,1,0,0,1,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,2,3,1,2,3,3,2,2,3,0,1,1,2,0,3,3,2,2,3,0,1,1,3,0,0,0,0, +3,1,0,3,3,0,2,0,2,1,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,3,2,3,3,0,1,3,1,1,2,1,2,1,1,3,1,1,0,2,3,1,1,1,1,1,1,1,1, +3,1,1,2,2,2,2,1,1,1,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,2,2,1,1,2,1,3,3,2,3,2,2,3,2,2,3,1,2,2,1,2,0,3,2,1,2,2,2,2,2,1, +3,2,1,2,2,2,1,1,1,1,0,0,1,1,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,1,3,3,0,2,1,0,3,2,0,0,3,1,0,1,1,0,1,0,0,0,0,0,1, +1,0,0,1,0,3,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,2,2,2,3,0,0,1,3,0,3,2,0,3,2,2,3,3,3,3,3,1,0,2,2,2,0,2,2,1,2, +0,2,3,0,0,0,0,1,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,0,2,3,1,3,3,2,3,3,0,3,3,0,3,2,2,3,2,3,3,3,0,0,2,2,3,0,1,1,1,3, +0,0,3,0,0,0,2,2,0,1,3,0,1,2,2,2,3,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1, +3,2,3,3,2,0,3,3,2,2,3,1,3,2,1,3,2,0,1,2,2,0,2,3,2,1,0,3,0,0,0,0, +3,0,0,2,3,1,3,0,0,3,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,3,2,2,2,1,2,0,1,3,1,1,3,1,3,0,0,2,1,1,1,1,2,1,1,1,0,2,1,0,1, +1,2,0,0,0,3,1,1,0,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0,3,1,0,0,0,1,0, +3,3,3,3,2,2,2,2,2,1,3,1,1,1,2,0,1,1,2,1,2,1,3,2,0,0,3,1,1,1,1,1, +3,1,0,2,3,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,2,3,0,3,3,0,2,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,1,3,0,0,1,2,0,0,2,0,3,3,2,3,3,3,2,3,0,0,2,2,2,0,0,0,2,2, +0,0,1,0,0,0,0,3,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +0,0,0,3,0,2,0,0,0,0,0,0,0,0,0,0,1,2,3,1,3,3,0,0,1,0,3,0,0,0,0,0, +0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,1,2,3,1,2,3,1,0,3,0,2,2,1,0,2,1,1,2,0,1,0,0,1,1,1,1,0,1,0,0, +1,0,0,0,0,1,1,0,3,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,0,1,1,1,3,1,2,2,2,2,2,2,1,1,1,1,0,3,1,0,1,3,1,1,1,1, +1,1,0,2,0,1,3,1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1, +3,0,2,2,1,3,3,2,3,3,0,1,1,0,2,2,1,2,1,3,3,1,0,0,3,2,0,0,0,0,2,1, +0,1,0,0,0,0,1,2,0,1,1,3,1,1,2,2,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,3,0,0,1,0,0,0,3,0,0,3,0,3,1,0,1,1,1,3,2,0,0,0,3,0,0,0,0,2,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,1,3,2,1,3,3,1,2,2,0,1,2,1,0,1,2,0,0,0,0,0,3,0,0,0,3,0,0,0,0, +3,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,2,0,3,3,3,2,2,0,1,1,0,1,3,0,0,0,2,2,0,0,0,0,3,1,0,1,0,0,0, +0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,2,3,1,2,0,0,2,1,0,3,1,0,1,2,0,1,1,1,1,3,0,0,3,1,1,0,2,2,1,1, +0,2,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,3,1,2,0,0,2,2,0,1,2,0,1,0,1,3,1,2,1,0,0,0,2,0,3,0,0,0,1,0, +0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,1,2,2,0,0,0,2,0,2,1,0,1,1,0,1,1,1,2,1,0,0,1,1,1,0,2,1,1,1, +0,1,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1, +0,0,0,2,0,1,3,1,1,1,1,0,0,0,0,3,2,0,1,0,0,0,1,2,0,0,0,1,0,0,0,0, +0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,2,3,2,2,0,0,0,1,0,0,0,0,2,3,2,1,2,2,3,0,0,0,2,3,1,0,0,0,1,1, +0,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0, +3,3,2,2,0,1,0,0,0,0,2,0,2,0,1,0,0,0,1,1,0,0,0,2,1,0,1,0,1,1,0,0, +0,1,0,2,0,0,1,0,3,0,1,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,1,0,0,1,0,0,0,0,0,1,1,2,0,0,0,0,1,0,0,1,3,1,0,0,0,0,1,1,0,0, +0,1,0,0,0,0,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0, +3,3,1,1,1,1,2,3,0,0,2,1,1,1,1,1,0,2,1,1,0,0,0,2,1,0,1,2,1,1,0,1, +2,1,0,3,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,3,1,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1, +0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,0,0,0,0,0,0,1,2,1,0,1,1,0,2,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,2,0,0,0,1,3,0,1,0,0,0,2,0,0,0,0,0,0,0,1,2,0,0,0,0,0, +3,3,0,0,1,1,2,0,0,1,2,1,0,1,1,1,0,1,1,0,0,2,1,1,0,1,0,0,1,1,1,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,1,0,0,0,0,1,0,0,0,0,3,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,0,0,1,1,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,0,1,2,0,1,2,0,0,1,1,0,2,0,1,0,0,1,0,0,0,0,1,0,0,0,2,0,0,0,0, +1,0,0,1,0,1,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,0,0,0,0,0,0,0,1,1,0,1,1,0,2,1,3,0,0,0,0,1,1,0,0,0,0,0,0,0,3, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,1,0,0,2,0,0,2,0,0,1,1,2,0,0,1,1,0,0,0,1,0,0,0,1,1,0,0,0, +1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,3,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0, +1,0,0,0,0,0,0,0,0,1,0,0,0,0,2,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,1,0,0,2,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +TIS620ThaiModel = { \ + 'charToOrderMap': TIS620CharToOrderMap, + 'precedenceMatrix': ThaiLangModel, + 'mTypicalPositiveRatio': 0.926386, + 'keepEnglishLetter': False, + 'charsetName': "TIS-620" +} diff --git a/libs/requests/packages/chardet2/latin1prober.py b/libs/requests/packages/chardet2/latin1prober.py new file mode 100644 index 00000000..9a3da6f6 --- /dev/null +++ b/libs/requests/packages/chardet2/latin1prober.py @@ -0,0 +1,135 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from . import constants + +FREQ_CAT_NUM = 4 + +UDF = 0 # undefined +OTH = 1 # other +ASC = 2 # ascii capital letter +ASS = 3 # ascii small letter +ACV = 4 # accent capital vowel +ACO = 5 # accent capital other +ASV = 6 # accent small vowel +ASO = 7 # accent small other +CLASS_NUM = 8 # total classes + +Latin1_CharToClass = ( \ + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 00 - 07 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 08 - 0F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 10 - 17 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 18 - 1F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 20 - 27 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 28 - 2F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 30 - 37 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 38 - 3F + OTH, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 40 - 47 + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 48 - 4F + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 50 - 57 + ASC, ASC, ASC, OTH, OTH, OTH, OTH, OTH, # 58 - 5F + OTH, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 60 - 67 + ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 68 - 6F + ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 70 - 77 + ASS, ASS, ASS, OTH, OTH, OTH, OTH, OTH, # 78 - 7F + OTH, UDF, OTH, ASO, OTH, OTH, OTH, OTH, # 80 - 87 + OTH, OTH, ACO, OTH, ACO, UDF, ACO, UDF, # 88 - 8F + UDF, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 90 - 97 + OTH, OTH, ASO, OTH, ASO, UDF, ASO, ACO, # 98 - 9F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A0 - A7 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A8 - AF + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B0 - B7 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B8 - BF + ACV, ACV, ACV, ACV, ACV, ACV, ACO, ACO, # C0 - C7 + ACV, ACV, ACV, ACV, ACV, ACV, ACV, ACV, # C8 - CF + ACO, ACO, ACV, ACV, ACV, ACV, ACV, OTH, # D0 - D7 + ACV, ACV, ACV, ACV, ACV, ACO, ACO, ACO, # D8 - DF + ASV, ASV, ASV, ASV, ASV, ASV, ASO, ASO, # E0 - E7 + ASV, ASV, ASV, ASV, ASV, ASV, ASV, ASV, # E8 - EF + ASO, ASO, ASV, ASV, ASV, ASV, ASV, OTH, # F0 - F7 + ASV, ASV, ASV, ASV, ASV, ASO, ASO, ASO, # F8 - FF +) + +# 0 : illegal +# 1 : very unlikely +# 2 : normal +# 3 : very likely +Latin1ClassModel = ( \ +# UDF OTH ASC ASS ACV ACO ASV ASO + 0, 0, 0, 0, 0, 0, 0, 0, # UDF + 0, 3, 3, 3, 3, 3, 3, 3, # OTH + 0, 3, 3, 3, 3, 3, 3, 3, # ASC + 0, 3, 3, 3, 1, 1, 3, 3, # ASS + 0, 3, 3, 3, 1, 2, 1, 2, # ACV + 0, 3, 3, 3, 3, 3, 3, 3, # ACO + 0, 3, 1, 3, 1, 1, 1, 3, # ASV + 0, 3, 1, 3, 1, 1, 3, 3, # ASO +) + +class Latin1Prober(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self.reset() + + def reset(self): + self._mLastCharClass = OTH + self._mFreqCounter = [0] * FREQ_CAT_NUM + CharSetProber.reset(self) + + def get_charset_name(self): + return "windows-1252" + + def feed(self, aBuf): + aBuf = self.filter_with_english_letters(aBuf) + for c in aBuf: + charClass = Latin1_CharToClass[c] + freq = Latin1ClassModel[(self._mLastCharClass * CLASS_NUM) + charClass] + if freq == 0: + self._mState = constants.eNotMe + break + self._mFreqCounter[freq] += 1 + self._mLastCharClass = charClass + + return self.get_state() + + def get_confidence(self): + if self.get_state() == constants.eNotMe: + return 0.01 + + total = sum(self._mFreqCounter) + if total < 0.01: + confidence = 0.0 + else: + confidence = (self._mFreqCounter[3] / total) - (self._mFreqCounter[1] * 20.0 / total) + if confidence < 0.0: + confidence = 0.0 + # lower the confidence of latin1 so that other more accurate detector + # can take priority. + confidence = confidence * 0.5 + return confidence diff --git a/libs/requests/packages/chardet2/mbcharsetprober.py b/libs/requests/packages/chardet2/mbcharsetprober.py new file mode 100644 index 00000000..a6171e0c --- /dev/null +++ b/libs/requests/packages/chardet2/mbcharsetprober.py @@ -0,0 +1,83 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Proofpoint, Inc. +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants +import sys +from .constants import eStart, eError, eItsMe +from .charsetprober import CharSetProber + +class MultiByteCharSetProber(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self._mDistributionAnalyzer = None + self._mCodingSM = None + self._mLastChar = [0, 0] + + def reset(self): + CharSetProber.reset(self) + if self._mCodingSM: + self._mCodingSM.reset() + if self._mDistributionAnalyzer: + self._mDistributionAnalyzer.reset() + self._mLastChar = [0, 0] + + def get_charset_name(self): + pass + + def feed(self, aBuf): + aLen = len(aBuf) + for i in range(0, aLen): + codingState = self._mCodingSM.next_state(aBuf[i]) + if codingState == eError: + if constants._debug: + sys.stderr.write(self.get_charset_name() + ' prober hit error at byte ' + str(i) + '\n') + self._mState = constants.eNotMe + break + elif codingState == eItsMe: + self._mState = constants.eFoundIt + break + elif codingState == eStart: + charLen = self._mCodingSM.get_current_charlen() + if i == 0: + self._mLastChar[1] = aBuf[0] + self._mDistributionAnalyzer.feed(self._mLastChar, charLen) + else: + self._mDistributionAnalyzer.feed(aBuf[i-1:i+1], charLen) + + self._mLastChar[0] = aBuf[aLen - 1] + + if self.get_state() == constants.eDetecting: + if self._mDistributionAnalyzer.got_enough_data() and \ + (self.get_confidence() > constants.SHORTCUT_THRESHOLD): + self._mState = constants.eFoundIt + + return self.get_state() + + def get_confidence(self): + return self._mDistributionAnalyzer.get_confidence() diff --git a/libs/requests/packages/chardet2/mbcsgroupprober.py b/libs/requests/packages/chardet2/mbcsgroupprober.py new file mode 100644 index 00000000..92ca6421 --- /dev/null +++ b/libs/requests/packages/chardet2/mbcsgroupprober.py @@ -0,0 +1,50 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Proofpoint, Inc. +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetgroupprober import CharSetGroupProber +from .utf8prober import UTF8Prober +from .sjisprober import SJISProber +from .eucjpprober import EUCJPProber +from .gb2312prober import GB2312Prober +from .euckrprober import EUCKRProber +from .big5prober import Big5Prober +from .euctwprober import EUCTWProber + +class MBCSGroupProber(CharSetGroupProber): + def __init__(self): + CharSetGroupProber.__init__(self) + self._mProbers = [ \ + UTF8Prober(), + SJISProber(), + EUCJPProber(), + GB2312Prober(), + EUCKRProber(), + Big5Prober(), + EUCTWProber()] + self.reset() diff --git a/libs/requests/packages/chardet2/mbcssm.py b/libs/requests/packages/chardet2/mbcssm.py new file mode 100644 index 00000000..c36813ea --- /dev/null +++ b/libs/requests/packages/chardet2/mbcssm.py @@ -0,0 +1,514 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .constants import eStart, eError, eItsMe + +# BIG5 + +BIG5_cls = ( \ + 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as legal value + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,1, # 78 - 7f + 4,4,4,4,4,4,4,4, # 80 - 87 + 4,4,4,4,4,4,4,4, # 88 - 8f + 4,4,4,4,4,4,4,4, # 90 - 97 + 4,4,4,4,4,4,4,4, # 98 - 9f + 4,3,3,3,3,3,3,3, # a0 - a7 + 3,3,3,3,3,3,3,3, # a8 - af + 3,3,3,3,3,3,3,3, # b0 - b7 + 3,3,3,3,3,3,3,3, # b8 - bf + 3,3,3,3,3,3,3,3, # c0 - c7 + 3,3,3,3,3,3,3,3, # c8 - cf + 3,3,3,3,3,3,3,3, # d0 - d7 + 3,3,3,3,3,3,3,3, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,3,3,3, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,3,3,0) # f8 - ff + +BIG5_st = ( \ + eError,eStart,eStart, 3,eError,eError,eError,eError,#00-07 + eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eError,#08-0f + eError,eStart,eStart,eStart,eStart,eStart,eStart,eStart)#10-17 + +Big5CharLenTable = (0, 1, 1, 2, 0) + +Big5SMModel = {'classTable': BIG5_cls, + 'classFactor': 5, + 'stateTable': BIG5_st, + 'charLenTable': Big5CharLenTable, + 'name': 'Big5'} + +# EUC-JP + +EUCJP_cls = ( \ + 4,4,4,4,4,4,4,4, # 00 - 07 + 4,4,4,4,4,4,5,5, # 08 - 0f + 4,4,4,4,4,4,4,4, # 10 - 17 + 4,4,4,5,4,4,4,4, # 18 - 1f + 4,4,4,4,4,4,4,4, # 20 - 27 + 4,4,4,4,4,4,4,4, # 28 - 2f + 4,4,4,4,4,4,4,4, # 30 - 37 + 4,4,4,4,4,4,4,4, # 38 - 3f + 4,4,4,4,4,4,4,4, # 40 - 47 + 4,4,4,4,4,4,4,4, # 48 - 4f + 4,4,4,4,4,4,4,4, # 50 - 57 + 4,4,4,4,4,4,4,4, # 58 - 5f + 4,4,4,4,4,4,4,4, # 60 - 67 + 4,4,4,4,4,4,4,4, # 68 - 6f + 4,4,4,4,4,4,4,4, # 70 - 77 + 4,4,4,4,4,4,4,4, # 78 - 7f + 5,5,5,5,5,5,5,5, # 80 - 87 + 5,5,5,5,5,5,1,3, # 88 - 8f + 5,5,5,5,5,5,5,5, # 90 - 97 + 5,5,5,5,5,5,5,5, # 98 - 9f + 5,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,2,2,2, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,2,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,0,5) # f8 - ff + +EUCJP_st = ( \ + 3, 4, 3, 5,eStart,eError,eError,eError,#00-07 + eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe,eStart,eError,eStart,eError,eError,eError,#10-17 + eError,eError,eStart,eError,eError,eError, 3,eError,#18-1f + 3,eError,eError,eError,eStart,eStart,eStart,eStart)#20-27 + +EUCJPCharLenTable = (2, 2, 2, 3, 1, 0) + +EUCJPSMModel = {'classTable': EUCJP_cls, + 'classFactor': 6, + 'stateTable': EUCJP_st, + 'charLenTable': EUCJPCharLenTable, + 'name': 'EUC-JP'} + +# EUC-KR + +EUCKR_cls = ( \ + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 1,1,1,1,1,1,1,1, # 40 - 47 + 1,1,1,1,1,1,1,1, # 48 - 4f + 1,1,1,1,1,1,1,1, # 50 - 57 + 1,1,1,1,1,1,1,1, # 58 - 5f + 1,1,1,1,1,1,1,1, # 60 - 67 + 1,1,1,1,1,1,1,1, # 68 - 6f + 1,1,1,1,1,1,1,1, # 70 - 77 + 1,1,1,1,1,1,1,1, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,3,3,3, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,3,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 2,2,2,2,2,2,2,2, # e0 - e7 + 2,2,2,2,2,2,2,2, # e8 - ef + 2,2,2,2,2,2,2,2, # f0 - f7 + 2,2,2,2,2,2,2,0) # f8 - ff + +EUCKR_st = ( + eError,eStart, 3,eError,eError,eError,eError,eError,#00-07 + eItsMe,eItsMe,eItsMe,eItsMe,eError,eError,eStart,eStart)#08-0f + +EUCKRCharLenTable = (0, 1, 2, 0) + +EUCKRSMModel = {'classTable': EUCKR_cls, + 'classFactor': 4, + 'stateTable': EUCKR_st, + 'charLenTable': EUCKRCharLenTable, + 'name': 'EUC-KR'} + +# EUC-TW + +EUCTW_cls = ( \ + 2,2,2,2,2,2,2,2, # 00 - 07 + 2,2,2,2,2,2,0,0, # 08 - 0f + 2,2,2,2,2,2,2,2, # 10 - 17 + 2,2,2,0,2,2,2,2, # 18 - 1f + 2,2,2,2,2,2,2,2, # 20 - 27 + 2,2,2,2,2,2,2,2, # 28 - 2f + 2,2,2,2,2,2,2,2, # 30 - 37 + 2,2,2,2,2,2,2,2, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,2, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,6,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,3,4,4,4,4,4,4, # a0 - a7 + 5,5,1,1,1,1,1,1, # a8 - af + 1,1,1,1,1,1,1,1, # b0 - b7 + 1,1,1,1,1,1,1,1, # b8 - bf + 1,1,3,1,3,3,3,3, # c0 - c7 + 3,3,3,3,3,3,3,3, # c8 - cf + 3,3,3,3,3,3,3,3, # d0 - d7 + 3,3,3,3,3,3,3,3, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,3,3,3, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,3,3,0) # f8 - ff + +EUCTW_st = ( \ + eError,eError,eStart, 3, 3, 3, 4,eError,#00-07 + eError,eError,eError,eError,eError,eError,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eError,eStart,eError,#10-17 + eStart,eStart,eStart,eError,eError,eError,eError,eError,#18-1f + 5,eError,eError,eError,eStart,eError,eStart,eStart,#20-27 + eStart,eError,eStart,eStart,eStart,eStart,eStart,eStart)#28-2f + +EUCTWCharLenTable = (0, 0, 1, 2, 2, 2, 3) + +EUCTWSMModel = {'classTable': EUCTW_cls, + 'classFactor': 7, + 'stateTable': EUCTW_st, + 'charLenTable': EUCTWCharLenTable, + 'name': 'x-euc-tw'} + +# GB2312 + +GB2312_cls = ( \ + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 3,3,3,3,3,3,3,3, # 30 - 37 + 3,3,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,4, # 78 - 7f + 5,6,6,6,6,6,6,6, # 80 - 87 + 6,6,6,6,6,6,6,6, # 88 - 8f + 6,6,6,6,6,6,6,6, # 90 - 97 + 6,6,6,6,6,6,6,6, # 98 - 9f + 6,6,6,6,6,6,6,6, # a0 - a7 + 6,6,6,6,6,6,6,6, # a8 - af + 6,6,6,6,6,6,6,6, # b0 - b7 + 6,6,6,6,6,6,6,6, # b8 - bf + 6,6,6,6,6,6,6,6, # c0 - c7 + 6,6,6,6,6,6,6,6, # c8 - cf + 6,6,6,6,6,6,6,6, # d0 - d7 + 6,6,6,6,6,6,6,6, # d8 - df + 6,6,6,6,6,6,6,6, # e0 - e7 + 6,6,6,6,6,6,6,6, # e8 - ef + 6,6,6,6,6,6,6,6, # f0 - f7 + 6,6,6,6,6,6,6,0) # f8 - ff + +GB2312_st = ( \ + eError,eStart,eStart,eStart,eStart,eStart, 3,eError,#00-07 + eError,eError,eError,eError,eError,eError,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eError,eError,eStart,#10-17 + 4,eError,eStart,eStart,eError,eError,eError,eError,#18-1f + eError,eError, 5,eError,eError,eError,eItsMe,eError,#20-27 + eError,eError,eStart,eStart,eStart,eStart,eStart,eStart)#28-2f + +# To be accurate, the length of class 6 can be either 2 or 4. +# But it is not necessary to discriminate between the two since +# it is used for frequency analysis only, and we are validing +# each code range there as well. So it is safe to set it to be +# 2 here. +GB2312CharLenTable = (0, 1, 1, 1, 1, 1, 2) + +GB2312SMModel = {'classTable': GB2312_cls, + 'classFactor': 7, + 'stateTable': GB2312_st, + 'charLenTable': GB2312CharLenTable, + 'name': 'GB2312'} + +# Shift_JIS + +SJIS_cls = ( \ + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,1, # 78 - 7f + 3,3,3,3,3,3,3,3, # 80 - 87 + 3,3,3,3,3,3,3,3, # 88 - 8f + 3,3,3,3,3,3,3,3, # 90 - 97 + 3,3,3,3,3,3,3,3, # 98 - 9f + #0xa0 is illegal in sjis encoding, but some pages does + #contain such byte. We need to be more error forgiven. + 2,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,2,2,2, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,2,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,4,4,4, # e8 - ef + 4,4,4,4,4,4,4,4, # f0 - f7 + 4,4,4,4,4,0,0,0) # f8 - ff + +SJIS_st = ( \ + eError,eStart,eStart, 3,eError,eError,eError,eError,#00-07 + eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe,eError,eError,eStart,eStart,eStart,eStart)#10-17 + +SJISCharLenTable = (0, 1, 1, 2, 0, 0) + +SJISSMModel = {'classTable': SJIS_cls, + 'classFactor': 6, + 'stateTable': SJIS_st, + 'charLenTable': SJISCharLenTable, + 'name': 'Shift_JIS'} + +# UCS2-BE + +UCS2BE_cls = ( \ + 0,0,0,0,0,0,0,0, # 00 - 07 + 0,0,1,0,0,2,0,0, # 08 - 0f + 0,0,0,0,0,0,0,0, # 10 - 17 + 0,0,0,3,0,0,0,0, # 18 - 1f + 0,0,0,0,0,0,0,0, # 20 - 27 + 0,3,3,3,3,3,0,0, # 28 - 2f + 0,0,0,0,0,0,0,0, # 30 - 37 + 0,0,0,0,0,0,0,0, # 38 - 3f + 0,0,0,0,0,0,0,0, # 40 - 47 + 0,0,0,0,0,0,0,0, # 48 - 4f + 0,0,0,0,0,0,0,0, # 50 - 57 + 0,0,0,0,0,0,0,0, # 58 - 5f + 0,0,0,0,0,0,0,0, # 60 - 67 + 0,0,0,0,0,0,0,0, # 68 - 6f + 0,0,0,0,0,0,0,0, # 70 - 77 + 0,0,0,0,0,0,0,0, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,0,0,0,0,0,0,0, # a0 - a7 + 0,0,0,0,0,0,0,0, # a8 - af + 0,0,0,0,0,0,0,0, # b0 - b7 + 0,0,0,0,0,0,0,0, # b8 - bf + 0,0,0,0,0,0,0,0, # c0 - c7 + 0,0,0,0,0,0,0,0, # c8 - cf + 0,0,0,0,0,0,0,0, # d0 - d7 + 0,0,0,0,0,0,0,0, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,4,5) # f8 - ff + +UCS2BE_st = ( \ + 5, 7, 7,eError, 4, 3,eError,eError,#00-07 + eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe, 6, 6, 6, 6,eError,eError,#10-17 + 6, 6, 6, 6, 6,eItsMe, 6, 6,#18-1f + 6, 6, 6, 6, 5, 7, 7,eError,#20-27 + 5, 8, 6, 6,eError, 6, 6, 6,#28-2f + 6, 6, 6, 6,eError,eError,eStart,eStart)#30-37 + +UCS2BECharLenTable = (2, 2, 2, 0, 2, 2) + +UCS2BESMModel = {'classTable': UCS2BE_cls, + 'classFactor': 6, + 'stateTable': UCS2BE_st, + 'charLenTable': UCS2BECharLenTable, + 'name': 'UTF-16BE'} + +# UCS2-LE + +UCS2LE_cls = ( \ + 0,0,0,0,0,0,0,0, # 00 - 07 + 0,0,1,0,0,2,0,0, # 08 - 0f + 0,0,0,0,0,0,0,0, # 10 - 17 + 0,0,0,3,0,0,0,0, # 18 - 1f + 0,0,0,0,0,0,0,0, # 20 - 27 + 0,3,3,3,3,3,0,0, # 28 - 2f + 0,0,0,0,0,0,0,0, # 30 - 37 + 0,0,0,0,0,0,0,0, # 38 - 3f + 0,0,0,0,0,0,0,0, # 40 - 47 + 0,0,0,0,0,0,0,0, # 48 - 4f + 0,0,0,0,0,0,0,0, # 50 - 57 + 0,0,0,0,0,0,0,0, # 58 - 5f + 0,0,0,0,0,0,0,0, # 60 - 67 + 0,0,0,0,0,0,0,0, # 68 - 6f + 0,0,0,0,0,0,0,0, # 70 - 77 + 0,0,0,0,0,0,0,0, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,0,0,0,0,0,0,0, # a0 - a7 + 0,0,0,0,0,0,0,0, # a8 - af + 0,0,0,0,0,0,0,0, # b0 - b7 + 0,0,0,0,0,0,0,0, # b8 - bf + 0,0,0,0,0,0,0,0, # c0 - c7 + 0,0,0,0,0,0,0,0, # c8 - cf + 0,0,0,0,0,0,0,0, # d0 - d7 + 0,0,0,0,0,0,0,0, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,4,5) # f8 - ff + +UCS2LE_st = ( \ + 6, 6, 7, 6, 4, 3,eError,eError,#00-07 + eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe,#08-0f + eItsMe,eItsMe, 5, 5, 5,eError,eItsMe,eError,#10-17 + 5, 5, 5,eError, 5,eError, 6, 6,#18-1f + 7, 6, 8, 8, 5, 5, 5,eError,#20-27 + 5, 5, 5,eError,eError,eError, 5, 5,#28-2f + 5, 5, 5,eError, 5,eError,eStart,eStart)#30-37 + +UCS2LECharLenTable = (2, 2, 2, 2, 2, 2) + +UCS2LESMModel = {'classTable': UCS2LE_cls, + 'classFactor': 6, + 'stateTable': UCS2LE_st, + 'charLenTable': UCS2LECharLenTable, + 'name': 'UTF-16LE'} + +# UTF-8 + +UTF8_cls = ( \ + 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as a legal value + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 1,1,1,1,1,1,1,1, # 40 - 47 + 1,1,1,1,1,1,1,1, # 48 - 4f + 1,1,1,1,1,1,1,1, # 50 - 57 + 1,1,1,1,1,1,1,1, # 58 - 5f + 1,1,1,1,1,1,1,1, # 60 - 67 + 1,1,1,1,1,1,1,1, # 68 - 6f + 1,1,1,1,1,1,1,1, # 70 - 77 + 1,1,1,1,1,1,1,1, # 78 - 7f + 2,2,2,2,3,3,3,3, # 80 - 87 + 4,4,4,4,4,4,4,4, # 88 - 8f + 4,4,4,4,4,4,4,4, # 90 - 97 + 4,4,4,4,4,4,4,4, # 98 - 9f + 5,5,5,5,5,5,5,5, # a0 - a7 + 5,5,5,5,5,5,5,5, # a8 - af + 5,5,5,5,5,5,5,5, # b0 - b7 + 5,5,5,5,5,5,5,5, # b8 - bf + 0,0,6,6,6,6,6,6, # c0 - c7 + 6,6,6,6,6,6,6,6, # c8 - cf + 6,6,6,6,6,6,6,6, # d0 - d7 + 6,6,6,6,6,6,6,6, # d8 - df + 7,8,8,8,8,8,8,8, # e0 - e7 + 8,8,8,8,8,9,8,8, # e8 - ef + 10,11,11,11,11,11,11,11, # f0 - f7 + 12,13,13,13,14,15,0,0) # f8 - ff + +UTF8_st = ( \ + eError,eStart,eError,eError,eError,eError, 12, 10,#00-07 + 9, 11, 8, 7, 6, 5, 4, 3,#08-0f + eError,eError,eError,eError,eError,eError,eError,eError,#10-17 + eError,eError,eError,eError,eError,eError,eError,eError,#18-1f + eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,#20-27 + eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,#28-2f + eError,eError, 5, 5, 5, 5,eError,eError,#30-37 + eError,eError,eError,eError,eError,eError,eError,eError,#38-3f + eError,eError,eError, 5, 5, 5,eError,eError,#40-47 + eError,eError,eError,eError,eError,eError,eError,eError,#48-4f + eError,eError, 7, 7, 7, 7,eError,eError,#50-57 + eError,eError,eError,eError,eError,eError,eError,eError,#58-5f + eError,eError,eError,eError, 7, 7,eError,eError,#60-67 + eError,eError,eError,eError,eError,eError,eError,eError,#68-6f + eError,eError, 9, 9, 9, 9,eError,eError,#70-77 + eError,eError,eError,eError,eError,eError,eError,eError,#78-7f + eError,eError,eError,eError,eError, 9,eError,eError,#80-87 + eError,eError,eError,eError,eError,eError,eError,eError,#88-8f + eError,eError, 12, 12, 12, 12,eError,eError,#90-97 + eError,eError,eError,eError,eError,eError,eError,eError,#98-9f + eError,eError,eError,eError,eError, 12,eError,eError,#a0-a7 + eError,eError,eError,eError,eError,eError,eError,eError,#a8-af + eError,eError, 12, 12, 12,eError,eError,eError,#b0-b7 + eError,eError,eError,eError,eError,eError,eError,eError,#b8-bf + eError,eError,eStart,eStart,eStart,eStart,eError,eError,#c0-c7 + eError,eError,eError,eError,eError,eError,eError,eError)#c8-cf + +UTF8CharLenTable = (0, 1, 0, 0, 0, 0, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6) + +UTF8SMModel = {'classTable': UTF8_cls, + 'classFactor': 16, + 'stateTable': UTF8_st, + 'charLenTable': UTF8CharLenTable, + 'name': 'UTF-8'} diff --git a/libs/requests/packages/chardet2/sbcharsetprober.py b/libs/requests/packages/chardet2/sbcharsetprober.py new file mode 100644 index 00000000..b276dac1 --- /dev/null +++ b/libs/requests/packages/chardet2/sbcharsetprober.py @@ -0,0 +1,107 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants +import sys +from .charsetprober import CharSetProber + +SAMPLE_SIZE = 64 +SB_ENOUGH_REL_THRESHOLD = 1024 +POSITIVE_SHORTCUT_THRESHOLD = 0.95 +NEGATIVE_SHORTCUT_THRESHOLD = 0.05 +SYMBOL_CAT_ORDER = 250 +NUMBER_OF_SEQ_CAT = 4 +POSITIVE_CAT = NUMBER_OF_SEQ_CAT - 1 +#NEGATIVE_CAT = 0 + +class SingleByteCharSetProber(CharSetProber): + def __init__(self, model, reversed=False, nameProber=None): + CharSetProber.__init__(self) + self._mModel = model + self._mReversed = reversed # TRUE if we need to reverse every pair in the model lookup + self._mNameProber = nameProber # Optional auxiliary prober for name decision + self.reset() + + def reset(self): + CharSetProber.reset(self) + self._mLastOrder = 255 # char order of last character + self._mSeqCounters = [0] * NUMBER_OF_SEQ_CAT + self._mTotalSeqs = 0 + self._mTotalChar = 0 + self._mFreqChar = 0 # characters that fall in our sampling range + + def get_charset_name(self): + if self._mNameProber: + return self._mNameProber.get_charset_name() + else: + return self._mModel['charsetName'] + + def feed(self, aBuf): + if not self._mModel['keepEnglishLetter']: + aBuf = self.filter_without_english_letters(aBuf) + aLen = len(aBuf) + if not aLen: + return self.get_state() + for c in aBuf: + order = self._mModel['charToOrderMap'][c] + if order < SYMBOL_CAT_ORDER: + self._mTotalChar += 1 + if order < SAMPLE_SIZE: + self._mFreqChar += 1 + if self._mLastOrder < SAMPLE_SIZE: + self._mTotalSeqs += 1 + if not self._mReversed: + self._mSeqCounters[self._mModel['precedenceMatrix'][(self._mLastOrder * SAMPLE_SIZE) + order]] += 1 + else: # reverse the order of the letters in the lookup + self._mSeqCounters[self._mModel['precedenceMatrix'][(order * SAMPLE_SIZE) + self._mLastOrder]] += 1 + self._mLastOrder = order + + if self.get_state() == constants.eDetecting: + if self._mTotalSeqs > SB_ENOUGH_REL_THRESHOLD: + cf = self.get_confidence() + if cf > POSITIVE_SHORTCUT_THRESHOLD: + if constants._debug: + sys.stderr.write('%s confidence = %s, we have a winner\n' % (self._mModel['charsetName'], cf)) + self._mState = constants.eFoundIt + elif cf < NEGATIVE_SHORTCUT_THRESHOLD: + if constants._debug: + sys.stderr.write('%s confidence = %s, below negative shortcut threshhold %s\n' % (self._mModel['charsetName'], cf, NEGATIVE_SHORTCUT_THRESHOLD)) + self._mState = constants.eNotMe + + return self.get_state() + + def get_confidence(self): + r = 0.01 + if self._mTotalSeqs > 0: +# print self._mSeqCounters[POSITIVE_CAT], self._mTotalSeqs, self._mModel['mTypicalPositiveRatio'] + r = (1.0 * self._mSeqCounters[POSITIVE_CAT]) / self._mTotalSeqs / self._mModel['mTypicalPositiveRatio'] +# print r, self._mFreqChar, self._mTotalChar + r = r * self._mFreqChar / self._mTotalChar + if r >= 1.0: + r = 0.99 + return r diff --git a/libs/requests/packages/chardet2/sbcsgroupprober.py b/libs/requests/packages/chardet2/sbcsgroupprober.py new file mode 100644 index 00000000..d258ce71 --- /dev/null +++ b/libs/requests/packages/chardet2/sbcsgroupprober.py @@ -0,0 +1,65 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants +import sys +from .charsetgroupprober import CharSetGroupProber +from .sbcharsetprober import SingleByteCharSetProber +from .langcyrillicmodel import Win1251CyrillicModel, Koi8rModel, Latin5CyrillicModel, MacCyrillicModel, Ibm866Model, Ibm855Model +from .langgreekmodel import Latin7GreekModel, Win1253GreekModel +from .langbulgarianmodel import Latin5BulgarianModel, Win1251BulgarianModel +from .langhungarianmodel import Latin2HungarianModel, Win1250HungarianModel +from .langthaimodel import TIS620ThaiModel +from .langhebrewmodel import Win1255HebrewModel +from .hebrewprober import HebrewProber + +class SBCSGroupProber(CharSetGroupProber): + def __init__(self): + CharSetGroupProber.__init__(self) + self._mProbers = [ \ + SingleByteCharSetProber(Win1251CyrillicModel), + SingleByteCharSetProber(Koi8rModel), + SingleByteCharSetProber(Latin5CyrillicModel), + SingleByteCharSetProber(MacCyrillicModel), + SingleByteCharSetProber(Ibm866Model), + SingleByteCharSetProber(Ibm855Model), + SingleByteCharSetProber(Latin7GreekModel), + SingleByteCharSetProber(Win1253GreekModel), + SingleByteCharSetProber(Latin5BulgarianModel), + SingleByteCharSetProber(Win1251BulgarianModel), + SingleByteCharSetProber(Latin2HungarianModel), + SingleByteCharSetProber(Win1250HungarianModel), + SingleByteCharSetProber(TIS620ThaiModel), + ] + hebrewProber = HebrewProber() + logicalHebrewProber = SingleByteCharSetProber(Win1255HebrewModel, False, hebrewProber) + visualHebrewProber = SingleByteCharSetProber(Win1255HebrewModel, True, hebrewProber) + hebrewProber.set_model_probers(logicalHebrewProber, visualHebrewProber) + self._mProbers.extend([hebrewProber, logicalHebrewProber, visualHebrewProber]) + + self.reset() diff --git a/libs/requests/packages/chardet2/sjisprober.py b/libs/requests/packages/chardet2/sjisprober.py new file mode 100644 index 00000000..a515c576 --- /dev/null +++ b/libs/requests/packages/chardet2/sjisprober.py @@ -0,0 +1,86 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import SJISDistributionAnalysis +from .jpcntx import SJISContextAnalysis +from .mbcssm import SJISSMModel +from . import constants +import sys +from .constants import eStart, eError, eItsMe + +class SJISProber(MultiByteCharSetProber): + def __init__(self): + MultiByteCharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(SJISSMModel) + self._mDistributionAnalyzer = SJISDistributionAnalysis() + self._mContextAnalyzer = SJISContextAnalysis() + self.reset() + + def reset(self): + MultiByteCharSetProber.reset(self) + self._mContextAnalyzer.reset() + + def get_charset_name(self): + return "SHIFT_JIS" + + def feed(self, aBuf): + aLen = len(aBuf) + for i in range(0, aLen): + codingState = self._mCodingSM.next_state(aBuf[i]) + if codingState == eError: + if constants._debug: + sys.stderr.write(self.get_charset_name() + ' prober hit error at byte ' + str(i) + '\n') + self._mState = constants.eNotMe + break + elif codingState == eItsMe: + self._mState = constants.eFoundIt + break + elif codingState == eStart: + charLen = self._mCodingSM.get_current_charlen() + if i == 0: + self._mLastChar[1] = aBuf[0] + self._mContextAnalyzer.feed(self._mLastChar[2 - charLen :], charLen) + self._mDistributionAnalyzer.feed(self._mLastChar, charLen) + else: + self._mContextAnalyzer.feed(aBuf[i + 1 - charLen : i + 3 - charLen], charLen) + self._mDistributionAnalyzer.feed(aBuf[i - 1 : i + 1], charLen) + + self._mLastChar[0] = aBuf[aLen - 1] + + if self.get_state() == constants.eDetecting: + if self._mContextAnalyzer.got_enough_data() and \ + (self.get_confidence() > constants.SHORTCUT_THRESHOLD): + self._mState = constants.eFoundIt + + return self.get_state() + + def get_confidence(self): + contxtCf = self._mContextAnalyzer.get_confidence() + distribCf = self._mDistributionAnalyzer.get_confidence() + return max(contxtCf, distribCf) diff --git a/libs/requests/packages/chardet2/test.py b/libs/requests/packages/chardet2/test.py new file mode 100644 index 00000000..10dbd711 --- /dev/null +++ b/libs/requests/packages/chardet2/test.py @@ -0,0 +1,21 @@ +from __future__ import print_function +import sys, glob +sys.path.insert(0, '..') +from chardet.universaldetector import UniversalDetector + +count = 0 +u = UniversalDetector() +for f in glob.glob(sys.argv[1]): + print(f.ljust(60), end=' ') + u.reset() + for line in open(f, 'rb'): + u.feed(line) + if u.done: break + u.close() + result = u.result + if result['encoding']: + print(result['encoding'], 'with confidence', result['confidence']) + else: + print('******** no result') + count += 1 +print(count, 'tests') diff --git a/libs/requests/packages/chardet2/universaldetector.py b/libs/requests/packages/chardet2/universaldetector.py new file mode 100644 index 00000000..3a2159c3 --- /dev/null +++ b/libs/requests/packages/chardet2/universaldetector.py @@ -0,0 +1,155 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants +import sys +from .latin1prober import Latin1Prober # windows-1252 +from .mbcsgroupprober import MBCSGroupProber # multi-byte character sets +from .sbcsgroupprober import SBCSGroupProber # single-byte character sets +from .escprober import EscCharSetProber # ISO-2122, etc. +import re + +MINIMUM_THRESHOLD = 0.20 +ePureAscii = 0 +eEscAscii = 1 +eHighbyte = 2 + +class UniversalDetector: + def __init__(self): + self._highBitDetector = re.compile(b'[\x80-\xFF]') + self._escDetector = re.compile(b'(\033|~{)') + self._mEscCharSetProber = None + self._mCharSetProbers = [] + self.reset() + + def reset(self): + self.result = {'encoding': None, 'confidence': 0.0} + self.done = False + self._mStart = True + self._mGotData = False + self._mInputState = ePureAscii + self._mLastChar = b'' + if self._mEscCharSetProber: + self._mEscCharSetProber.reset() + for prober in self._mCharSetProbers: + prober.reset() + + def feed(self, aBuf): + if self.done: return + + aLen = len(aBuf) + if not aLen: return + + if not self._mGotData: + # If the data starts with BOM, we know it is UTF + if aBuf[:3] == '\xEF\xBB\xBF': + # EF BB BF UTF-8 with BOM + self.result = {'encoding': "UTF-8", 'confidence': 1.0} + elif aBuf[:4] == '\xFF\xFE\x00\x00': + # FF FE 00 00 UTF-32, little-endian BOM + self.result = {'encoding': "UTF-32LE", 'confidence': 1.0} + elif aBuf[:4] == '\x00\x00\xFE\xFF': + # 00 00 FE FF UTF-32, big-endian BOM + self.result = {'encoding': "UTF-32BE", 'confidence': 1.0} + elif aBuf[:4] == '\xFE\xFF\x00\x00': + # FE FF 00 00 UCS-4, unusual octet order BOM (3412) + self.result = {'encoding': "X-ISO-10646-UCS-4-3412", 'confidence': 1.0} + elif aBuf[:4] == '\x00\x00\xFF\xFE': + # 00 00 FF FE UCS-4, unusual octet order BOM (2143) + self.result = {'encoding': "X-ISO-10646-UCS-4-2143", 'confidence': 1.0} + elif aBuf[:2] == '\xFF\xFE': + # FF FE UTF-16, little endian BOM + self.result = {'encoding': "UTF-16LE", 'confidence': 1.0} + elif aBuf[:2] == '\xFE\xFF': + # FE FF UTF-16, big endian BOM + self.result = {'encoding': "UTF-16BE", 'confidence': 1.0} + + self._mGotData = True + if self.result['encoding'] and (self.result['confidence'] > 0.0): + self.done = True + return + + if self._mInputState == ePureAscii: + if self._highBitDetector.search(aBuf): + self._mInputState = eHighbyte + elif (self._mInputState == ePureAscii) and self._escDetector.search(self._mLastChar + aBuf): + self._mInputState = eEscAscii + + self._mLastChar = aBuf[-1:] + + if self._mInputState == eEscAscii: + if not self._mEscCharSetProber: + self._mEscCharSetProber = EscCharSetProber() + if self._mEscCharSetProber.feed(aBuf) == constants.eFoundIt: + self.result = {'encoding': self._mEscCharSetProber.get_charset_name(), + 'confidence': self._mEscCharSetProber.get_confidence()} + self.done = True + elif self._mInputState == eHighbyte: + if not self._mCharSetProbers: + self._mCharSetProbers = [MBCSGroupProber(), SBCSGroupProber(), Latin1Prober()] + for prober in self._mCharSetProbers: + if prober.feed(aBuf) == constants.eFoundIt: + self.result = {'encoding': prober.get_charset_name(), + 'confidence': prober.get_confidence()} + self.done = True + break + + def close(self): + if self.done: return + if not self._mGotData: + if constants._debug: + sys.stderr.write('no data received!\n') + return + self.done = True + + if self._mInputState == ePureAscii: + self.result = {'encoding': 'ascii', 'confidence': 1.0} + return self.result + + if self._mInputState == eHighbyte: + proberConfidence = None + maxProberConfidence = 0.0 + maxProber = None + for prober in self._mCharSetProbers: + if not prober: continue + proberConfidence = prober.get_confidence() + if proberConfidence > maxProberConfidence: + maxProberConfidence = proberConfidence + maxProber = prober + if maxProber and (maxProberConfidence > MINIMUM_THRESHOLD): + self.result = {'encoding': maxProber.get_charset_name(), + 'confidence': maxProber.get_confidence()} + return self.result + + if constants._debug: + sys.stderr.write('no probers hit minimum threshhold\n') + for prober in self._mCharSetProbers[0].mProbers: + if not prober: continue + sys.stderr.write('%s confidence = %s\n' % \ + (prober.get_charset_name(), \ + prober.get_confidence())) diff --git a/libs/requests/packages/chardet2/utf8prober.py b/libs/requests/packages/chardet2/utf8prober.py new file mode 100644 index 00000000..6746c5d6 --- /dev/null +++ b/libs/requests/packages/chardet2/utf8prober.py @@ -0,0 +1,77 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from . import constants +import sys +from .constants import eStart, eError, eItsMe +from .charsetprober import CharSetProber +from .codingstatemachine import CodingStateMachine +from .mbcssm import UTF8SMModel + +ONE_CHAR_PROB = 0.5 + +class UTF8Prober(CharSetProber): + def __init__(self): + CharSetProber.__init__(self) + self._mCodingSM = CodingStateMachine(UTF8SMModel) + self.reset() + + def reset(self): + CharSetProber.reset(self) + self._mCodingSM.reset() + self._mNumOfMBChar = 0 + + def get_charset_name(self): + return "utf-8" + + def feed(self, aBuf): + for c in aBuf: + codingState = self._mCodingSM.next_state(c) + if codingState == eError: + self._mState = constants.eNotMe + break + elif codingState == eItsMe: + self._mState = constants.eFoundIt + break + elif codingState == eStart: + if self._mCodingSM.get_current_charlen() >= 2: + self._mNumOfMBChar += 1 + + if self.get_state() == constants.eDetecting: + if self.get_confidence() > constants.SHORTCUT_THRESHOLD: + self._mState = constants.eFoundIt + + return self.get_state() + + def get_confidence(self): + unlike = 0.99 + if self._mNumOfMBChar < 6: + for i in range(0, self._mNumOfMBChar): + unlike = unlike * ONE_CHAR_PROB + return 1.0 - unlike + else: + return unlike diff --git a/libs/requests/packages/oauthlib/__init__.py b/libs/requests/packages/oauthlib/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/libs/requests/packages/oauthlib/common.py b/libs/requests/packages/oauthlib/common.py new file mode 100644 index 00000000..70fb6a00 --- /dev/null +++ b/libs/requests/packages/oauthlib/common.py @@ -0,0 +1,229 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +""" +oauthlib.common +~~~~~~~~~~~~~~ + +This module provides data structures and utilities common +to all implementations of OAuth. +""" + +import random +import re +import string +import time +import urllib +import urlparse + +UNICODE_ASCII_CHARACTER_SET = (string.ascii_letters.decode('ascii') + + string.digits.decode('ascii')) + +always_safe = (u'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + u'abcdefghijklmnopqrstuvwxyz' + u'0123456789' u'_.-') + + +def quote(s, safe=u'/'): + encoded = s.encode("utf-8") + quoted = urllib.quote(encoded, safe) + return quoted.decode("utf-8") + + +def unquote(s): + encoded = s.encode("utf-8") + unquoted = urllib.unquote(encoded) + return unquoted.decode("utf-8") + + +def urlencode(params): + utf8_params = encode_params_utf8(params) + urlencoded = urllib.urlencode(utf8_params) + return urlencoded.decode("utf-8") + + +def encode_params_utf8(params): + """Ensures that all parameters in a list of 2-element tuples are encoded to + bytestrings using UTF-8 + """ + encoded = [] + for k, v in params: + encoded.append(( + k.encode('utf-8') if isinstance(k, unicode) else k, + v.encode('utf-8') if isinstance(v, unicode) else v)) + return encoded + + +def decode_params_utf8(params): + """Ensures that all parameters in a list of 2-element tuples are decoded to + unicode using UTF-8. + """ + decoded = [] + for k, v in params: + decoded.append(( + k.decode('utf-8') if isinstance(k, str) else k, + v.decode('utf-8') if isinstance(v, str) else v)) + return decoded + + +urlencoded = set(always_safe) | set(u'=&;%+~') + + +def urldecode(query): + """Decode a query string in x-www-form-urlencoded format into a sequence + of two-element tuples. + + Unlike urlparse.parse_qsl(..., strict_parsing=True) urldecode will enforce + correct formatting of the query string by validation. If validation fails + a ValueError will be raised. urllib.parse_qsl will only raise errors if + any of name-value pairs omits the equals sign. + """ + # Check if query contains invalid characters + if query and not set(query) <= urlencoded: + raise ValueError('Invalid characters in query string.') + + # Check for correctly hex encoded values using a regular expression + # All encoded values begin with % followed by two hex characters + # correct = %00, %A0, %0A, %FF + # invalid = %G0, %5H, %PO + invalid_hex = u'%[^0-9A-Fa-f]|%[0-9A-Fa-f][^0-9A-Fa-f]' + if len(re.findall(invalid_hex, query)): + raise ValueError('Invalid hex encoding in query string.') + + query = query.decode('utf-8') if isinstance(query, str) else query + # We want to allow queries such as "c2" whereas urlparse.parse_qsl + # with the strict_parsing flag will not. + params = urlparse.parse_qsl(query, keep_blank_values=True) + + # unicode all the things + return decode_params_utf8(params) + + +def extract_params(raw): + """Extract parameters and return them as a list of 2-tuples. + + Will successfully extract parameters from urlencoded query strings, + dicts, or lists of 2-tuples. Empty strings/dicts/lists will return an + empty list of parameters. Any other input will result in a return + value of None. + """ + if isinstance(raw, basestring): + try: + params = urldecode(raw) + except ValueError: + params = None + elif hasattr(raw, '__iter__'): + try: + dict(raw) + except ValueError: + params = None + except TypeError: + params = None + else: + params = list(raw.items() if isinstance(raw, dict) else raw) + params = decode_params_utf8(params) + else: + params = None + + return params + + +def generate_nonce(): + """Generate pseudorandom nonce that is unlikely to repeat. + + Per `section 3.3`_ of the OAuth 1 RFC 5849 spec. + Per `section 3.2.1`_ of the MAC Access Authentication spec. + + A random 64-bit number is appended to the epoch timestamp for both + randomness and to decrease the likelihood of collisions. + + .. _`section 3.2.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-3.2.1 + .. _`section 3.3`: http://tools.ietf.org/html/rfc5849#section-3.3 + """ + return unicode(unicode(random.getrandbits(64)) + generate_timestamp()) + + +def generate_timestamp(): + """Get seconds since epoch (UTC). + + Per `section 3.3`_ of the OAuth 1 RFC 5849 spec. + Per `section 3.2.1`_ of the MAC Access Authentication spec. + + .. _`section 3.2.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-3.2.1 + .. _`section 3.3`: http://tools.ietf.org/html/rfc5849#section-3.3 + """ + return unicode(int(time.time())) + + +def generate_token(length=30, chars=UNICODE_ASCII_CHARACTER_SET): + """Generates a non-guessable OAuth token + + OAuth (1 and 2) does not specify the format of tokens except that they + should be strings of random characters. Tokens should not be guessable + and entropy when generating the random characters is important. Which is + why SystemRandom is used instead of the default random.choice method. + """ + rand = random.SystemRandom() + return u''.join(rand.choice(chars) for x in range(length)) + + +def add_params_to_qs(query, params): + """Extend a query with a list of two-tuples.""" + queryparams = urlparse.parse_qsl(query, keep_blank_values=True) + queryparams.extend(params) + return urlencode(queryparams) + + +def add_params_to_uri(uri, params): + """Add a list of two-tuples to the uri query components.""" + sch, net, path, par, query, fra = urlparse.urlparse(uri) + query = add_params_to_qs(query, params) + return urlparse.urlunparse((sch, net, path, par, query, fra)) + +def safe_string_equals(a, b): + """ Near-constant time string comparison. + + Used in order to avoid timing attacks on sensitive information such + as secret keys during request verification (`rootLabs`_). + + .. _`rootLabs`: http://rdist.root.org/2010/01/07/timing-independent-array-comparison/ + + """ + if len(a) != len(b): + return False + + result = 0 + for x, y in zip(a, b): + result |= ord(x) ^ ord(y) + return result == 0 + +class Request(object): + """A malleable representation of a signable HTTP request. + + Body argument may contain any data, but parameters will only be decoded if + they are one of: + + * urlencoded query string + * dict + * list of 2-tuples + + Anything else will be treated as raw body data to be passed through + unmolested. + """ + + def __init__(self, uri, http_method=u'GET', body=None, headers=None): + self.uri = uri + self.http_method = http_method + self.headers = headers or {} + self.body = body + self.decoded_body = extract_params(body) + self.oauth_params = [] + + @property + def uri_query(self): + return urlparse.urlparse(self.uri).query + + @property + def uri_query_params(self): + return urlparse.parse_qsl(self.uri_query, keep_blank_values=True, + strict_parsing=True) diff --git a/libs/requests/packages/oauthlib/oauth1/__init__.py b/libs/requests/packages/oauthlib/oauth1/__init__.py new file mode 100644 index 00000000..ef692b57 --- /dev/null +++ b/libs/requests/packages/oauthlib/oauth1/__init__.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +""" +oauthlib.oauth1 +~~~~~~~~~~~~~~ + +This module is a wrapper for the most recent implementation of OAuth 1.0 Client +and Server classes. +""" + +from .rfc5849 import Client, Server + diff --git a/libs/requests/packages/oauthlib/oauth1/rfc5849/__init__.py b/libs/requests/packages/oauthlib/oauth1/rfc5849/__init__.py new file mode 100644 index 00000000..da3988da --- /dev/null +++ b/libs/requests/packages/oauthlib/oauth1/rfc5849/__init__.py @@ -0,0 +1,889 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +""" +oauthlib.oauth1.rfc5849 +~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for signing and checking OAuth 1.0 RFC 5849 requests. +""" + +import logging +import time +import urlparse + +from oauthlib.common import Request, urlencode, generate_nonce +from oauthlib.common import generate_timestamp +from . import parameters, signature, utils + +logger = logging.getLogger(__name__) + +SIGNATURE_HMAC = u"HMAC-SHA1" +SIGNATURE_RSA = u"RSA-SHA1" +SIGNATURE_PLAINTEXT = u"PLAINTEXT" +SIGNATURE_METHODS = (SIGNATURE_HMAC, SIGNATURE_RSA, SIGNATURE_PLAINTEXT) + +SIGNATURE_TYPE_AUTH_HEADER = u'AUTH_HEADER' +SIGNATURE_TYPE_QUERY = u'QUERY' +SIGNATURE_TYPE_BODY = u'BODY' + +CONTENT_TYPE_FORM_URLENCODED = u'application/x-www-form-urlencoded' + + +class Client(object): + """A client used to sign OAuth 1.0 RFC 5849 requests""" + def __init__(self, client_key, + client_secret=None, + resource_owner_key=None, + resource_owner_secret=None, + callback_uri=None, + signature_method=SIGNATURE_HMAC, + signature_type=SIGNATURE_TYPE_AUTH_HEADER, + rsa_key=None, verifier=None): + self.client_key = client_key + self.client_secret = client_secret + self.resource_owner_key = resource_owner_key + self.resource_owner_secret = resource_owner_secret + self.signature_method = signature_method + self.signature_type = signature_type + self.callback_uri = callback_uri + self.rsa_key = rsa_key + self.verifier = verifier + + if self.signature_method == SIGNATURE_RSA and self.rsa_key is None: + raise ValueError('rsa_key is required when using RSA signature method.') + + def get_oauth_signature(self, request): + """Get an OAuth signature to be used in signing a request + """ + if self.signature_method == SIGNATURE_PLAINTEXT: + # fast-path + return signature.sign_plaintext(self.client_secret, + self.resource_owner_secret) + + uri, headers, body = self._render(request) + + collected_params = signature.collect_parameters( + uri_query=urlparse.urlparse(uri).query, + body=body, + headers=headers) + logger.debug("Collected params: {0}".format(collected_params)) + + normalized_params = signature.normalize_parameters(collected_params) + normalized_uri = signature.normalize_base_string_uri(request.uri) + logger.debug("Normalized params: {0}".format(normalized_params)) + logger.debug("Normalized URI: {0}".format(normalized_uri)) + + base_string = signature.construct_base_string(request.http_method, + normalized_uri, normalized_params) + + logger.debug("Base signing string: {0}".format(base_string)) + + if self.signature_method == SIGNATURE_HMAC: + sig = signature.sign_hmac_sha1(base_string, self.client_secret, + self.resource_owner_secret) + elif self.signature_method == SIGNATURE_RSA: + sig = signature.sign_rsa_sha1(base_string, self.rsa_key) + else: + sig = signature.sign_plaintext(self.client_secret, + self.resource_owner_secret) + + logger.debug("Signature: {0}".format(sig)) + return sig + + def get_oauth_params(self): + """Get the basic OAuth parameters to be used in generating a signature. + """ + params = [ + (u'oauth_nonce', generate_nonce()), + (u'oauth_timestamp', generate_timestamp()), + (u'oauth_version', u'1.0'), + (u'oauth_signature_method', self.signature_method), + (u'oauth_consumer_key', self.client_key), + ] + if self.resource_owner_key: + params.append((u'oauth_token', self.resource_owner_key)) + if self.callback_uri: + params.append((u'oauth_callback', self.callback_uri)) + if self.verifier: + params.append((u'oauth_verifier', self.verifier)) + + return params + + def _render(self, request, formencode=False): + """Render a signed request according to signature type + + Returns a 3-tuple containing the request URI, headers, and body. + + If the formencode argument is True and the body contains parameters, it + is escaped and returned as a valid formencoded string. + """ + # TODO what if there are body params on a header-type auth? + # TODO what if there are query params on a body-type auth? + + uri, headers, body = request.uri, request.headers, request.body + + # TODO: right now these prepare_* methods are very narrow in scope--they + # only affect their little thing. In some cases (for example, with + # header auth) it might be advantageous to allow these methods to touch + # other parts of the request, like the headers—so the prepare_headers + # method could also set the Content-Type header to x-www-form-urlencoded + # like the spec requires. This would be a fundamental change though, and + # I'm not sure how I feel about it. + if self.signature_type == SIGNATURE_TYPE_AUTH_HEADER: + headers = parameters.prepare_headers(request.oauth_params, request.headers) + elif self.signature_type == SIGNATURE_TYPE_BODY and request.decoded_body is not None: + body = parameters.prepare_form_encoded_body(request.oauth_params, request.decoded_body) + if formencode: + body = urlencode(body) + headers['Content-Type'] = u'application/x-www-form-urlencoded' + elif self.signature_type == SIGNATURE_TYPE_QUERY: + uri = parameters.prepare_request_uri_query(request.oauth_params, request.uri) + else: + raise ValueError('Unknown signature type specified.') + + return uri, headers, body + + def sign(self, uri, http_method=u'GET', body=None, headers=None): + """Sign a request + + Signs an HTTP request with the specified parts. + + Returns a 3-tuple of the signed request's URI, headers, and body. + Note that http_method is not returned as it is unaffected by the OAuth + signing process. + + The body argument may be a dict, a list of 2-tuples, or a formencoded + string. The Content-Type header must be 'application/x-www-form-urlencoded' + if it is present. + + If the body argument is not one of the above, it will be returned + verbatim as it is unaffected by the OAuth signing process. Attempting to + sign a request with non-formencoded data using the OAuth body signature + type is invalid and will raise an exception. + + If the body does contain parameters, it will be returned as a properly- + formatted formencoded string. + + All string data MUST be unicode. This includes strings inside body + dicts, for example. + """ + # normalize request data + request = Request(uri, http_method, body, headers) + + # sanity check + content_type = request.headers.get('Content-Type', None) + multipart = content_type and content_type.startswith('multipart/') + should_have_params = content_type == CONTENT_TYPE_FORM_URLENCODED + has_params = request.decoded_body is not None + # 3.4.1.3.1. Parameter Sources + # [Parameters are collected from the HTTP request entity-body, but only + # if [...]: + # * The entity-body is single-part. + if multipart and has_params: + raise ValueError("Headers indicate a multipart body but body contains parameters.") + # * The entity-body follows the encoding requirements of the + # "application/x-www-form-urlencoded" content-type as defined by + # [W3C.REC-html40-19980424]. + elif should_have_params and not has_params: + raise ValueError("Headers indicate a formencoded body but body was not decodable.") + # * The HTTP request entity-header includes the "Content-Type" + # header field set to "application/x-www-form-urlencoded". + elif not should_have_params and has_params: + raise ValueError("Body contains parameters but Content-Type header was not set.") + + # 3.5.2. Form-Encoded Body + # Protocol parameters can be transmitted in the HTTP request entity- + # body, but only if the following REQUIRED conditions are met: + # o The entity-body is single-part. + # o The entity-body follows the encoding requirements of the + # "application/x-www-form-urlencoded" content-type as defined by + # [W3C.REC-html40-19980424]. + # o The HTTP request entity-header includes the "Content-Type" header + # field set to "application/x-www-form-urlencoded". + elif self.signature_type == SIGNATURE_TYPE_BODY and not ( + should_have_params and has_params and not multipart): + raise ValueError('Body signatures may only be used with form-urlencoded content') + + # generate the basic OAuth parameters + request.oauth_params = self.get_oauth_params() + + # generate the signature + request.oauth_params.append((u'oauth_signature', self.get_oauth_signature(request))) + + # render the signed request and return it + return self._render(request, formencode=True) + + +class Server(object): + """A server base class used to verify OAuth 1.0 RFC 5849 requests + + OAuth providers should inherit from Server and implement the methods + and properties outlined below. Further details are provided in the + documentation for each method and property. + + Methods used to check the format of input parameters. Common tests include + length, character set, membership, range or pattern. These tests are + referred to as `whitelisting or blacklisting`_. Whitelisting is better + but blacklisting can be usefull to spot malicious activity. + The following have methods a default implementation: + + - check_client_key + - check_request_token + - check_access_token + - check_nonce + - check_verifier + - check_realm + + The methods above default to whitelist input parameters, checking that they + are alphanumerical and between a minimum and maximum length. Rather than + overloading the methods a few properties can be used to configure these + methods. + + @ safe_characters -> (character set) + @ client_key_length -> (min, max) + @ request_token_length -> (min, max) + @ access_token_length -> (min, max) + @ nonce_length -> (min, max) + @ verifier_length -> (min, max) + @ realms -> [list, of, realms] + + Methods used to validate input parameters. These checks usually hit either + persistent or temporary storage such as databases or the filesystem. See + each methods documentation for detailed usage. + The following methods must be implemented: + + - validate_client + - validate_request_token + - validate_access_token + - validate_nonce_and_timestamp + - validate_redirect_uri + - validate_requested_realm + - validate_realm + - validate_verifier + + Method used to retrieve sensitive information from storage. + The following methods must be implemented: + + - get_client_secret + - get_request_token_secret + - get_access_token_secret + - get_rsa_key + + To prevent timing attacks it is necessary to not exit early even if the + client key or resource owner key is invalid. Instead dummy values should + be used during the remaining verification process. It is very important + that the dummy client and token are valid input parameters to the methods + get_client_secret, get_rsa_key and get_(access/request)_token_secret and + that the running time of those methods when given a dummy value remain + equivalent to the running time when given a valid client/resource owner. + The following properties must be implemented: + + @ dummy_client + @ dummy_request_token + @ dummy_access_token + + .. _`whitelisting or blacklisting`: http://www.schneier.com/blog/archives/2011/01/whitelisting_vs.html + """ + + def __init__(self): + pass + + @property + def allowed_signature_methods(self): + return SIGNATURE_METHODS + + @property + def safe_characters(self): + return set(utils.UNICODE_ASCII_CHARACTER_SET) + + @property + def client_key_length(self): + return 20, 30 + + @property + def request_token_length(self): + return 20, 30 + + @property + def access_token_length(self): + return 20, 30 + + @property + def timestamp_lifetime(self): + return 600 + + @property + def nonce_length(self): + return 20, 30 + + @property + def verifier_length(self): + return 20, 30 + + @property + def realms(self): + return [] + + @property + def enforce_ssl(self): + return True + + def check_client_key(self, client_key): + """Check that the client key only contains safe characters + and is no shorter than lower and no longer than upper. + """ + lower, upper = self.client_key_length + return (set(client_key) <= self.safe_characters and + lower <= len(client_key) <= upper) + + def check_request_token(self, request_token): + """Checks that the request token contains only safe characters + and is no shorter than lower and no longer than upper. + """ + lower, upper = self.request_token_length + return (set(request_token) <= self.safe_characters and + lower <= len(request_token) <= upper) + + def check_access_token(self, request_token): + """Checks that the token contains only safe characters + and is no shorter than lower and no longer than upper. + """ + lower, upper = self.access_token_length + return (set(request_token) <= self.safe_characters and + lower <= len(request_token) <= upper) + + def check_nonce(self, nonce): + """Checks that the nonce only contains only safe characters + and is no shorter than lower and no longer than upper. + """ + lower, upper = self.nonce_length + return (set(nonce) <= self.safe_characters and + lower <= len(nonce) <= upper) + + def check_verifier(self, verifier): + """Checks that the verifier contains only safe characters + and is no shorter than lower and no longer than upper. + """ + lower, upper = self.verifier_length + return (set(verifier) <= self.safe_characters and + lower <= len(verifier) <= upper) + + def check_realm(self, realm): + """Check that the realm is one of a set allowed realms. + """ + return realm in self.realms + + def get_client_secret(self, client_key): + """Retrieves the client secret associated with the client key. + + This method must allow the use of a dummy client_key value. + Fetching the secret using the dummy key must take the same amount of + time as fetching a secret for a valid client. + + Note that the returned key must be in plaintext. + """ + raise NotImplementedError("Subclasses must implement this function.") + + @property + def dummy_client(self): + """Dummy client used when an invalid client key is supplied. + + The dummy client should be associated with either a client secret, + a rsa key or both depending on which signature methods are supported. + Providers should make sure that + + get_client_secret(dummy_client) + get_rsa_key(dummy_client) + + return a valid secret or key for the dummy client. + """ + raise NotImplementedError("Subclasses must implement this function.") + + def get_request_token_secret(self, client_key, request_token): + """Retrieves the shared secret associated with the request token. + + This method must allow the use of a dummy values and the running time + must be roughly equivalent to that of the running time of valid values. + + Note that the returned key must be in plaintext. + """ + raise NotImplementedError("Subclasses must implement this function.") + + def get_access_token_secret(self, client_key, access_token): + """Retrieves the shared secret associated with the access token. + + This method must allow the use of a dummy values and the running time + must be roughly equivalent to that of the running time of valid values. + + Note that the returned key must be in plaintext. + """ + raise NotImplementedError("Subclasses must implement this function.") + + @property + def dummy_request_token(self): + """Dummy request token used when an invalid token was supplied. + + The dummy request token should be associated with a request token + secret such that get_request_token_secret(.., dummy_request_token) + returns a valid secret. + """ + raise NotImplementedError("Subclasses must implement this function.") + + @property + def dummy_access_token(self): + """Dummy access token used when an invalid token was supplied. + + The dummy access token should be associated with an access token + secret such that get_access_token_secret(.., dummy_access_token) + returns a valid secret. + """ + raise NotImplementedError("Subclasses must implement this function.") + + def get_rsa_key(self, client_key): + """Retrieves a previously stored client provided RSA key. + + This method must allow the use of a dummy client_key value. Fetching + the rsa key using the dummy key must take the same aount of time + as fetching a key for a valid client. + + Note that the key must be returned in plaintext. + """ + raise NotImplementedError("Subclasses must implement this function.") + + def get_signature_type_and_params(self, request): + """Extracts parameters from query, headers and body. Signature type + is set to the source in which parameters were found. + """ + header_params = signature.collect_parameters(headers=request.headers, + exclude_oauth_signature=False) + body_params = signature.collect_parameters(body=request.body, + exclude_oauth_signature=False) + query_params = signature.collect_parameters(uri_query=request.uri_query, + exclude_oauth_signature=False) + + params = [] + params.extend(header_params) + params.extend(body_params) + params.extend(query_params) + signature_types_with_oauth_params = filter(lambda s: s[2], ( + (SIGNATURE_TYPE_AUTH_HEADER, params, + utils.filter_oauth_params(header_params)), + (SIGNATURE_TYPE_BODY, params, + utils.filter_oauth_params(body_params)), + (SIGNATURE_TYPE_QUERY, params, + utils.filter_oauth_params(query_params)) + )) + + if len(signature_types_with_oauth_params) > 1: + raise ValueError('oauth_ params must come from only 1 signature type but were found in %s' % ', '.join( + [s[0] for s in signature_types_with_oauth_params])) + try: + signature_type, params, oauth_params = signature_types_with_oauth_params[0] + except IndexError: + raise ValueError('oauth_ params are missing. Could not determine signature type.') + + return signature_type, params, oauth_params + + def validate_client_key(self, client_key): + """Validates that supplied client key is a registered and valid client. + + Note that if the dummy client is supplied it should validate in same + or nearly the same amount of time as a valid one. + + Bad: + + if client_key == self.dummy_client: + return False + else: + return storage.has_client(client_key) + + Good: + + return storage.has_client(client_key) and client_key != self.dummy_client + """ + raise NotImplementedError("Subclasses must implement this function.") + + def validate_request_token(self, client_key, request_token): + """Validates that supplied request token is registered and valid. + + Note that if the dummy request_token is supplied it should validate in + the same nearly the same amount of time as a valid one. + + Bad: + + if request_token == self.dummy_request_token: + return False + else: + return storage.has_request_token(request_token) + + Good: + + return (storage.has_request_token(request_token) and + request_token != self.dummy_request_token) + """ + raise NotImplementedError("Subclasses must implement this function.") + + def validate_access_token(self, client_key, access_token): + """Validates that supplied access token is registered and valid. + + Note that if the dummy access token is supplied it should validate in + the same or nearly the same amount of time as a valid one. + + Bad: + + if access_token == self.dummy_access_token: + return False + else: + return storage.has_access_token(access_token) + + Good: + + return (storage.has_access_token(access_token) and + access_token != self.dummy_access_token) + """ + raise NotImplementedError("Subclasses must implement this function.") + + def validate_timestamp_and_nonce(self, client_key, timestamp, nonce, + request_token=None, access_token=None): + """Validates that the nonce has not been used before. + + Per `Section 3.3`_ of the spec. + + "A nonce is a random string, uniquely generated by the client to allow + the server to verify that a request has never been made before and + helps prevent replay attacks when requests are made over a non-secure + channel. The nonce value MUST be unique across all requests with the + same timestamp, client credentials, and token combinations." + + .. _`Section 3.3`: http://tools.ietf.org/html/rfc5849#section-3.3 + + """ + raise NotImplementedError("Subclasses must implement this function.") + + def validate_redirect_uri(self, client_key, redirect_uri): + """Validates the client supplied redirection URI. + + It is highly recommended that OAuth providers require their clients + to register all redirection URIs prior to using them in requests and + register them as absolute URIs. See `CWE-601`_ for more information + about open redirection attacks. + + By requiring registration of all redirection URIs it should be + straightforward for the provider to verify whether the supplied + redirect_uri is valid or not. + + .. _`CWE-601`: http://cwe.mitre.org/top25/index.html#CWE-601 + """ + raise NotImplementedError("Subclasses must implement this function.") + + + def validate_requested_realm(self, client_key, realm): + """Validates that the client may request access to the realm. + + This method is invoked when obtaining a request token and should + tie a realm to the request token and after user authorization + this realm restriction should transfer to the access token. + """ + raise NotImplementedError("Subclasses must implement this function.") + + def validate_realm(self, client_key, access_token, uri=None, + required_realm=None): + """Validates access to the request realm. + + How providers choose to use the realm parameter is outside the OAuth + specification but it is commonly used to restrict access to a subset + of protected resources such as "photos". + + required_realm is a convenience parameter which can be used to provide + a per view method pre-defined list of allowed realms. + """ + raise NotImplementedError("Subclasses must implement this function.") + + def validate_verifier(self, client_key, request_token, verifier): + """Validates a verification code. + + OAuth providers issue a verification code to clients after the + resource owner authorizes access. This code is used by the client to + obtain token credentials and the provider must verify that the + verifier is valid and associated with the client as well as the + resource owner. + """ + raise NotImplementedError("Subclasses must implement this function.") + + def verify_request(self, uri, http_method=u'GET', body=None, + headers=None, require_resource_owner=True, require_verifier=False, + require_realm=False, required_realm=None): + """Verifies a request ensuring that the following is true: + + Per `section 3.2`_ of the spec. + + - all mandated OAuth parameters are supplied + - parameters are only supplied in one source which may be the URI + query, the Authorization header or the body + - all parameters are checked and validated, see comments and the + methods and properties of this class for further details. + - the supplied signature is verified against a recalculated one + + A ValueError will be raised if any parameter is missing, + supplied twice or invalid. A HTTP 400 Response should be returned + upon catching an exception. + + A HTTP 401 Response should be returned if verify_request returns False. + + `Timing attacks`_ are prevented through the use of dummy credentials to + create near constant time verification even if an invalid credential + is used. Early exit on invalid credentials would enable attackers + to perform `enumeration attacks`_. Near constant time string comparison + is used to prevent secret key guessing. Note that timing attacks can + only be prevented through near constant time execution, not by adding + a random delay which would only require more samples to be gathered. + + .. _`section 3.2`: http://tools.ietf.org/html/rfc5849#section-3.2 + .. _`Timing attacks`: http://rdist.root.org/2010/07/19/exploiting-remote-timing-attacks/ + .. _`enumeration attacks`: http://www.sans.edu/research/security-laboratory/article/attacks-browsing + """ + # Only include body data from x-www-form-urlencoded requests + headers = headers or {} + if (u"Content-Type" in headers and + headers[u"Content-Type"] == CONTENT_TYPE_FORM_URLENCODED): + request = Request(uri, http_method, body, headers) + else: + request = Request(uri, http_method, u'', headers) + + if self.enforce_ssl and not request.uri.lower().startswith("https://"): + raise ValueError("Insecure transport, only HTTPS is allowed.") + + signature_type, params, oauth_params = self.get_signature_type_and_params(request) + + # The server SHOULD return a 400 (Bad Request) status code when + # receiving a request with duplicated protocol parameters. + if len(dict(oauth_params)) != len(oauth_params): + raise ValueError("Duplicate OAuth entries.") + + oauth_params = dict(oauth_params) + request_signature = oauth_params.get(u'oauth_signature') + client_key = oauth_params.get(u'oauth_consumer_key') + resource_owner_key = oauth_params.get(u'oauth_token') + nonce = oauth_params.get(u'oauth_nonce') + timestamp = oauth_params.get(u'oauth_timestamp') + callback_uri = oauth_params.get(u'oauth_callback') + verifier = oauth_params.get(u'oauth_verifier') + signature_method = oauth_params.get(u'oauth_signature_method') + realm = dict(params).get(u'realm') + + # The server SHOULD return a 400 (Bad Request) status code when + # receiving a request with missing parameters. + if not all((request_signature, client_key, nonce, + timestamp, signature_method)): + raise ValueError("Missing OAuth parameters.") + + # OAuth does not mandate a particular signature method, as each + # implementation can have its own unique requirements. Servers are + # free to implement and document their own custom methods. + # Recommending any particular method is beyond the scope of this + # specification. Implementers should review the Security + # Considerations section (`Section 4`_) before deciding on which + # method to support. + # .. _`Section 4`: http://tools.ietf.org/html/rfc5849#section-4 + if not signature_method in self.allowed_signature_methods: + raise ValueError("Invalid signature method.") + + # Servers receiving an authenticated request MUST validate it by: + # If the "oauth_version" parameter is present, ensuring its value is + # "1.0". + if u'oauth_version' in oauth_params and oauth_params[u'oauth_version'] != u'1.0': + raise ValueError("Invalid OAuth version.") + + # The timestamp value MUST be a positive integer. Unless otherwise + # specified by the server's documentation, the timestamp is expressed + # in the number of seconds since January 1, 1970 00:00:00 GMT. + if len(timestamp) != 10: + raise ValueError("Invalid timestamp size") + try: + ts = int(timestamp) + + except ValueError: + raise ValueError("Timestamp must be an integer") + + else: + # To avoid the need to retain an infinite number of nonce values for + # future checks, servers MAY choose to restrict the time period after + # which a request with an old timestamp is rejected. + if time.time() - ts > self.timestamp_lifetime: + raise ValueError("Request too old, over 10 minutes.") + + # Provider specific validation of parameters, used to enforce + # restrictions such as character set and length. + if not self.check_client_key(client_key): + raise ValueError("Invalid client key.") + + if not resource_owner_key and require_resource_owner: + raise ValueError("Missing resource owner.") + + if (require_resource_owner and not require_verifier and + not self.check_access_token(resource_owner_key)): + raise ValueError("Invalid resource owner key.") + + if (require_resource_owner and require_verifier and + not self.check_request_token(resource_owner_key)): + raise ValueError("Invalid resource owner key.") + + if not self.check_nonce(nonce): + raise ValueError("Invalid nonce.") + + if realm and not self.check_realm(realm): + raise ValueError("Invalid realm. Allowed are %s" % self.realms) + + if not verifier and require_verifier: + raise ValueError("Missing verifier.") + + if require_verifier and not self.check_verifier(verifier): + raise ValueError("Invalid verifier.") + + # Servers receiving an authenticated request MUST validate it by: + # If using the "HMAC-SHA1" or "RSA-SHA1" signature methods, ensuring + # that the combination of nonce/timestamp/token (if present) + # received from the client has not been used before in a previous + # request (the server MAY reject requests with stale timestamps as + # described in `Section 3.3`_). + # .._`Section 3.3`: http://tools.ietf.org/html/rfc5849#section-3.3 + # + # We check this before validating client and resource owner for + # increased security and performance, both gained by doing less work. + if require_verifier: + token = {"request_token": resource_owner_key} + else: + token = {"access_token": resource_owner_key} + if not self.validate_timestamp_and_nonce(client_key, timestamp, + nonce, **token): + return False + + # The server SHOULD return a 401 (Unauthorized) status code when + # receiving a request with invalid client credentials. + # Note: This is postponed in order to avoid timing attacks, instead + # a dummy client is assigned and used to maintain near constant + # time request verification. + # + # Note that early exit would enable client enumeration + valid_client = self.validate_client_key(client_key) + if not valid_client: + client_key = self.dummy_client + + # Ensure a valid redirection uri is used + valid_redirect = self.validate_redirect_uri(client_key, callback_uri) + + # The server SHOULD return a 401 (Unauthorized) status code when + # receiving a request with invalid or expired token. + # Note: This is postponed in order to avoid timing attacks, instead + # a dummy token is assigned and used to maintain near constant + # time request verification. + # + # Note that early exit would enable resource owner enumeration + if resource_owner_key: + if require_verifier: + valid_resource_owner = self.validate_request_token( + client_key, resource_owner_key) + else: + valid_resource_owner = self.validate_access_token( + client_key, resource_owner_key) + if not valid_resource_owner: + resource_owner_key = self.dummy_resource_owner + else: + valid_resource_owner = True + + # Note that `realm`_ is only used in authorization headers and how + # it should be interepreted is not included in the OAuth spec. + # However they could be seen as a scope or realm to which the + # client has access and as such every client should be checked + # to ensure it is authorized access to that scope or realm. + # .. _`realm`: http://tools.ietf.org/html/rfc2617#section-1.2 + # + # Note that early exit would enable client realm access enumeration. + # + # The require_realm indicates this is the first step in the OAuth + # workflow where a client requests access to a specific realm. + # + # Clients obtaining an access token will not supply a realm and it will + # not be checked. Instead the previously requested realm should be + # transferred from the request token to the access token. + # + # Access to protected resources will always validate the realm but note + # that the realm is now tied to the access token and not provided by + # the client. + if require_realm and not resource_owner_key: + valid_realm = self.validate_requested_realm(client_key, realm) + elif require_verifier: + valid_realm = True + else: + valid_realm = self.validate_realm(client_key, resource_owner_key, + uri=request.uri, required_realm=required_realm) + + # The server MUST verify (Section 3.2) the validity of the request, + # ensure that the resource owner has authorized the provisioning of + # token credentials to the client, and ensure that the temporary + # credentials have not expired or been used before. The server MUST + # also verify the verification code received from the client. + # .. _`Section 3.2`: http://tools.ietf.org/html/rfc5849#section-3.2 + # + # Note that early exit would enable resource owner authorization + # verifier enumertion. + if verifier: + valid_verifier = self.validate_verifier(client_key, + resource_owner_key, verifier) + else: + valid_verifier = True + + # Parameters to Client depend on signature method which may vary + # for each request. Note that HMAC-SHA1 and PLAINTEXT share parameters + + request.params = filter(lambda x: x[0] != "oauth_signature", params) + request.signature = request_signature + + # ---- RSA Signature verification ---- + if signature_method == SIGNATURE_RSA: + # The server verifies the signature per `[RFC3447] section 8.2.2`_ + # .. _`[RFC3447] section 8.2.2`: http://tools.ietf.org/html/rfc3447#section-8.2.1 + rsa_key = self.get_rsa_key(client_key) + valid_signature = signature.verify_rsa_sha1(request, rsa_key) + + # ---- HMAC or Plaintext Signature verification ---- + else: + # Servers receiving an authenticated request MUST validate it by: + # Recalculating the request signature independently as described in + # `Section 3.4`_ and comparing it to the value received from the + # client via the "oauth_signature" parameter. + # .. _`Section 3.4`: http://tools.ietf.org/html/rfc5849#section-3.4 + client_secret = self.get_client_secret(client_key) + if require_verifier: + resource_owner_secret = self.get_request_token_secret( + client_key, resource_owner_key) + else: + resource_owner_secret = self.get_access_token_secret( + client_key, resource_owner_key) + + if signature_method == SIGNATURE_HMAC: + valid_signature = signature.verify_hmac_sha1(request, + client_secret, resource_owner_secret) + else: + valid_signature = signature.verify_plaintext(request, + client_secret, resource_owner_secret) + + # We delay checking validity until the very end, using dummy values for + # calculations and fetching secrets/keys to ensure the flow of every + # request remains almost identical regardless of whether valid values + # have been supplied. This ensures near constant time execution and + # prevents malicious users from guessing sensitive information + v = all((valid_client, valid_resource_owner, valid_realm, + valid_redirect, valid_verifier, valid_signature)) + logger = logging.getLogger("oauthlib") + if not v: + logger.info("[Failure] OAuthLib request verification failed.") + logger.info("Valid client:\t%s" % valid_client) + logger.info("Valid token:\t%s\t(Required: %s" % (valid_resource_owner, require_resource_owner)) + logger.info("Valid realm:\t%s\t(Required: %s)" % (valid_realm, require_realm)) + logger.info("Valid callback:\t%s" % valid_redirect) + logger.info("Valid verifier:\t%s\t(Required: %s)" % (valid_verifier, require_verifier)) + logger.info("Valid signature:\t%s" % valid_signature) + return v diff --git a/libs/requests/packages/oauthlib/oauth1/rfc5849/parameters.py b/libs/requests/packages/oauthlib/oauth1/rfc5849/parameters.py new file mode 100644 index 00000000..dee23a43 --- /dev/null +++ b/libs/requests/packages/oauthlib/oauth1/rfc5849/parameters.py @@ -0,0 +1,134 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +""" +oauthlib.parameters +~~~~~~~~~~~~~~~~~~~ + +This module contains methods related to `section 3.5`_ of the OAuth 1.0a spec. + +.. _`section 3.5`: http://tools.ietf.org/html/rfc5849#section-3.5 +""" + +from urlparse import urlparse, urlunparse +from . import utils +from oauthlib.common import extract_params, urlencode + + +# TODO: do we need filter_params now that oauth_params are handled by Request? +# We can easily pass in just oauth protocol params. +@utils.filter_params +def prepare_headers(oauth_params, headers=None, realm=None): + """**Prepare the Authorization header.** + Per `section 3.5.1`_ of the spec. + + Protocol parameters can be transmitted using the HTTP "Authorization" + header field as defined by `RFC2617`_ with the auth-scheme name set to + "OAuth" (case insensitive). + + For example:: + + Authorization: OAuth realm="Example", + oauth_consumer_key="0685bd9184jfhq22", + oauth_token="ad180jjd733klru7", + oauth_signature_method="HMAC-SHA1", + oauth_signature="wOJIO9A2W5mFwDgiDvZbTSMK%2FPY%3D", + oauth_timestamp="137131200", + oauth_nonce="4572616e48616d6d65724c61686176", + oauth_version="1.0" + + + .. _`section 3.5.1`: http://tools.ietf.org/html/rfc5849#section-3.5.1 + .. _`RFC2617`: http://tools.ietf.org/html/rfc2617 + """ + headers = headers or {} + + # Protocol parameters SHALL be included in the "Authorization" header + # field as follows: + authorization_header_parameters_parts = [] + for oauth_parameter_name, value in oauth_params: + # 1. Parameter names and values are encoded per Parameter Encoding + # (`Section 3.6`_) + # + # .. _`Section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6 + escaped_name = utils.escape(oauth_parameter_name) + escaped_value = utils.escape(value) + + # 2. Each parameter's name is immediately followed by an "=" character + # (ASCII code 61), a """ character (ASCII code 34), the parameter + # value (MAY be empty), and another """ character (ASCII code 34). + part = u'{0}="{1}"'.format(escaped_name, escaped_value) + + authorization_header_parameters_parts.append(part) + + # 3. Parameters are separated by a "," character (ASCII code 44) and + # OPTIONAL linear whitespace per `RFC2617`_. + # + # .. _`RFC2617`: http://tools.ietf.org/html/rfc2617 + authorization_header_parameters = ', '.join( + authorization_header_parameters_parts) + + # 4. The OPTIONAL "realm" parameter MAY be added and interpreted per + # `RFC2617 section 1.2`_. + # + # .. _`RFC2617 section 1.2`: http://tools.ietf.org/html/rfc2617#section-1.2 + if realm: + # NOTE: realm should *not* be escaped + authorization_header_parameters = (u'realm="%s", ' % realm + + authorization_header_parameters) + + # the auth-scheme name set to "OAuth" (case insensitive). + authorization_header = u'OAuth %s' % authorization_header_parameters + + # contribute the Authorization header to the given headers + full_headers = {} + full_headers.update(headers) + full_headers[u'Authorization'] = authorization_header + return full_headers + + +def _append_params(oauth_params, params): + """Append OAuth params to an existing set of parameters. + + Both params and oauth_params is must be lists of 2-tuples. + + Per `section 3.5.2`_ and `3.5.3`_ of the spec. + + .. _`section 3.5.2`: http://tools.ietf.org/html/rfc5849#section-3.5.2 + .. _`3.5.3`: http://tools.ietf.org/html/rfc5849#section-3.5.3 + + """ + merged = list(params) + merged.extend(oauth_params) + # The request URI / entity-body MAY include other request-specific + # parameters, in which case, the protocol parameters SHOULD be appended + # following the request-specific parameters, properly separated by an "&" + # character (ASCII code 38) + merged.sort(key=lambda i: i[0].startswith('oauth_')) + return merged + + +def prepare_form_encoded_body(oauth_params, body): + """Prepare the Form-Encoded Body. + + Per `section 3.5.2`_ of the spec. + + .. _`section 3.5.2`: http://tools.ietf.org/html/rfc5849#section-3.5.2 + + """ + # append OAuth params to the existing body + return _append_params(oauth_params, body) + + +def prepare_request_uri_query(oauth_params, uri): + """Prepare the Request URI Query. + + Per `section 3.5.3`_ of the spec. + + .. _`section 3.5.3`: http://tools.ietf.org/html/rfc5849#section-3.5.3 + + """ + # append OAuth params to the existing set of query components + sch, net, path, par, query, fra = urlparse(uri) + query = urlencode(_append_params(oauth_params, extract_params(query) or [])) + return urlunparse((sch, net, path, par, query, fra)) diff --git a/libs/requests/packages/oauthlib/oauth1/rfc5849/signature.py b/libs/requests/packages/oauthlib/oauth1/rfc5849/signature.py new file mode 100644 index 00000000..dbd43aa5 --- /dev/null +++ b/libs/requests/packages/oauthlib/oauth1/rfc5849/signature.py @@ -0,0 +1,551 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import +""" +oauthlib.oauth1.rfc5849.signature +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This module represents a direct implementation of `section 3.4`_ of the spec. + +Terminology: + * Client: software interfacing with an OAuth API + * Server: the API provider + * Resource Owner: the user who is granting authorization to the client + +Steps for signing a request: + +1. Collect parameters from the uri query, auth header, & body +2. Normalize those parameters +3. Normalize the uri +4. Pass the normalized uri, normalized parameters, and http method to + construct the base string +5. Pass the base string and any keys needed to a signing function + +.. _`section 3.4`: http://tools.ietf.org/html/rfc5849#section-3.4 +""" +import binascii +import hashlib +import hmac +import urlparse +from . import utils +from oauthlib.common import extract_params, safe_string_equals + + +def construct_base_string(http_method, base_string_uri, + normalized_encoded_request_parameters): + """**String Construction** + Per `section 3.4.1.1`_ of the spec. + + For example, the HTTP request:: + + POST /request?b5=%3D%253D&a3=a&c%40=&a2=r%20b HTTP/1.1 + Host: example.com + Content-Type: application/x-www-form-urlencoded + Authorization: OAuth realm="Example", + oauth_consumer_key="9djdj82h48djs9d2", + oauth_token="kkk9d7dh3k39sjv7", + oauth_signature_method="HMAC-SHA1", + oauth_timestamp="137131201", + oauth_nonce="7d8f3e4a", + oauth_signature="bYT5CMsGcbgUdFHObYMEfcx6bsw%3D" + + c2&a3=2+q + + is represented by the following signature base string (line breaks + are for display purposes only):: + + POST&http%3A%2F%2Fexample.com%2Frequest&a2%3Dr%2520b%26a3%3D2%2520q + %26a3%3Da%26b5%3D%253D%25253D%26c%2540%3D%26c2%3D%26oauth_consumer_ + key%3D9djdj82h48djs9d2%26oauth_nonce%3D7d8f3e4a%26oauth_signature_m + ethod%3DHMAC-SHA1%26oauth_timestamp%3D137131201%26oauth_token%3Dkkk + 9d7dh3k39sjv7 + + .. _`section 3.4.1.1`: http://tools.ietf.org/html/rfc5849#section-3.4.1.1 + """ + + # The signature base string is constructed by concatenating together, + # in order, the following HTTP request elements: + + # 1. The HTTP request method in uppercase. For example: "HEAD", + # "GET", "POST", etc. If the request uses a custom HTTP method, it + # MUST be encoded (`Section 3.6`_). + # + # .. _`Section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6 + base_string = utils.escape(http_method.upper()) + + # 2. An "&" character (ASCII code 38). + base_string += u'&' + + # 3. The base string URI from `Section 3.4.1.2`_, after being encoded + # (`Section 3.6`_). + # + # .. _`Section 3.4.1.2`: http://tools.ietf.org/html/rfc5849#section-3.4.1.2 + # .. _`Section 3.4.6`: http://tools.ietf.org/html/rfc5849#section-3.4.6 + base_string += utils.escape(base_string_uri) + + # 4. An "&" character (ASCII code 38). + base_string += u'&' + + # 5. The request parameters as normalized in `Section 3.4.1.3.2`_, after + # being encoded (`Section 3.6`). + # + # .. _`Section 3.4.1.3.2`: http://tools.ietf.org/html/rfc5849#section-3.4.1.3.2 + # .. _`Section 3.4.6`: http://tools.ietf.org/html/rfc5849#section-3.4.6 + base_string += utils.escape(normalized_encoded_request_parameters) + + return base_string + + +def normalize_base_string_uri(uri): + """**Base String URI** + Per `section 3.4.1.2`_ of the spec. + + For example, the HTTP request:: + + GET /r%20v/X?id=123 HTTP/1.1 + Host: EXAMPLE.COM:80 + + is represented by the base string URI: "http://example.com/r%20v/X". + + In another example, the HTTPS request:: + + GET /?q=1 HTTP/1.1 + Host: www.example.net:8080 + + is represented by the base string URI: "https://www.example.net:8080/". + + .. _`section 3.4.1.2`: http://tools.ietf.org/html/rfc5849#section-3.4.1.2 + """ + if not isinstance(uri, unicode): + raise ValueError('uri must be a unicode object.') + + # FIXME: urlparse does not support unicode + scheme, netloc, path, params, query, fragment = urlparse.urlparse(uri) + + # The scheme, authority, and path of the request resource URI `RFC3986` + # are included by constructing an "http" or "https" URI representing + # the request resource (without the query or fragment) as follows: + # + # .. _`RFC2616`: http://tools.ietf.org/html/rfc3986 + + # 1. The scheme and host MUST be in lowercase. + scheme = scheme.lower() + netloc = netloc.lower() + + # 2. The host and port values MUST match the content of the HTTP + # request "Host" header field. + # TODO: enforce this constraint + + # 3. The port MUST be included if it is not the default port for the + # scheme, and MUST be excluded if it is the default. Specifically, + # the port MUST be excluded when making an HTTP request `RFC2616`_ + # to port 80 or when making an HTTPS request `RFC2818`_ to port 443. + # All other non-default port numbers MUST be included. + # + # .. _`RFC2616`: http://tools.ietf.org/html/rfc2616 + # .. _`RFC2818`: http://tools.ietf.org/html/rfc2818 + default_ports = ( + (u'http', u'80'), + (u'https', u'443'), + ) + if u':' in netloc: + host, port = netloc.split(u':', 1) + if (scheme, port) in default_ports: + netloc = host + + return urlparse.urlunparse((scheme, netloc, path, u'', u'', u'')) + + +# ** Request Parameters ** +# +# Per `section 3.4.1.3`_ of the spec. +# +# In order to guarantee a consistent and reproducible representation of +# the request parameters, the parameters are collected and decoded to +# their original decoded form. They are then sorted and encoded in a +# particular manner that is often different from their original +# encoding scheme, and concatenated into a single string. +# +# .. _`section 3.4.1.3`: http://tools.ietf.org/html/rfc5849#section-3.4.1.3 + +def collect_parameters(uri_query='', body=[], headers=None, + exclude_oauth_signature=True): + """**Parameter Sources** + + Parameters starting with `oauth_` will be unescaped. + + Body parameters must be supplied as a dict, a list of 2-tuples, or a + formencoded query string. + + Headers must be supplied as a dict. + + Per `section 3.4.1.3.1`_ of the spec. + + For example, the HTTP request:: + + POST /request?b5=%3D%253D&a3=a&c%40=&a2=r%20b HTTP/1.1 + Host: example.com + Content-Type: application/x-www-form-urlencoded + Authorization: OAuth realm="Example", + oauth_consumer_key="9djdj82h48djs9d2", + oauth_token="kkk9d7dh3k39sjv7", + oauth_signature_method="HMAC-SHA1", + oauth_timestamp="137131201", + oauth_nonce="7d8f3e4a", + oauth_signature="djosJKDKJSD8743243%2Fjdk33klY%3D" + + c2&a3=2+q + + contains the following (fully decoded) parameters used in the + signature base sting:: + + +------------------------+------------------+ + | Name | Value | + +------------------------+------------------+ + | b5 | =%3D | + | a3 | a | + | c@ | | + | a2 | r b | + | oauth_consumer_key | 9djdj82h48djs9d2 | + | oauth_token | kkk9d7dh3k39sjv7 | + | oauth_signature_method | HMAC-SHA1 | + | oauth_timestamp | 137131201 | + | oauth_nonce | 7d8f3e4a | + | c2 | | + | a3 | 2 q | + +------------------------+------------------+ + + Note that the value of "b5" is "=%3D" and not "==". Both "c@" and + "c2" have empty values. While the encoding rules specified in this + specification for the purpose of constructing the signature base + string exclude the use of a "+" character (ASCII code 43) to + represent an encoded space character (ASCII code 32), this practice + is widely used in "application/x-www-form-urlencoded" encoded values, + and MUST be properly decoded, as demonstrated by one of the "a3" + parameter instances (the "a3" parameter is used twice in this + request). + + .. _`section 3.4.1.3.1`: http://tools.ietf.org/html/rfc5849#section-3.4.1.3.1 + """ + headers = headers or {} + params = [] + + # The parameters from the following sources are collected into a single + # list of name/value pairs: + + # * The query component of the HTTP request URI as defined by + # `RFC3986, Section 3.4`_. The query component is parsed into a list + # of name/value pairs by treating it as an + # "application/x-www-form-urlencoded" string, separating the names + # and values and decoding them as defined by + # `W3C.REC-html40-19980424`_, Section 17.13.4. + # + # .. _`RFC3986, Section 3.4`: http://tools.ietf.org/html/rfc3986#section-3.4 + # .. _`W3C.REC-html40-19980424`: http://tools.ietf.org/html/rfc5849#ref-W3C.REC-html40-19980424 + if uri_query: + params.extend(urlparse.parse_qsl(uri_query, keep_blank_values=True)) + + # * The OAuth HTTP "Authorization" header field (`Section 3.5.1`_) if + # present. The header's content is parsed into a list of name/value + # pairs excluding the "realm" parameter if present. The parameter + # values are decoded as defined by `Section 3.5.1`_. + # + # .. _`Section 3.5.1`: http://tools.ietf.org/html/rfc5849#section-3.5.1 + if headers: + headers_lower = dict((k.lower(), v) for k, v in headers.items()) + authorization_header = headers_lower.get(u'authorization') + if authorization_header is not None: + params.extend([i for i in utils.parse_authorization_header( + authorization_header) if i[0] != u'realm']) + + # * The HTTP request entity-body, but only if all of the following + # conditions are met: + # * The entity-body is single-part. + # + # * The entity-body follows the encoding requirements of the + # "application/x-www-form-urlencoded" content-type as defined by + # `W3C.REC-html40-19980424`_. + + # * The HTTP request entity-header includes the "Content-Type" + # header field set to "application/x-www-form-urlencoded". + # + # .._`W3C.REC-html40-19980424`: http://tools.ietf.org/html/rfc5849#ref-W3C.REC-html40-19980424 + + # TODO: enforce header param inclusion conditions + bodyparams = extract_params(body) or [] + params.extend(bodyparams) + + # ensure all oauth params are unescaped + unescaped_params = [] + for k, v in params: + if k.startswith(u'oauth_'): + v = utils.unescape(v) + unescaped_params.append((k, v)) + + # The "oauth_signature" parameter MUST be excluded from the signature + # base string if present. + if exclude_oauth_signature: + unescaped_params = filter(lambda i: i[0] != u'oauth_signature', + unescaped_params) + + return unescaped_params + + +def normalize_parameters(params): + """**Parameters Normalization** + Per `section 3.4.1.3.2`_ of the spec. + + For example, the list of parameters from the previous section would + be normalized as follows: + + Encoded:: + + +------------------------+------------------+ + | Name | Value | + +------------------------+------------------+ + | b5 | %3D%253D | + | a3 | a | + | c%40 | | + | a2 | r%20b | + | oauth_consumer_key | 9djdj82h48djs9d2 | + | oauth_token | kkk9d7dh3k39sjv7 | + | oauth_signature_method | HMAC-SHA1 | + | oauth_timestamp | 137131201 | + | oauth_nonce | 7d8f3e4a | + | c2 | | + | a3 | 2%20q | + +------------------------+------------------+ + + Sorted:: + + +------------------------+------------------+ + | Name | Value | + +------------------------+------------------+ + | a2 | r%20b | + | a3 | 2%20q | + | a3 | a | + | b5 | %3D%253D | + | c%40 | | + | c2 | | + | oauth_consumer_key | 9djdj82h48djs9d2 | + | oauth_nonce | 7d8f3e4a | + | oauth_signature_method | HMAC-SHA1 | + | oauth_timestamp | 137131201 | + | oauth_token | kkk9d7dh3k39sjv7 | + +------------------------+------------------+ + + Concatenated Pairs:: + + +-------------------------------------+ + | Name=Value | + +-------------------------------------+ + | a2=r%20b | + | a3=2%20q | + | a3=a | + | b5=%3D%253D | + | c%40= | + | c2= | + | oauth_consumer_key=9djdj82h48djs9d2 | + | oauth_nonce=7d8f3e4a | + | oauth_signature_method=HMAC-SHA1 | + | oauth_timestamp=137131201 | + | oauth_token=kkk9d7dh3k39sjv7 | + +-------------------------------------+ + + and concatenated together into a single string (line breaks are for + display purposes only):: + + a2=r%20b&a3=2%20q&a3=a&b5=%3D%253D&c%40=&c2=&oauth_consumer_key=9dj + dj82h48djs9d2&oauth_nonce=7d8f3e4a&oauth_signature_method=HMAC-SHA1 + &oauth_timestamp=137131201&oauth_token=kkk9d7dh3k39sjv7 + + .. _`section 3.4.1.3.2`: http://tools.ietf.org/html/rfc5849#section-3.4.1.3.2 + """ + + # The parameters collected in `Section 3.4.1.3`_ are normalized into a + # single string as follows: + # + # .. _`Section 3.4.1.3`: http://tools.ietf.org/html/rfc5849#section-3.4.1.3 + + # 1. First, the name and value of each parameter are encoded + # (`Section 3.6`_). + # + # .. _`Section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6 + key_values = [(utils.escape(k), utils.escape(v)) for k, v in params] + + # 2. The parameters are sorted by name, using ascending byte value + # ordering. If two or more parameters share the same name, they + # are sorted by their value. + key_values.sort() + + # 3. The name of each parameter is concatenated to its corresponding + # value using an "=" character (ASCII code 61) as a separator, even + # if the value is empty. + parameter_parts = [u'{0}={1}'.format(k, v) for k, v in key_values] + + # 4. The sorted name/value pairs are concatenated together into a + # single string by using an "&" character (ASCII code 38) as + # separator. + return u'&'.join(parameter_parts) + + +def sign_hmac_sha1(base_string, client_secret, resource_owner_secret): + """**HMAC-SHA1** + + The "HMAC-SHA1" signature method uses the HMAC-SHA1 signature + algorithm as defined in `RFC2104`_:: + + digest = HMAC-SHA1 (key, text) + + Per `section 3.4.2`_ of the spec. + + .. _`RFC2104`: http://tools.ietf.org/html/rfc2104 + .. _`section 3.4.2`: http://tools.ietf.org/html/rfc5849#section-3.4.2 + """ + + # The HMAC-SHA1 function variables are used in following way: + + # text is set to the value of the signature base string from + # `Section 3.4.1.1`_. + # + # .. _`Section 3.4.1.1`: http://tools.ietf.org/html/rfc5849#section-3.4.1.1 + text = base_string + + # key is set to the concatenated values of: + # 1. The client shared-secret, after being encoded (`Section 3.6`_). + # + # .. _`Section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6 + key = utils.escape(client_secret or u'') + + # 2. An "&" character (ASCII code 38), which MUST be included + # even when either secret is empty. + key += u'&' + + # 3. The token shared-secret, after being encoded (`Section 3.6`_). + # + # .. _`Section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6 + key += utils.escape(resource_owner_secret or u'') + + # FIXME: HMAC does not support unicode! + key_utf8 = key.encode('utf-8') + text_utf8 = text.encode('utf-8') + signature = hmac.new(key_utf8, text_utf8, hashlib.sha1) + + # digest is used to set the value of the "oauth_signature" protocol + # parameter, after the result octet string is base64-encoded + # per `RFC2045, Section 6.8`. + # + # .. _`RFC2045, Section 6.8`: http://tools.ietf.org/html/rfc2045#section-6.8 + return binascii.b2a_base64(signature.digest())[:-1].decode('utf-8') + + +def sign_rsa_sha1(base_string, rsa_private_key): + """**RSA-SHA1** + + Per `section 3.4.3`_ of the spec. + + The "RSA-SHA1" signature method uses the RSASSA-PKCS1-v1_5 signature + algorithm as defined in `RFC3447, Section 8.2`_ (also known as + PKCS#1), using SHA-1 as the hash function for EMSA-PKCS1-v1_5. To + use this method, the client MUST have established client credentials + with the server that included its RSA public key (in a manner that is + beyond the scope of this specification). + + NOTE: this method requires the python-rsa library. + + .. _`section 3.4.3`: http://tools.ietf.org/html/rfc5849#section-3.4.3 + .. _`RFC3447, Section 8.2`: http://tools.ietf.org/html/rfc3447#section-8.2 + + """ + # TODO: finish RSA documentation + from Crypto.PublicKey import RSA + from Crypto.Signature import PKCS1_v1_5 + from Crypto.Hash import SHA + key = RSA.importKey(rsa_private_key) + h = SHA.new(base_string) + p = PKCS1_v1_5.new(key) + return binascii.b2a_base64(p.sign(h))[:-1].decode('utf-8') + + +def sign_plaintext(client_secret, resource_owner_secret): + """Sign a request using plaintext. + + Per `section 3.4.4`_ of the spec. + + The "PLAINTEXT" method does not employ a signature algorithm. It + MUST be used with a transport-layer mechanism such as TLS or SSL (or + sent over a secure channel with equivalent protections). It does not + utilize the signature base string or the "oauth_timestamp" and + "oauth_nonce" parameters. + + .. _`section 3.4.4`: http://tools.ietf.org/html/rfc5849#section-3.4.4 + + """ + + # The "oauth_signature" protocol parameter is set to the concatenated + # value of: + + # 1. The client shared-secret, after being encoded (`Section 3.6`_). + # + # .. _`Section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6 + signature = utils.escape(client_secret or u'') + + # 2. An "&" character (ASCII code 38), which MUST be included even + # when either secret is empty. + signature += u'&' + + # 3. The token shared-secret, after being encoded (`Section 3.6`_). + # + # .. _`Section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6 + signature += utils.escape(resource_owner_secret or u'') + + return signature + + +def verify_hmac_sha1(request, client_secret=None, + resource_owner_secret=None): + """Verify a HMAC-SHA1 signature. + + Per `section 3.4`_ of the spec. + + .. _`section 3.4`: http://tools.ietf.org/html/rfc5849#section-3.4 + """ + norm_params = normalize_parameters(request.params) + uri = normalize_base_string_uri(request.uri) + base_string = construct_base_string(request.http_method, uri, norm_params) + signature = sign_hmac_sha1(base_string, client_secret, + resource_owner_secret) + return safe_string_equals(signature, request.signature) + + +def verify_rsa_sha1(request, rsa_public_key): + """Verify a RSASSA-PKCS #1 v1.5 base64 encoded signature. + + Per `section 3.4.3`_ of the spec. + + Note this method requires the PyCrypto library. + + .. _`section 3.4.3`: http://tools.ietf.org/html/rfc5849#section-3.4.3 + + """ + from Crypto.PublicKey import RSA + from Crypto.Signature import PKCS1_v1_5 + from Crypto.Hash import SHA + key = RSA.importKey(rsa_public_key) + norm_params = normalize_parameters(request.params) + uri = normalize_base_string_uri(request.uri) + message = construct_base_string(request.http_method, uri, norm_params) + h = SHA.new(message) + p = PKCS1_v1_5.new(key) + sig = binascii.a2b_base64(request.signature) + return p.verify(h, sig) + + +def verify_plaintext(request, client_secret=None, resource_owner_secret=None): + """Verify a PLAINTEXT signature. + + Per `section 3.4`_ of the spec. + + .. _`section 3.4`: http://tools.ietf.org/html/rfc5849#section-3.4 + """ + signature = sign_plaintext(client_secret, resource_owner_secret) + return safe_string_equals(signature, request.signature) diff --git a/libs/requests/packages/oauthlib/oauth1/rfc5849/utils.py b/libs/requests/packages/oauthlib/oauth1/rfc5849/utils.py new file mode 100644 index 00000000..8fb0e77c --- /dev/null +++ b/libs/requests/packages/oauthlib/oauth1/rfc5849/utils.py @@ -0,0 +1,99 @@ +# -*- coding: utf-8 -*- + +""" +oauthlib.utils +~~~~~~~~~~~~~~ + +This module contains utility methods used by various parts of the OAuth +spec. +""" + +import string +import urllib2 + +from oauthlib.common import quote, unquote + +UNICODE_ASCII_CHARACTER_SET = (string.ascii_letters.decode('ascii') + + string.digits.decode('ascii')) + + +def filter_params(target): + """Decorator which filters params to remove non-oauth_* parameters + + Assumes the decorated method takes a params dict or list of tuples as its + first argument. + """ + def wrapper(params, *args, **kwargs): + params = filter_oauth_params(params) + return target(params, *args, **kwargs) + + wrapper.__doc__ = target.__doc__ + return wrapper + + +def filter_oauth_params(params): + """Removes all non oauth parameters from a dict or a list of params.""" + is_oauth = lambda kv: kv[0].startswith(u"oauth_") + if isinstance(params, dict): + return filter(is_oauth, params.items()) + else: + return filter(is_oauth, params) + + +def escape(u): + """Escape a unicode string in an OAuth-compatible fashion. + + Per `section 3.6`_ of the spec. + + .. _`section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6 + + """ + if not isinstance(u, unicode): + raise ValueError('Only unicode objects are escapable.') + # Letters, digits, and the characters '_.-' are already treated as safe + # by urllib.quote(). We need to add '~' to fully support rfc5849. + return quote(u, safe='~') + + +def unescape(u): + if not isinstance(u, unicode): + raise ValueError('Only unicode objects are unescapable.') + return unquote(u) + + +def urlencode(query): + """Encode a sequence of two-element tuples or dictionary into a URL query string. + + Operates using an OAuth-safe escape() method, in contrast to urllib.urlencode. + """ + # Convert dictionaries to list of tuples + if isinstance(query, dict): + query = query.items() + return u"&".join([u'='.join([escape(k), escape(v)]) for k, v in query]) + + +def parse_keqv_list(l): + """A unicode-safe version of urllib2.parse_keqv_list""" + encoded_list = [u.encode('utf-8') for u in l] + encoded_parsed = urllib2.parse_keqv_list(encoded_list) + return dict((k.decode('utf-8'), + v.decode('utf-8')) for k, v in encoded_parsed.items()) + + +def parse_http_list(u): + """A unicode-safe version of urllib2.parse_http_list""" + encoded_str = u.encode('utf-8') + encoded_list = urllib2.parse_http_list(encoded_str) + return [s.decode('utf-8') for s in encoded_list] + + +def parse_authorization_header(authorization_header): + """Parse an OAuth authorization header into a list of 2-tuples""" + auth_scheme = u'OAuth ' + if authorization_header.startswith(auth_scheme): + authorization_header = authorization_header.replace(auth_scheme, u'', 1) + items = parse_http_list(authorization_header) + try: + return parse_keqv_list(items).items() + except ValueError: + raise ValueError('Malformed authorization header') diff --git a/libs/requests/packages/oauthlib/oauth2/__init__.py b/libs/requests/packages/oauthlib/oauth2/__init__.py new file mode 100644 index 00000000..0e8933cf --- /dev/null +++ b/libs/requests/packages/oauthlib/oauth2/__init__.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +""" +oauthlib.oauth2 +~~~~~~~~~~~~~~ + +This module is a wrapper for the most recent implementation of OAuth 2.0 Client +and Server classes. +""" + +from .draft25 import Client, Server + diff --git a/libs/requests/packages/oauthlib/oauth2/draft25/__init__.py b/libs/requests/packages/oauthlib/oauth2/draft25/__init__.py new file mode 100644 index 00000000..7c905734 --- /dev/null +++ b/libs/requests/packages/oauthlib/oauth2/draft25/__init__.py @@ -0,0 +1,497 @@ +""" +oauthlib.oauth2.draft_25 +~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for signing and checking OAuth 2.0 draft 25 requests. +""" +from tokens import prepare_bearer_uri, prepare_bearer_headers +from tokens import prepare_bearer_body, prepare_mac_header +from parameters import prepare_grant_uri, prepare_token_request +from parameters import parse_authorization_code_response +from parameters import parse_implicit_response, parse_token_response + + +AUTH_HEADER = u'auth_header' +URI_QUERY = u'query' +BODY = u'body' + + +class Client(object): + + def __init__(self, client_id, + default_redirect_uri=None, + token_type=None, + access_token=None, + refresh_token=None): + """Initialize a client with commonly used attributes.""" + + self.client_id = client_id + self.default_redirect_uri = default_redirect_uri + self.token_type = token_type + self.access_token = access_token + self.refresh_token = refresh_token + self.token_types = { + u'bearer': self._add_bearer_token, + u'mac': self._add_mac_token + } + + def add_token(self, uri, http_method=u'GET', body=None, headers=None, + token_placement=AUTH_HEADER): + """Add token to the request uri, body or authorization header. + + The access token type provides the client with the information + required to successfully utilize the access token to make a protected + resource request (along with type-specific attributes). The client + MUST NOT use an access token if it does not understand the token + type. + + For example, the "bearer" token type defined in + [I-D.ietf-oauth-v2-bearer] is utilized by simply including the access + token string in the request: + + GET /resource/1 HTTP/1.1 + Host: example.com + Authorization: Bearer mF_9.B5f-4.1JqM + + while the "mac" token type defined in [I-D.ietf-oauth-v2-http-mac] is + utilized by issuing a MAC key together with the access token which is + used to sign certain components of the HTTP requests: + + GET /resource/1 HTTP/1.1 + Host: example.com + Authorization: MAC id="h480djs93hd8", + nonce="274312:dj83hs9s", + mac="kDZvddkndxvhGRXZhvuDjEWhGeE=" + + .. _`I-D.ietf-oauth-v2-bearer`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#ref-I-D.ietf-oauth-v2-bearer + .. _`I-D.ietf-oauth-v2-http-mac`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#ref-I-D.ietf-oauth-v2-http-mac + """ + return self.token_types[self.token_type](uri, http_method, body, + headers, token_placement) + + def prepare_refresh_body(self, body=u'', refresh_token=None, scope=None): + """Prepare an access token request, using a refresh token. + + If the authorization server issued a refresh token to the client, the + client makes a refresh request to the token endpoint by adding the + following parameters using the "application/x-www-form-urlencoded" + format in the HTTP request entity-body: + + grant_type + REQUIRED. Value MUST be set to "refresh_token". + refresh_token + REQUIRED. The refresh token issued to the client. + scope + OPTIONAL. The scope of the access request as described by + Section 3.3. The requested scope MUST NOT include any scope + not originally granted by the resource owner, and if omitted is + treated as equal to the scope originally granted by the + resource owner. + """ + refresh_token = refresh_token or self.refresh_token + return prepare_token_request(u'refresh_token', body=body, scope=scope, + refresh_token=refresh_token) + + def _add_bearer_token(self, uri, http_method=u'GET', body=None, + headers=None, token_placement=AUTH_HEADER): + """Add a bearer token to the request uri, body or authorization header.""" + if token_placement == AUTH_HEADER: + headers = prepare_bearer_headers(self.token, headers) + + if token_placement == URI_QUERY: + uri = prepare_bearer_uri(self.token, uri) + + if token_placement == BODY: + body = prepare_bearer_body(self.token, body) + + return uri, headers, body + + def _add_mac_token(self, uri, http_method=u'GET', body=None, + headers=None, token_placement=AUTH_HEADER): + """Add a MAC token to the request authorization header.""" + headers = prepare_mac_header(self.token, uri, self.key, http_method, + headers=headers, body=body, ext=self.ext, + hash_algorithm=self.hash_algorithm) + return uri, headers, body + + def _populate_attributes(self, response): + """Add commonly used values such as access_token to self.""" + + if u'access_token' in response: + self.access_token = response.get(u'access_token') + + if u'refresh_token' in response: + self.refresh_token = response.get(u'refresh_token') + + if u'token_type' in response: + self.token_type = response.get(u'token_type') + + if u'expires_in' in response: + self.expires_in = response.get(u'expires_in') + + if u'code' in response: + self.code = response.get(u'code') + + def prepare_request_uri(self, *args, **kwargs): + """Abstract method used to create request URIs.""" + raise NotImplementedError("Must be implemented by inheriting classes.") + + def prepare_request_body(self, *args, **kwargs): + """Abstract method used to create request bodies.""" + raise NotImplementedError("Must be implemented by inheriting classes.") + + def parse_request_uri_response(self, *args, **kwargs): + """Abstract method used to parse redirection responses.""" + + def parse_request_body_response(self, *args, **kwargs): + """Abstract method used to parse JSON responses.""" + + +class WebApplicationClient(Client): + """A client utilizing the authorization code grant workflow. + + A web application is a confidential client running on a web + server. Resource owners access the client via an HTML user + interface rendered in a user-agent on the device used by the + resource owner. The client credentials as well as any access + token issued to the client are stored on the web server and are + not exposed to or accessible by the resource owner. + + The authorization code grant type is used to obtain both access + tokens and refresh tokens and is optimized for confidential clients. + As a redirection-based flow, the client must be capable of + interacting with the resource owner's user-agent (typically a web + browser) and capable of receiving incoming requests (via redirection) + from the authorization server. + """ + + def prepare_request_uri(self, uri, redirect_uri=None, scope=None, + state=None, **kwargs): + """Prepare the authorization code request URI + + The client constructs the request URI by adding the following + parameters to the query component of the authorization endpoint URI + using the "application/x-www-form-urlencoded" format as defined by + [`W3C.REC-html401-19991224`_]: + + response_type + REQUIRED. Value MUST be set to "code". + client_id + REQUIRED. The client identifier as described in `Section 2.2`_. + redirect_uri + OPTIONAL. As described in `Section 3.1.2`_. + scope + OPTIONAL. The scope of the access request as described by + `Section 3.3`_. + state + RECOMMENDED. An opaque value used by the client to maintain + state between the request and callback. The authorization + server includes this value when redirecting the user-agent back + to the client. The parameter SHOULD be used for preventing + cross-site request forgery as described in `Section 10.12`_. + + .. _`W3C.REC-html401-19991224`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#ref-W3C.REC-html401-19991224 + .. _`Section 2.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-2.2 + .. _`Section 3.1.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.1.2 + .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3 + .. _`Section 10.12`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-10.12 + """ + redirect_uri = redirect_uri or self.default_redirect_uri + return prepare_grant_uri(uri, self.client_id, u'code', + redirect_uri=redirect_uri, scope=scope, state=state, **kwargs) + + def prepare_request_body(self, code, body=u'', redirect_uri=None, **kwargs): + """Prepare the access token request body. + + The client makes a request to the token endpoint by adding the + following parameters using the "application/x-www-form-urlencoded" + format in the HTTP request entity-body: + + grant_type + REQUIRED. Value MUST be set to "authorization_code". + code + REQUIRED. The authorization code received from the + authorization server. + redirect_uri + REQUIRED, if the "redirect_uri" parameter was included in the + authorization request as described in Section 4.1.1, and their + values MUST be identical. + + .. _`Section 4.1.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-4.1.1 + """ + redirect_uri = redirect_uri or self.default_redirect_uri + code = code or self.code + return prepare_token_request(u'authorization_code', code=code, body=body, + redirect_uri=redirect_uri, **kwargs) + + def parse_request_uri_response(self, uri, state=None): + """Parse the URI query for code and state. + + If the resource owner grants the access request, the authorization + server issues an authorization code and delivers it to the client by + adding the following parameters to the query component of the + redirection URI using the "application/x-www-form-urlencoded" format: + + code + REQUIRED. The authorization code generated by the + authorization server. The authorization code MUST expire + shortly after it is issued to mitigate the risk of leaks. A + maximum authorization code lifetime of 10 minutes is + RECOMMENDED. The client MUST NOT use the authorization code + more than once. If an authorization code is used more than + once, the authorization server MUST deny the request and SHOULD + revoke (when possible) all tokens previously issued based on + that authorization code. The authorization code is bound to + the client identifier and redirection URI. + state + REQUIRED if the "state" parameter was present in the client + authorization request. The exact value received from the + client. + """ + response = parse_authorization_code_response(uri, state=state) + self._populate_attributes(response) + return response + + def parse_request_body_response(self, body, scope=None): + """Parse the JSON response body. + + If the access token request is valid and authorized, the + authorization server issues an access token and optional refresh + token as described in `Section 5.1`_. If the request client + authentication failed or is invalid, the authorization server returns + an error response as described in `Section 5.2`_. + + .. `Section 5.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.1 + .. `Section 5.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.2 + """ + response = parse_token_response(body, scope=scope) + self._populate_attributes(response) + return response + + +class UserAgentClient(Client): + """A public client utilizing the implicit code grant workflow. + + A user-agent-based application is a public client in which the + client code is downloaded from a web server and executes within a + user-agent (e.g. web browser) on the device used by the resource + owner. Protocol data and credentials are easily accessible (and + often visible) to the resource owner. Since such applications + reside within the user-agent, they can make seamless use of the + user-agent capabilities when requesting authorization. + + The implicit grant type is used to obtain access tokens (it does not + support the issuance of refresh tokens) and is optimized for public + clients known to operate a particular redirection URI. These clients + are typically implemented in a browser using a scripting language + such as JavaScript. + + As a redirection-based flow, the client must be capable of + interacting with the resource owner's user-agent (typically a web + browser) and capable of receiving incoming requests (via redirection) + from the authorization server. + + Unlike the authorization code grant type in which the client makes + separate requests for authorization and access token, the client + receives the access token as the result of the authorization request. + + The implicit grant type does not include client authentication, and + relies on the presence of the resource owner and the registration of + the redirection URI. Because the access token is encoded into the + redirection URI, it may be exposed to the resource owner and other + applications residing on the same device. + """ + + def prepare_request_uri(self, uri, redirect_uri=None, scope=None, + state=None, **kwargs): + """Prepare the implicit grant request URI. + + The client constructs the request URI by adding the following + parameters to the query component of the authorization endpoint URI + using the "application/x-www-form-urlencoded" format: + + response_type + REQUIRED. Value MUST be set to "token". + client_id + REQUIRED. The client identifier as described in Section 2.2. + redirect_uri + OPTIONAL. As described in Section 3.1.2. + scope + OPTIONAL. The scope of the access request as described by + Section 3.3. + state + RECOMMENDED. An opaque value used by the client to maintain + state between the request and callback. The authorization + server includes this value when redirecting the user-agent back + to the client. The parameter SHOULD be used for preventing + cross-site request forgery as described in Section 10.12. + """ + redirect_uri = redirect_uri or self.default_redirect_uri + return prepare_grant_uri(uri, self.client_id, u'token', + redirect_uri=redirect_uri, state=state, scope=scope, **kwargs) + + def parse_request_uri_response(self, uri, state=None, scope=None): + """Parse the response URI fragment. + + If the resource owner grants the access request, the authorization + server issues an access token and delivers it to the client by adding + the following parameters to the fragment component of the redirection + URI using the "application/x-www-form-urlencoded" format: + + access_token + REQUIRED. The access token issued by the authorization server. + token_type + REQUIRED. The type of the token issued as described in + `Section 7.1`_. Value is case insensitive. + expires_in + RECOMMENDED. The lifetime in seconds of the access token. For + example, the value "3600" denotes that the access token will + expire in one hour from the time the response was generated. + If omitted, the authorization server SHOULD provide the + expiration time via other means or document the default value. + scope + OPTIONAL, if identical to the scope requested by the client, + otherwise REQUIRED. The scope of the access token as described + by `Section 3.3`_. + state + REQUIRED if the "state" parameter was present in the client + authorization request. The exact value received from the + client. + + .. _`Section 7.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-7.1 + .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3 + """ + response = parse_implicit_response(uri, state=state, scope=scope) + self._populate_attributes(response) + return response + + +class NativeApplicationClient(Client): + """A public client utilizing the client credentials grant workflow. + + A native application is a public client installed and executed on + the device used by the resource owner. Protocol data and + credentials are accessible to the resource owner. It is assumed + that any client authentication credentials included in the + application can be extracted. On the other hand, dynamically + issued credentials such as access tokens or refresh tokens can + receive an acceptable level of protection. At a minimum, these + credentials are protected from hostile servers with which the + application may interact with. On some platforms these + credentials might be protected from other applications residing on + the same device. + + The client can request an access token using only its client + credentials (or other supported means of authentication) when the + client is requesting access to the protected resources under its + control, or those of another resource owner which has been previously + arranged with the authorization server (the method of which is beyond + the scope of this specification). + + The client credentials grant type MUST only be used by confidential + clients. + + Since the client authentication is used as the authorization grant, + no additional authorization request is needed. + """ + + def prepare_request_body(self, body=u'', scope=None, **kwargs): + """Add the client credentials to the request body. + + The client makes a request to the token endpoint by adding the + following parameters using the "application/x-www-form-urlencoded" + format in the HTTP request entity-body: + + grant_type + REQUIRED. Value MUST be set to "client_credentials". + scope + OPTIONAL. The scope of the access request as described by + `Section 3.3`_. + + .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3 + """ + return prepare_token_request(u'client_credentials', body=body, + scope=scope, **kwargs) + + def parse_request_body_response(self, body, scope=None): + """Parse the JSON response body. + + If the access token request is valid and authorized, the + authorization server issues an access token as described in + `Section 5.1`_. A refresh token SHOULD NOT be included. If the request + failed client authentication or is invalid, the authorization server + returns an error response as described in `Section 5.2`_. + + .. `Section 5.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.1 + .. `Section 5.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.2 + """ + response = parse_token_response(body, scope=scope) + self._populate_attributes(response) + return response + + +class PasswordCredentialsClient(Client): + """A public client using the resource owner password and username directly. + + The resource owner password credentials grant type is suitable in + cases where the resource owner has a trust relationship with the + client, such as the device operating system or a highly privileged + application. The authorization server should take special care when + enabling this grant type, and only allow it when other flows are not + viable. + + The grant type is suitable for clients capable of obtaining the + resource owner's credentials (username and password, typically using + an interactive form). It is also used to migrate existing clients + using direct authentication schemes such as HTTP Basic or Digest + authentication to OAuth by converting the stored credentials to an + access token. + + The method through which the client obtains the resource owner + credentials is beyond the scope of this specification. The client + MUST discard the credentials once an access token has been obtained. + """ + + def prepare_request_body(self, username, password, body=u'', scope=None, + **kwargs): + """Add the resource owner password and username to the request body. + + The client makes a request to the token endpoint by adding the + following parameters using the "application/x-www-form-urlencoded" + format in the HTTP request entity-body: + + grant_type + REQUIRED. Value MUST be set to "password". + username + REQUIRED. The resource owner username. + password + REQUIRED. The resource owner password. + scope + OPTIONAL. The scope of the access request as described by + `Section 3.3`_. + + .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3 + """ + return prepare_token_request(u'password', body=body, username=username, + password=password, scope=scope, **kwargs) + + def parse_request_body_response(self, body, scope=None): + """Parse the JSON response body. + + If the access token request is valid and authorized, the + authorization server issues an access token and optional refresh + token as described in `Section 5.1`_. If the request failed client + authentication or is invalid, the authorization server returns an + error response as described in `Section 5.2`_. + + .. `Section 5.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.1 + .. `Section 5.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.2 + """ + response = parse_token_response(body, scope=scope) + self._populate_attributes(response) + return response + + +class Server(object): + pass diff --git a/libs/requests/packages/oauthlib/oauth2/draft25/parameters.py b/libs/requests/packages/oauthlib/oauth2/draft25/parameters.py new file mode 100644 index 00000000..ecc9f63a --- /dev/null +++ b/libs/requests/packages/oauthlib/oauth2/draft25/parameters.py @@ -0,0 +1,256 @@ +""" +oauthlib.oauth2_draft28.parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This module contains methods related to `Section 4`_ of the OAuth 2 draft. + +.. _`Section 4`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-4 +""" + +import json +import urlparse +from oauthlib.common import add_params_to_uri, add_params_to_qs + + +def prepare_grant_uri(uri, client_id, response_type, redirect_uri=None, + scope=None, state=None, **kwargs): + """Prepare the authorization grant request URI. + + The client constructs the request URI by adding the following + parameters to the query component of the authorization endpoint URI + using the "application/x-www-form-urlencoded" format as defined by + [W3C.REC-html401-19991224]: + + response_type + REQUIRED. Value MUST be set to "code". + client_id + REQUIRED. The client identifier as described in `Section 2.2`_. + redirect_uri + OPTIONAL. As described in `Section 3.1.2`_. + scope + OPTIONAL. The scope of the access request as described by + `Section 3.3`_. + state + RECOMMENDED. An opaque value used by the client to maintain + state between the request and callback. The authorization + server includes this value when redirecting the user-agent back + to the client. The parameter SHOULD be used for preventing + cross-site request forgery as described in `Section 10.12`_. + + GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz + &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1 + Host: server.example.com + + .. _`W3C.REC-html401-19991224`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#ref-W3C.REC-html401-19991224 + .. _`Section 2.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-2.2 + .. _`Section 3.1.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.1.2 + .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3 + .. _`section 10.12`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-10.12 + """ + params = [((u'response_type', response_type)), + ((u'client_id', client_id))] + + if redirect_uri: + params.append((u'redirect_uri', redirect_uri)) + if scope: + params.append((u'scope', scope)) + if state: + params.append((u'state', state)) + + for k in kwargs: + params.append((unicode(k), kwargs[k])) + + return add_params_to_uri(uri, params) + + +def prepare_token_request(grant_type, body=u'', **kwargs): + """Prepare the access token request. + + The client makes a request to the token endpoint by adding the + following parameters using the "application/x-www-form-urlencoded" + format in the HTTP request entity-body: + + grant_type + REQUIRED. Value MUST be set to "authorization_code". + code + REQUIRED. The authorization code received from the + authorization server. + redirect_uri + REQUIRED, if the "redirect_uri" parameter was included in the + authorization request as described in `Section 4.1.1`_, and their + values MUST be identical. + + grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA + &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb + + .. _`Section 4.1.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-4.1.1 + """ + params = [(u'grant_type', grant_type)] + for k in kwargs: + params.append((unicode(k), kwargs[k])) + + return add_params_to_qs(body, params) + + +def parse_authorization_code_response(uri, state=None): + """Parse authorization grant response URI into a dict. + + If the resource owner grants the access request, the authorization + server issues an authorization code and delivers it to the client by + adding the following parameters to the query component of the + redirection URI using the "application/x-www-form-urlencoded" format: + + code + REQUIRED. The authorization code generated by the + authorization server. The authorization code MUST expire + shortly after it is issued to mitigate the risk of leaks. A + maximum authorization code lifetime of 10 minutes is + RECOMMENDED. The client MUST NOT use the authorization code + more than once. If an authorization code is used more than + once, the authorization server MUST deny the request and SHOULD + revoke (when possible) all tokens previously issued based on + that authorization code. The authorization code is bound to + the client identifier and redirection URI. + state + REQUIRED if the "state" parameter was present in the client + authorization request. The exact value received from the + client. + + For example, the authorization server redirects the user-agent by + sending the following HTTP response: + + HTTP/1.1 302 Found + Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA + &state=xyz + + """ + query = urlparse.urlparse(uri).query + params = dict(urlparse.parse_qsl(query)) + + if not u'code' in params: + raise KeyError("Missing code parameter in response.") + + if state and params.get(u'state', None) != state: + raise ValueError("Mismatching or missing state in response.") + + return params + + +def parse_implicit_response(uri, state=None, scope=None): + """Parse the implicit token response URI into a dict. + + If the resource owner grants the access request, the authorization + server issues an access token and delivers it to the client by adding + the following parameters to the fragment component of the redirection + URI using the "application/x-www-form-urlencoded" format: + + access_token + REQUIRED. The access token issued by the authorization server. + token_type + REQUIRED. The type of the token issued as described in + Section 7.1. Value is case insensitive. + expires_in + RECOMMENDED. The lifetime in seconds of the access token. For + example, the value "3600" denotes that the access token will + expire in one hour from the time the response was generated. + If omitted, the authorization server SHOULD provide the + expiration time via other means or document the default value. + scope + OPTIONAL, if identical to the scope requested by the client, + otherwise REQUIRED. The scope of the access token as described + by Section 3.3. + state + REQUIRED if the "state" parameter was present in the client + authorization request. The exact value received from the + client. + + HTTP/1.1 302 Found + Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA + &state=xyz&token_type=example&expires_in=3600 + """ + fragment = urlparse.urlparse(uri).fragment + params = dict(urlparse.parse_qsl(fragment, keep_blank_values=True)) + validate_token_parameters(params, scope) + + if state and params.get(u'state', None) != state: + raise ValueError("Mismatching or missing state in params.") + + return params + + +def parse_token_response(body, scope=None): + """Parse the JSON token response body into a dict. + + The authorization server issues an access token and optional refresh + token, and constructs the response by adding the following parameters + to the entity body of the HTTP response with a 200 (OK) status code: + + access_token + REQUIRED. The access token issued by the authorization server. + token_type + REQUIRED. The type of the token issued as described in + `Section 7.1`_. Value is case insensitive. + expires_in + RECOMMENDED. The lifetime in seconds of the access token. For + example, the value "3600" denotes that the access token will + expire in one hour from the time the response was generated. + If omitted, the authorization server SHOULD provide the + expiration time via other means or document the default value. + refresh_token + OPTIONAL. The refresh token which can be used to obtain new + access tokens using the same authorization grant as described + in `Section 6`_. + scope + OPTIONAL, if identical to the scope requested by the client, + otherwise REQUIRED. The scope of the access token as described + by `Section 3.3`_. + + The parameters are included in the entity body of the HTTP response + using the "application/json" media type as defined by [`RFC4627`_]. The + parameters are serialized into a JSON structure by adding each + parameter at the highest structure level. Parameter names and string + values are included as JSON strings. Numerical values are included + as JSON numbers. The order of parameters does not matter and can + vary. + + For example: + + HTTP/1.1 200 OK + Content-Type: application/json;charset=UTF-8 + Cache-Control: no-store + Pragma: no-cache + + { + "access_token":"2YotnFZFEjr1zCsicMWpAA", + "token_type":"example", + "expires_in":3600, + "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", + "example_parameter":"example_value" + } + + .. _`Section 7.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-7.1 + .. _`Section 6`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-6 + .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3 + .. _`RFC4627`: http://tools.ietf.org/html/rfc4627 + """ + params = json.loads(body) + validate_token_parameters(params, scope) + return params + + +def validate_token_parameters(params, scope=None): + """Ensures token precence, token type, expiration and scope in params.""" + + if not u'access_token' in params: + raise KeyError("Missing access token parameter.") + + if not u'token_type' in params: + raise KeyError("Missing token type parameter.") + + # If the issued access token scope is different from the one requested by + # the client, the authorization server MUST include the "scope" response + # parameter to inform the client of the actual scope granted. + # http://tools.ietf.org/html/draft-ietf-oauth-v2-25#section-3.3 + new_scope = params.get(u'scope', None) + if scope and new_scope and scope != new_scope: + raise Warning("Scope has changed to %s." % new_scope) diff --git a/libs/requests/packages/oauthlib/oauth2/draft25/tokens.py b/libs/requests/packages/oauthlib/oauth2/draft25/tokens.py new file mode 100644 index 00000000..74491fb9 --- /dev/null +++ b/libs/requests/packages/oauthlib/oauth2/draft25/tokens.py @@ -0,0 +1,132 @@ +from __future__ import absolute_import +""" +oauthlib.oauth2.draft25.tokens +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This module contains methods for adding two types of access tokens to requests. + +- Bearer http://tools.ietf.org/html/draft-ietf-oauth-saml2-bearer-08 +- MAC http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-00 + +""" +from binascii import b2a_base64 +import hashlib +import hmac +from urlparse import urlparse + +from oauthlib.common import add_params_to_uri, add_params_to_qs +from . import utils + + +def prepare_mac_header(token, uri, key, http_method, nonce=None, headers=None, + body=None, ext=u'', hash_algorithm=u'hmac-sha-1'): + """Add an `MAC Access Authentication`_ signature to headers. + + Unlike OAuth 1, this HMAC signature does not require inclusion of the request + payload/body, neither does it use a combination of client_secret and + token_secret but rather a mac_key provided together with the access token. + + Currently two algorithms are supported, "hmac-sha-1" and "hmac-sha-256", + `extension algorithms`_ are not supported. + + Example MAC Authorization header, linebreaks added for clarity + + Authorization: MAC id="h480djs93hd8", + nonce="1336363200:dj83hs9s", + mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM=" + + .. _`MAC Access Authentication`: http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01 + .. _`extension algorithms`: http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-7.1 + + :param uri: Request URI. + :param headers: Request headers as a dictionary. + :param http_method: HTTP Request method. + :param key: MAC given provided by token endpoint. + :param algorithm: HMAC algorithm provided by token endpoint. + :return: headers dictionary with the authorization field added. + """ + http_method = http_method.upper() + host, port = utils.host_from_uri(uri) + + if hash_algorithm.lower() == u'hmac-sha-1': + h = hashlib.sha1 + else: + h = hashlib.sha256 + + nonce = nonce or u'{0}:{1}'.format(utils.generate_nonce(), utils.generate_timestamp()) + sch, net, path, par, query, fra = urlparse(uri) + + if query: + request_uri = path + u'?' + query + else: + request_uri = path + + # Hash the body/payload + if body is not None: + bodyhash = b2a_base64(h(body).digest())[:-1].decode('utf-8') + else: + bodyhash = u'' + + # Create the normalized base string + base = [] + base.append(nonce) + base.append(http_method.upper()) + base.append(request_uri) + base.append(host) + base.append(port) + base.append(bodyhash) + base.append(ext) + base_string = '\n'.join(base) + u'\n' + + # hmac struggles with unicode strings - http://bugs.python.org/issue5285 + if isinstance(key, unicode): + key = key.encode('utf-8') + sign = hmac.new(key, base_string, h) + sign = b2a_base64(sign.digest())[:-1].decode('utf-8') + + header = [] + header.append(u'MAC id="%s"' % token) + header.append(u'nonce="%s"' % nonce) + if bodyhash: + header.append(u'bodyhash="%s"' % bodyhash) + if ext: + header.append(u'ext="%s"' % ext) + header.append(u'mac="%s"' % sign) + + headers = headers or {} + headers[u'Authorization'] = u', '.join(header) + return headers + + +def prepare_bearer_uri(token, uri): + """Add a `Bearer Token`_ to the request URI. + Not recommended, use only if client can't use authorization header or body. + + http://www.example.com/path?access_token=h480djs93hd8 + + .. _`Bearer Token`: http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-18 + """ + return add_params_to_uri(uri, [((u'access_token', token))]) + + +def prepare_bearer_headers(token, headers=None): + """Add a `Bearer Token`_ to the request URI. + Recommended method of passing bearer tokens. + + Authorization: Bearer h480djs93hd8 + + .. _`Bearer Token`: http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-18 + """ + headers = headers or {} + headers[u'Authorization'] = u'Bearer %s' % token + return headers + + +def prepare_bearer_body(token, body=u''): + """Add a `Bearer Token`_ to the request body. + + access_token=h480djs93hd8 + + .. _`Bearer Token`: http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-18 + """ + return add_params_to_qs(body, [((u'access_token', token))]) diff --git a/libs/requests/packages/oauthlib/oauth2/draft25/utils.py b/libs/requests/packages/oauthlib/oauth2/draft25/utils.py new file mode 100644 index 00000000..75d5fcc6 --- /dev/null +++ b/libs/requests/packages/oauthlib/oauth2/draft25/utils.py @@ -0,0 +1,39 @@ +""" +oauthlib.utils +~~~~~~~~~~~~~~ + +This module contains utility methods used by various parts of the OAuth 2 spec. +""" + +import urllib +import urlparse + + +def host_from_uri(uri): + """Extract hostname and port from URI. + + Will use default port for HTTP and HTTPS if none is present in the URI. + """ + default_ports = { + u'HTTP': u'80', + u'HTTPS': u'443', + } + + sch, netloc, path, par, query, fra = urlparse.urlparse(uri) + if u':' in netloc: + netloc, port = netloc.split(u':', 1) + else: + port = default_ports.get(sch.upper()) + + return netloc, port + + +def escape(u): + """Escape a string in an OAuth-compatible fashion. + + TODO: verify whether this can in fact be used for OAuth 2 + + """ + if not isinstance(u, unicode): + raise ValueError('Only unicode objects are escapable.') + return urllib.quote(u.encode('utf-8'), safe='~') diff --git a/libs/requests/packages/urllib3/__init__.py b/libs/requests/packages/urllib3/__init__.py index 81e76f50..55de87e4 100644 --- a/libs/requests/packages/urllib3/__init__.py +++ b/libs/requests/packages/urllib3/__init__.py @@ -28,7 +28,7 @@ from .util import make_headers, get_host # Set default logging handler to avoid "No handler found" warnings. import logging -try: +try: # Python 2.7+ from logging import NullHandler except ImportError: class NullHandler(logging.Handler): @@ -37,6 +37,22 @@ except ImportError: logging.getLogger(__name__).addHandler(NullHandler()) +def add_stderr_logger(level=logging.DEBUG): + """ + Helper for quickly adding a StreamHandler to the logger. Useful for + debugging. + + Returns the handler after adding it. + """ + # This method needs to be in this __init__.py to get the __name__ correct + # even if urllib3 is vendored within another package. + logger = logging.getLogger(__name__) + handler = logging.StreamHandler() + handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s')) + logger.addHandler(handler) + logger.setLevel(level) + logger.debug('Added an stderr logging handler to logger: %s' % __name__) + return handler + # ... Clean up. -del logging del NullHandler diff --git a/libs/requests/packages/urllib3/_collections.py b/libs/requests/packages/urllib3/_collections.py index 3cef081e..a052b1da 100644 --- a/libs/requests/packages/urllib3/_collections.py +++ b/libs/requests/packages/urllib3/_collections.py @@ -4,128 +4,91 @@ # This module is part of urllib3 and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php -from collections import deque +from collections import MutableMapping +from threading import Lock + +try: # Python 2.7+ + from collections import OrderedDict +except ImportError: + from .packages.ordered_dict import OrderedDict -from threading import RLock __all__ = ['RecentlyUsedContainer'] -class AccessEntry(object): - __slots__ = ('key', 'is_valid') - - def __init__(self, key, is_valid=True): - self.key = key - self.is_valid = is_valid +_Null = object() -class RecentlyUsedContainer(dict): +class RecentlyUsedContainer(MutableMapping): """ - Provides a dict-like that maintains up to ``maxsize`` keys while throwing - away the least-recently-used keys beyond ``maxsize``. + Provides a thread-safe dict-like container which maintains up to + ``maxsize`` keys while throwing away the least-recently-used keys beyond + ``maxsize``. + + :param maxsize: + Maximum number of recent elements to retain. + + :param dispose_func: + Every time an item is evicted from the container, + ``dispose_func(value)`` is called. Callback which will get called """ - # If len(self.access_log) exceeds self._maxsize * CLEANUP_FACTOR, then we - # will attempt to cleanup the invalidated entries in the access_log - # datastructure during the next 'get' operation. - CLEANUP_FACTOR = 10 + ContainerCls = OrderedDict - def __init__(self, maxsize=10): + def __init__(self, maxsize=10, dispose_func=None): self._maxsize = maxsize + self.dispose_func = dispose_func - self._container = {} - - # We use a deque to to store our keys ordered by the last access. - self.access_log = deque() - self.access_log_lock = RLock() - - # We look up the access log entry by the key to invalidate it so we can - # insert a new authorative entry at the head without having to dig and - # find the old entry for removal immediately. - self.access_lookup = {} - - # Trigger a heap cleanup when we get past this size - self.access_log_limit = maxsize * self.CLEANUP_FACTOR - - def _invalidate_entry(self, key): - "If exists: Invalidate old entry and return it." - old_entry = self.access_lookup.get(key) - if old_entry: - old_entry.is_valid = False - - return old_entry - - def _push_entry(self, key): - "Push entry onto our access log, invalidate the old entry if exists." - self._invalidate_entry(key) - - new_entry = AccessEntry(key) - self.access_lookup[key] = new_entry - - self.access_log_lock.acquire() - self.access_log.appendleft(new_entry) - self.access_log_lock.release() - - def _prune_entries(self, num): - "Pop entries from our access log until we popped ``num`` valid ones." - while num > 0: - self.access_log_lock.acquire() - p = self.access_log.pop() - self.access_log_lock.release() - - if not p.is_valid: - continue # Invalidated entry, skip - - dict.pop(self, p.key, None) - self.access_lookup.pop(p.key, None) - num -= 1 - - def _prune_invalidated_entries(self): - "Rebuild our access_log without the invalidated entries." - self.access_log_lock.acquire() - self.access_log = deque(e for e in self.access_log if e.is_valid) - self.access_log_lock.release() - - def _get_ordered_access_keys(self): - "Return ordered access keys for inspection. Used for testing." - self.access_log_lock.acquire() - r = [e.key for e in self.access_log if e.is_valid] - self.access_log_lock.release() - - return r + self._container = self.ContainerCls() + self._lock = Lock() def __getitem__(self, key): - item = dict.get(self, key) + # Re-insert the item, moving it to the end of the eviction line. + with self._lock: + item = self._container.pop(key) + self._container[key] = item + return item - if not item: - raise KeyError(key) + def __setitem__(self, key, value): + evicted_value = _Null + with self._lock: + # Possibly evict the existing value of 'key' + evicted_value = self._container.get(key, _Null) + self._container[key] = value - # Insert new entry with new high priority, also implicitly invalidates - # the old entry. - self._push_entry(key) + # If we didn't evict an existing value, we might have to evict the + # least recently used item from the beginning of the container. + if len(self._container) > self._maxsize: + _key, evicted_value = self._container.popitem(last=False) - if len(self.access_log) > self.access_log_limit: - # Heap is getting too big, try to clean up any tailing invalidated - # entries. - self._prune_invalidated_entries() - - return item - - def __setitem__(self, key, item): - # Add item to our container and access log - dict.__setitem__(self, key, item) - self._push_entry(key) - - # Discard invalid and excess entries - self._prune_entries(len(self) - self._maxsize) + if self.dispose_func and evicted_value is not _Null: + self.dispose_func(evicted_value) def __delitem__(self, key): - self._invalidate_entry(key) - self.access_lookup.pop(key, None) - dict.__delitem__(self, key) + with self._lock: + value = self._container.pop(key) - def get(self, key, default=None): - try: - return self[key] - except KeyError: - return default + if self.dispose_func: + self.dispose_func(value) + + def __len__(self): + with self._lock: + return len(self._container) + + def __iter__(self): + raise NotImplementedError('Iteration over this class is unlikely to be threadsafe.') + + def clear(self): + with self._lock: + # Copy pointers to all values, then wipe the mapping + # under Python 2, this copies the list of values twice :-| + values = list(self._container.values()) + self._container.clear() + + if self.dispose_func: + for value in values: + self.dispose_func(value) + + def keys(self): + with self._lock: + return self._container.keys() diff --git a/libs/requests/packages/urllib3/connectionpool.py b/libs/requests/packages/urllib3/connectionpool.py index 336aa773..97da5446 100644 --- a/libs/requests/packages/urllib3/connectionpool.py +++ b/libs/requests/packages/urllib3/connectionpool.py @@ -7,27 +7,27 @@ import logging import socket -from socket import error as SocketError, timeout as SocketTimeout +from socket import timeout as SocketTimeout -try: # Python 3 +try: # Python 3 from http.client import HTTPConnection, HTTPException from http.client import HTTP_PORT, HTTPS_PORT except ImportError: from httplib import HTTPConnection, HTTPException from httplib import HTTP_PORT, HTTPS_PORT -try: # Python 3 +try: # Python 3 from queue import LifoQueue, Empty, Full except ImportError: from Queue import LifoQueue, Empty, Full -try: # Compiled with SSL? +try: # Compiled with SSL? HTTPSConnection = object BaseSSLError = None ssl = None - try: # Python 3 + try: # Python 3 from http.client import HTTPSConnection except ImportError: from httplib import HTTPSConnection @@ -35,7 +35,7 @@ try: # Compiled with SSL? import ssl BaseSSLError = ssl.SSLError -except (ImportError, AttributeError): +except (ImportError, AttributeError): # Platform-specific: No SSL. pass @@ -43,6 +43,7 @@ from .request import RequestMethods from .response import HTTPResponse from .util import get_host, is_connection_dropped from .exceptions import ( + ClosedPoolError, EmptyPoolError, HostChangedError, MaxRetryError, @@ -206,10 +207,8 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods): try: conn = self.pool.get(block=self.block, timeout=timeout) - # If this is a persistent connection, check if it got disconnected - if conn and is_connection_dropped(conn): - log.info("Resetting dropped connection: %s" % self.host) - conn.close() + except AttributeError: # self.pool is None + raise ClosedPoolError(self, "Pool is closed.") except Empty: if self.block: @@ -218,6 +217,11 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods): "connections are allowed.") pass # Oh well, we'll create a new connection then + # If this is a persistent connection, check if it got disconnected + if conn and is_connection_dropped(conn): + log.info("Resetting dropped connection: %s" % self.host) + conn.close() + return conn or self._new_conn() def _put_conn(self, conn): @@ -228,17 +232,26 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods): Connection object for the current host and port as returned by :meth:`._new_conn` or :meth:`._get_conn`. - If the pool is already full, the connection is discarded because we - exceeded maxsize. If connections are discarded frequently, then maxsize - should be increased. + If the pool is already full, the connection is closed and discarded + because we exceeded maxsize. If connections are discarded frequently, + then maxsize should be increased. + + If the pool is closed, then the connection will be closed and discarded. """ try: self.pool.put(conn, block=False) + return # Everything is dandy, done. + except AttributeError: + # self.pool is None. + pass except Full: # This should never happen if self.block == True log.warning("HttpConnectionPool is full, discarding connection: %s" % self.host) + # Connection never got put back into the pool, close it. + conn.close() + def _make_request(self, conn, method, url, timeout=_Default, **httplib_request_kw): """ @@ -258,22 +271,42 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods): if sock: sock.settimeout(timeout) - httplib_response = conn.getresponse() + try: # Python 2.7+, use buffering of HTTP responses + httplib_response = conn.getresponse(buffering=True) + except TypeError: # Python 2.6 and older + httplib_response = conn.getresponse() # AppEngine doesn't have a version attr. - http_version = getattr(conn, '_http_vsn_str', 'HTTP/?'), + http_version = getattr(conn, '_http_vsn_str', 'HTTP/?') log.debug("\"%s %s %s\" %s %s" % (method, url, http_version, httplib_response.status, httplib_response.length)) - return httplib_response + def close(self): + """ + Close all pooled connections and disable the pool. + """ + # Disable access to the pool + old_pool, self.pool = self.pool, None + + try: + while True: + conn = old_pool.get(block=False) + if conn: + conn.close() + + except Empty: + pass # Done. def is_same_host(self, url): """ Check if the given ``url`` is a member of the same host as this connection pool. """ + if url.startswith('/'): + return True + # TODO: Add optional support for socket.gethostbyname checking. scheme, host, port = get_host(url) @@ -281,8 +314,7 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods): # Use explicit default port for comparison when none is given. port = port_by_scheme.get(scheme) - return (url.startswith('/') or - (scheme, host, port) == (self.scheme, self.host, self.port)) + return (scheme, host, port) == (self.scheme, self.host, self.port) def urlopen(self, method, url, body=None, headers=None, retries=3, redirect=True, assert_same_host=True, timeout=_Default, @@ -321,8 +353,8 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods): Number of retries to allow before raising a MaxRetryError exception. :param redirect: - Automatically handle redirects (status codes 301, 302, 303, 307), - each redirect counts as a retry. + If True, automatically handle redirects (status codes 301, 302, + 303, 307). Each redirect counts as a retry. :param assert_same_host: If ``True``, will make sure that the host of the pool requests is @@ -375,7 +407,6 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods): try: # Request a connection from the queue - # (Could raise SocketError: Bad file descriptor) conn = self._get_conn(timeout=pool_timeout) # Make the request on the httplib connection object @@ -418,29 +449,38 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods): # Name mismatch raise SSLError(e) - except (HTTPException, SocketError) as e: + except HTTPException as e: # Connection broken, discard. It will be replaced next _get_conn(). conn = None # This is necessary so we can access e below err = e finally: - if conn and release_conn: - # Put the connection back to be reused + if release_conn: + # Put the connection back to be reused. If the connection is + # expired then it will be None, which will get replaced with a + # fresh connection during _get_conn. self._put_conn(conn) if not conn: + # Try again log.warn("Retrying (%d attempts remain) after connection " "broken by '%r': %s" % (retries, err, url)) return self.urlopen(method, url, body, headers, retries - 1, - redirect, assert_same_host) # Try again + redirect, assert_same_host, + timeout=timeout, pool_timeout=pool_timeout, + release_conn=release_conn, **response_kw) # Handle redirect? redirect_location = redirect and response.get_redirect_location() if redirect_location: + if response.status == 303: + method = 'GET' log.info("Redirecting %s -> %s" % (url, redirect_location)) return self.urlopen(method, redirect_location, body, headers, - retries - 1, redirect, assert_same_host) + retries - 1, redirect, assert_same_host, + timeout=timeout, pool_timeout=pool_timeout, + release_conn=release_conn, **response_kw) return response diff --git a/libs/requests/packages/urllib3/exceptions.py b/libs/requests/packages/urllib3/exceptions.py index 15c9699e..99ebb67e 100644 --- a/libs/requests/packages/urllib3/exceptions.py +++ b/libs/requests/packages/urllib3/exceptions.py @@ -24,6 +24,11 @@ class SSLError(HTTPError): pass +class DecodeError(HTTPError): + "Raised when automatic decoding based on Content-Type fails." + pass + + ## Leaf Exceptions class MaxRetryError(PoolError): @@ -57,6 +62,11 @@ class EmptyPoolError(PoolError): pass +class ClosedPoolError(PoolError): + "Raised when a request enters a pool after the pool has been closed." + pass + + class LocationParseError(ValueError, HTTPError): "Raised when get_host or similar fails to parse the URL input." diff --git a/libs/requests/packages/urllib3/filepost.py b/libs/requests/packages/urllib3/filepost.py index 344a1030..e679b939 100644 --- a/libs/requests/packages/urllib3/filepost.py +++ b/libs/requests/packages/urllib3/filepost.py @@ -7,11 +7,7 @@ import codecs import mimetypes -try: - from mimetools import choose_boundary -except ImportError: - from .packages.mimetools_choose_boundary import choose_boundary - +from uuid import uuid4 from io import BytesIO from .packages import six @@ -20,6 +16,13 @@ from .packages.six import b writer = codecs.lookup('utf-8')[3] +def choose_boundary(): + """ + Our embarassingly-simple replacement for mimetools.choose_boundary. + """ + return uuid4().hex + + def get_content_type(filename): return mimetypes.guess_type(filename)[0] or 'application/octet-stream' diff --git a/libs/requests/packages/urllib3/packages/mimetools_choose_boundary/__init__.py b/libs/requests/packages/urllib3/packages/mimetools_choose_boundary/__init__.py deleted file mode 100644 index a0109abf..00000000 --- a/libs/requests/packages/urllib3/packages/mimetools_choose_boundary/__init__.py +++ /dev/null @@ -1,47 +0,0 @@ -"""The function mimetools.choose_boundary() from Python 2.7, which seems to -have disappeared in Python 3 (although email.generator._make_boundary() might -work as a replacement?). - -Tweaked to use lock from threading rather than thread. -""" -import os -from threading import Lock -_counter_lock = Lock() - -_counter = 0 -def _get_next_counter(): - global _counter - with _counter_lock: - _counter += 1 - return _counter - -_prefix = None - -def choose_boundary(): - """Return a string usable as a multipart boundary. - - The string chosen is unique within a single program run, and - incorporates the user id (if available), process id (if available), - and current time. So it's very unlikely the returned string appears - in message text, but there's no guarantee. - - The boundary contains dots so you have to quote it in the header.""" - - global _prefix - import time - if _prefix is None: - import socket - try: - hostid = socket.gethostbyname(socket.gethostname()) - except socket.gaierror: - hostid = '127.0.0.1' - try: - uid = repr(os.getuid()) - except AttributeError: - uid = '1' - try: - pid = repr(os.getpid()) - except AttributeError: - pid = '1' - _prefix = hostid + '.' + uid + '.' + pid - return "%s.%.3f.%d" % (_prefix, time.time(), _get_next_counter()) diff --git a/libs/requests/packages/urllib3/packages/ordered_dict.py b/libs/requests/packages/urllib3/packages/ordered_dict.py new file mode 100644 index 00000000..7f8ee154 --- /dev/null +++ b/libs/requests/packages/urllib3/packages/ordered_dict.py @@ -0,0 +1,260 @@ +# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. +# Passes Python2.7's test suite and incorporates all the latest updates. +# Copyright 2009 Raymond Hettinger, released under the MIT License. +# http://code.activestate.com/recipes/576693/ + +try: + from thread import get_ident as _get_ident +except ImportError: + from dummy_thread import get_ident as _get_ident + +try: + from _abcoll import KeysView, ValuesView, ItemsView +except ImportError: + pass + + +class OrderedDict(dict): + 'Dictionary that remembers insertion order' + # An inherited dict maps keys to values. + # The inherited dict provides __getitem__, __len__, __contains__, and get. + # The remaining methods are order-aware. + # Big-O running times for all methods are the same as for regular dictionaries. + + # The internal self.__map dictionary maps keys to links in a doubly linked list. + # The circular doubly linked list starts and ends with a sentinel element. + # The sentinel element never gets deleted (this simplifies the algorithm). + # Each link is stored as a list of length three: [PREV, NEXT, KEY]. + + def __init__(self, *args, **kwds): + '''Initialize an ordered dictionary. Signature is the same as for + regular dictionaries, but keyword arguments are not recommended + because their insertion order is arbitrary. + + ''' + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__root + except AttributeError: + self.__root = root = [] # sentinel node + root[:] = [root, root, None] + self.__map = {} + self.__update(*args, **kwds) + + def __setitem__(self, key, value, dict_setitem=dict.__setitem__): + 'od.__setitem__(i, y) <==> od[i]=y' + # Setting a new item creates a new link which goes at the end of the linked + # list, and the inherited dictionary is updated with the new key/value pair. + if key not in self: + root = self.__root + last = root[0] + last[1] = root[0] = self.__map[key] = [last, root, key] + dict_setitem(self, key, value) + + def __delitem__(self, key, dict_delitem=dict.__delitem__): + 'od.__delitem__(y) <==> del od[y]' + # Deleting an existing item uses self.__map to find the link which is + # then removed by updating the links in the predecessor and successor nodes. + dict_delitem(self, key) + link_prev, link_next, key = self.__map.pop(key) + link_prev[1] = link_next + link_next[0] = link_prev + + def __iter__(self): + 'od.__iter__() <==> iter(od)' + root = self.__root + curr = root[1] + while curr is not root: + yield curr[2] + curr = curr[1] + + def __reversed__(self): + 'od.__reversed__() <==> reversed(od)' + root = self.__root + curr = root[0] + while curr is not root: + yield curr[2] + curr = curr[0] + + def clear(self): + 'od.clear() -> None. Remove all items from od.' + try: + for node in self.__map.itervalues(): + del node[:] + root = self.__root + root[:] = [root, root, None] + self.__map.clear() + except AttributeError: + pass + dict.clear(self) + + def popitem(self, last=True): + '''od.popitem() -> (k, v), return and remove a (key, value) pair. + Pairs are returned in LIFO order if last is true or FIFO order if false. + + ''' + if not self: + raise KeyError('dictionary is empty') + root = self.__root + if last: + link = root[0] + link_prev = link[0] + link_prev[1] = root + root[0] = link_prev + else: + link = root[1] + link_next = link[1] + root[1] = link_next + link_next[0] = root + key = link[2] + del self.__map[key] + value = dict.pop(self, key) + return key, value + + # -- the following methods do not depend on the internal structure -- + + def keys(self): + 'od.keys() -> list of keys in od' + return list(self) + + def values(self): + 'od.values() -> list of values in od' + return [self[key] for key in self] + + def items(self): + 'od.items() -> list of (key, value) pairs in od' + return [(key, self[key]) for key in self] + + def iterkeys(self): + 'od.iterkeys() -> an iterator over the keys in od' + return iter(self) + + def itervalues(self): + 'od.itervalues -> an iterator over the values in od' + for k in self: + yield self[k] + + def iteritems(self): + 'od.iteritems -> an iterator over the (key, value) items in od' + for k in self: + yield (k, self[k]) + + def update(*args, **kwds): + '''od.update(E, **F) -> None. Update od from dict/iterable E and F. + + If E is a dict instance, does: for k in E: od[k] = E[k] + If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] + Or if E is an iterable of items, does: for k, v in E: od[k] = v + In either case, this is followed by: for k, v in F.items(): od[k] = v + + ''' + if len(args) > 2: + raise TypeError('update() takes at most 2 positional ' + 'arguments (%d given)' % (len(args),)) + elif not args: + raise TypeError('update() takes at least 1 argument (0 given)') + self = args[0] + # Make progressively weaker assumptions about "other" + other = () + if len(args) == 2: + other = args[1] + if isinstance(other, dict): + for key in other: + self[key] = other[key] + elif hasattr(other, 'keys'): + for key in other.keys(): + self[key] = other[key] + else: + for key, value in other: + self[key] = value + for key, value in kwds.items(): + self[key] = value + + __update = update # let subclasses override update without breaking __init__ + + __marker = object() + + def pop(self, key, default=__marker): + '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. + If key is not found, d is returned if given, otherwise KeyError is raised. + + ''' + if key in self: + result = self[key] + del self[key] + return result + if default is self.__marker: + raise KeyError(key) + return default + + def setdefault(self, key, default=None): + 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' + if key in self: + return self[key] + self[key] = default + return default + + def __repr__(self, _repr_running={}): + 'od.__repr__() <==> repr(od)' + call_key = id(self), _get_ident() + if call_key in _repr_running: + return '...' + _repr_running[call_key] = 1 + try: + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + finally: + del _repr_running[call_key] + + def __reduce__(self): + 'Return state information for pickling' + items = [[k, self[k]] for k in self] + inst_dict = vars(self).copy() + for k in vars(OrderedDict()): + inst_dict.pop(k, None) + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + + def copy(self): + 'od.copy() -> a shallow copy of od' + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S + and values equal to v (which defaults to None). + + ''' + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive + while comparison to a regular mapping is order-insensitive. + + ''' + if isinstance(other, OrderedDict): + return len(self)==len(other) and self.items() == other.items() + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other + + # -- the following methods are only used in Python 2.7 -- + + def viewkeys(self): + "od.viewkeys() -> a set-like object providing a view on od's keys" + return KeysView(self) + + def viewvalues(self): + "od.viewvalues() -> an object providing a view on od's values" + return ValuesView(self) + + def viewitems(self): + "od.viewitems() -> a set-like object providing a view on od's items" + return ItemsView(self) diff --git a/libs/requests/packages/urllib3/poolmanager.py b/libs/requests/packages/urllib3/poolmanager.py index 310ea21d..8f5b54c1 100644 --- a/libs/requests/packages/urllib3/poolmanager.py +++ b/libs/requests/packages/urllib3/poolmanager.py @@ -8,9 +8,9 @@ import logging from ._collections import RecentlyUsedContainer from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool -from .connectionpool import get_host, connection_from_url, port_by_scheme -from .exceptions import HostChangedError +from .connectionpool import connection_from_url, port_by_scheme from .request import RequestMethods +from .util import parse_url __all__ = ['PoolManager', 'ProxyManager', 'proxy_from_url'] @@ -48,19 +48,29 @@ class PoolManager(RequestMethods): """ - # TODO: Make sure there are no memory leaks here. - def __init__(self, num_pools=10, **connection_pool_kw): self.connection_pool_kw = connection_pool_kw - self.pools = RecentlyUsedContainer(num_pools) + self.pools = RecentlyUsedContainer(num_pools, + dispose_func=lambda p: p.close()) - def connection_from_host(self, host, port=80, scheme='http'): + def clear(self): + """ + Empty our store of pools and direct them all to close. + + This will not affect in-flight connections, but they will not be + re-used after completion. + """ + self.pools.clear() + + def connection_from_host(self, host, port=None, scheme='http'): """ Get a :class:`ConnectionPool` based on the host, port, and scheme. - Note that an appropriate ``port`` value is required here to normalize - connection pools in our container most effectively. + If ``port`` isn't given, it will be derived from the ``scheme`` using + ``urllib3.connectionpool.port_by_scheme``. """ + port = port or port_by_scheme.get(scheme, 80) + pool_key = (scheme, host, port) # If the scheme, host, or port doesn't match existing open connections, @@ -86,26 +96,36 @@ class PoolManager(RequestMethods): Additional parameters are taken from the :class:`.PoolManager` constructor. """ - scheme, host, port = get_host(url) + u = parse_url(url) + return self.connection_from_host(u.host, port=u.port, scheme=u.scheme) - port = port or port_by_scheme.get(scheme, 80) - - return self.connection_from_host(host, port=port, scheme=scheme) - - def urlopen(self, method, url, **kw): + def urlopen(self, method, url, redirect=True, **kw): """ - Same as :meth:`urllib3.connectionpool.HTTPConnectionPool.urlopen`. + Same as :meth:`urllib3.connectionpool.HTTPConnectionPool.urlopen` + with custom cross-host redirect logic and only sends the request-uri + portion of the ``url``. - ``url`` must be absolute, such that an appropriate + The given ``url`` parameter must be absolute, such that an appropriate :class:`urllib3.connectionpool.ConnectionPool` can be chosen for it. """ - conn = self.connection_from_url(url) - try: - return conn.urlopen(method, url, **kw) + u = parse_url(url) + conn = self.connection_from_host(u.host, port=u.port, scheme=u.scheme) - except HostChangedError as e: - kw['retries'] = e.retries # Persist retries countdown - return self.urlopen(method, e.url, **kw) + kw['assert_same_host'] = False + kw['redirect'] = False + + response = conn.urlopen(method, u.request_uri, **kw) + + redirect_location = redirect and response.get_redirect_location() + if not redirect_location: + return response + + if response.status == 303: + method = 'GET' + + log.info("Redirecting %s -> %s" % (url, redirect_location)) + kw['retries'] = kw.get('retries', 3) - 1 # Persist retries countdown + return self.urlopen(method, redirect_location, **kw) class ProxyManager(RequestMethods): diff --git a/libs/requests/packages/urllib3/response.py b/libs/requests/packages/urllib3/response.py index 5fab8243..28537d3b 100644 --- a/libs/requests/packages/urllib3/response.py +++ b/libs/requests/packages/urllib3/response.py @@ -10,7 +10,7 @@ import zlib from io import BytesIO -from .exceptions import HTTPError +from .exceptions import DecodeError from .packages.six import string_types as basestring @@ -148,9 +148,9 @@ class HTTPResponse(object): try: if decode_content and decoder: data = decoder(data) - except IOError: - raise HTTPError("Received response with content-encoding: %s, but " - "failed to decode it." % content_encoding) + except (IOError, zlib.error): + raise DecodeError("Received response with content-encoding: %s, but " + "failed to decode it." % content_encoding) if cache_content: self._body = data diff --git a/libs/requests/packages/urllib3/util.py b/libs/requests/packages/urllib3/util.py index 2684a2fd..8ec990bc 100644 --- a/libs/requests/packages/urllib3/util.py +++ b/libs/requests/packages/urllib3/util.py @@ -6,6 +6,8 @@ from base64 import b64encode +from collections import namedtuple +from socket import error as SocketError try: from select import poll, POLLIN @@ -20,6 +22,152 @@ from .packages import six from .exceptions import LocationParseError +class Url(namedtuple('Url', ['scheme', 'auth', 'host', 'port', 'path', 'query', 'fragment'])): + """ + Datastructure for representing an HTTP URL. Used as a return value for + :func:`parse_url`. + """ + slots = () + + def __new__(cls, scheme=None, auth=None, host=None, port=None, path=None, query=None, fragment=None): + return super(Url, cls).__new__(cls, scheme, auth, host, port, path, query, fragment) + + @property + def hostname(self): + """For backwards-compatibility with urlparse. We're nice like that.""" + return self.host + + @property + def request_uri(self): + """Absolute path including the query string.""" + uri = self.path or '/' + + if self.query is not None: + uri += '?' + self.query + + return uri + + +def split_first(s, delims): + """ + Given a string and an iterable of delimiters, split on the first found + delimiter. Return two split parts and the matched delimiter. + + If not found, then the first part is the full input string. + + Example: :: + + >>> split_first('foo/bar?baz', '?/=') + ('foo', 'bar?baz', '/') + >>> split_first('foo/bar?baz', '123') + ('foo/bar?baz', '', None) + + Scales linearly with number of delims. Not ideal for large number of delims. + """ + min_idx = None + min_delim = None + for d in delims: + idx = s.find(d) + if idx < 0: + continue + + if min_idx is None or idx < min_idx: + min_idx = idx + min_delim = d + + if min_idx is None or min_idx < 0: + return s, '', None + + return s[:min_idx], s[min_idx+1:], min_delim + + +def parse_url(url): + """ + Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is + performed to parse incomplete urls. Fields not provided will be None. + + Partly backwards-compatible with :mod:`urlparse`. + + Example: :: + + >>> parse_url('http://google.com/mail/') + Url(scheme='http', host='google.com', port=None, path='/', ...) + >>> prase_url('google.com:80') + Url(scheme=None, host='google.com', port=80, path=None, ...) + >>> prase_url('/foo?bar') + Url(scheme=None, host=None, port=None, path='/foo', query='bar', ...) + """ + + # While this code has overlap with stdlib's urlparse, it is much + # simplified for our needs and less annoying. + # Additionally, this imeplementations does silly things to be optimal + # on CPython. + + scheme = None + auth = None + host = None + port = None + path = None + fragment = None + query = None + + # Scheme + if '://' in url: + scheme, url = url.split('://', 1) + + # Find the earliest Authority Terminator + # (http://tools.ietf.org/html/rfc3986#section-3.2) + url, path_, delim = split_first(url, ['/', '?', '#']) + + if delim: + # Reassemble the path + path = delim + path_ + + # Auth + if '@' in url: + auth, url = url.split('@', 1) + + # IPv6 + if url and url[0] == '[': + host, url = url[1:].split(']', 1) + + # Port + if ':' in url: + _host, port = url.split(':', 1) + + if not host: + host = _host + + if not port.isdigit(): + raise LocationParseError("Failed to parse: %s" % url) + + port = int(port) + + elif not host and url: + host = url + + if not path: + return Url(scheme, auth, host, port, path, query, fragment) + + # Fragment + if '#' in path: + path, fragment = path.split('#', 1) + + # Query + if '?' in path: + path, query = path.split('?', 1) + + return Url(scheme, auth, host, port, path, query, fragment) + + +def get_host(url): + """ + Deprecated. Use :func:`.parse_url` instead. + """ + p = parse_url(url) + return p.scheme or 'http', p.hostname, p.port + + def make_headers(keep_alive=None, accept_encoding=None, user_agent=None, basic_auth=None): """ @@ -72,60 +220,28 @@ def make_headers(keep_alive=None, accept_encoding=None, user_agent=None, return headers -def get_host(url): - """ - Given a url, return its scheme, host and port (None if it's not there). - - For example: :: - - >>> get_host('http://google.com/mail/') - ('http', 'google.com', None) - >>> get_host('google.com:80') - ('http', 'google.com', 80) - """ - - # This code is actually similar to urlparse.urlsplit, but much - # simplified for our needs. - port = None - scheme = 'http' - - if '://' in url: - scheme, url = url.split('://', 1) - if '/' in url: - url, _path = url.split('/', 1) - if '@' in url: - _auth, url = url.split('@', 1) - if ':' in url: - url, port = url.split(':', 1) - - if not port.isdigit(): - raise LocationParseError("Failed to parse: %s" % url) - - port = int(port) - - return scheme, url, port - - - def is_connection_dropped(conn): """ Returns True if the connection is dropped and should be closed. :param conn: - ``HTTPConnection`` object. + :class:`httplib.HTTPConnection` object. Note: For platforms like AppEngine, this will always return ``False`` to let the platform handle connection recycling transparently for us. """ sock = getattr(conn, 'sock', False) - if not sock: #Platform-specific: AppEngine + if not sock: # Platform-specific: AppEngine return False if not poll: # Platform-specific - if not select: #Platform-specific: AppEngine + if not select: # Platform-specific: AppEngine return False - return select([sock], [], [], 0.0)[0] + try: + return select([sock], [], [], 0.0)[0] + except SocketError: + return True # This version is better on platforms that support it. p = poll() diff --git a/libs/requests/safe_mode.py b/libs/requests/safe_mode.py index 619d368c..0fb8d705 100644 --- a/libs/requests/safe_mode.py +++ b/libs/requests/safe_mode.py @@ -16,23 +16,25 @@ from .packages.urllib3.response import HTTPResponse from .exceptions import RequestException, ConnectionError, HTTPError import socket + def catch_exceptions_if_in_safe_mode(function): """New implementation of safe_mode. We catch all exceptions at the API level and then return a blank Response object with the error field filled. This decorator wraps request() in api.py. """ - + def wrapped(method, url, **kwargs): # if save_mode, we catch exceptions and fill error field - if (kwargs.get('config') and kwargs.get('config').get('safe_mode')) or (kwargs.get('session') + if (kwargs.get('config') and kwargs.get('config').get('safe_mode')) or (kwargs.get('session') and kwargs.get('session').config.get('safe_mode')): try: return function(method, url, **kwargs) - except (RequestException, ConnectionError, HTTPError, socket.timeout) as e: + except (RequestException, ConnectionError, HTTPError, + socket.timeout, socket.gaierror) as e: r = Response() r.error = e - r.raw = HTTPResponse() # otherwise, tests fail - r.status_code = 0 # with this status_code, content returns None + r.raw = HTTPResponse() # otherwise, tests fail + r.status_code = 0 # with this status_code, content returns None return r return function(method, url, **kwargs) return wrapped diff --git a/libs/requests/sessions.py b/libs/requests/sessions.py index 3113c787..f0d4f3c7 100644 --- a/libs/requests/sessions.py +++ b/libs/requests/sessions.py @@ -15,9 +15,10 @@ from .cookies import cookiejar_from_dict, remove_cookie_by_name from .defaults import defaults from .models import Request from .hooks import dispatch_hook -from .utils import header_expand +from .utils import header_expand, from_key_val_list from .packages.urllib3.poolmanager import PoolManager + def merge_kwargs(local_kwarg, default_kwarg): """Merges kwarg dictionaries. @@ -37,12 +38,15 @@ def merge_kwargs(local_kwarg, default_kwarg): if not hasattr(default_kwarg, 'items'): return local_kwarg + default_kwarg = from_key_val_list(default_kwarg) + local_kwarg = from_key_val_list(local_kwarg) + # Update new values. kwargs = default_kwarg.copy() kwargs.update(local_kwarg) # Remove keys that are set to None. - for (k, v) in list(local_kwarg.items()): + for (k, v) in local_kwarg.items(): if v is None: del kwargs[k] @@ -56,7 +60,6 @@ class Session(object): 'headers', 'cookies', 'auth', 'timeout', 'proxies', 'hooks', 'params', 'config', 'verify', 'cert', 'prefetch'] - def __init__(self, headers=None, cookies=None, @@ -66,17 +69,17 @@ class Session(object): hooks=None, params=None, config=None, - prefetch=False, + prefetch=True, verify=True, cert=None): - self.headers = headers or {} + self.headers = from_key_val_list(headers or []) self.auth = auth self.timeout = timeout - self.proxies = proxies or {} - self.hooks = hooks or {} - self.params = params or {} - self.config = config or {} + self.proxies = from_key_val_list(proxies or []) + self.hooks = from_key_val_list(hooks or {}) + self.params = from_key_val_list(params or []) + self.config = from_key_val_list(config or {}) self.prefetch = prefetch self.verify = verify self.cert = cert @@ -105,7 +108,15 @@ class Session(object): return self def __exit__(self, *args): - pass + self.close() + + def close(self): + """Dispose of any internal state. + + Currently, this just closes the PoolManager, which closes pooled + connections. + """ + self.poolmanager.clear() def request(self, method, url, params=None, @@ -120,7 +131,7 @@ class Session(object): hooks=None, return_response=True, config=None, - prefetch=False, + prefetch=None, verify=None, cert=None): @@ -140,7 +151,7 @@ class Session(object): :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. :param return_response: (optional) If False, an un-sent Request object will returned. :param config: (optional) A configuration dictionary. See ``request.defaults`` for allowed keys and their default values. - :param prefetch: (optional) if ``True``, the response content will be immediately downloaded. + :param prefetch: (optional) whether to immediately download the response content. Defaults to ``True``. :param verify: (optional) if ``True``, the SSL cert will be verified. A CA_BUNDLE path can also be provided. :param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair. """ @@ -148,12 +159,12 @@ class Session(object): method = str(method).upper() # Default empty dicts for dict params. - data = {} if data is None else data - files = {} if files is None else files + data = [] if data is None else data + files = [] if files is None else files headers = {} if headers is None else headers params = {} if params is None else params hooks = {} if hooks is None else hooks - prefetch = self.prefetch or prefetch + prefetch = prefetch if prefetch is not None else self.prefetch # use session's hooks as defaults for key, cb in list(self.hooks.items()): @@ -161,23 +172,23 @@ class Session(object): # Expand header values. if headers: - for k, v in list(headers.items()) or {}: + for k, v in list(headers.items() or {}): headers[k] = header_expand(v) args = dict( method=method, url=url, data=data, - params=params, - headers=headers, + params=from_key_val_list(params), + headers=from_key_val_list(headers), cookies=cookies, files=files, auth=auth, - hooks=hooks, + hooks=from_key_val_list(hooks), timeout=timeout, allow_redirects=allow_redirects, - proxies=proxies, - config=config, + proxies=from_key_val_list(proxies), + config=from_key_val_list(config), prefetch=prefetch, verify=verify, cert=cert, @@ -232,7 +243,6 @@ class Session(object): # Return the response. return r.response - def get(self, url, **kwargs): """Sends a GET request. Returns :class:`Response` object. @@ -243,7 +253,6 @@ class Session(object): kwargs.setdefault('allow_redirects', True) return self.request('get', url, **kwargs) - def options(self, url, **kwargs): """Sends a OPTIONS request. Returns :class:`Response` object. @@ -254,7 +263,6 @@ class Session(object): kwargs.setdefault('allow_redirects', True) return self.request('options', url, **kwargs) - def head(self, url, **kwargs): """Sends a HEAD request. Returns :class:`Response` object. @@ -265,7 +273,6 @@ class Session(object): kwargs.setdefault('allow_redirects', False) return self.request('head', url, **kwargs) - def post(self, url, data=None, **kwargs): """Sends a POST request. Returns :class:`Response` object. @@ -276,7 +283,6 @@ class Session(object): return self.request('post', url, data=data, **kwargs) - def put(self, url, data=None, **kwargs): """Sends a PUT request. Returns :class:`Response` object. @@ -287,7 +293,6 @@ class Session(object): return self.request('put', url, data=data, **kwargs) - def patch(self, url, data=None, **kwargs): """Sends a PATCH request. Returns :class:`Response` object. @@ -298,7 +303,6 @@ class Session(object): return self.request('patch', url, data=data, **kwargs) - def delete(self, url, **kwargs): """Sends a DELETE request. Returns :class:`Response` object. diff --git a/libs/requests/status_codes.py b/libs/requests/status_codes.py index da74286d..e25ecdb9 100644 --- a/libs/requests/status_codes.py +++ b/libs/requests/status_codes.py @@ -83,4 +83,4 @@ for (code, titles) in list(_codes.items()): for title in titles: setattr(codes, title, code) if not title.startswith('\\'): - setattr(codes, title.upper(), code) \ No newline at end of file + setattr(codes, title.upper(), code) diff --git a/libs/requests/structures.py b/libs/requests/structures.py index fd1051a8..3fda9843 100644 --- a/libs/requests/structures.py +++ b/libs/requests/structures.py @@ -47,6 +47,7 @@ class CaseInsensitiveDict(dict): else: return default + class LookupDict(dict): """Dictionary lookup object.""" diff --git a/libs/requests/utils.py b/libs/requests/utils.py index 8c445e7b..63b281a2 100644 --- a/libs/requests/utils.py +++ b/libs/requests/utils.py @@ -12,12 +12,15 @@ that are also useful for external consumption. import cgi import codecs import os +import platform import re +import sys import zlib from netrc import netrc, NetrcParseError +from . import __version__ from .compat import parse_http_list as _parse_list_header -from .compat import quote, urlparse, basestring, bytes, str +from .compat import quote, urlparse, basestring, bytes, str, OrderedDict from .cookies import RequestsCookieJar, cookiejar_from_dict _hush_pyflakes = (RequestsCookieJar,) @@ -25,8 +28,8 @@ _hush_pyflakes = (RequestsCookieJar,) CERTIFI_BUNDLE_PATH = None try: # see if requests's own CA certificate bundle is installed - import certifi - CERTIFI_BUNDLE_PATH = certifi.where() + from . import certs + CERTIFI_BUNDLE_PATH = certs.where() except ImportError: pass @@ -40,8 +43,13 @@ POSSIBLE_CA_BUNDLE_PATHS = [ '/etc/ssl/certs/ca-certificates.crt', # FreeBSD (provided by the ca_root_nss package): '/usr/local/share/certs/ca-root-nss.crt', + # openSUSE (provided by the ca-certificates package), the 'certs' directory is the + # preferred way but may not be supported by the SSL module, thus it has 'ca-bundle.pem' + # as a fallback (which is generated from pem files in the 'certs' directory): + '/etc/ssl/ca-bundle.pem', ] + def get_os_ca_bundle_path(): """Try to pick an available CA certificate bundle provided by the OS.""" for path in POSSIBLE_CA_BUNDLE_PATHS: @@ -53,6 +61,7 @@ def get_os_ca_bundle_path(): # otherwise, try and use the OS bundle DEFAULT_CA_BUNDLE_PATH = CERTIFI_BUNDLE_PATH or get_os_ca_bundle_path() + def dict_to_sequence(d): """Returns an internal sequence dictionary update.""" @@ -94,7 +103,7 @@ def get_netrc_auth(url): pass # AppEngine hackiness. - except AttributeError: + except (ImportError, AttributeError): pass @@ -105,6 +114,54 @@ def guess_filename(obj): return name +def from_key_val_list(value): + """Take an object and test to see if it can be represented as a + dictionary. Unless it can not be represented as such, return an + OrderedDict, e.g., + + :: + + >>> from_key_val_list([('key', 'val')]) + OrderedDict([('key', 'val')]) + >>> from_key_val_list('string') + ValueError: need more than 1 value to unpack + >>> from_key_val_list({'key': 'val'}) + OrderedDict([('key', 'val')]) + """ + if value is None: + return None + + if isinstance(value, (str, bytes, bool, int)): + raise ValueError('cannot encode objects that are not 2-tuples') + + return OrderedDict(value) + + +def to_key_val_list(value): + """Take an object and test to see if it can be represented as a + dictionary. If it can be, return a list of tuples, e.g., + + :: + + >>> to_key_val_list([('key', 'val')]) + [('key', 'val')] + >>> to_key_val_list({'key': 'val'}) + [('key', 'val')] + >>> to_key_val_list('string') + ValueError: cannot encode objects that are not 2-tuples. + """ + if value is None: + return None + + if isinstance(value, (str, bytes, bool, int)): + raise ValueError('cannot encode objects that are not 2-tuples') + + if isinstance(value, dict): + value = value.items() + + return list(value) + + # From mitsuhiko/werkzeug (used with permission). def parse_list_header(value): """Parse lists as described by RFC 2068 Section 2. @@ -254,11 +311,8 @@ def dict_from_cookiejar(cj): cookie_dict = {} - for _, cookies in list(cj._cookies.items()): - for _, cookies in list(cookies.items()): - for cookie in list(cookies.values()): - # print cookie - cookie_dict[cookie.name] = cookie.value + for cookie in cj: + cookie_dict[cookie.name] = cookie.value return cookie_dict @@ -324,6 +378,12 @@ def stream_decode_response_unicode(iterator, r): if rv: yield rv +def iter_slices(string, slice_length): + """Iterate over slices of a string.""" + pos = 0 + while pos < len(string): + yield string[pos:pos+slice_length] + pos += slice_length def get_unicode_from_response(r): """Returns the requested content back in unicode. @@ -438,6 +498,7 @@ def requote_uri(uri): # or '%') return quote(unquote_unreserved(uri), safe="!#$%&'()*+,/:;=?@[]~") + def get_environ_proxies(): """Return a dict of environment proxies.""" @@ -453,3 +514,64 @@ def get_environ_proxies(): get_proxy = lambda k: os.environ.get(k) or os.environ.get(k.upper()) proxies = [(key, get_proxy(key + '_proxy')) for key in proxy_keys] return dict([(key, val) for (key, val) in proxies if val]) + + +def default_user_agent(): + """Return a string representing the default user agent.""" + _implementation = platform.python_implementation() + + if _implementation == 'CPython': + _implementation_version = platform.python_version() + elif _implementation == 'PyPy': + _implementation_version = '%s.%s.%s' % ( + sys.pypy_version_info.major, + sys.pypy_version_info.minor, + sys.pypy_version_info.micro + ) + if sys.pypy_version_info.releaselevel != 'final': + _implementation_version = ''.join([_implementation_version, sys.pypy_version_info.releaselevel]) + elif _implementation == 'Jython': + _implementation_version = platform.python_version() # Complete Guess + elif _implementation == 'IronPython': + _implementation_version = platform.python_version() # Complete Guess + else: + _implementation_version = 'Unknown' + + return " ".join([ + 'python-requests/%s' % __version__, + '%s/%s' % (_implementation, _implementation_version), + '%s/%s' % (platform.system(), platform.release()), + ]) + +def parse_header_links(value): + """Return a dict of parsed link headers proxies. + + i.e. Link: ; rel=front; type="image/jpeg",; rel=back;type="image/jpeg" + + """ + + links = [] + + replace_chars = " '\"" + + for val in value.split(","): + try: + url, params = val.split(";", 1) + except ValueError: + url, params = val, '' + + link = {} + + link["url"] = url.strip("<> '\"") + + for param in params.split(";"): + try: + key,value = param.split("=") + except ValueError: + break + + link[key.strip(replace_chars)] = value.strip(replace_chars) + + links.append(link) + + return links diff --git a/libs/subliminal/__init__.py b/libs/subliminal/__init__.py old mode 100644 new mode 100755 diff --git a/libs/subliminal/api.py b/libs/subliminal/api.py old mode 100644 new mode 100755 diff --git a/libs/subliminal/async.py b/libs/subliminal/async.py old mode 100644 new mode 100755 diff --git a/libs/subliminal/cache.py b/libs/subliminal/cache.py old mode 100644 new mode 100755 diff --git a/libs/subliminal/core.py b/libs/subliminal/core.py old mode 100644 new mode 100755 diff --git a/libs/subliminal/exceptions.py b/libs/subliminal/exceptions.py old mode 100644 new mode 100755 diff --git a/libs/subliminal/infos.py b/libs/subliminal/infos.py old mode 100644 new mode 100755 index 46039ac3..220ea859 --- a/libs/subliminal/infos.py +++ b/libs/subliminal/infos.py @@ -15,4 +15,4 @@ # # You should have received a copy of the GNU Lesser General Public License # along with subliminal. If not, see . -__version__ = '0.6.1' +__version__ = '0.6.2' diff --git a/libs/subliminal/language.py b/libs/subliminal/language.py old mode 100644 new mode 100755 diff --git a/libs/subliminal/services/__init__.py b/libs/subliminal/services/__init__.py old mode 100644 new mode 100755 diff --git a/libs/subliminal/services/addic7ed.py b/libs/subliminal/services/addic7ed.py old mode 100644 new mode 100755 index de32dd51..492fd744 --- a/libs/subliminal/services/addic7ed.py +++ b/libs/subliminal/services/addic7ed.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- # Copyright 2012 Olivier Leveau +# Copyright 2012 Antoine Bertin # # This file is part of subliminal. # @@ -20,7 +21,7 @@ from ..cache import cachedmethod from ..exceptions import DownloadFailedError from ..language import Language, language_set from ..subtitles import get_subtitle_path, ResultSubtitle -from ..utils import get_keywords +from ..utils import get_keywords, split_keyword from ..videos import Episode from bs4 import BeautifulSoup import logging @@ -31,97 +32,32 @@ import re logger = logging.getLogger(__name__) -def match(pattern, string): - try: - return re.search(pattern, string).group(1) - except AttributeError: - logger.debug(u'Could not match %r on %r' % (pattern, string)) - return None - - -def matches(pattern, string): - try: - return re.search(pattern, string).group(1, 2) - except AttributeError: - logger.debug(u'Could not match %r on %r' % (pattern, string)) - return None - - class Addic7ed(ServiceBase): server_url = 'http://www.addic7ed.com' api_based = False #TODO: Complete this - languages = language_set(['ar', 'ca', 'de', 'el', 'en', 'es', 'eu', 'fr', 'ga', 'he', 'hr', 'hu', 'it', - 'pl', 'pt', 'ro', 'ru', 'se', 'pt-br']) + languages = language_set(['ar', 'ca', 'de', 'el', 'en', 'es', 'eu', 'fr', 'ga', 'gl', 'he', 'hr', 'hu', + 'it', 'pl', 'pt', 'ro', 'ru', 'se', 'pt-br']) language_map = {'Portuguese (Brazilian)': Language('por-BR'), 'Greek': Language('gre'), - 'Spanish (Latin America)': Language('spa'), } + 'Spanish (Latin America)': Language('spa'), 'Galego': Language('glg'), + u'Català': Language('cat')} videos = [Episode] require_video = False required_features = ['permissive'] @cachedmethod - def get_likely_series_id(self, name): + def get_series_id(self, name): + """Get the show page and cache every show found in it""" r = self.session.get('%s/shows.php' % self.server_url) soup = BeautifulSoup(r.content, self.required_features) - for elem in soup.find_all('h3'): - show_name = elem.a.text.lower() - show_id = int(match('show/([0-9]+)', elem.a['href'])) - # we could just return the id of the queried show, but as we - # already downloaded the whole page we might as well fill in the - # information for all the shows - self.cache_for(self.get_likely_series_id, args=(show_name,), result=show_id) - return self.cached_value(self.get_likely_series_id, args=(name,)) - - @cachedmethod - def get_episode_url(self, series_id, season, number): - """Get the Addic7ed id for the given episode. Raises KeyError if none - could be found - - """ - # download the page of the show, contains ids for all episodes all seasons - r = self.session.get('%s/show/%d' % (self.server_url, series_id)) - soup = BeautifulSoup(r.content, self.required_features) - form = soup.find('form', attrs={'name': 'multidl'}) - for table in form.find_all('table'): - for row in table.find_all('tr'): - cell = row.find('td', 'MultiDldS') - if not cell: - continue - m = matches('/serie/.+/([0-9]+)/([0-9]+)/', cell.a['href']) - if not m: - continue - episode_url = cell.a['href'] - season_number = int(m[0]) - episode_number = int(m[1]) - # we could just return the url of the queried episode, but as we - # already downloaded the whole page we might as well fill in the - # information for all the episodes of the show - self.cache_for(self.get_episode_url, args=(series_id, season_number, episode_number), result=episode_url) - # raises KeyError if not found - return self.cached_value(self.get_episode_url, args=(series_id, season, number)) - - # Do not cache this method in order to always check for the most recent - # subtitles - def get_sub_urls(self, episode_url): - suburls = [] - r = self.session.get('%s/%s' % (self.server_url, episode_url)) - epsoup = BeautifulSoup(r.content, self.required_features) - for releaseTable in epsoup.find_all('table', 'tabel95'): - releaseRow = releaseTable.find('td', 'NewsTitle') - if not releaseRow: + for html_series in soup.select('h3 > a'): + series_name = html_series.text.lower() + match = re.search('show/([0-9]+)', html_series['href']) + if match is None: continue - release = releaseRow.text.strip() - for row in releaseTable.find_all('tr'): - link = row.find('a', 'buttonDownload') - if not link: - continue - if 'href' not in link.attrs or not (link['href'].startswith('/original') or link['href'].startswith('/updated')): - continue - suburl = link['href'] - lang = self.get_language(row.find('td', 'language').text.strip()) - result = {'suburl': suburl, 'language': lang, 'release': release} - suburls.append(result) - return suburls + series_id = int(match.group(1)) + self.cache_for(self.get_series_id, args=(series_name,), result=series_id) + return self.cached_value(self.get_series_id, args=(name,)) def list_checked(self, video, languages): return self.query(video.path or video.release, languages, get_keywords(video.guess), video.series, video.season, video.episode) @@ -130,25 +66,36 @@ class Addic7ed(ServiceBase): logger.debug(u'Getting subtitles for %s season %d episode %d with languages %r' % (series, season, episode, languages)) self.init_cache() try: - sid = self.get_likely_series_id(series.lower()) + series_id = self.get_series_id(series.lower()) except KeyError: logger.debug(u'Could not find series id for %s' % series) return [] - try: - ep_url = self.get_episode_url(sid, season, episode) - except KeyError: - logger.debug(u'Could not find episode id for %s season %d episode %d' % (series, season, episode)) - return [] - suburls = self.get_sub_urls(ep_url) - # filter the subtitles with our queried languages + r = self.session.get('%s/show/%d&season=%d' % (self.server_url, series_id, season)) + soup = BeautifulSoup(r.content, self.required_features) subtitles = [] - for suburl in suburls: - language = suburl['language'] - if language not in languages: + for row in soup('tr', {'class': 'epeven completed'}): + cells = row('td') + if int(cells[0].text.strip()) != season or int(cells[1].text.strip()) != episode: continue - path = get_subtitle_path(filepath, language, self.config.multi) - subtitle = ResultSubtitle(path, language, self.__class__.__name__.lower(), '%s/%s' % (self.server_url, suburl['suburl']), - keywords=[suburl['release']]) + if cells[6].text.strip(): + logger.debug(u'Skipping hearing impaired') + continue + sub_status = cells[5].text.strip() + if sub_status != 'Completed': + logger.debug(u'Wrong subtitle status %s' % sub_status) + continue + sub_language = self.get_language(cells[3].text.strip()) + if sub_language not in languages: + logger.debug(u'Language %r not in wanted languages %r' % (sub_language, languages)) + continue + sub_keywords = split_keyword(cells[4].text.strip().lower()) + #TODO: Maybe allow empty keywords here? (same in Subtitulos) + if not keywords & sub_keywords: + logger.debug(u'None of subtitle keywords %r in %r' % (sub_keywords, keywords)) + continue + sub_link = '%s/%s' % (self.server_url, cells[9].a['href']) + sub_path = get_subtitle_path(filepath, sub_language, self.config.multi) + subtitle = ResultSubtitle(sub_path, sub_language, self.__class__.__name__.lower(), sub_link, keywords=sub_keywords) subtitles.append(subtitle) return subtitles diff --git a/libs/subliminal/services/bierdopje.py b/libs/subliminal/services/bierdopje.py old mode 100644 new mode 100755 index 66738fa6..03577cd8 --- a/libs/subliminal/services/bierdopje.py +++ b/libs/subliminal/services/bierdopje.py @@ -36,6 +36,7 @@ logger = logging.getLogger(__name__) class BierDopje(ServiceBase): server_url = 'http://api.bierdopje.com/A2B638AC5D804C2E/' + user_agent = 'Subliminal/0.6' api_based = True languages = language_set(['eng', 'dut']) videos = [Episode] diff --git a/libs/subliminal/services/opensubtitles.py b/libs/subliminal/services/opensubtitles.py old mode 100644 new mode 100755 diff --git a/libs/subliminal/services/podnapisi.py b/libs/subliminal/services/podnapisi.py old mode 100644 new mode 100755 diff --git a/libs/subliminal/services/subswiki.py b/libs/subliminal/services/subswiki.py old mode 100644 new mode 100755 index a7b98539..add79a5f --- a/libs/subliminal/services/subswiki.py +++ b/libs/subliminal/services/subswiki.py @@ -19,11 +19,10 @@ from . import ServiceBase from ..exceptions import ServiceError from ..language import language_set, Language from ..subtitles import get_subtitle_path, ResultSubtitle +from ..utils import get_keywords, split_keyword from ..videos import Episode, Movie from bs4 import BeautifulSoup -from subliminal.utils import get_keywords, split_keyword import logging -import re import urllib @@ -40,7 +39,6 @@ class SubsWiki(ServiceBase): language_code = 'name' videos = [Episode, Movie] require_video = False - release_pattern = re.compile('\nVersion (.+), ([0-9]+).([0-9])+ MBs') required_features = ['permissive'] def list_checked(self, video, languages): @@ -78,22 +76,22 @@ class SubsWiki(ServiceBase): soup = BeautifulSoup(r.content, self.required_features) subtitles = [] for sub in soup('td', {'class': 'NewsTitle'}): - sub_keywords = split_keyword(self.release_pattern.search(sub.contents[1]).group(1).lower()) + sub_keywords = split_keyword(sub.b.string.lower()) if not keywords & sub_keywords: logger.debug(u'None of subtitle keywords %r in %r' % (sub_keywords, keywords)) continue - for html_language in sub.parent.parent.findAll('td', {'class': 'language'}): + for html_language in sub.parent.parent.find_all('td', {'class': 'language'}): language = self.get_language(html_language.string.strip()) if language not in languages: logger.debug(u'Language %r not in wanted languages %r' % (language, languages)) continue - html_status = html_language.findNextSibling('td') - status = html_status.find('strong').string.strip() - if status != 'Completed': + html_status = html_language.find_next_sibling('td') + status = html_status.strong.string.strip() + if status != 'Completado': logger.debug(u'Wrong subtitle status %s' % status) continue path = get_subtitle_path(filepath, language, self.config.multi) - subtitle = ResultSubtitle(path, language, self.__class__.__name__.lower(), '%s%s' % (self.server_url, html_status.findNext('td').find('a')['href'])) + subtitle = ResultSubtitle(path, language, self.__class__.__name__.lower(), '%s%s' % (self.server_url, html_status.find_next('td').find('a')['href'])) subtitles.append(subtitle) return subtitles diff --git a/libs/subliminal/services/subtitulos.py b/libs/subliminal/services/subtitulos.py old mode 100644 new mode 100755 index c40b76d2..ee225b8b --- a/libs/subliminal/services/subtitulos.py +++ b/libs/subliminal/services/subtitulos.py @@ -18,9 +18,9 @@ from . import ServiceBase from ..language import language_set, Language from ..subtitles import get_subtitle_path, ResultSubtitle +from ..utils import get_keywords, split_keyword from ..videos import Episode from bs4 import BeautifulSoup -from subliminal.utils import get_keywords, split_keyword import logging import re import unicodedata diff --git a/libs/subliminal/services/thesubdb.py b/libs/subliminal/services/thesubdb.py old mode 100644 new mode 100755 diff --git a/libs/subliminal/services/tvsubtitles.py b/libs/subliminal/services/tvsubtitles.py old mode 100644 new mode 100755 diff --git a/libs/subliminal/subtitles.py b/libs/subliminal/subtitles.py old mode 100644 new mode 100755 index a8664777..117871b3 --- a/libs/subliminal/subtitles.py +++ b/libs/subliminal/subtitles.py @@ -23,7 +23,7 @@ import os.path __all__ = ['Subtitle', 'EmbeddedSubtitle', 'ExternalSubtitle', 'ResultSubtitle', 'get_subtitle_path'] #: Subtitles extensions -EXTENSIONS = ['.srt', '.sub', '.txt'] +EXTENSIONS = ['.srt', '.sub', '.txt', '.ass'] class Subtitle(object): diff --git a/libs/subliminal/tasks.py b/libs/subliminal/tasks.py old mode 100644 new mode 100755 diff --git a/libs/subliminal/utils.py b/libs/subliminal/utils.py old mode 100644 new mode 100755 diff --git a/libs/subliminal/videos.py b/libs/subliminal/videos.py old mode 100644 new mode 100755 index a63bfee1..8bbb0a39 --- a/libs/subliminal/videos.py +++ b/libs/subliminal/videos.py @@ -18,7 +18,7 @@ from . import subtitles from .language import Language from .utils import to_unicode -import enzyme +import enzyme.core import guessit import hashlib import logging @@ -135,6 +135,8 @@ class Video(object): # brackets inside the filename, so we have to use basic string # startswith/endswith comparisons folder, basename = os.path.split(basepath) + if folder == '': + folder = '.' existing = [f for f in os.listdir(folder) if f.startswith(basename)] for path in existing: for ext in subtitles.EXTENSIONS: From 8bfad087e1a2317b83f938d491f255d109603d14 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 14 Oct 2012 20:17:13 +0200 Subject: [PATCH 69/92] Add podnapisi to subtitle providers --- couchpotato/core/plugins/subtitle/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/subtitle/main.py b/couchpotato/core/plugins/subtitle/main.py index fc0a3904..cde1b929 100644 --- a/couchpotato/core/plugins/subtitle/main.py +++ b/couchpotato/core/plugins/subtitle/main.py @@ -14,7 +14,7 @@ log = CPLog(__name__) class Subtitle(Plugin): - services = ['opensubtitles', 'thesubdb', 'subswiki'] + services = ['opensubtitles', 'thesubdb', 'subswiki', 'podnapisi'] def __init__(self): addEvent('renamer.before', self.searchSingle) From ad0a1b1efec064f734912a507d3e80f6fce9869d Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 14 Oct 2012 20:26:10 +0200 Subject: [PATCH 70/92] Pass all the renamed files when adding new release --- couchpotato/core/plugins/manage/main.py | 6 +++--- couchpotato/core/plugins/renamer/main.py | 4 ++-- couchpotato/core/plugins/scanner/main.py | 9 +++++---- couchpotato/core/plugins/trailer/main.py | 2 ++ couchpotato/core/providers/metadata/base.py | 1 + 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/couchpotato/core/plugins/manage/main.py b/couchpotato/core/plugins/manage/main.py index c5f3828f..f09a127e 100644 --- a/couchpotato/core/plugins/manage/main.py +++ b/couchpotato/core/plugins/manage/main.py @@ -2,7 +2,7 @@ from couchpotato.api import addApiView from couchpotato.core.event import fireEvent, addEvent, fireEventAsync from couchpotato.core.helpers.encoding import ss from couchpotato.core.helpers.request import jsonified, getParam -from couchpotato.core.helpers.variable import getTitle +from couchpotato.core.helpers.variable import getTitle, splitString from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin from couchpotato.environment import Env @@ -26,7 +26,7 @@ class Manage(Plugin): # Add files after renaming def after_rename(message = None, group = {}): return self.scanFilesToLibrary(folder = group['destination_dir'], files = group['renamed_files']) - addEvent('renamer.after', after_rename) + addEvent('renamer.after', after_rename, priority = 110) addApiView('manage.update', self.updateLibraryView, docs = { 'desc': 'Update the library by scanning for new movies', @@ -176,7 +176,7 @@ class Manage(Plugin): def directories(self): try: - return [x.strip() for x in self.conf('library', default = '').split('::')] + return splitString(self.conf('library', default = ''), '::') except: return [] diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 60692a57..670e5d67 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -50,7 +50,7 @@ class Renamer(Plugin): return if self.renaming_started is True: - log.info('Renamer is disabled to avoid infinite looping of the same error.') + log.info('Renamer is already running, if you see this often, check the logs above for errors.') return # Check to see if the "to" folder is inside the "from" folder. @@ -379,7 +379,7 @@ class Renamer(Plugin): # Notify on download, search for trailers etc download_message = 'Downloaded %s (%s)' % (movie_title, replacements['quality']) - fireEventAsync('renamer.after', message = download_message, group = group) + fireEvent('renamer.after', message = download_message, group = group, in_order = True) # Break if CP wants to shut down if self.shuttingDown(): diff --git a/couchpotato/core/plugins/scanner/main.py b/couchpotato/core/plugins/scanner/main.py index a25a31c7..d83d87de 100644 --- a/couchpotato/core/plugins/scanner/main.py +++ b/couchpotato/core/plugins/scanner/main.py @@ -86,7 +86,7 @@ class Scanner(Plugin): addEvent('scanner.name_year', self.getReleaseNameYear) addEvent('scanner.partnumber', self.getPartNumber) - def scan(self, folder = None, files = [], simple = False, newer_than = 0, on_found = None): + def scan(self, folder = None, files = None, simple = False, newer_than = 0, on_found = None): folder = ss(os.path.normpath(folder)) @@ -99,7 +99,8 @@ class Scanner(Plugin): leftovers = [] # Scan all files of the folder if no files are set - if len(files) == 0: + if not files: + check_file_date = True try: files = [] for root, dirs, walk_files in os.walk(folder): @@ -108,6 +109,7 @@ class Scanner(Plugin): except: log.error('Failed getting files from %s: %s', (folder, traceback.format_exc())) else: + check_file_date = False files = [ss(x) for x in files] db = get_session() @@ -237,7 +239,6 @@ class Scanner(Plugin): del path_identifiers[identifier] del delete_identifiers - # Make sure we remove older / still extracting files valid_files = {} while True and not self.shuttingDown(): @@ -261,7 +262,7 @@ class Scanner(Plugin): if file_too_new: break - if file_too_new: + if check_file_date and file_too_new: try: time_string = time.ctime(file_time[0]) except: diff --git a/couchpotato/core/plugins/trailer/main.py b/couchpotato/core/plugins/trailer/main.py index 8b9f1e1c..9a322658 100644 --- a/couchpotato/core/plugins/trailer/main.py +++ b/couchpotato/core/plugins/trailer/main.py @@ -28,6 +28,8 @@ class Trailer(Plugin): else: log.debug('Trailer already exists: %s', destination) + group['renamed_files'].append(destination) + # Download first and break break diff --git a/couchpotato/core/providers/metadata/base.py b/couchpotato/core/providers/metadata/base.py index 078d7e1d..d37ff78f 100644 --- a/couchpotato/core/providers/metadata/base.py +++ b/couchpotato/core/providers/metadata/base.py @@ -49,6 +49,7 @@ class MetaDataBase(Plugin): shutil.copy2(content, name) else: self.createFile(name, content) + group['renamed_files'].append(name) except: log.error('Unable to create %s file: %s', (file_type, traceback.format_exc())) From 9dc1843f2595916f2be73479c2187d747ee7772f Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 14 Oct 2012 20:42:12 +0200 Subject: [PATCH 71/92] Also use data param on notifier --- couchpotato/core/notifications/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/notifications/base.py b/couchpotato/core/notifications/base.py index 52582b56..6efb716e 100644 --- a/couchpotato/core/notifications/base.py +++ b/couchpotato/core/notifications/base.py @@ -30,10 +30,10 @@ class Notification(Plugin): addEvent(listener, self.createNotifyHandler(listener)) def createNotifyHandler(self, listener): - def notify(message = None, group = {}): + def notify(message = None, group = {}, data = {}): if not self.conf('on_snatch', default = True) and listener == 'movie.snatched': return - return self.notify(message = message, data = group, listener = listener) + return self.notify(message = message, data = group if group != {} else data, listener = listener) return notify From 907f821e50344d1c30c04438e45b72e831f2533c Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 14 Oct 2012 20:42:31 +0200 Subject: [PATCH 72/92] Some more logging for SABNZBd --- couchpotato/core/downloaders/sabnzbd/main.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index eaf91b56..5b2de6b0 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -2,6 +2,7 @@ from couchpotato.core.downloaders.base import Downloader from couchpotato.core.helpers.encoding import tryUrlencode from couchpotato.core.helpers.variable import cleanHost, mergeDicts from couchpotato.core.logger import CPLog +from urllib2 import URLError import json import traceback @@ -43,8 +44,11 @@ class Sabnzbd(Downloader): sab = self.urlopen(url, timeout = 60, params = {"nzbfile": (nzb_filename, filedata)}, multipart = True, show_error = False) else: sab = self.urlopen(url, timeout = 60, show_error = False) + except URLError: + log.error('Failed sending release, probably wrong HOST: %s', traceback.format_exc(0)) + return False except: - log.error('Failed sending release: %s', traceback.format_exc()) + log.error('Failed sending release, use API key, NOT the NZB key: %s', traceback.format_exc(0)) return False result = sab.strip() @@ -53,14 +57,12 @@ class Sabnzbd(Downloader): return False log.debug("Result text from SAB: " + result[:40]) + print result if result == "ok": log.info("NZB sent to SAB successfully.") return True - elif result == "Missing authentication": - log.error("Incorrect username/password.") - return False else: - log.error("Unknown error: " + result[:40]) + log.error(result[:40]) return False def getAllDownloadStatus(self): @@ -75,7 +77,7 @@ class Sabnzbd(Downloader): 'mode': 'queue', }) except: - log.error('Failed getting queue: %s', traceback.format_exc()) + log.error('Failed getting queue: %s', traceback.format_exc(0)) return False # Go through history items @@ -85,7 +87,7 @@ class Sabnzbd(Downloader): 'limit': 15, }) except: - log.error('Failed getting history json: %s', traceback.format_exc()) + log.error('Failed getting history json: %s', traceback.format_exc(0)) return False statuses = [] @@ -134,7 +136,7 @@ class Sabnzbd(Downloader): 'value': item['id'] }, use_json = False) except: - log.error('Failed deleting: %s', traceback.format_exc()) + log.error('Failed deleting: %s', traceback.format_exc(0)) return False return True From 9ebc4dbf38b08bbc75068428c725f92e4c54d95e Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 15 Oct 2012 23:50:05 +0200 Subject: [PATCH 73/92] Reworked some download code. #924 --- couchpotato/core/downloaders/sabnzbd/main.py | 22 ++++--- couchpotato/core/notifications/base.py | 4 +- couchpotato/core/plugins/searcher/main.py | 63 ++++++++++---------- 3 files changed, 48 insertions(+), 41 deletions(-) diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index 5b2de6b0..8b7383ba 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -37,11 +37,11 @@ class Sabnzbd(Downloader): else: params['name'] = data.get('url') - url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params) + url = cleanHost(self.conf('host')) + 'api?' + tryUrlencode(params) try: if params.get('mode') is 'addfile': - sab = self.urlopen(url, timeout = 60, params = {"nzbfile": (nzb_filename, filedata)}, multipart = True, show_error = False) + sab = self.urlopen(url, timeout = 60, params = {'nzbfile': (nzb_filename, filedata)}, multipart = True, show_error = False) else: sab = self.urlopen(url, timeout = 60, show_error = False) except URLError: @@ -53,13 +53,12 @@ class Sabnzbd(Downloader): result = sab.strip() if not result: - log.error("SABnzbd didn't return anything.") + log.error('SABnzbd didn\'t return anything.') return False - log.debug("Result text from SAB: " + result[:40]) - print result - if result == "ok": - log.info("NZB sent to SAB successfully.") + log.debug('Result text from SAB: %s', result[:40]) + if result[:2] == 'ok': + log.info('NZB sent to SAB successfully.') return True else: log.error(result[:40]) @@ -143,14 +142,19 @@ class Sabnzbd(Downloader): def call(self, params, use_json = True): - url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(mergeDicts(params, { + url = cleanHost(self.conf('host')) + 'api?' + tryUrlencode(mergeDicts(params, { 'apikey': self.conf('api_key'), 'output': 'json' })) data = self.urlopen(url, timeout = 60, show_error = False) if use_json: - return json.loads(data)[params['mode']] + d = json.loads(data) + if d.get('error'): + log.error('Error getting data from SABNZBd: %s', d.get('error')) + return {} + + return d[params['mode']] else: return data diff --git a/couchpotato/core/notifications/base.py b/couchpotato/core/notifications/base.py index 6efb716e..7e98fa51 100644 --- a/couchpotato/core/notifications/base.py +++ b/couchpotato/core/notifications/base.py @@ -30,10 +30,10 @@ class Notification(Plugin): addEvent(listener, self.createNotifyHandler(listener)) def createNotifyHandler(self, listener): - def notify(message = None, group = {}, data = {}): + def notify(message = None, group = {}, data = None): if not self.conf('on_snatch', default = True) and listener == 'movie.snatched': return - return self.notify(message = message, data = group if group != {} else data, listener = listener) + return self.notify(message = message, data = data if data else group, listener = listener) return notify diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index f0bccc71..edad31f7 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -180,10 +180,8 @@ class Searcher(Plugin): status_id = available_status.get('id') ) db.add(rls) - db.commit() else: [db.delete(info) for info in rls.info] - db.commit() for info in nzb: try: @@ -195,12 +193,13 @@ class Searcher(Plugin): value = toUnicode(nzb[info]) ) rls.info.append(rls_info) - db.commit() except InterfaceError: log.debug('Couldn\'t add %s to ReleaseInfo: %s', (info, traceback.format_exc())) nzb['status_id'] = rls.status_id + db.commit() + for nzb in sorted_results: if nzb['status_id'] == ignored_status.get('id'): @@ -245,38 +244,42 @@ class Searcher(Plugin): if successful: - # Mark release as snatched - db = get_session() - rls = db.query(Release).filter_by(identifier = md5(data['url'])).first() - rls.status_id = snatched_status.get('id') - db.commit() + try: + # Mark release as snatched + db = get_session() + rls = db.query(Release).filter_by(identifier = md5(data['url'])).first() + if rls: + rls.status_id = snatched_status.get('id') + db.commit() - log_movie = '%s (%s) in %s' % (getTitle(movie['library']), movie['library']['year'], rls.quality.label) - snatch_message = 'Snatched "%s": %s' % (data.get('name'), log_movie) - log.info(snatch_message) - fireEvent('movie.snatched', message = snatch_message, data = rls.to_dict()) + log_movie = '%s (%s) in %s' % (getTitle(movie['library']), movie['library']['year'], rls.quality.label) + snatch_message = 'Snatched "%s": %s' % (data.get('name'), log_movie) + log.info(snatch_message) + fireEvent('movie.snatched', message = snatch_message, data = rls.to_dict()) + # If renamer isn't used, mark movie done + if not Env.setting('enabled', 'renamer'): + active_status = fireEvent('status.get', 'active', single = True) + done_status = fireEvent('status.get', 'done', single = True) + try: + if movie['status_id'] == active_status.get('id'): + for profile_type in movie['profile']['types']: + if rls and profile_type['quality_id'] == rls.quality.id and profile_type['finish']: + log.info('Renamer disabled, marking movie as finished: %s', log_movie) - # If renamer isn't used, mark movie done - if not Env.setting('enabled', 'renamer'): - active_status = fireEvent('status.get', 'active', single = True) - done_status = fireEvent('status.get', 'done', single = True) - try: - if movie['status_id'] == active_status.get('id'): - for profile_type in movie['profile']['types']: - if profile_type['quality_id'] == rls.quality.id and profile_type['finish']: - log.info('Renamer disabled, marking movie as finished: %s', log_movie) + # Mark release done + rls.status_id = done_status.get('id') + db.commit() - # Mark release done - rls.status_id = done_status.get('id') - db.commit() + # Mark movie done + mvie = db.query(Movie).filter_by(id = movie['id']).first() + mvie.status_id = done_status.get('id') + db.commit() + except: + log.error('Failed marking movie finished, renamer disabled: %s', traceback.format_exc()) - # Mark movie done - mvie = db.query(Movie).filter_by(id = movie['id']).first() - mvie.status_id = done_status.get('id') - db.commit() - except Exception, e: - log.error('Failed marking movie finished: %s %s', (e, traceback.format_exc())) + except: + log.error('Failed marking movie finished: %s', traceback.format_exc()) return True From 84eccbf9cfb4dd9c7f280001bcb4e6a61b2886a4 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 16 Oct 2012 22:18:37 +0200 Subject: [PATCH 74/92] Chmod metadata. fix #928 --- couchpotato/core/providers/metadata/base.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/couchpotato/core/providers/metadata/base.py b/couchpotato/core/providers/metadata/base.py index d37ff78f..b41960a0 100644 --- a/couchpotato/core/providers/metadata/base.py +++ b/couchpotato/core/providers/metadata/base.py @@ -2,6 +2,7 @@ from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.helpers.variable import mergeDicts from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin +from couchpotato.environment import Env import os import shutil import traceback @@ -51,6 +52,11 @@ class MetaDataBase(Plugin): self.createFile(name, content) group['renamed_files'].append(name) + try: + os.chmod(name, Env.getPermission('file')) + except: + log.debug('Failed setting permissions for %s: %s', (name, traceback.format_exc())) + except: log.error('Unable to create %s file: %s', (file_type, traceback.format_exc())) From 5bda44d41916c702d5091354dad12a46c3ea62c9 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 20 Oct 2012 11:30:10 +0200 Subject: [PATCH 75/92] Add api for file types --- couchpotato/core/plugins/file/main.py | 28 +++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/couchpotato/core/plugins/file/main.py b/couchpotato/core/plugins/file/main.py index 49256201..5c40df02 100644 --- a/couchpotato/core/plugins/file/main.py +++ b/couchpotato/core/plugins/file/main.py @@ -2,6 +2,7 @@ from couchpotato import get_session from couchpotato.api import addApiView from couchpotato.core.event import addEvent from couchpotato.core.helpers.encoding import toUnicode +from couchpotato.core.helpers.request import jsonified from couchpotato.core.helpers.variable import md5, getExt from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin @@ -30,6 +31,27 @@ class FileManager(Plugin): 'return': {'type': 'file'} }) + addApiView('file.types', self.getTypesView, docs = { + 'desc': 'Return a list of all the file types and their ids.', + 'return': {'type': 'object', 'example': """{ + 'types': [ + { + "identifier": "poster_original", + "type": "image", + "id": 1, + "name": "Poster_original" + }, + { + "identifier": "poster", + "type": "image", + "id": 2, + "name": "Poster" + }, + etc + ] +}"""} + }) + addEvent('app.load', self.cleanup) addEvent('app.load', self.init) @@ -129,3 +151,9 @@ class FileManager(Plugin): types.append(type_object.to_dict()) return types + + def getTypesView(self): + + return jsonified({ + 'types': self.getTypes() + }) From fbeadb8d9e7ef92bff2dbb5e6031525a391c0b0c Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 21 Oct 2012 12:11:37 +0200 Subject: [PATCH 76/92] Don't show "add your first movie" when searching. fix #937 --- couchpotato/core/plugins/movie/static/list.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/movie/static/list.js b/couchpotato/core/plugins/movie/static/list.js index fcc446bb..b4e48199 100644 --- a/couchpotato/core/plugins/movie/static/list.js +++ b/couchpotato/core/plugins/movie/static/list.js @@ -105,6 +105,7 @@ var MovieList = new Class({ self.createMovie(movie); }); + self.total_movies = total; self.setCounter(total); }, @@ -500,7 +501,7 @@ var MovieList = new Class({ checkIfEmpty: function(){ var self = this; - var is_empty = self.movies.length == 0; + var is_empty = self.movies.length == 0 && self.total_movies == 0; if(is_empty && self.options.on_empty_element){ self.el.grab(self.options.on_empty_element); From 09f723bda54e27f0a866816ce76d23ddb26da973 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 21 Oct 2012 13:37:45 +0200 Subject: [PATCH 77/92] Use jsonrpc for xbmc request. fix #927 #945 --- couchpotato/core/notifications/xbmc/main.py | 51 +++++++++++++-------- couchpotato/core/plugins/base.py | 2 +- 2 files changed, 34 insertions(+), 19 deletions(-) mode change 100644 => 100755 couchpotato/core/notifications/xbmc/main.py diff --git a/couchpotato/core/notifications/xbmc/main.py b/couchpotato/core/notifications/xbmc/main.py old mode 100644 new mode 100755 index 30759716..a2a81d70 --- a/couchpotato/core/notifications/xbmc/main.py +++ b/couchpotato/core/notifications/xbmc/main.py @@ -1,7 +1,7 @@ -from couchpotato.core.helpers.encoding import tryUrlencode from couchpotato.core.helpers.variable import splitString from couchpotato.core.logger import CPLog from couchpotato.core.notifications.base import Notification +from flask.helpers import json import base64 log = CPLog(__name__) @@ -17,28 +17,43 @@ class XBMC(Notification): hosts = splitString(self.conf('host')) successful = 0 for host in hosts: - if self.send({'command': 'ExecBuiltIn', 'parameter': 'Notification(CouchPotato, %s)' % message}, host): - successful += 1 - if self.send({'command': 'ExecBuiltIn', 'parameter': 'XBMC.updatelibrary(video)'}, host): - successful += 1 + response = self.request(host, [ + ('GUI.ShowNotification', {"title":"CouchPotato", "message":message}), + ('VideoLibrary.Scan', {}), + ]) + + for result in response: + if result['result'] == "OK": + successful += 1 return successful == len(hosts) * 2 - def send(self, command, host): + def request(self, host, requests): + server = 'http://%s/jsonrpc' % host - url = 'http://%s/xbmcCmds/xbmcHttp/?%s' % (host, tryUrlencode(command)) + data = [] + for req in requests: + method, kwargs = req + data.append({ + 'method': method, + 'params': kwargs, + 'jsonrpc': '2.0', + 'id': method, + }) + data = json.dumps(data) + + headers = { + 'Content-Type': 'application/json', + } - headers = {} if self.conf('password'): - headers = { - 'Authorization': "Basic %s" % base64.encodestring('%s:%s' % (self.conf('username'), self.conf('password')))[:-1] - } + base64string = base64.encodestring('%s:%s' % (self.conf('username'), self.conf('password'))).replace('\n', '') + headers['Authorization'] = 'Basic %s' % base64string - try: - self.urlopen(url, headers = headers, show_error = False) - except: - log.error("Couldn't sent command to XBMC") - return False + log.debug('Sending request to %s: %s', (host, data)) + rdata = self.urlopen(server, headers = headers, params = data, multipart = True) + response = json.loads(rdata) + log.debug('Returned from request %s: %s', (host, response)) + + return response - log.info('XBMC notification to %s successful.', host) - return True diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index 5f3a9a44..46847154 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -124,7 +124,7 @@ class Plugin(object): try: if multipart: - log.info('Opening multipart url: %s, params: %s', (url, [x for x in params.iterkeys()])) + log.info('Opening multipart url: %s, params: %s', (url, [x for x in params.iterkeys()] if isinstance(params, dict) else 'with data')) request = urllib2.Request(url, params, headers) cookies = cookielib.CookieJar() From 19f74e398f3e6a0054411474ef939f213635036f Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 21 Oct 2012 14:38:58 +0200 Subject: [PATCH 78/92] Commit before adding more info --- couchpotato/core/plugins/searcher/main.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index edad31f7..7e3aefdc 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -181,7 +181,9 @@ class Searcher(Plugin): ) db.add(rls) else: - [db.delete(info) for info in rls.info] + [db.delete(old_info) for old_info in rls.info] + + db.commit() for info in nzb: try: @@ -196,9 +198,9 @@ class Searcher(Plugin): except InterfaceError: log.debug('Couldn\'t add %s to ReleaseInfo: %s', (info, traceback.format_exc())) - nzb['status_id'] = rls.status_id + db.commit() - db.commit() + nzb['status_id'] = rls.status_id for nzb in sorted_results: From bcdc633a5e727c7396d56e00b67226e8b1b07620 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 21 Oct 2012 15:26:29 +0200 Subject: [PATCH 79/92] Use urlopen for Prowl notifier. fix #932 --- couchpotato/core/notifications/prowl/main.py | 34 +++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/couchpotato/core/notifications/prowl/main.py b/couchpotato/core/notifications/prowl/main.py index 715965db..0990d0d1 100644 --- a/couchpotato/core/notifications/prowl/main.py +++ b/couchpotato/core/notifications/prowl/main.py @@ -1,39 +1,35 @@ -from couchpotato.core.helpers.encoding import toUnicode, tryUrlencode +from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.logger import CPLog from couchpotato.core.notifications.base import Notification -from httplib import HTTPSConnection +import traceback log = CPLog(__name__) class Prowl(Notification): + urls = { + 'api': 'https://api.prowlapp.com/publicapi/add' + } + def notify(self, message = '', data = {}, listener = None): if self.isDisabled(): return - http_handler = HTTPSConnection('api.prowlapp.com') - data = { 'apikey': self.conf('api_key'), 'application': self.default_title, 'description': toUnicode(message), 'priority': self.conf('priority'), } + headers = { + 'Content-type': 'application/x-www-form-urlencoded' + } - http_handler.request('POST', - '/publicapi/add', - headers = {'Content-type': 'application/x-www-form-urlencoded'}, - body = tryUrlencode(data) - ) - response = http_handler.getresponse() - request_status = response.status - - if request_status == 200: + try: + self.urlopen(self.urls['api'], headers = headers, params = data, multipart = True, show_error = False) log.info('Prowl notifications sent.') return True - elif request_status == 401: - log.error('Prowl auth failed: %s', response.reason) - return False - else: - log.error('Prowl notification failed.') - return False + except: + log.error('Prowl failed: %s', traceback.format_exc()) + + return False From 4fb7467e972a5f84c9b3dae6788bc4140ab89d06 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 21 Oct 2012 16:14:11 +0200 Subject: [PATCH 80/92] Send 2 tweets when message is above 140 chars. fix #441 --- .../core/notifications/twitter/main.py | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/couchpotato/core/notifications/twitter/main.py b/couchpotato/core/notifications/twitter/main.py index a5c16a73..bbb9262b 100644 --- a/couchpotato/core/notifications/twitter/main.py +++ b/couchpotato/core/notifications/twitter/main.py @@ -38,22 +38,33 @@ class Twitter(Notification): direct_message = self.conf('direct_message') direct_message_users = self.conf('screen_name') - + mention = self.conf('mention') + mention_tag = None if mention: if direct_message: direct_message_users = '%s %s' % (direct_message_users, mention) - direct_message_users = direct_message_users.replace('@',' ') - direct_message_users = direct_message_users.replace(',',' ') + direct_message_users = direct_message_users.replace('@', ' ') + direct_message_users = direct_message_users.replace(',', ' ') else: - message = '%s @%s' % (message, mention.lstrip('@')) + mention_tag = '@%s' % mention.lstrip('@') + message = '%s %s' % (message, mention_tag) try: if direct_message: for user in direct_message_users.split(): api.PostDirectMessage(user, '[%s] %s' % (self.default_title, message)) else: - api.PostUpdate('[%s] %s' % (self.default_title, message)) + update_message = '[%s] %s' % (self.default_title, message) + if len(update_message) > 140: + if mention_tag: + api.PostUpdate(update_message[:135 - len(mention_tag)] + ('%s 1/2 ' % mention_tag)) + api.PostUpdate(update_message[135 - len(mention_tag):] + ('%s 2/2 ' % mention_tag)) + else: + api.PostUpdate(update_message[:135] + ' 1/2') + api.PostUpdate(update_message[135:] + ' 2/2') + else: + api.PostUpdate(update_message) except Exception, e: log.error('Error sending tweet: %s', e) return False From 6f7b56510365aa0df7e5e9e0418532cea73829c2 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 21 Oct 2012 18:07:14 +0200 Subject: [PATCH 81/92] Use multiple tag when renaming extras. fix #652 --- couchpotato/core/plugins/renamer/main.py | 53 ++++++++++++++---------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 670e5d67..6487bedc 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -129,6 +129,8 @@ class Renamer(Plugin): 'resolution_width': group['meta_data'].get('resolution_width'), 'resolution_height': group['meta_data'].get('resolution_height'), 'imdb_id': library['identifier'], + 'cd': '', + 'cd_nr': '', } for file_type in group['files']: @@ -146,7 +148,7 @@ class Renamer(Plugin): continue # Move other files - multiple = len(group['files']['movie']) > 1 and not group['is_dvd'] + multiple = len(group['files'][file_type]) > 1 and not group['is_dvd'] cd = 1 if multiple else 0 for current_file in sorted(list(group['files'][file_type])): @@ -159,23 +161,19 @@ class Renamer(Plugin): replacements['ext'] = getExt(current_file) # cd # - replacements['cd'] = ' cd%d' % cd if cd else '' - replacements['cd_nr'] = cd + replacements['cd'] = ' cd%d' % cd if multiple else '' + replacements['cd_nr'] = cd if multiple else '' # Naming final_folder_name = self.doReplace(folder_name, replacements) final_file_name = self.doReplace(file_name, replacements) replacements['filename'] = final_file_name[:-(len(getExt(final_file_name)) + 1)] - # Group filename without cd extension - replacements['cd'] = '' - replacements['cd_nr'] = '' - # Meta naming if file_type is 'trailer': - final_file_name = self.doReplace(trailer_name, replacements) + final_file_name = self.doReplace(trailer_name, replacements, remove_multiple = True) elif file_type is 'nfo': - final_file_name = self.doReplace(nfo_name, replacements) + final_file_name = self.doReplace(nfo_name, replacements, remove_multiple = True) # Seperator replace if separator: @@ -206,10 +204,16 @@ class Renamer(Plugin): # Check for extra subtitle files if file_type is 'subtitle': - # rename subtitles with or without language - rename_files[current_file] = os.path.join(destination, final_folder_name, final_file_name) + remove_multiple = False + if len(group['files']['movie']) == 1: + remove_multiple = True + sub_langs = group['subtitle_language'].get(current_file, []) + # rename subtitles with or without language + sub_name = self.doReplace(file_name, replacements, remove_multiple = remove_multiple) + rename_files[current_file] = os.path.join(destination, final_folder_name, sub_name) + rename_extras = self.getRenameExtras( extra_type = 'subtitle_extra', replacements = replacements, @@ -217,20 +221,19 @@ class Renamer(Plugin): file_name = file_name, destination = destination, group = group, - current_file = current_file + current_file = current_file, + remove_multiple = remove_multiple, ) - # Don't add language if multiple languages in 1 file - if len(sub_langs) > 1: - rename_files[current_file] = os.path.join(destination, final_folder_name, final_file_name) - elif len(sub_langs) == 1: + # Don't add language if multiple languages in 1 subtitle file + if len(sub_langs) == 1: sub_name = final_file_name.replace(replacements['ext'], '%s.%s' % (sub_langs[0], replacements['ext'])) rename_files[current_file] = os.path.join(destination, final_folder_name, sub_name) rename_files = mergeDicts(rename_files, rename_extras) # Filename without cd etc - if file_type is 'movie': + elif file_type is 'movie': rename_extras = self.getRenameExtras( extra_type = 'movie_extra', replacements = replacements, @@ -242,7 +245,7 @@ class Renamer(Plugin): ) rename_files = mergeDicts(rename_files, rename_extras) - group['filename'] = self.doReplace(file_name, replacements)[:-(len(getExt(final_file_name)) + 1)] + group['filename'] = self.doReplace(file_name, replacements, remove_multiple = True)[:-(len(getExt(final_file_name)) + 1)] group['destination_dir'] = os.path.join(destination, final_folder_name) if multiple: @@ -387,8 +390,9 @@ class Renamer(Plugin): self.renaming_started = False - def getRenameExtras(self, extra_type = '', replacements = {}, folder_name = '', file_name = '', destination = '', group = {}, current_file = ''): + def getRenameExtras(self, extra_type = '', replacements = {}, folder_name = '', file_name = '', destination = '', group = {}, current_file = '', remove_multiple = False): + replacements = replacements.copy() rename_files = {} def test(s): @@ -397,8 +401,8 @@ class Renamer(Plugin): for extra in set(filter(test, group['files'][extra_type])): replacements['ext'] = getExt(extra) - final_folder_name = self.doReplace(folder_name, replacements) - final_file_name = self.doReplace(file_name, replacements) + final_folder_name = self.doReplace(folder_name, replacements, remove_multiple = remove_multiple) + final_file_name = self.doReplace(file_name, replacements, remove_multiple = remove_multiple) rename_files[extra] = os.path.join(destination, final_folder_name, final_file_name) return rename_files @@ -453,11 +457,16 @@ class Renamer(Plugin): return True - def doReplace(self, string, replacements): + def doReplace(self, string, replacements, remove_multiple = False): ''' replace confignames with the real thing ''' + replacements = replacements.copy() + if remove_multiple: + replacements['cd'] = '' + replacements['cd_nr'] = '' + replaced = toUnicode(string) for x, r in replacements.iteritems(): if r is not None: From 7b1f17c0626964673ec5c6db9950cdb602cfe500 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 21 Oct 2012 20:02:06 +0200 Subject: [PATCH 82/92] Limit threads per event --- couchpotato/core/event.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/event.py b/couchpotato/core/event.py index 3a5b9009..99ca6f50 100644 --- a/couchpotato/core/event.py +++ b/couchpotato/core/event.py @@ -19,7 +19,7 @@ def addEvent(name, handler, priority = 100): if events.get(name): e = events[name] else: - e = events[name] = Event(name = name, threads = 20, exc_info = True, traceback = True, lock = threading.RLock()) + e = events[name] = Event(name = name, threads = 10, exc_info = True, traceback = True, lock = threading.RLock()) def createHandle(*args, **kwargs): From 61a3a0386ed564c31b29c5317202ce5c71b7a43f Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 21 Oct 2012 20:02:24 +0200 Subject: [PATCH 83/92] Search after added all movies. fix #702 --- couchpotato/core/plugins/automation/main.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/automation/main.py b/couchpotato/core/plugins/automation/main.py index 12571e4f..9ac9d22f 100644 --- a/couchpotato/core/plugins/automation/main.py +++ b/couchpotato/core/plugins/automation/main.py @@ -18,9 +18,16 @@ class Automation(Plugin): def addMovies(self): movies = fireEvent('automation.get_movies', merge = True) + movie_ids = [] + for imdb_id in movies: prop_name = 'automation.added.%s' % imdb_id added = Env.prop(prop_name, default = False) if not added: - fireEvent('movie.add', params = {'identifier': imdb_id}, force_readd = False) + added_movie = fireEvent('movie.add', params = {'identifier': imdb_id}, force_readd = False, search_after = False, single = True) + movie_ids.append(added_movie['id']) Env.prop(prop_name, True) + + for movie_id in movie_ids: + movie_dict = fireEvent('movie.get', movie_id, single = True) + fireEvent('searcher.single', movie_dict) From ac04121dd3b3427cb6eba30fff86b9e48b33d6aa Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 21 Oct 2012 20:49:54 +0200 Subject: [PATCH 84/92] Just use q as name in imdbapi search. --- couchpotato/core/providers/movie/imdbapi/main.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/providers/movie/imdbapi/main.py b/couchpotato/core/providers/movie/imdbapi/main.py index 5b421c9c..53f503e1 100644 --- a/couchpotato/core/providers/movie/imdbapi/main.py +++ b/couchpotato/core/providers/movie/imdbapi/main.py @@ -27,8 +27,10 @@ class IMDBAPI(MovieProvider): name_year = fireEvent('scanner.name_year', q, single = True) - if not q or not name_year or (name_year and not name_year.get('name')): - return [] + if not name_year or (name_year and not name_year.get('name')): + name_year = { + 'name': q + } cache_key = 'imdbapi.cache.%s' % q cached = self.getCache(cache_key, self.urls['search'] % tryUrlencode({'t': name_year.get('name'), 'y': name_year.get('year', '')}), timeout = 3) From a432ad4f5a71690ba423fb58dc647e375e04c5a9 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 22 Oct 2012 21:42:42 +0200 Subject: [PATCH 85/92] Use new kat.ph url. fix #959 Also use https while we're at it. --- .../core/providers/torrent/kickasstorrents/main.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/couchpotato/core/providers/torrent/kickasstorrents/main.py b/couchpotato/core/providers/torrent/kickasstorrents/main.py index 6c157a6b..f59d8df5 100644 --- a/couchpotato/core/providers/torrent/kickasstorrents/main.py +++ b/couchpotato/core/providers/torrent/kickasstorrents/main.py @@ -1,6 +1,7 @@ from bs4 import BeautifulSoup from couchpotato.core.event import fireEvent -from couchpotato.core.helpers.variable import tryInt +from couchpotato.core.helpers.encoding import simplifyString +from couchpotato.core.helpers.variable import tryInt, getTitle from couchpotato.core.logger import CPLog from couchpotato.core.providers.torrent.base import TorrentProvider import re @@ -12,9 +13,9 @@ log = CPLog(__name__) class KickAssTorrents(TorrentProvider): urls = { - 'test': 'http://kat.ph/', - 'detail': 'http://kat.ph/%s', - 'search': 'http://kat.ph/i%s/', + 'test': 'https://kat.ph/', + 'detail': 'https://kat.ph/%s', + 'search': 'https://kat.ph/%s-i%s/', } cat_ids = [ @@ -35,8 +36,10 @@ class KickAssTorrents(TorrentProvider): if self.isDisabled(): return results + title = simplifyString(getTitle(movie['library'])).replace(' ', '-') + cache_key = 'kickasstorrents.%s.%s' % (movie['library']['identifier'], quality.get('identifier')) - data = self.getCache(cache_key, self.urls['search'] % (movie['library']['identifier'].replace('tt', ''))) + data = self.getCache(cache_key, self.urls['search'] % (title, movie['library']['identifier'].replace('tt', ''))) if data: cat_ids = self.getCatId(quality['identifier']) From b71f003ad84c1e8caa3eb7be74e869e482a903e7 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 22 Oct 2012 22:22:52 +0200 Subject: [PATCH 86/92] Use secure connections when available. --- couchpotato/core/providers/automation/bluray/main.py | 1 - couchpotato/core/providers/nzb/mysterbin/__init__.py | 2 +- couchpotato/core/providers/nzb/newznab/__init__.py | 2 +- couchpotato/core/providers/nzb/nzbindex/__init__.py | 2 +- couchpotato/core/providers/nzb/nzbindex/main.py | 4 ++-- .../core/providers/torrent/passthepopcorn/__init__.py | 2 +- .../core/providers/torrent/publichd/__init__.py | 2 +- couchpotato/core/providers/torrent/publichd/main.py | 6 +++--- couchpotato/core/providers/torrent/scenehd/__init__.py | 2 +- couchpotato/core/providers/torrent/scenehd/main.py | 10 +++++----- 10 files changed, 16 insertions(+), 17 deletions(-) diff --git a/couchpotato/core/providers/automation/bluray/main.py b/couchpotato/core/providers/automation/bluray/main.py index 20f733b7..ac28152c 100644 --- a/couchpotato/core/providers/automation/bluray/main.py +++ b/couchpotato/core/providers/automation/bluray/main.py @@ -2,7 +2,6 @@ from couchpotato.core.helpers.rss import RSS from couchpotato.core.helpers.variable import md5, tryInt from couchpotato.core.logger import CPLog from couchpotato.core.providers.automation.base import Automation -from couchpotato.environment import Env import xml.etree.ElementTree as XMLTree log = CPLog(__name__) diff --git a/couchpotato/core/providers/nzb/mysterbin/__init__.py b/couchpotato/core/providers/nzb/mysterbin/__init__.py index b34f72fc..fd4de655 100644 --- a/couchpotato/core/providers/nzb/mysterbin/__init__.py +++ b/couchpotato/core/providers/nzb/mysterbin/__init__.py @@ -10,7 +10,7 @@ config = [{ 'tab': 'searcher', 'subtab': 'nzb_providers', 'name': 'Mysterbin', - 'description': 'Free provider, less accurate. See Mysterbin', + 'description': 'Free provider, less accurate. See Mysterbin', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/providers/nzb/newznab/__init__.py b/couchpotato/core/providers/nzb/newznab/__init__.py index 712f03e5..b0e8b484 100644 --- a/couchpotato/core/providers/nzb/newznab/__init__.py +++ b/couchpotato/core/providers/nzb/newznab/__init__.py @@ -11,7 +11,7 @@ config = [{ 'subtab': 'nzb_providers', 'name': 'newznab', 'order': 10, - 'description': 'Enable multiple NewzNab providers such as NZB.su and nzbs.org', + 'description': 'Enable multiple NewzNab providers such as NZB.su and nzbs.org', 'wizard': True, 'options': [ { diff --git a/couchpotato/core/providers/nzb/nzbindex/__init__.py b/couchpotato/core/providers/nzb/nzbindex/__init__.py index 5bf5cd4d..51ee6d94 100644 --- a/couchpotato/core/providers/nzb/nzbindex/__init__.py +++ b/couchpotato/core/providers/nzb/nzbindex/__init__.py @@ -10,7 +10,7 @@ config = [{ 'tab': 'searcher', 'subtab': 'nzb_providers', 'name': 'nzbindex', - 'description': 'Free provider, less accurate. See NZBIndex', + 'description': 'Free provider, less accurate. See NZBIndex', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/providers/nzb/nzbindex/main.py b/couchpotato/core/providers/nzb/nzbindex/main.py index ee2092c2..109792e0 100644 --- a/couchpotato/core/providers/nzb/nzbindex/main.py +++ b/couchpotato/core/providers/nzb/nzbindex/main.py @@ -19,8 +19,8 @@ log = CPLog(__name__) class NzbIndex(NZBProvider, RSS): urls = { - 'download': 'http://www.nzbindex.nl/download/', - 'api': 'http://www.nzbindex.nl/rss/', + 'download': 'https://www.nzbindex.com/download/', + 'api': 'https://www.nzbindex.com/rss/', } http_time_between_calls = 1 # Seconds diff --git a/couchpotato/core/providers/torrent/passthepopcorn/__init__.py b/couchpotato/core/providers/torrent/passthepopcorn/__init__.py index 44d98cb7..507c1042 100644 --- a/couchpotato/core/providers/torrent/passthepopcorn/__init__.py +++ b/couchpotato/core/providers/torrent/passthepopcorn/__init__.py @@ -10,7 +10,7 @@ config = [{ 'tab': 'searcher', 'subtab': 'torrent_providers', 'name': 'PassThePopcorn', - 'description': 'See PassThePopcorn.me', + 'description': 'See PassThePopcorn.me', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/providers/torrent/publichd/__init__.py b/couchpotato/core/providers/torrent/publichd/__init__.py index edffeba8..648c6766 100644 --- a/couchpotato/core/providers/torrent/publichd/__init__.py +++ b/couchpotato/core/providers/torrent/publichd/__init__.py @@ -10,7 +10,7 @@ config = [{ 'tab': 'searcher', 'subtab': 'torrent_providers', 'name': 'PublicHD', - 'description': 'Public Torrent site with only HD content. See PublicHD', + 'description': 'Public Torrent site with only HD content. See PublicHD', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/providers/torrent/publichd/main.py b/couchpotato/core/providers/torrent/publichd/main.py index 5996fe92..c43d1ab7 100644 --- a/couchpotato/core/providers/torrent/publichd/main.py +++ b/couchpotato/core/providers/torrent/publichd/main.py @@ -14,9 +14,9 @@ log = CPLog(__name__) class PublicHD(TorrentProvider): urls = { - 'test': 'http://publichd.eu', - 'detail': 'http://publichd.eu/index.php?page=torrent-details&id=%s', - 'search': 'http://publichd.eu/index.php', + 'test': 'https://publichd.eu', + 'detail': 'https://publichd.eu/index.php?page=torrent-details&id=%s', + 'search': 'https://publichd.eu/index.php', } http_time_between_calls = 0 diff --git a/couchpotato/core/providers/torrent/scenehd/__init__.py b/couchpotato/core/providers/torrent/scenehd/__init__.py index a3d03130..69cf8a17 100644 --- a/couchpotato/core/providers/torrent/scenehd/__init__.py +++ b/couchpotato/core/providers/torrent/scenehd/__init__.py @@ -10,7 +10,7 @@ config = [{ 'tab': 'searcher', 'subtab': 'torrent_providers', 'name': 'SceneHD', - 'description': 'See SceneHD', + 'description': 'See SceneHD', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/providers/torrent/scenehd/main.py b/couchpotato/core/providers/torrent/scenehd/main.py index 596cb5bb..40e0bafa 100644 --- a/couchpotato/core/providers/torrent/scenehd/main.py +++ b/couchpotato/core/providers/torrent/scenehd/main.py @@ -12,11 +12,11 @@ log = CPLog(__name__) class SceneHD(TorrentProvider): urls = { - 'test': 'http://scenehd.org/', - 'login' : 'http://scenehd.org/takelogin.php', - 'detail': 'http://scenehd.org/details.php?id=%s', - 'search': 'http://scenehd.org/browse.php?ajax', - 'download': 'http://scenehd.org/download.php?id=%s', + 'test': 'https://scenehd.org/', + 'login' : 'https://scenehd.org/takelogin.php', + 'detail': 'https://scenehd.org/details.php?id=%s', + 'search': 'https://scenehd.org/browse.php?ajax', + 'download': 'https://scenehd.org/download.php?id=%s', } http_time_between_calls = 1 #seconds From e918e6b12faae7c2a9f0b02d586a6b22b95f0aeb Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 23 Oct 2012 00:20:04 +0200 Subject: [PATCH 87/92] Check watchlist adds in automation plugin, not the providers. fix #838 --- couchpotato/core/plugins/automation/main.py | 5 +++-- couchpotato/core/plugins/movie/main.py | 4 ++-- couchpotato/core/providers/automation/base.py | 9 +++++++++ .../core/providers/automation/imdb/main.py | 17 ----------------- .../core/providers/automation/movies_io/main.py | 15 --------------- 5 files changed, 14 insertions(+), 36 deletions(-) diff --git a/couchpotato/core/plugins/automation/main.py b/couchpotato/core/plugins/automation/main.py index 9ac9d22f..f4ede40d 100644 --- a/couchpotato/core/plugins/automation/main.py +++ b/couchpotato/core/plugins/automation/main.py @@ -24,8 +24,9 @@ class Automation(Plugin): prop_name = 'automation.added.%s' % imdb_id added = Env.prop(prop_name, default = False) if not added: - added_movie = fireEvent('movie.add', params = {'identifier': imdb_id}, force_readd = False, search_after = False, single = True) - movie_ids.append(added_movie['id']) + added_movie = fireEvent('movie.add', params = {'identifier': imdb_id}, force_readd = False, search_after = False, update_library = True, single = True) + if added_movie: + movie_ids.append(added_movie['id']) Env.prop(prop_name, True) for movie_id in movie_ids: diff --git a/couchpotato/core/plugins/movie/main.py b/couchpotato/core/plugins/movie/main.py index 821eea18..8b0761c1 100644 --- a/couchpotato/core/plugins/movie/main.py +++ b/couchpotato/core/plugins/movie/main.py @@ -283,7 +283,7 @@ class MoviePlugin(Plugin): 'movies': movies, }) - def add(self, params = {}, force_readd = True, search_after = True): + def add(self, params = {}, force_readd = True, search_after = True, update_library = False): if not params.get('identifier'): msg = 'Can\'t add movie without imdb identifier.' @@ -303,7 +303,7 @@ class MoviePlugin(Plugin): pass - library = fireEvent('library.add', single = True, attrs = params, update_after = False) + library = fireEvent('library.add', single = True, attrs = params, update_after = update_library) # Status status_active = fireEvent('status.add', 'active', single = True) diff --git a/couchpotato/core/providers/automation/base.py b/couchpotato/core/providers/automation/base.py index d3af2632..9f86ad12 100644 --- a/couchpotato/core/providers/automation/base.py +++ b/couchpotato/core/providers/automation/base.py @@ -28,9 +28,18 @@ class Automation(Plugin): return self.getIMDBids() def search(self, name, year = None, imdb_only = False): + + prop_name = 'automation.cached.%s.%s' % (name, year) + cached_imdb = Env.prop(prop_name, default = False) + if cached_imdb and imdb_only: + return cached_imdb + result = fireEvent('movie.search', q = '%s %s' % (name, year if year else ''), limit = 1, merge = True) if len(result) > 0: + if imdb_only and result[0].get('imdb'): + Env.prop(prop_name, result[0].get('imdb')) + return result[0].get('imdb') if imdb_only else result[0] else: return None diff --git a/couchpotato/core/providers/automation/imdb/main.py b/couchpotato/core/providers/automation/imdb/main.py index 6b8cbf79..a4511b49 100644 --- a/couchpotato/core/providers/automation/imdb/main.py +++ b/couchpotato/core/providers/automation/imdb/main.py @@ -2,9 +2,6 @@ from couchpotato.core.helpers.rss import RSS from couchpotato.core.helpers.variable import md5, getImdb from couchpotato.core.logger import CPLog from couchpotato.core.providers.automation.base import Automation -from couchpotato.environment import Env -from dateutil.parser import parse -import time import traceback import xml.etree.ElementTree as XMLTree @@ -34,10 +31,6 @@ class IMDB(Automation, RSS): log.error('This isn\'t the correct url.: %s', rss_url) continue - prop_name = 'automation.imdb.last_update.%s' % md5(rss_url) - last_update = float(Env.prop(prop_name, default = 0)) - - last_movie_added = 0 try: cache_key = 'imdb.rss.%s' % md5(rss_url) @@ -46,20 +39,10 @@ class IMDB(Automation, RSS): rss_movies = self.getElements(data, 'channel/item') for movie in rss_movies: - created = int(time.mktime(parse(self.getTextElement(movie, "pubDate")).timetuple())) imdb = getImdb(self.getTextElement(movie, "link")) - - if created > last_movie_added: - last_movie_added = created - - if not imdb or created <= last_update: - continue - movies.append(imdb) except: log.error('Failed loading IMDB watchlist: %s %s', (rss_url, traceback.format_exc())) - Env.prop(prop_name, last_movie_added) - return movies diff --git a/couchpotato/core/providers/automation/movies_io/main.py b/couchpotato/core/providers/automation/movies_io/main.py index 3a5a2f0e..5875a4d9 100644 --- a/couchpotato/core/providers/automation/movies_io/main.py +++ b/couchpotato/core/providers/automation/movies_io/main.py @@ -3,10 +3,7 @@ from couchpotato.core.helpers.rss import RSS from couchpotato.core.helpers.variable import md5 from couchpotato.core.logger import CPLog from couchpotato.core.providers.automation.base import Automation -from couchpotato.environment import Env -from dateutil.parser import parse from xml.etree.ElementTree import ParseError -import time import traceback import xml.etree.ElementTree as XMLTree @@ -33,10 +30,6 @@ class MoviesIO(Automation, RSS): if not enablers[index]: continue - prop_name = 'automation.moviesio.last_update.%s' % md5(rss_url) - last_update = float(Env.prop(prop_name, default = 0)) - - last_movie_added = 0 try: cache_key = 'imdb.rss.%s' % md5(rss_url) @@ -45,12 +38,6 @@ class MoviesIO(Automation, RSS): rss_movies = self.getElements(data, 'channel/item') for movie in rss_movies: - created = int(time.mktime(parse(self.getTextElement(movie, "pubDate")).timetuple())) - - if created > last_movie_added: - last_movie_added = created - if created <= last_update: - continue nameyear = fireEvent('scanner.name_year', self.getTextElement(movie, "title"), single = True) imdb = self.search(nameyear.get('name'), nameyear.get('year'), imdb_only = True) @@ -64,6 +51,4 @@ class MoviesIO(Automation, RSS): except: log.error('Failed loading Movies.io watchlist: %s %s', (rss_url, traceback.format_exc())) - Env.prop(prop_name, last_movie_added) - return movies From d636314971c662a6adfa75dbf8ceffd534241d8d Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 26 Oct 2012 14:53:35 +0200 Subject: [PATCH 88/92] Contributing.md --- contribute.md | 1 - contributing.md | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) delete mode 100644 contribute.md create mode 100644 contributing.md diff --git a/contribute.md b/contribute.md deleted file mode 100644 index fce79f7f..00000000 --- a/contribute.md +++ /dev/null @@ -1 +0,0 @@ -So you feel like \ No newline at end of file diff --git a/contributing.md b/contributing.md new file mode 100644 index 00000000..5bb77037 --- /dev/null +++ b/contributing.md @@ -0,0 +1,14 @@ +#So you feel like posting a bug, sending me a pull request or just telling me how awesome I am. No problem! + +##Just make sure you think of the following things: + + * Search through the existing (and closed) issues first. See if you can get your answer there. + * Double check the result manually, because it could be an external issue. + * Post logs! Without seeing what is going on, I can't reproduce the error. + * What are you settings for the specific problem + * What providers are you using. (While your logs include these, scanning through hundred of lines of log isn't my hobby) + * Give me a short step by step of how to reproduce + * What hardware / OS are you using and what are the limits? NAS can be slow and maybe have a different python installed then when you use CP on OSX or Windows for example. + * I will mark issues with the "can't reproduce" tag. Don't go asking me "why closed" if it clearly says the issue in the tag ;) + +**If I don't get enough info, the change of the issue getting closed is a lot bigger ;)** \ No newline at end of file From a86522a81086dbea5805d3dd42e9997e66264215 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 26 Oct 2012 22:02:17 +0200 Subject: [PATCH 89/92] Don't download next when the release isn't found in downloaded. fix #924 --- couchpotato/core/plugins/renamer/main.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 6487bedc..207af6b3 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -3,7 +3,8 @@ from couchpotato.api import addApiView from couchpotato.core.event import addEvent, fireEvent, fireEventAsync from couchpotato.core.helpers.encoding import toUnicode, ss from couchpotato.core.helpers.request import jsonified -from couchpotato.core.helpers.variable import getExt, mergeDicts, getTitle +from couchpotato.core.helpers.variable import getExt, mergeDicts, getTitle, \ + getImdb from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin from couchpotato.core.settings.model import Library, File, Profile, Release @@ -521,7 +522,7 @@ class Renamer(Plugin): if rels: self.checking_snatched = True log.debug('Checking status snatched releases...') - # get queue and history (once) from SABnzbd + statuses = fireEvent('download.status', merge = True) if not statuses: log.debug('Download status functionality is not implemented for active downloaders.') @@ -548,7 +549,7 @@ class Renamer(Plugin): found = False for item in statuses: - if item['name'] == nzbname: + if item['name'] == nzbname or getImdb(item['name']) == movie_dict['library']['identifier']: timeleft = 'N/A' if item['timeleft'] == -1 else item['timeleft'] log.debug('Found %s: %s, time to go: %s', (item['name'], item['status'].upper(), timeleft)) @@ -572,11 +573,6 @@ class Renamer(Plugin): if not found: log.info('%s not found in downloaders', nzbname) - rel.status_id = ignored_status.get('id') - db.commit() - - if self.conf('next_on_failed'): - fireEvent('searcher.try_next_release', movie_id = rel.movie_id) except: log.error('Failed checking for release in downloader: %s', traceback.format_exc()) From 7420785eaf1060cf9786703f7471663d5153fa30 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 26 Oct 2012 22:14:48 +0200 Subject: [PATCH 90/92] Show branch on about page --- couchpotato/core/_base/updater/main.py | 2 +- couchpotato/static/scripts/page/about.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/_base/updater/main.py b/couchpotato/core/_base/updater/main.py index fabc4596..dab8077f 100644 --- a/couchpotato/core/_base/updater/main.py +++ b/couchpotato/core/_base/updater/main.py @@ -406,7 +406,7 @@ class DesktopUpdater(BaseUpdater): 'last_check': self.last_check, 'update_version': self.update_version, 'version': self.getVersion(), - 'branch': 'desktop_build', + 'branch': self.branch, } def check(self): diff --git a/couchpotato/static/scripts/page/about.js b/couchpotato/static/scripts/page/about.js index d155800f..ba451c84 100644 --- a/couchpotato/static/scripts/page/about.js +++ b/couchpotato/static/scripts/page/about.js @@ -117,7 +117,7 @@ var AboutSettingTab = new Class({ var self = this; var date = new Date(json.version.date * 1000); self.version_text.set('text', json.version.hash + (json.version.date ? ' ('+date.toLocaleString()+')' : '')); - self.updater_type.set('text', json.version.type); + self.updater_type.set('text', json.version.type + ', ' + json.branch); } }); From d1e798323c631dd86cf51fa3850a49024e932881 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 26 Oct 2012 23:50:59 +0200 Subject: [PATCH 91/92] SAB error doesn't show anything. Add 1 more line --- couchpotato/core/downloaders/sabnzbd/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index 8b7383ba..9bd6922d 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -76,7 +76,7 @@ class Sabnzbd(Downloader): 'mode': 'queue', }) except: - log.error('Failed getting queue: %s', traceback.format_exc(0)) + log.error('Failed getting queue: %s', traceback.format_exc(1)) return False # Go through history items @@ -86,7 +86,7 @@ class Sabnzbd(Downloader): 'limit': 15, }) except: - log.error('Failed getting history json: %s', traceback.format_exc(0)) + log.error('Failed getting history json: %s', traceback.format_exc(1)) return False statuses = [] From b66af0b6c65258c6e7f2e44951e9cca42cfe7b86 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 27 Oct 2012 11:52:59 +0200 Subject: [PATCH 92/92] One up --- version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.py b/version.py index a038b504..fcba2b40 100644 --- a/version.py +++ b/version.py @@ -1,2 +1,2 @@ -VERSION = '2.0.0.pre2' +VERSION = '2.0.1' BRANCH = 'develop'