From 75838df107193f24fab2db52ce66ed04e976bfbd Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Tue, 22 Mar 2022 13:54:45 +0100 Subject: [PATCH 001/350] Handle timecode and audio state --- .../plugins/publish/extract_review_slate.py | 122 ++++++++++++++++-- 1 file changed, 110 insertions(+), 12 deletions(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 505ae75169..a21751aecc 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -10,7 +10,6 @@ from openpype.lib import ( get_ffmpeg_format_args, ) - class ExtractReviewSlate(openpype.api.Extractor): """ Will add slate frame at the start of the video files @@ -58,6 +57,7 @@ class ExtractReviewSlate(openpype.api.Extractor): pixel_aspect = inst_data.get("pixelAspect", 1) fps = inst_data.get("fps") + self.log.debug("fps {} ".format(fps)) for idx, repre in enumerate(inst_data["representations"]): self.log.debug("repre ({}): `{}`".format(idx + 1, repre)) @@ -82,12 +82,55 @@ class ExtractReviewSlate(openpype.api.Extractor): # - there may be a better way (checking `codec_type`?) input_width = None input_height = None + input_timecode = None + input_frame_rate = None + input_audio = False + audio_channels = None + audio_sample_rate = None + audio_channel_layout = None for stream in video_streams: - if "width" in stream and "height" in stream: - input_width = int(stream["width"]) - input_height = int(stream["height"]) - break - + self.log.debug("__ ffprobe: {}".format(stream)) + if "codec_type" in stream: + if stream["codec_type"] == "video": + if stream["tags"]["timecode"]: + # get timecode of the first frame + input_timecode = stream["tags"]["timecode"] + self.log.debug("__Video Timecode : {}".format(input_timecode)) + if "width" in stream and "height" in stream: + input_width = int(stream["width"]) + input_height = int(stream["height"]) + if "r_frame_rate" in stream: + # get frame rate in a form of x/y, like 24000/1001 for 23.976 + input_frame_rate = str(stream["r_frame_rate"]) + if stream["codec_type"] == "audio": + # get audio details for generating silent audio track for slate + if stream["channels"]: + audio_channels = str(stream["channels"]) + if stream["sample_rate"]: + audio_sample_rate = stream["sample_rate"] + if stream["channel_layout"]: + audio_channel_layout = stream["channel_layout"] + # calculate duration of one frame in seconds + if input_frame_rate: + # it is divided by two to make sure audio will be shorter then video + one_frame_duration = str( float(1.0 / eval(input_frame_rate)) / 2 ) + else: + # same sane default (1 frame @ 25 fps) + one_frame_duration = 0.04 + self.log.debug( + "One frame duration is {} sec".format(one_frame_duration)) + # confirm we gathered all needed audio parameters + if audio_channel_layout: + if audio_sample_rate: + if audio_channels: + input_audio = True + self.log.debug("__Audio : channels {}".format( + audio_channels)) + self.log.debug("__Audio : sample_rate {}".format( + audio_sample_rate)) + self.log.debug("__Audio : channel_layout {}".format( + audio_channel_layout)) + # Raise exception of any stream didn't define input resolution if input_width is None: raise AssertionError(( @@ -144,18 +187,34 @@ class ExtractReviewSlate(openpype.api.Extractor): input_args = [] output_args = [] + # if input has audio, add silent audio to the slate + if input_audio: + input_args.extend( + ["-f lavfi -i anullsrc=r={}:cl={}:d={}".format( + audio_sample_rate, + audio_channel_layout, + one_frame_duration + )] + ) # preset's input data if use_legacy_code: input_args.extend(repre["_profile"].get('input', [])) else: input_args.extend(repre["outputDef"].get('input', [])) - input_args.append("-loop 1 -i {}".format( + # enforce framerate before -i + input_args.append("-framerate {} -i {}".format( + input_frame_rate, path_to_subprocess_arg(slate_path) )) - input_args.extend([ - "-r {}".format(fps), - "-t 0.04" - ]) + # add timecode from source to the slate, substract one frame + if input_timecode: + offset_timecode = self._tc_offset( + str(input_timecode), + framerate=fps, + frame_offset=-1 + ) + self.log.debug("Timecode: `{}`".format(offset_timecode)) + input_args.extend(["-timecode {}".format(offset_timecode)]) if use_legacy_code: codec_args = repre["_profile"].get('codec', []) @@ -213,11 +272,16 @@ class ExtractReviewSlate(openpype.api.Extractor): width_scale, height_scale, to_width, to_height, width_half_pad, height_half_pad ) - + # add output frame rate as a filter, just in case + scaling_arg += ",fps={}".format(input_frame_rate) vf_back = self.add_video_filter_args(output_args, scaling_arg) # add it to output_args output_args.insert(0, vf_back) + # use video duration for silent audio duration + if input_audio: + output_args.append("-shortest") + # overrides output file output_args.append("-y") @@ -371,3 +435,37 @@ class ExtractReviewSlate(openpype.api.Extractor): ) return codec_args + + def _tc_offset(self, timecode='00:00:00:00', framerate=24.0, frame_offset=-1): + """Offsets timecode by frame""" + def _seconds(value, framerate): + if isinstance(value, str): + _zip_ft = zip((3600, 60, 1, 1/framerate), value.split(':')) + _s = sum(f * float(t) for f,t in _zip_ft) + elif isinstance(value, (int, float)): + _s = value / framerate + else: + _s = 0 + return _s + + def _frames(seconds, framerate, frame_offset): + _f = seconds * framerate + frame_offset + if _f < 0: + _f = framerate * 60 * 60 * 24 + _f + return _f + + def _timecode(seconds, framerate): + return '{h:02d}:{m:02d}:{s:02d}:{f:02d}' \ + .format(h=int(seconds/3600), + m=int(seconds/60%60), + s=int(seconds%60), + f=int(round((seconds-int(seconds))*framerate))) + drop = False + if ';' in timecode: + timecode = timecode.replace(';', ':') + drop = True + frames = _frames(_seconds(timecode, framerate), framerate, frame_offset) + tc = _timecode(_seconds(frames, framerate), framerate) + if drop: + tc = ';'.join(tc.rsplit(':', 1)) + return tc \ No newline at end of file From 2dd38c74c04814c33356a05dfda32efeda470ffd Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Tue, 22 Mar 2022 14:13:00 +0100 Subject: [PATCH 002/350] fix hound --- .../plugins/publish/extract_review_slate.py | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index a21751aecc..5cfb0997a5 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -95,15 +95,18 @@ class ExtractReviewSlate(openpype.api.Extractor): if stream["tags"]["timecode"]: # get timecode of the first frame input_timecode = stream["tags"]["timecode"] - self.log.debug("__Video Timecode : {}".format(input_timecode)) + self.log.debug("__Video Timecode : {}".format( + input_timecode)) if "width" in stream and "height" in stream: input_width = int(stream["width"]) input_height = int(stream["height"]) if "r_frame_rate" in stream: - # get frame rate in a form of x/y, like 24000/1001 for 23.976 + # get frame rate in a form of + # x/y, like 24000/1001 for 23.976 input_frame_rate = str(stream["r_frame_rate"]) if stream["codec_type"] == "audio": - # get audio details for generating silent audio track for slate + # get audio details + # for generating silent audio track for slate if stream["channels"]: audio_channels = str(stream["channels"]) if stream["sample_rate"]: @@ -112,8 +115,10 @@ class ExtractReviewSlate(openpype.api.Extractor): audio_channel_layout = stream["channel_layout"] # calculate duration of one frame in seconds if input_frame_rate: - # it is divided by two to make sure audio will be shorter then video - one_frame_duration = str( float(1.0 / eval(input_frame_rate)) / 2 ) + # it is halved to make sure audio will be shorter then video + one_frame_duration = str( + float(1.0 / eval(input_frame_rate)) / 2 + ) else: # same sane default (1 frame @ 25 fps) one_frame_duration = 0.04 @@ -436,7 +441,7 @@ class ExtractReviewSlate(openpype.api.Extractor): return codec_args - def _tc_offset(self, timecode='00:00:00:00', framerate=24.0, frame_offset=-1): + def _tc_offset(self, timecode, framerate=24.0, frame_offset=-1): """Offsets timecode by frame""" def _seconds(value, framerate): if isinstance(value, str): @@ -456,16 +461,20 @@ class ExtractReviewSlate(openpype.api.Extractor): def _timecode(seconds, framerate): return '{h:02d}:{m:02d}:{s:02d}:{f:02d}' \ - .format(h=int(seconds/3600), - m=int(seconds/60%60), - s=int(seconds%60), - f=int(round((seconds-int(seconds))*framerate))) + .format(h=int(seconds / 3600), + m=int(seconds / 60 % 60), + s=int(seconds % 60), + f=int(round((seconds -int(seconds)) * framerate))) drop = False if ';' in timecode: timecode = timecode.replace(';', ':') drop = True - frames = _frames(_seconds(timecode, framerate), framerate, frame_offset) + frames = _frames( + _seconds(timecode, framerate), + framerate, + frame_offset + ) tc = _timecode(_seconds(frames, framerate), framerate) if drop: tc = ';'.join(tc.rsplit(':', 1)) - return tc \ No newline at end of file + return tc From c67a5504516b2eddea46d230a1d7d6f9c7ec71c5 Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Tue, 22 Mar 2022 14:17:56 +0100 Subject: [PATCH 003/350] Fix Hound2 --- openpype/plugins/publish/extract_review_slate.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 5cfb0997a5..d6857c7915 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -105,7 +105,7 @@ class ExtractReviewSlate(openpype.api.Extractor): # x/y, like 24000/1001 for 23.976 input_frame_rate = str(stream["r_frame_rate"]) if stream["codec_type"] == "audio": - # get audio details + # get audio details # for generating silent audio track for slate if stream["channels"]: audio_channels = str(stream["channels"]) @@ -117,7 +117,7 @@ class ExtractReviewSlate(openpype.api.Extractor): if input_frame_rate: # it is halved to make sure audio will be shorter then video one_frame_duration = str( - float(1.0 / eval(input_frame_rate)) / 2 + float(1.0 / eval(input_frame_rate)) / 2 ) else: # same sane default (1 frame @ 25 fps) @@ -460,11 +460,11 @@ class ExtractReviewSlate(openpype.api.Extractor): return _f def _timecode(seconds, framerate): - return '{h:02d}:{m:02d}:{s:02d}:{f:02d}' \ - .format(h=int(seconds / 3600), - m=int(seconds / 60 % 60), - s=int(seconds % 60), - f=int(round((seconds -int(seconds)) * framerate))) + return '{h:02d}:{m:02d}:{s:02d}:{f:02d}'.format( + h = int(seconds / 3600), + m = int(seconds / 60 % 60), + s = int(seconds % 60), + f = int(round((seconds - int(seconds)) * framerate))) drop = False if ';' in timecode: timecode = timecode.replace(';', ':') From 406575ebd8c7056febce78b0575e85204458d10b Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Tue, 22 Mar 2022 14:22:27 +0100 Subject: [PATCH 004/350] Hound3 --- .../projects_schema/schemas/schema_representation_tags.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_representation_tags.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_representation_tags.json index 7607e1a8c1..484fbf9d07 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_representation_tags.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_representation_tags.json @@ -24,6 +24,9 @@ }, { "sequence": "Output as image sequence" + }, + { + "no-audio": "Do not add audio" } ] } From 16817c30f67476578d30130b1aa721c66b7aa2dc Mon Sep 17 00:00:00 2001 From: Jiri Sindelar <45896205+jrsndl@users.noreply.github.com> Date: Tue, 22 Mar 2022 14:25:07 +0100 Subject: [PATCH 005/350] remove no-audio tag settings --- .../schemas/schema_representation_tags.json | 32 ------------------- 1 file changed, 32 deletions(-) delete mode 100644 openpype/settings/entities/schemas/projects_schema/schemas/schema_representation_tags.json diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_representation_tags.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_representation_tags.json deleted file mode 100644 index 484fbf9d07..0000000000 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_representation_tags.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "key": "tags", - "label": "Tags", - "type": "enum", - "multiselection": true, - "enum_items": [ - { - "burnin": "Add burnins" - }, - { - "review": "Create review" - }, - { - "ftrackreview": "Add review to Ftrack" - }, - { - "delete": "Delete output" - }, - { - "slate-frame": "Add slate frame" - }, - { - "no-handles": "Skip handle frames" - }, - { - "sequence": "Output as image sequence" - }, - { - "no-audio": "Do not add audio" - } - ] -} From f866bf2a757540c925a95864ccd2d9ac4d9b3a03 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 22 Mar 2022 16:36:41 +0100 Subject: [PATCH 006/350] adding back `schema_representation_tags` --- .../schemas/schema_representation_tags.json | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 openpype/settings/entities/schemas/projects_schema/schemas/schema_representation_tags.json diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_representation_tags.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_representation_tags.json new file mode 100644 index 0000000000..7607e1a8c1 --- /dev/null +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_representation_tags.json @@ -0,0 +1,29 @@ +{ + "key": "tags", + "label": "Tags", + "type": "enum", + "multiselection": true, + "enum_items": [ + { + "burnin": "Add burnins" + }, + { + "review": "Create review" + }, + { + "ftrackreview": "Add review to Ftrack" + }, + { + "delete": "Delete output" + }, + { + "slate-frame": "Add slate frame" + }, + { + "no-handles": "Skip handle frames" + }, + { + "sequence": "Output as image sequence" + } + ] +} From ef0210a98aba43e8a17ba23dc0a1cf57ad38034f Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Mon, 28 Mar 2022 16:48:01 +0200 Subject: [PATCH 007/350] Error Handling, ffmpeg fixes --- igniter/3} | 0 .../plugins/publish/extract_review_slate.py | 172 +++++++++--------- 2 files changed, 90 insertions(+), 82 deletions(-) create mode 100644 igniter/3} diff --git a/igniter/3} b/igniter/3} new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index d6857c7915..2854108022 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -1,4 +1,5 @@ import os +import shutil import openpype.api import pyblish from openpype.lib import ( @@ -73,74 +74,72 @@ class ExtractReviewSlate(openpype.api.Extractor): os.path.normpath(stagingdir), repre["files"]) self.log.debug("__ input_path: {}".format(input_path)) - video_streams = get_ffprobe_streams( + streams = get_ffprobe_streams( input_path, self.log ) - - # Try to find first stream with defined 'width' and 'height' - # - this is to avoid order of streams where audio can be as first - # - there may be a better way (checking `codec_type`?) - input_width = None - input_height = None - input_timecode = None - input_frame_rate = None - input_audio = False - audio_channels = None - audio_sample_rate = None - audio_channel_layout = None - for stream in video_streams: - self.log.debug("__ ffprobe: {}".format(stream)) + # get video metadata + for stream in streams: + input_timecode = None + input_width = None + input_height = None + input_frame_rate = None if "codec_type" in stream: if stream["codec_type"] == "video": - if stream["tags"]["timecode"]: - # get timecode of the first frame - input_timecode = stream["tags"]["timecode"] - self.log.debug("__Video Timecode : {}".format( - input_timecode)) + self.log.debug("__Ffprobe Video: {}".format(stream)) + tags = stream.get("tags") or {} + input_timecode = tags.get("timecode") or "" if "width" in stream and "height" in stream: - input_width = int(stream["width"]) - input_height = int(stream["height"]) + input_width = int(stream.get("width")) + input_height = int(stream.get("height")) if "r_frame_rate" in stream: # get frame rate in a form of # x/y, like 24000/1001 for 23.976 - input_frame_rate = str(stream["r_frame_rate"]) - if stream["codec_type"] == "audio": - # get audio details - # for generating silent audio track for slate - if stream["channels"]: - audio_channels = str(stream["channels"]) - if stream["sample_rate"]: - audio_sample_rate = stream["sample_rate"] - if stream["channel_layout"]: - audio_channel_layout = stream["channel_layout"] - # calculate duration of one frame in seconds - if input_frame_rate: - # it is halved to make sure audio will be shorter then video - one_frame_duration = str( - float(1.0 / eval(input_frame_rate)) / 2 - ) - else: - # same sane default (1 frame @ 25 fps) - one_frame_duration = 0.04 - self.log.debug( - "One frame duration is {} sec".format(one_frame_duration)) - # confirm we gathered all needed audio parameters - if audio_channel_layout: - if audio_sample_rate: - if audio_channels: - input_audio = True - self.log.debug("__Audio : channels {}".format( - audio_channels)) - self.log.debug("__Audio : sample_rate {}".format( - audio_sample_rate)) - self.log.debug("__Audio : channel_layout {}".format( - audio_channel_layout)) - + input_frame_rate = str(stream.get("r_frame_rate")) + if ( + input_timecode + and input_width + and input_height + and input_frame_rate + ): + break # Raise exception of any stream didn't define input resolution if input_width is None: raise AssertionError(( "FFprobe couldn't read resolution from input file: \"{}\"" ).format(input_path)) + # Get audio metadata + for stream in streams: + audio_channels = None + audio_sample_rate = None + audio_channel_layout = None + input_audio = False + if stream["codec_type"] == "audio": + self.log.debug("__Ffprobe Audio: {}".format(stream)) + if stream["channels"]: + audio_channels = str(stream.get("channels")) + if stream["sample_rate"]: + audio_sample_rate = str(stream.get("sample_rate")) + if stream["channel_layout"]: + audio_channel_layout = str(stream.get("channel_layout")) + if ( + audio_channels + and audio_sample_rate + and audio_channel_layout + ): + input_audio = True + break + # Get duration of one frame in micro seconds + one_frame_duration = "40000us" + if input_frame_rate: + items = input_frame_rate.split("/") + if len(items) == 1: + one_frame_duration = float(1.0) / float(items[0]) + elif len(items) == 2: + one_frame_duration = float(items[1]) / float(items[0]) + one_frame_duration *= 1000000 + one_frame_duration = str(int(one_frame_duration))+"us" + self.log.debug( + "One frame duration is {}".format(one_frame_duration)) # values are set in ExtractReview if use_legacy_code: @@ -192,7 +191,16 @@ class ExtractReviewSlate(openpype.api.Extractor): input_args = [] output_args = [] - # if input has audio, add silent audio to the slate + # preset's input data + if use_legacy_code: + input_args.extend(repre["_profile"].get('input', [])) + else: + input_args.extend(repre["outputDef"].get('input', [])) + + input_args.append("-loop 1 -i {}".format( + openpype.lib.path_to_subprocess_arg(slate_path) + )) + # if input has an audio, add silent audio to the slate if input_audio: input_args.extend( ["-f lavfi -i anullsrc=r={}:cl={}:d={}".format( @@ -201,16 +209,9 @@ class ExtractReviewSlate(openpype.api.Extractor): one_frame_duration )] ) - # preset's input data - if use_legacy_code: - input_args.extend(repre["_profile"].get('input', [])) - else: - input_args.extend(repre["outputDef"].get('input', [])) - # enforce framerate before -i - input_args.append("-framerate {} -i {}".format( - input_frame_rate, - path_to_subprocess_arg(slate_path) - )) + + input_args.extend(["-r {}".format(input_frame_rate)]) + input_args.extend(["-frames:v 1"]) # add timecode from source to the slate, substract one frame if input_timecode: offset_timecode = self._tc_offset( @@ -218,9 +219,14 @@ class ExtractReviewSlate(openpype.api.Extractor): framerate=fps, frame_offset=-1 ) - self.log.debug("Timecode: `{}`".format(offset_timecode)) - input_args.extend(["-timecode {}".format(offset_timecode)]) - + self.log.debug("Slate Timecode: `{}`".format( + offset_timecode + )) + if offset_timecode: + input_args.extend(["-timecode {}".format(offset_timecode)]) + else: + # fall back to input timecode if offset fails + input_args.extend(["-timecode {}".format(input_timecode)]) if use_legacy_code: codec_args = repre["_profile"].get('codec', []) output_args.extend(codec_args) @@ -283,10 +289,6 @@ class ExtractReviewSlate(openpype.api.Extractor): # add it to output_args output_args.insert(0, vf_back) - # use video duration for silent audio duration - if input_audio: - output_args.append("-shortest") - # overrides output file output_args.append("-y") @@ -334,17 +336,23 @@ class ExtractReviewSlate(openpype.api.Extractor): "-f", "concat", "-safe", "0", "-i", conc_text_path, - "-c", "copy", + "-c:v", "copy", output_path ] - - # ffmpeg concat subprocess - self.log.debug( - "Executing concat: {}".format(" ".join(concat_args)) - ) - openpype.api.run_subprocess( - concat_args, logger=self.log - ) + if not input_audio: + # ffmpeg concat subprocess + self.log.debug( + "Executing concat: {}".format(" ".join(concat_args)) + ) + openpype.api.run_subprocess( + concat_args, logger=self.log + ) + else: + self.log.warning("Audio found. Creating slate with audio" + " is not supported at this time. Outputing slate-less" + ":\n{}".format(input_file)) + # skip concatenating slate, use slate-less file instead + shutil.copyfile(input_path, output_path) self.log.debug("__ repre[tags]: {}".format(repre["tags"])) repre_update = { From 027081700e47ef4c5eddee20cb30d885b9a3c8d7 Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Mon, 28 Mar 2022 19:14:46 +0200 Subject: [PATCH 008/350] hound --- openpype/plugins/publish/extract_review_slate.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 2854108022..d2a7b9a12a 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -120,7 +120,8 @@ class ExtractReviewSlate(openpype.api.Extractor): if stream["sample_rate"]: audio_sample_rate = str(stream.get("sample_rate")) if stream["channel_layout"]: - audio_channel_layout = str(stream.get("channel_layout")) + audio_channel_layout = str( + stream.get("channel_layout")) if ( audio_channels and audio_sample_rate From 90e29c6f521bd78d84444c357171b6f7b499a8bf Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Mon, 28 Mar 2022 19:35:25 +0200 Subject: [PATCH 009/350] hound2 --- openpype/plugins/publish/extract_review_slate.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index d2a7b9a12a..037535342d 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -138,7 +138,7 @@ class ExtractReviewSlate(openpype.api.Extractor): elif len(items) == 2: one_frame_duration = float(items[1]) / float(items[0]) one_frame_duration *= 1000000 - one_frame_duration = str(int(one_frame_duration))+"us" + one_frame_duration = str(int(one_frame_duration)) + "us" self.log.debug( "One frame duration is {}".format(one_frame_duration)) @@ -199,8 +199,7 @@ class ExtractReviewSlate(openpype.api.Extractor): input_args.extend(repre["outputDef"].get('input', [])) input_args.append("-loop 1 -i {}".format( - openpype.lib.path_to_subprocess_arg(slate_path) - )) + openpype.lib.path_to_subprocess_arg(slate_path))) # if input has an audio, add silent audio to the slate if input_audio: input_args.extend( @@ -350,10 +349,10 @@ class ExtractReviewSlate(openpype.api.Extractor): ) else: self.log.warning("Audio found. Creating slate with audio" - " is not supported at this time. Outputing slate-less" - ":\n{}".format(input_file)) + " is not supported at this time. Outputing slate-less" + ":\n{}".format(input_file)) # skip concatenating slate, use slate-less file instead - shutil.copyfile(input_path, output_path) + shutil.copyfile(input_path, output_path) self.log.debug("__ repre[tags]: {}".format(repre["tags"])) repre_update = { From 13f6b03637e7d696ad45418856c6576883c9892f Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Mon, 28 Mar 2022 20:38:47 +0200 Subject: [PATCH 010/350] hound3 --- openpype/plugins/publish/extract_review_slate.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 037535342d..c8ee2ec7ed 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -348,7 +348,8 @@ class ExtractReviewSlate(openpype.api.Extractor): concat_args, logger=self.log ) else: - self.log.warning("Audio found. Creating slate with audio" + self.log.warning( + "Audio found. Creating slate with audio" " is not supported at this time. Outputing slate-less" ":\n{}".format(input_file)) # skip concatenating slate, use slate-less file instead From 0db0fa0de9fe085f48f62d2b1ffe766edf95e897 Mon Sep 17 00:00:00 2001 From: Jiri Sindelar <45896205+jrsndl@users.noreply.github.com> Date: Tue, 29 Mar 2022 09:27:33 +0200 Subject: [PATCH 011/350] stray empty file? --- igniter/3} | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 igniter/3} diff --git a/igniter/3} b/igniter/3} deleted file mode 100644 index e69de29bb2..0000000000 From e6fd10925db80eeb73038a06330617325e318aab Mon Sep 17 00:00:00 2001 From: Paolo Berto Durante Date: Sun, 10 Apr 2022 20:17:22 +0900 Subject: [PATCH 012/350] plugins: modified labels for multiverse creators/publishers/loader --- openpype/hosts/maya/plugins/create/create_multiverse_usd.py | 4 ++-- .../hosts/maya/plugins/create/create_multiverse_usd_over.py | 2 +- openpype/hosts/maya/plugins/load/load_multiverse_usd.py | 4 ++-- openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py | 4 ++-- .../hosts/maya/plugins/publish/extract_multiverse_usd_over.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/maya/plugins/create/create_multiverse_usd.py b/openpype/hosts/maya/plugins/create/create_multiverse_usd.py index b2266e5a57..ff08bf3015 100644 --- a/openpype/hosts/maya/plugins/create/create_multiverse_usd.py +++ b/openpype/hosts/maya/plugins/create/create_multiverse_usd.py @@ -2,10 +2,10 @@ from openpype.hosts.maya.api import plugin, lib class CreateMultiverseUsd(plugin.Creator): - """Multiverse USD data""" + """Multiverse USD asset data""" name = "usdMain" - label = "Multiverse USD" + label = "Multiverse USD Asset" family = "usd" icon = "cubes" diff --git a/openpype/hosts/maya/plugins/create/create_multiverse_usd_over.py b/openpype/hosts/maya/plugins/create/create_multiverse_usd_over.py index bb82ab2039..22c9ce1890 100644 --- a/openpype/hosts/maya/plugins/create/create_multiverse_usd_over.py +++ b/openpype/hosts/maya/plugins/create/create_multiverse_usd_over.py @@ -2,7 +2,7 @@ from openpype.hosts.maya.api import plugin, lib class CreateMultiverseUsdOver(plugin.Creator): - """Multiverse USD data""" + """Multiverse USD Override""" name = "usdOverrideMain" label = "Multiverse USD Override" diff --git a/openpype/hosts/maya/plugins/load/load_multiverse_usd.py b/openpype/hosts/maya/plugins/load/load_multiverse_usd.py index c03f2c5d92..ed0ffc8ef1 100644 --- a/openpype/hosts/maya/plugins/load/load_multiverse_usd.py +++ b/openpype/hosts/maya/plugins/load/load_multiverse_usd.py @@ -14,13 +14,13 @@ from openpype.hosts.maya.api.pipeline import containerise class MultiverseUsdLoader(load.LoaderPlugin): - """Load the USD by Multiverse""" + """Read USD data in a Multiverse Compound""" families = ["model", "usd", "usdComposition", "usdOverride", "pointcache", "animation"] representations = ["usd", "usda", "usdc", "usdz", "abc"] - label = "Read USD by Multiverse" + label = "Load USD to Multiverse" order = -10 icon = "code-fork" color = "orange" diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py index 4e4efdc32c..678a4eb7df 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py @@ -8,9 +8,9 @@ from openpype.hosts.maya.api.lib import maintained_selection class ExtractMultiverseUsd(openpype.api.Extractor): - """Extractor for USD by Multiverse.""" + """Extractor for Multiverse USD asset data.""" - label = "Extract Multiverse USD" + label = "Extract Multiverse USD Asset" hosts = ["maya"] families = ["usd"] diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py index ce0e8a392a..4a78635c8b 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py @@ -7,7 +7,7 @@ from maya import cmds class ExtractMultiverseUsdOverride(openpype.api.Extractor): - """Extractor for USD Override by Multiverse.""" + """Extractor for Multiverse USD Override.""" label = "Extract Multiverse USD Override" hosts = ["maya"] From 70fe3f87127b7476f6c3d84437e292dba5022459 Mon Sep 17 00:00:00 2001 From: Paolo Berto Durante Date: Sun, 10 Apr 2022 20:17:55 +0900 Subject: [PATCH 013/350] documentation: added initial multiverse docs --- website/docs/artist_hosts_maya.md | 163 ++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/website/docs/artist_hosts_maya.md b/website/docs/artist_hosts_maya.md index 73e89384e8..84285bc6dd 100644 --- a/website/docs/artist_hosts_maya.md +++ b/website/docs/artist_hosts_maya.md @@ -598,6 +598,169 @@ about customizing review process refer to [admin section](project_settings/setti If you don't move `modelMain` into `reviewMain`, review will be generated but it will be published as separate entity. + +## Working with Multiverse in OpenPype + +OpenPype supports creating, publishing and loading of [Multiverse | USD]( +https://multi-verse.io) data. + +More specifically it is possible to: + +- Create USD Assets, USD compositions and USD Overrides. This _creates_ OpenPype + instances as Maya set nodes that contain information for published USD data. +- Publish USD Assets, USD compositions and USD Overrides. This _writes_ USD + files to disk and _publishes_ information to the OpenPype database. +- Load any USD data into Multiverse "Compound" shape nodes. This _reads_ USD + files (and also Alembic files) into Maya by streaming them to the viewport. +- Rendering USD data procedurally with 3DelightNSI, Arnold, Redshift, + RenderMan and VRay. This reads USD files by streaming them procedurally to the renderer, at render time. + +USD files written by Multiverse are 100% native USD data, they can be exchanged +with any other DCC applications able to interchange USD. Likewise, Multiverse +can read native USD data created by other applications. All the extensions are +supported: `.usd`, `.usdc`, `.usda`, `.usdz`. Sequences of USD files can also be +read, as USD clips. + +It is also possible to load Alembic data (`.abc`) in Multiverse Compounds, +further compose it & override it in other USD files, and render it procedurally. +Alembic data is always converted on the fly (in memory) to USD data. USD clip +from Alembic data are also supported. + +### Configuration + +To configure Multiverse in OpenPype, a user with admin privileges needs to setup +a new tool in OpenPype Project Settings, using a similar configuration as +depicted here: + +![Maya - Multiverse Setup](assets/maya-multiverse_setup.png) + +For more information about setup of Multiverse please refer to: LINK. + + +### Understanding Assets, Compositions and Overrides + +In Multiverse there are three main concepts for representing USD data. + + +#### Assets + +In Multiverse, the term "asset" refers to a USD file that contains a hierarchy +of primitives (transforms and shapes). In Maya this is typically a hierarchy of +nodes, as it can be seen in Outliner, that is written out to a USD file. Once +loaded, the same hierarchy will be visible in MEOW (Multiverse Explore and +Override Window). + +![Maya - Outliner vs MEOW](assets/maya-multiverse_asset_outliner_meow.png) + +An asset typically contains static or animated data such as: poly meshes, blend +shapes, reference objects, particles/points, curves, joint, subdivision surfaces +and other attributes such as normals, UVs, color sets, tangents, skin weights, +material assignment and shading networks, cameras, lights etc. It is also +possible to specify Maya data to be part of variants and to be used as proxies +by tagging them with attributes. + +An asset is typically read back into Maya into a Multiverse Compound shape +node and it can be composed and overridden. + +![Maya - Multiverse Compound Shape(assets/maya-multiverse_compound.png) + + +#### Composition + +In Multiverse, the term "composition" refers to a USD file that contains a +hierarchy of Multiverse Compounds shape nodes and Maya transform nodes, as it +can be seen in Outliner. This hierarchy is written out to a USD file that +effectively contains a static or animated composition of other USD files written +as references or payloads (according to the relative setting in the Compound). + +![Maya - Multiverse Composition](assets/maya-multiverse_composition_outliner_meow.png) + +A Composition is is typically read back into Maya into a Multiverse Compound +shape and it can be further composed and overridden. + + +#### Override + +In Multiverse, the term "override" refers to a USD file that contains static or animated overrides for a USD hierarchy. Overrides are set in MEOW, they can be: + +- render visibility overrides +- transform overrides +- attribute overrides +- material assignment overrides +- variant and variant definition overrides +- Instancing state overrides +- activity state overrides + +![Maya - Multiverse Override](assets/maya-multiverse_override_meow.png) + +Overrides are written out to a USD file that effectively contains a static or +animated hierarchy of overrides that can be "layered" on top of Assets, +Compositions and other Overrides. + +![Maya - Multiverse Override](assets/maya-multiverse_override_compound_layer.png) + +An Override is is typically read back into Maya as a layer of a Multiverse +Compound shape and it can be further composed and overridden. + + +### Creators + +It is possible to create OpenPype "instances" (Maya sets) for publishing +Multiverse USD Asset, Composition and Override. + +![Maya - Multiverse Creators](assets/maya-multiverse_openpype_creator.png) + +When creating OpenPype instances for Multiverse USD asset, compositions and +overrides the creator plug-in will put the relative selected data in a Maya set +node which holds the properties used by the Multiverse data writer for +publishing. + + +### Publishers + +The relative publishers for Asset, Composition and Overrides are available. They +all write USD files to disk and communicate publish info to the OpenPype +database. + +![Maya - Multiverse Creators](assets/maya-multiverse_openpype_publisher.png) + + +### Loader + +The loader creates a Multiverse Compound shape node reading the USD file of +choice. All data is streamed to the viewport and not contained in Maya. Thanks +to the various viewport load options the user can strategically decide how to +minimize the cost of viewport draw effectively being able to load any data, this +allows to bring into Maya scenes of virtually unlimited complexity. + +![Maya - Multiverse Loader](assets/maya-multiverse_openpype_loader.png) + +:::tip Note +When using the Loader, Multiverse, by design, never "imports" USD data into the +Maya scene as Maya data. Instead, when desired, Multiverse permits to import +specific USD primitives into the Maya scene as Maya data selectively from MEOW, +it also tracks what is being imported, so upon modification, it is possible to +write (create & publish) the modifies data as a USD file for being layered on +top of its relative Compound. See LINK. +::: + +### Rendering + +Multiverse offers procedural rendering with all the major production renderers: + +- 3DelightNSI +- Arnold +- Redshift +- RenderMan +- VRay + +This is completely transparent to the user: Multiverse Compound nodes present in +the scene, once a render is launched, will stream data to the renderer in a +procedural fashion. + +![Maya - Multiverse Rendering](assets/maya-multiverse_rendering.png) + + ## Working with Yeti in OpenPype OpenPype can work with [Yeti](https://peregrinelabs.com/yeti/) in two data modes. From df1a42c5306b855b893a88a10db2f2713c497620 Mon Sep 17 00:00:00 2001 From: Paolo Berto Durante Date: Sun, 10 Apr 2022 20:18:25 +0900 Subject: [PATCH 014/350] website: added jcube as a contributor to homepage --- website/src/pages/index.js | 10 +++++++--- website/static/img/jcube_logo_bw.png | Bin 0 -> 11762 bytes 2 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 website/static/img/jcube_logo_bw.png diff --git a/website/src/pages/index.js b/website/src/pages/index.js index 791b309bbc..1f4a645f61 100644 --- a/website/src/pages/index.js +++ b/website/src/pages/index.js @@ -68,6 +68,10 @@ const collab = [ title: 'Ellipse Studio', image: '/img/ellipse-studio.png', infoLink: 'http://www.dargaudmedia.com' + }, { + title: 'J Cube Inc', + image: '/img/jcube_logo_bw.png', + infoLink: 'https://j-cube.jp' } ]; @@ -224,7 +228,7 @@ function Home() { Get Support - +

OpenPYPE is developed, maintained and supported by PYPE.club

@@ -285,7 +289,7 @@ function Home() { - +

Integrations

@@ -334,7 +338,7 @@ function Home() { After Effects - + Unreal Engine (Beta) diff --git a/website/static/img/jcube_logo_bw.png b/website/static/img/jcube_logo_bw.png new file mode 100644 index 0000000000000000000000000000000000000000..76b897a865f52e1c38b68509d3f08c64481f0145 GIT binary patch literal 11762 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 Date: Thu, 14 Apr 2022 19:00:58 +0200 Subject: [PATCH 015/350] fix merge conflict --- .../plugins/publish/extract_review_slate.py | 2393 +++-------------- 1 file changed, 400 insertions(+), 1993 deletions(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 3ecea1f8bd..c8ee2ec7ed 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -1,1755 +1,387 @@ import os -import re -import copy -import json import shutil - -from abc import ABCMeta, abstractmethod -import six - -import clique - -import pyblish.api import openpype.api +import pyblish from openpype.lib import ( - get_ffmpeg_tool_path, - get_ffprobe_streams, - path_to_subprocess_arg, - - should_convert_for_ffmpeg, - convert_for_ffmpeg, - get_transcode_temp_directory + get_ffmpeg_tool_path, + get_ffprobe_data, + get_ffprobe_streams, + get_ffmpeg_codec_args, + get_ffmpeg_format_args, ) -import speedcopy - -class ExtractReview(pyblish.api.InstancePlugin): - """Extracting Review mov file for Ftrack - - Compulsory attribute of representation is tags list with "review", - otherwise the representation is ignored. - - All new representations are created and encoded by ffmpeg following - presets found in OpenPype Settings interface at - `project_settings/global/publish/ExtractReview/profiles:outputs`. +class ExtractReviewSlate(openpype.api.Extractor): + """ + Will add slate frame at the start of the video files """ - label = "Extract Review" - order = pyblish.api.ExtractorOrder + 0.02 - families = ["review"] - hosts = [ - "nuke", - "maya", - "shell", - "hiero", - "premiere", - "harmony", - "standalonepublisher", - "fusion", - "tvpaint", - "resolve", - "webpublisher", - "aftereffects", - "flame" - ] + label = "Review with Slate frame" + order = pyblish.api.ExtractorOrder + 0.031 + families = ["slate", "review"] + match = pyblish.api.Subset - # Supported extensions - image_exts = ["exr", "jpg", "jpeg", "png", "dpx"] - video_exts = ["mov", "mp4"] - supported_exts = image_exts + video_exts - - alpha_exts = ["exr", "png", "dpx"] - - # FFmpeg tools paths - ffmpeg_path = get_ffmpeg_tool_path("ffmpeg") - - # Preset attributes - profiles = None + hosts = ["nuke", "shell"] + optional = True def process(self, instance): - self.log.debug(str(instance.data["representations"])) - # Skip review when requested. - if not instance.data.get("review", True): - return + inst_data = instance.data + if "representations" not in inst_data: + raise RuntimeError("Burnin needs already created mov to work on.") - # Run processing - self.main_process(instance) - - # Make sure cleanup happens and pop representations with "delete" tag. - for repre in tuple(instance.data["representations"]): - tags = repre.get("tags") or [] - if "delete" in tags and "thumbnail" not in tags: - instance.data["representations"].remove(repre) - - def _get_outputs_for_instance(self, instance): - host_name = instance.context.data["hostName"] - task_name = os.environ["AVALON_TASK"] - family = self.main_family_from_instance(instance) - - self.log.info("Host: \"{}\"".format(host_name)) - self.log.info("Task: \"{}\"".format(task_name)) - self.log.info("Family: \"{}\"".format(family)) - - profile = self.find_matching_profile( - host_name, task_name, family - ) - if not profile: - self.log.info(( - "Skipped instance. None of profiles in presets are for" - " Host: \"{}\" | Family: \"{}\" | Task \"{}\"" - ).format(host_name, family, task_name)) - return - - self.log.debug("Matching profile: \"{}\"".format(json.dumps(profile))) - - subset_name = instance.data.get("subset") - instance_families = self.families_from_instance(instance) - filtered_outputs = self.filter_output_defs( - profile, subset_name, instance_families - ) - # Store `filename_suffix` to save arguments - profile_outputs = [] - for filename_suffix, definition in filtered_outputs.items(): - definition["filename_suffix"] = filename_suffix - profile_outputs.append(definition) - - if not filtered_outputs: - self.log.info(( - "Skipped instance. All output definitions from selected" - " profile does not match to instance families. \"{}\"" - ).format(str(instance_families))) - return profile_outputs - - def _get_outputs_per_representations(self, instance, profile_outputs): - outputs_per_representations = [] - for repre in instance.data["representations"]: - repre_name = str(repre.get("name")) - tags = repre.get("tags") or [] - if "review" not in tags: - self.log.debug(( - "Repre: {} - Didn't found \"review\" in tags. Skipping" - ).format(repre_name)) - continue - - if "thumbnail" in tags: - self.log.debug(( - "Repre: {} - Found \"thumbnail\" in tags. Skipping" - ).format(repre_name)) - continue - - if "passing" in tags: - self.log.debug(( - "Repre: {} - Found \"passing\" in tags. Skipping" - ).format(repre_name)) - continue - - input_ext = repre["ext"] - if input_ext.startswith("."): - input_ext = input_ext[1:] - - if input_ext not in self.supported_exts: - self.log.info( - "Representation has unsupported extension \"{}\"".format( - input_ext - ) - ) - continue - - # Filter output definition by representation tags (optional) - outputs = self.filter_outputs_by_tags(profile_outputs, tags) - if not outputs: - self.log.info(( - "Skipped representation. All output definitions from" - " selected profile does not match to representation's" - " tags. \"{}\"" - ).format(str(tags))) - continue - outputs_per_representations.append((repre, outputs)) - return outputs_per_representations - - @staticmethod - def get_instance_label(instance): - return ( - getattr(instance, "label", None) - or instance.data.get("label") - or instance.data.get("name") - or str(instance) - ) - - def main_process(self, instance): - instance_label = self.get_instance_label(instance) - self.log.debug("Processing instance \"{}\"".format(instance_label)) - profile_outputs = self._get_outputs_for_instance(instance) - if not profile_outputs: - return - - # Loop through representations - outputs_per_repres = self._get_outputs_per_representations( - instance, profile_outputs - ) - fill_data = copy.deepcopy(instance.data["anatomyData"]) - for repre, outputs in outputs_per_repres: - # Check if input should be preconverted before processing - # Store original staging dir (it's value may change) - src_repre_staging_dir = repre["stagingDir"] - # Receive filepath to first file in representation - first_input_path = None - if not self.input_is_sequence(repre): - first_input_path = os.path.join( - src_repre_staging_dir, repre["files"] - ) - else: - for filename in repre["files"]: - first_input_path = os.path.join( - src_repre_staging_dir, filename - ) - break - - # Skip if file is not set - if first_input_path is None: - self.log.warning(( - "Representation \"{}\" have empty files. Skipped." - ).format(repre["name"])) - continue - - # Determine if representation requires pre conversion for ffmpeg - do_convert = should_convert_for_ffmpeg(first_input_path) - # If result is None the requirement of conversion can't be - # determined - if do_convert is None: - self.log.info(( - "Can't determine if representation requires conversion." - " Skipped." - )) - continue - - # Do conversion if needed - # - change staging dir of source representation - # - must be set back after output definitions processing - if do_convert: - new_staging_dir = get_transcode_temp_directory() - repre["stagingDir"] = new_staging_dir - - frame_start = instance.data["frameStart"] - frame_end = instance.data["frameEnd"] - convert_for_ffmpeg( - first_input_path, - new_staging_dir, - frame_start, - frame_end, - self.log - ) - - for _output_def in outputs: - output_def = copy.deepcopy(_output_def) - # Make sure output definition has "tags" key - if "tags" not in output_def: - output_def["tags"] = [] - - if "burnins" not in output_def: - output_def["burnins"] = [] - - # Create copy of representation - new_repre = copy.deepcopy(repre) - # Make sure new representation has origin staging dir - # - this is because source representation may change - # it's staging dir because of ffmpeg conversion - new_repre["stagingDir"] = src_repre_staging_dir - - # Remove "delete" tag from new repre if there is - if "delete" in new_repre["tags"]: - new_repre["tags"].remove("delete") - - # Add additional tags from output definition to representation - for tag in output_def["tags"]: - if tag not in new_repre["tags"]: - new_repre["tags"].append(tag) - - # Add burnin link from output definition to representation - for burnin in output_def["burnins"]: - if burnin not in new_repre.get("burnins", []): - if not new_repre.get("burnins"): - new_repre["burnins"] = [] - new_repre["burnins"].append(str(burnin)) - - self.log.debug( - "Linked burnins: `{}`".format(new_repre.get("burnins")) - ) - - self.log.debug( - "New representation tags: `{}`".format( - new_repre.get("tags")) - ) - - temp_data = self.prepare_temp_data( - instance, repre, output_def) - files_to_clean = [] - if temp_data["input_is_sequence"]: - self.log.info("Filling gaps in sequence.") - files_to_clean = self.fill_sequence_gaps( - temp_data["origin_repre"]["files"], - new_repre["stagingDir"], - temp_data["frame_start"], - temp_data["frame_end"]) - - # create or update outputName - output_name = new_repre.get("outputName", "") - output_ext = new_repre["ext"] - if output_name: - output_name += "_" - output_name += output_def["filename_suffix"] - if temp_data["without_handles"]: - output_name += "_noHandles" - - # add outputName to anatomy format fill_data - fill_data.update({ - "output": output_name, - "ext": output_ext - }) - - try: # temporary until oiiotool is supported cross platform - ffmpeg_args = self._ffmpeg_arguments( - output_def, instance, new_repre, temp_data, fill_data - ) - except ZeroDivisionError: - if 'exr' in temp_data["origin_repre"]["ext"]: - self.log.debug("Unsupported compression on input " + - "files. Skipping!!!") - return - raise NotImplementedError - - subprcs_cmd = " ".join(ffmpeg_args) - - # run subprocess - self.log.debug("Executing: {}".format(subprcs_cmd)) - - openpype.api.run_subprocess( - subprcs_cmd, shell=True, logger=self.log - ) - - # delete files added to fill gaps - if files_to_clean: - for f in files_to_clean: - os.unlink(f) - - new_repre.update({ - "name": "{}_{}".format(output_name, output_ext), - "outputName": output_name, - "outputDef": output_def, - "frameStartFtrack": temp_data["output_frame_start"], - "frameEndFtrack": temp_data["output_frame_end"], - "ffmpeg_cmd": subprcs_cmd - }) - - # Force to pop these key if are in new repre - new_repre.pop("preview", None) - new_repre.pop("thumbnail", None) - if "clean_name" in new_repre.get("tags", []): - new_repre.pop("outputName") - - # adding representation - self.log.debug( - "Adding new representation: {}".format(new_repre) - ) - instance.data["representations"].append(new_repre) - - # Cleanup temp staging dir after procesisng of output definitions - if do_convert: - temp_dir = repre["stagingDir"] - shutil.rmtree(temp_dir) - # Set staging dir of source representation back to previous - # value - repre["stagingDir"] = src_repre_staging_dir - - def input_is_sequence(self, repre): - """Deduce from representation data if input is sequence.""" - # TODO GLOBAL ISSUE - Find better way how to find out if input - # is sequence. Issues( in theory): - # - there may be multiple files ant not be sequence - # - remainders are not checked at all - # - there can be more than one collection - return isinstance(repre["files"], (list, tuple)) - - def prepare_temp_data(self, instance, repre, output_def): - """Prepare dictionary with values used across extractor's process. - - All data are collected from instance, context, origin representation - and output definition. - - There are few required keys in Instance data: "frameStart", "frameEnd" - and "fps". - - Args: - instance (Instance): Currently processed instance. - repre (dict): Representation from which new representation was - copied. - output_def (dict): Definition of output of this plugin. - - Returns: - dict: All data which are used across methods during process. - Their values should not change during process but new keys - with values may be added. - """ - - frame_start = instance.data["frameStart"] - frame_end = instance.data["frameEnd"] - - # Try to get handles from instance - handle_start = instance.data.get("handleStart") - handle_end = instance.data.get("handleEnd") - # If even one of handle values is not set on instance use - # handles from context - if handle_start is None or handle_end is None: - handle_start = instance.context.data["handleStart"] - handle_end = instance.context.data["handleEnd"] - - frame_start_handle = frame_start - handle_start - frame_end_handle = frame_end + handle_end - - # Change output frames when output should be without handles - without_handles = bool("no-handles" in output_def["tags"]) - if without_handles: - output_frame_start = frame_start - output_frame_end = frame_end - else: - output_frame_start = frame_start_handle - output_frame_end = frame_end_handle - - handles_are_set = handle_start > 0 or handle_end > 0 - - with_audio = True - if ( - # Check if has `no-audio` tag - "no-audio" in output_def["tags"] - # Check if instance has ny audio in data - or not instance.data.get("audio") - ): - with_audio = False - - input_is_sequence = self.input_is_sequence(repre) - input_allow_bg = False - if input_is_sequence and repre["files"]: - ext = os.path.splitext(repre["files"][0])[1].replace(".", "") - if ext in self.alpha_exts: - input_allow_bg = True - - return { - "fps": float(instance.data["fps"]), - "frame_start": frame_start, - "frame_end": frame_end, - "handle_start": handle_start, - "handle_end": handle_end, - "frame_start_handle": frame_start_handle, - "frame_end_handle": frame_end_handle, - "output_frame_start": int(output_frame_start), - "output_frame_end": int(output_frame_end), - "pixel_aspect": instance.data.get("pixelAspect", 1), - "resolution_width": instance.data.get("resolutionWidth"), - "resolution_height": instance.data.get("resolutionHeight"), - "origin_repre": repre, - "input_is_sequence": input_is_sequence, - "input_allow_bg": input_allow_bg, - "with_audio": with_audio, - "without_handles": without_handles, - "handles_are_set": handles_are_set - } - - def _ffmpeg_arguments( - self, output_def, instance, new_repre, temp_data, fill_data - ): - """Prepares ffmpeg arguments for expected extraction. - - Prepares input and output arguments based on output definition and - input files. - - Args: - output_def (dict): Currently processed output definition. - instance (Instance): Currently processed instance. - new_repre (dict): Representation representing output of this - process. - temp_data (dict): Base data for successful process. - """ - - # Get FFmpeg arguments from profile presets - out_def_ffmpeg_args = output_def.get("ffmpeg_args") or {} - - _ffmpeg_input_args = out_def_ffmpeg_args.get("input") or [] - _ffmpeg_output_args = out_def_ffmpeg_args.get("output") or [] - _ffmpeg_video_filters = out_def_ffmpeg_args.get("video_filters") or [] - _ffmpeg_audio_filters = out_def_ffmpeg_args.get("audio_filters") or [] - - # Cleanup empty strings - ffmpeg_input_args = [ - value for value in _ffmpeg_input_args if value.strip() - ] - ffmpeg_video_filters = [ - value for value in _ffmpeg_video_filters if value.strip() - ] - ffmpeg_audio_filters = [ - value for value in _ffmpeg_audio_filters if value.strip() - ] - - ffmpeg_output_args = [] - for value in _ffmpeg_output_args: - value = value.strip() - if not value: - continue - try: - value = value.format(**fill_data) - except Exception: - self.log.warning( - "Failed to format ffmpeg argument: {}".format(value), - exc_info=True - ) - pass - ffmpeg_output_args.append(value) - - # Prepare input and output filepaths - self.input_output_paths(new_repre, output_def, temp_data) - - # Set output frames len to 1 when ouput is single image - if ( - temp_data["output_ext_is_image"] - and not temp_data["output_is_sequence"] - ): - output_frames_len = 1 - - else: - output_frames_len = ( - temp_data["output_frame_end"] - - temp_data["output_frame_start"] - + 1 - ) - - duration_seconds = float(output_frames_len / temp_data["fps"]) - - if temp_data["input_is_sequence"]: - # Set start frame of input sequence (just frame in filename) - # - definition of input filepath - ffmpeg_input_args.append( - "-start_number {}".format(temp_data["output_frame_start"]) - ) - - # TODO add fps mapping `{fps: fraction}` ? - # - e.g.: { - # "25": "25/1", - # "24": "24/1", - # "23.976": "24000/1001" - # } - # Add framerate to input when input is sequence - ffmpeg_input_args.append( - "-framerate {}".format(temp_data["fps"]) - ) - - if temp_data["output_is_sequence"]: - # Set start frame of output sequence (just frame in filename) - # - this is definition of an output - ffmpeg_output_args.append( - "-start_number {}".format(temp_data["output_frame_start"]) - ) - - # Change output's duration and start point if should not contain - # handles - start_sec = 0 - if temp_data["without_handles"] and temp_data["handles_are_set"]: - # Set start time without handles - # - check if handle_start is bigger than 0 to avoid zero division - if temp_data["handle_start"] > 0: - start_sec = float(temp_data["handle_start"]) / temp_data["fps"] - ffmpeg_input_args.append("-ss {:0.10f}".format(start_sec)) - - # Set output duration inn seconds - ffmpeg_output_args.append("-t {:0.10}".format(duration_seconds)) - - # Set frame range of output when input or output is sequence - elif temp_data["output_is_sequence"]: - ffmpeg_output_args.append("-frames:v {}".format(output_frames_len)) - - # Add duration of an input sequence if output is video - if ( - temp_data["input_is_sequence"] - and not temp_data["output_is_sequence"] - ): - ffmpeg_input_args.append("-to {:0.10f}".format( - duration_seconds + start_sec - )) - - # Add video/image input path - ffmpeg_input_args.append( - "-i {}".format( - path_to_subprocess_arg(temp_data["full_input_path"]) - ) - ) - - # Add audio arguments if there are any. Skipped when output are images. - if not temp_data["output_ext_is_image"] and temp_data["with_audio"]: - audio_in_args, audio_filters, audio_out_args = self.audio_args( - instance, temp_data, duration_seconds - ) - ffmpeg_input_args.extend(audio_in_args) - ffmpeg_audio_filters.extend(audio_filters) - ffmpeg_output_args.extend(audio_out_args) - - res_filters = self.rescaling_filters(temp_data, output_def, new_repre) - ffmpeg_video_filters.extend(res_filters) - - ffmpeg_input_args = self.split_ffmpeg_args(ffmpeg_input_args) - - lut_filters = self.lut_filters(new_repre, instance, ffmpeg_input_args) - ffmpeg_video_filters.extend(lut_filters) - - bg_alpha = 0 - bg_color = output_def.get("bg_color") - if bg_color: - bg_red, bg_green, bg_blue, bg_alpha = bg_color - - if bg_alpha > 0: - if not temp_data["input_allow_bg"]: - self.log.info(( - "Output definition has defined BG color input was" - " resolved as does not support adding BG." - )) - else: - bg_color_hex = "#{0:0>2X}{1:0>2X}{2:0>2X}".format( - bg_red, bg_green, bg_blue - ) - bg_color_alpha = float(bg_alpha) / 255 - bg_color_str = "{}@{}".format(bg_color_hex, bg_color_alpha) - - self.log.info("Applying BG color {}".format(bg_color_str)) - color_args = [ - "split=2[bg][fg]", - "[bg]drawbox=c={}:replace=1:t=fill[bg]".format( - bg_color_str - ), - "[bg][fg]overlay=format=auto" - ] - # Prepend bg color change before all video filters - # NOTE at the time of creation it is required as video filters - # from settings may affect color of BG - # e.g. `eq` can remove alpha from input - for arg in reversed(color_args): - ffmpeg_video_filters.insert(0, arg) - - # Add argument to override output file - ffmpeg_output_args.append("-y") - - # NOTE This must be latest added item to output arguments. - ffmpeg_output_args.append( - path_to_subprocess_arg(temp_data["full_output_path"]) - ) - - return self.ffmpeg_full_args( - ffmpeg_input_args, - ffmpeg_video_filters, - ffmpeg_audio_filters, - ffmpeg_output_args - ) - - def split_ffmpeg_args(self, in_args): - """Makes sure all entered arguments are separated in individual items. - - Split each argument string with " -" to identify if string contains - one or more arguments. - """ - splitted_args = [] - for arg in in_args: - sub_args = arg.split(" -") - if len(sub_args) == 1: - if arg and arg not in splitted_args: - splitted_args.append(arg) - continue - - for idx, arg in enumerate(sub_args): - if idx != 0: - arg = "-" + arg - - if arg and arg not in splitted_args: - splitted_args.append(arg) - return splitted_args - - def ffmpeg_full_args( - self, input_args, video_filters, audio_filters, output_args - ): - """Post processing of collected FFmpeg arguments. - - Just verify that output arguments does not contain video or audio - filters which may cause issues because of duplicated argument entry. - Filters found in output arguments are moved to list they belong to. - - Args: - input_args (list): All collected ffmpeg arguments with inputs. - video_filters (list): All collected video filters. - audio_filters (list): All collected audio filters. - output_args (list): All collected ffmpeg output arguments with - output filepath. - - Returns: - list: Containing all arguments ready to run in subprocess. - """ - output_args = self.split_ffmpeg_args(output_args) - - video_args_dentifiers = ["-vf", "-filter:v"] - audio_args_dentifiers = ["-af", "-filter:a"] - for arg in tuple(output_args): - for identifier in video_args_dentifiers: - if arg.startswith("{} ".format(identifier)): - output_args.remove(arg) - arg = arg.replace(identifier, "").strip() - video_filters.append(arg) - - for identifier in audio_args_dentifiers: - if arg.startswith("{} ".format(identifier)): - output_args.remove(arg) - arg = arg.replace(identifier, "").strip() - audio_filters.append(arg) - - all_args = [] - all_args.append(path_to_subprocess_arg(self.ffmpeg_path)) - all_args.extend(input_args) - if video_filters: - all_args.append("-filter:v") - all_args.append("\"{}\"".format(",".join(video_filters))) - - if audio_filters: - all_args.append("-filter:a") - all_args.append("\"{}\"".format(",".join(audio_filters))) - - all_args.extend(output_args) - - return all_args - - def fill_sequence_gaps(self, files, staging_dir, start_frame, end_frame): - # type: (list, str, int, int) -> list - """Fill missing files in sequence by duplicating existing ones. - - This will take nearest frame file and copy it with so as to fill - gaps in sequence. Last existing file there is is used to for the - hole ahead. - - Args: - files (list): List of representation files. - staging_dir (str): Path to staging directory. - start_frame (int): Sequence start (no matter what files are there) - end_frame (int): Sequence end (no matter what files are there) - - Returns: - list of added files. Those should be cleaned after work - is done. - - Raises: - AssertionError: if more then one collection is obtained. - - """ - start_frame = int(start_frame) - end_frame = int(end_frame) - collections = clique.assemble(files)[0] - assert len(collections) == 1, "Multiple collections found." - col = collections[0] - - # do nothing if no gap is found in input range - not_gap = True - for fr in range(start_frame, end_frame + 1): - if fr not in col.indexes: - not_gap = False - - if not_gap: - return [] - - holes = col.holes() - - # generate ideal sequence - complete_col = clique.assemble( - [("{}{:0" + str(col.padding) + "d}{}").format( - col.head, f, col.tail - ) for f in range(start_frame, end_frame)] - )[0][0] # type: clique.Collection - - new_files = {} - last_existing_file = None - - for idx in holes.indexes: - # get previous existing file - test_file = os.path.normpath(os.path.join( - staging_dir, - ("{}{:0" + str(complete_col.padding) + "d}{}").format( - complete_col.head, idx - 1, complete_col.tail))) - if os.path.isfile(test_file): - new_files[idx] = test_file - last_existing_file = test_file - else: - if not last_existing_file: - # previous file is not found (sequence has a hole - # at the beginning. Use first available frame - # there is. - try: - last_existing_file = list(col)[0] - except IndexError: - # empty collection? - raise AssertionError( - "Invalid sequence collected") - new_files[idx] = os.path.normpath( - os.path.join(staging_dir, last_existing_file)) - - files_to_clean = [] - if new_files: - # so now new files are dict with missing frame as a key and - # existing file as a value. - for frame, file in new_files.items(): - self.log.info( - "Filling gap {} with {}".format(frame, file)) - - hole = os.path.join( - staging_dir, - ("{}{:0" + str(col.padding) + "d}{}").format( - col.head, frame, col.tail)) - speedcopy.copyfile(file, hole) - files_to_clean.append(hole) - - return files_to_clean - - def input_output_paths(self, new_repre, output_def, temp_data): - """Deduce input nad output file paths based on entered data. - - Input may be sequence of images, video file or single image file and - same can be said about output, this method helps to find out what - their paths are. - - It is validated that output directory exist and creates if not. - - During process are set "files", "stagingDir", "ext" and - "sequence_file" (if output is sequence) keys to new representation. - """ - - repre = temp_data["origin_repre"] - src_staging_dir = repre["stagingDir"] - dst_staging_dir = new_repre["stagingDir"] - - if temp_data["input_is_sequence"]: - collections = clique.assemble(repre["files"])[0] - full_input_path = os.path.join( - src_staging_dir, - collections[0].format("{head}{padding}{tail}") - ) - - filename = collections[0].format("{head}") - if filename.endswith("."): - filename = filename[:-1] - - # Make sure to have full path to one input file - full_input_path_single_file = os.path.join( - src_staging_dir, repre["files"][0] - ) - - else: - full_input_path = os.path.join( - src_staging_dir, repre["files"] - ) - filename = os.path.splitext(repre["files"])[0] - - # Make sure to have full path to one input file - full_input_path_single_file = full_input_path - - filename_suffix = output_def["filename_suffix"] - - output_ext = output_def.get("ext") - # Use input extension if output definition do not specify it - if output_ext is None: - output_ext = os.path.splitext(full_input_path)[1] - - # TODO Define if extension should have dot or not - if output_ext.startswith("."): - output_ext = output_ext[1:] - - # Store extension to representation - new_repre["ext"] = output_ext - - self.log.debug("New representation ext: `{}`".format(output_ext)) - - # Output is image file sequence witht frames - output_ext_is_image = bool(output_ext in self.image_exts) - output_is_sequence = bool( - output_ext_is_image - and "sequence" in output_def["tags"] - ) - if output_is_sequence: - new_repre_files = [] - frame_start = temp_data["output_frame_start"] - frame_end = temp_data["output_frame_end"] - - filename_base = "{}_{}".format(filename, filename_suffix) - # Temporary tempalte for frame filling. Example output: - # "basename.%04d.exr" when `frame_end` == 1001 - repr_file = "{}.%{:0>2}d.{}".format( - filename_base, len(str(frame_end)), output_ext - ) - - for frame in range(frame_start, frame_end + 1): - new_repre_files.append(repr_file % frame) - - new_repre["sequence_file"] = repr_file - full_output_path = os.path.join( - dst_staging_dir, filename_base, repr_file - ) - - else: - repr_file = "{}_{}.{}".format( - filename, filename_suffix, output_ext - ) - full_output_path = os.path.join(dst_staging_dir, repr_file) - new_repre_files = repr_file - - # Store files to representation - new_repre["files"] = new_repre_files - - # Make sure stagingDire exists - dst_staging_dir = os.path.normpath(os.path.dirname(full_output_path)) - if not os.path.exists(dst_staging_dir): - self.log.debug("Creating dir: {}".format(dst_staging_dir)) - os.makedirs(dst_staging_dir) - - # Store stagingDir to representaion - new_repre["stagingDir"] = dst_staging_dir - - # Store paths to temp data - temp_data["full_input_path"] = full_input_path - temp_data["full_input_path_single_file"] = full_input_path_single_file - temp_data["full_output_path"] = full_output_path - - # Store information about output - temp_data["output_ext_is_image"] = output_ext_is_image - temp_data["output_is_sequence"] = output_is_sequence - - self.log.debug("Input path {}".format(full_input_path)) - self.log.debug("Output path {}".format(full_output_path)) - - def audio_args(self, instance, temp_data, duration_seconds): - """Prepares FFMpeg arguments for audio inputs.""" - audio_in_args = [] - audio_filters = [] - audio_out_args = [] - audio_inputs = instance.data.get("audio") - if not audio_inputs: - return audio_in_args, audio_filters, audio_out_args - - for audio in audio_inputs: - # NOTE modified, always was expected "frameStartFtrack" which is - # STRANGE?!!! There should be different key, right? - # TODO use different frame start! - offset_seconds = 0 - frame_start_ftrack = instance.data.get("frameStartFtrack") - if frame_start_ftrack is not None: - offset_frames = frame_start_ftrack - audio["offset"] - offset_seconds = offset_frames / temp_data["fps"] - - if offset_seconds > 0: - audio_in_args.append( - "-ss {}".format(offset_seconds) - ) - - elif offset_seconds < 0: - audio_in_args.append( - "-itsoffset {}".format(abs(offset_seconds)) - ) - - # Audio duration is offset from `-ss` - audio_duration = duration_seconds + offset_seconds - - # Set audio duration - audio_in_args.append("-to {:0.10f}".format(audio_duration)) - - # Add audio input path - audio_in_args.append("-i {}".format( - path_to_subprocess_arg(audio["filename"]) - )) - - # NOTE: These were changed from input to output arguments. - # NOTE: value in "-ac" was hardcoded to 2, changed to audio inputs len. - # Need to merge audio if there are more than 1 input. - if len(audio_inputs) > 1: - audio_out_args.append("-filter_complex amerge") - audio_out_args.append("-ac {}".format(len(audio_inputs))) - - return audio_in_args, audio_filters, audio_out_args - - def get_letterbox_filters( - self, - letter_box_def, - output_width, - output_height - ): - output = [] - - ratio = letter_box_def["ratio"] - fill_color = letter_box_def["fill_color"] - f_red, f_green, f_blue, f_alpha = fill_color - fill_color_hex = "{0:0>2X}{1:0>2X}{2:0>2X}".format( - f_red, f_green, f_blue - ) - fill_color_alpha = float(f_alpha) / 255 - - line_thickness = letter_box_def["line_thickness"] - line_color = letter_box_def["line_color"] - l_red, l_green, l_blue, l_alpha = line_color - line_color_hex = "{0:0>2X}{1:0>2X}{2:0>2X}".format( - l_red, l_green, l_blue - ) - line_color_alpha = float(l_alpha) / 255 - - # test ratios and define if pillar or letter boxes - output_ratio = float(output_width) / float(output_height) - self.log.debug("Output ratio: {} LetterBox ratio: {}".format( - output_ratio, ratio - )) - pillar = output_ratio > ratio - need_mask = format(output_ratio, ".3f") != format(ratio, ".3f") - if not need_mask: - return [] - - if not pillar: - if fill_color_alpha > 0: - top_box = ( - "drawbox=0:0:{width}" - ":round(({height}-({width}/{ratio}))/2)" - ":t=fill:c={color}@{alpha}" - ).format( - width=output_width, - height=output_height, - ratio=ratio, - color=fill_color_hex, - alpha=fill_color_alpha - ) - - bottom_box = ( - "drawbox=0" - ":{height}-round(({height}-({width}/{ratio}))/2)" - ":{width}" - ":round(({height}-({width}/{ratio}))/2)" - ":t=fill:c={color}@{alpha}" - ).format( - width=output_width, - height=output_height, - ratio=ratio, - color=fill_color_hex, - alpha=fill_color_alpha - ) - output.extend([top_box, bottom_box]) - - if line_color_alpha > 0 and line_thickness > 0: - top_line = ( - "drawbox=0" - ":round(({height}-({width}/{ratio}))/2)-{l_thick}" - ":{width}:{l_thick}:t=fill:c={l_color}@{l_alpha}" - ).format( - width=output_width, - height=output_height, - ratio=ratio, - l_thick=line_thickness, - l_color=line_color_hex, - l_alpha=line_color_alpha - ) - bottom_line = ( - "drawbox=0" - ":{height}-round(({height}-({width}/{ratio}))/2)" - ":{width}:{l_thick}:t=fill:c={l_color}@{l_alpha}" - ).format( - width=output_width, - height=output_height, - ratio=ratio, - l_thick=line_thickness, - l_color=line_color_hex, - l_alpha=line_color_alpha - ) - output.extend([top_line, bottom_line]) - - else: - if fill_color_alpha > 0: - left_box = ( - "drawbox=0:0" - ":round(({width}-({height}*{ratio}))/2)" - ":{height}" - ":t=fill:c={color}@{alpha}" - ).format( - width=output_width, - height=output_height, - ratio=ratio, - color=fill_color_hex, - alpha=fill_color_alpha - ) - - right_box = ( - "drawbox=" - "{width}-round(({width}-({height}*{ratio}))/2)" - ":0" - ":round(({width}-({height}*{ratio}))/2)" - ":{height}" - ":t=fill:c={color}@{alpha}" - ).format( - width=output_width, - height=output_height, - ratio=ratio, - color=fill_color_hex, - alpha=fill_color_alpha - ) - output.extend([left_box, right_box]) - - if line_color_alpha > 0 and line_thickness > 0: - left_line = ( - "drawbox=round(({width}-({height}*{ratio}))/2)" - ":0:{l_thick}:{height}:t=fill:c={l_color}@{l_alpha}" - ).format( - width=output_width, - height=output_height, - ratio=ratio, - l_thick=line_thickness, - l_color=line_color_hex, - l_alpha=line_color_alpha - ) - - right_line = ( - "drawbox={width}-round(({width}-({height}*{ratio}))/2)" - ":0:{l_thick}:{height}:t=fill:c={l_color}@{l_alpha}" - ).format( - width=output_width, - height=output_height, - ratio=ratio, - l_thick=line_thickness, - l_color=line_color_hex, - l_alpha=line_color_alpha - ) - output.extend([left_line, right_line]) - - return output - - def rescaling_filters(self, temp_data, output_def, new_repre): - """Prepare vieo filters based on tags in new representation. - - It is possible to add letterboxes to output video or rescale to - different resolution. - - During this preparation "resolutionWidth" and "resolutionHeight" are - set to new representation. - """ - filters = [] - - # if reformat input video file is already reforamted from upstream - reformat_in_baking = bool("reformated" in new_repre["tags"]) - self.log.debug("reformat_in_baking: `{}`".format(reformat_in_baking)) - - # Get instance data - pixel_aspect = temp_data["pixel_aspect"] - - if reformat_in_baking: - self.log.debug(( - "Using resolution from input. It is already " - "reformated from upstream process" - )) - pixel_aspect = 1 - - # NOTE Skipped using instance's resolution - full_input_path_single_file = temp_data["full_input_path_single_file"] - try: - streams = get_ffprobe_streams( - full_input_path_single_file, self.log - ) - except Exception as exc: - raise AssertionError(( - "FFprobe couldn't read information about input file: \"{}\"." - " Error message: {}" - ).format(full_input_path_single_file, str(exc))) + suffix = "_slate" + slate_path = inst_data.get("slateFrame") + ffmpeg_path = get_ffmpeg_tool_path("ffmpeg") + slate_streams = get_ffprobe_streams(slate_path, self.log) # Try to find first stream with defined 'width' and 'height' # - this is to avoid order of streams where audio can be as first - # - there may be a better way (checking `codec_type`?) - input_width = None - input_height = None - output_width = None - output_height = None - for stream in streams: - if "width" in stream and "height" in stream: - input_width = int(stream["width"]) - input_height = int(stream["height"]) + # - there may be a better way (checking `codec_type`?)+ + slate_width = None + slate_height = None + for slate_stream in slate_streams: + if "width" in slate_stream and "height" in slate_stream: + slate_width = int(slate_stream["width"]) + slate_height = int(slate_stream["height"]) break - # Get instance data - pixel_aspect = temp_data["pixel_aspect"] - - if reformat_in_baking: - self.log.debug(( - "Using resolution from input. It is already " - "reformated from upstream process" - )) - pixel_aspect = 1 - output_width = input_width - output_height = input_height - # Raise exception of any stream didn't define input resolution - if input_width is None: + if slate_width is None: raise AssertionError(( "FFprobe couldn't read resolution from input file: \"{}\"" - ).format(full_input_path_single_file)) + ).format(slate_path)) - # NOTE Setting only one of `width` or `heigth` is not allowed - # - settings value can't have None but has value of 0 - output_width = output_def.get("width") or output_width or None - output_height = output_def.get("height") or output_height or None + if "reviewToWidth" in inst_data: + use_legacy_code = True + else: + use_legacy_code = False - # Overscal color - overscan_color_value = "black" - overscan_color = output_def.get("overscan_color") - if overscan_color: - bg_red, bg_green, bg_blue, _ = overscan_color - overscan_color_value = "#{0:0>2X}{1:0>2X}{2:0>2X}".format( - bg_red, bg_green, bg_blue + pixel_aspect = inst_data.get("pixelAspect", 1) + fps = inst_data.get("fps") + self.log.debug("fps {} ".format(fps)) + + for idx, repre in enumerate(inst_data["representations"]): + self.log.debug("repre ({}): `{}`".format(idx + 1, repre)) + + p_tags = repre.get("tags", []) + if "slate-frame" not in p_tags: + continue + + # get repre file + stagingdir = repre["stagingDir"] + input_file = "{0}".format(repre["files"]) + input_path = os.path.join( + os.path.normpath(stagingdir), repre["files"]) + self.log.debug("__ input_path: {}".format(input_path)) + + streams = get_ffprobe_streams( + input_path, self.log ) - self.log.debug("Overscan color: `{}`".format(overscan_color_value)) - - # Convert overscan value video filters - overscan_crop = output_def.get("overscan_crop") - overscan = OverscanCrop( - input_width, input_height, overscan_crop, overscan_color_value - ) - overscan_crop_filters = overscan.video_filters() - # Add overscan filters to filters if are any and modify input - # resolution by it's values - if overscan_crop_filters: - filters.extend(overscan_crop_filters) - input_width = overscan.width() - input_height = overscan.height() - # Use output resolution as inputs after cropping to skip usage of - # instance data resolution - if output_width is None or output_height is None: - output_width = input_width - output_height = input_height - - # Make sure input width and height is not an odd number - input_width_is_odd = bool(input_width % 2 != 0) - input_height_is_odd = bool(input_height % 2 != 0) - if input_width_is_odd or input_height_is_odd: - # Add padding to input and make sure this filter is at first place - filters.append("pad=width=ceil(iw/2)*2:height=ceil(ih/2)*2") - - # Change input width or height as first filter will change them - if input_width_is_odd: - self.log.info(( - "Converting input width from odd to even number. {} -> {}" - ).format(input_width, input_width + 1)) - input_width += 1 - - if input_height_is_odd: - self.log.info(( - "Converting input height from odd to even number. {} -> {}" - ).format(input_height, input_height + 1)) - input_height += 1 - - self.log.debug("pixel_aspect: `{}`".format(pixel_aspect)) - self.log.debug("input_width: `{}`".format(input_width)) - self.log.debug("input_height: `{}`".format(input_height)) - - # Use instance resolution if output definition has not set it. - if output_width is None or output_height is None: - output_width = temp_data["resolution_width"] - output_height = temp_data["resolution_height"] - - # Use source's input resolution instance does not have set it. - if output_width is None or output_height is None: - self.log.debug("Using resolution from input.") - output_width = input_width - output_height = input_height - - output_width = int(output_width) - output_height = int(output_height) - - # Make sure output width and height is not an odd number - # When this can happen: - # - if output definition has set width and height with odd number - # - `instance.data` contain width and height with odd numbeer - if output_width % 2 != 0: - self.log.warning(( - "Converting output width from odd to even number. {} -> {}" - ).format(output_width, output_width + 1)) - output_width += 1 - - if output_height % 2 != 0: - self.log.warning(( - "Converting output height from odd to even number. {} -> {}" - ).format(output_height, output_height + 1)) - output_height += 1 - - self.log.debug( - "Output resolution is {}x{}".format(output_width, output_height) - ) - - letter_box_def = output_def["letter_box"] - letter_box_enabled = letter_box_def["enabled"] - - # Skip processing if resolution is same as input's and letterbox is - # not set - if ( - output_width == input_width - and output_height == input_height - and not letter_box_enabled - and pixel_aspect == 1 - ): + # get video metadata + for stream in streams: + input_timecode = None + input_width = None + input_height = None + input_frame_rate = None + if "codec_type" in stream: + if stream["codec_type"] == "video": + self.log.debug("__Ffprobe Video: {}".format(stream)) + tags = stream.get("tags") or {} + input_timecode = tags.get("timecode") or "" + if "width" in stream and "height" in stream: + input_width = int(stream.get("width")) + input_height = int(stream.get("height")) + if "r_frame_rate" in stream: + # get frame rate in a form of + # x/y, like 24000/1001 for 23.976 + input_frame_rate = str(stream.get("r_frame_rate")) + if ( + input_timecode + and input_width + and input_height + and input_frame_rate + ): + break + # Raise exception of any stream didn't define input resolution + if input_width is None: + raise AssertionError(( + "FFprobe couldn't read resolution from input file: \"{}\"" + ).format(input_path)) + # Get audio metadata + for stream in streams: + audio_channels = None + audio_sample_rate = None + audio_channel_layout = None + input_audio = False + if stream["codec_type"] == "audio": + self.log.debug("__Ffprobe Audio: {}".format(stream)) + if stream["channels"]: + audio_channels = str(stream.get("channels")) + if stream["sample_rate"]: + audio_sample_rate = str(stream.get("sample_rate")) + if stream["channel_layout"]: + audio_channel_layout = str( + stream.get("channel_layout")) + if ( + audio_channels + and audio_sample_rate + and audio_channel_layout + ): + input_audio = True + break + # Get duration of one frame in micro seconds + one_frame_duration = "40000us" + if input_frame_rate: + items = input_frame_rate.split("/") + if len(items) == 1: + one_frame_duration = float(1.0) / float(items[0]) + elif len(items) == 2: + one_frame_duration = float(items[1]) / float(items[0]) + one_frame_duration *= 1000000 + one_frame_duration = str(int(one_frame_duration)) + "us" self.log.debug( - "Output resolution is same as input's" - " and \"letter_box\" key is not set. Skipping reformat part." - ) - new_repre["resolutionWidth"] = input_width - new_repre["resolutionHeight"] = input_height - return filters + "One frame duration is {}".format(one_frame_duration)) - # defining image ratios - input_res_ratio = ( - (float(input_width) * pixel_aspect) / input_height - ) - output_res_ratio = float(output_width) / float(output_height) - self.log.debug("input_res_ratio: `{}`".format(input_res_ratio)) - self.log.debug("output_res_ratio: `{}`".format(output_res_ratio)) - - # Round ratios to 2 decimal places for comparing - input_res_ratio = round(input_res_ratio, 2) - output_res_ratio = round(output_res_ratio, 2) - - # get scale factor - scale_factor_by_width = ( - float(output_width) / (input_width * pixel_aspect) - ) - scale_factor_by_height = ( - float(output_height) / input_height - ) - - self.log.debug( - "scale_factor_by_with: `{}`".format(scale_factor_by_width) - ) - self.log.debug( - "scale_factor_by_height: `{}`".format(scale_factor_by_height) - ) - - # scaling none square pixels and 1920 width - if ( - input_height != output_height - or input_width != output_width - or pixel_aspect != 1 - ): - if input_res_ratio < output_res_ratio: - self.log.debug( - "Input's resolution ratio is lower then output's" - ) - width_scale = int(input_width * scale_factor_by_height) - width_half_pad = int((output_width - width_scale) / 2) - height_scale = output_height - height_half_pad = 0 + # values are set in ExtractReview + if use_legacy_code: + to_width = inst_data["reviewToWidth"] + to_height = inst_data["reviewToHeight"] else: - self.log.debug("Input is heigher then output") - width_scale = output_width - width_half_pad = 0 - height_scale = int(input_height * scale_factor_by_width) - height_half_pad = int((output_height - height_scale) / 2) + to_width = input_width + to_height = input_height - self.log.debug("width_scale: `{}`".format(width_scale)) - self.log.debug("width_half_pad: `{}`".format(width_half_pad)) - self.log.debug("height_scale: `{}`".format(height_scale)) - self.log.debug("height_half_pad: `{}`".format(height_half_pad)) + self.log.debug("to_width: `{}`".format(to_width)) + self.log.debug("to_height: `{}`".format(to_height)) - filters.extend([ - "scale={}x{}:flags=lanczos".format( - width_scale, height_scale - ), - "pad={}:{}:{}:{}:{}".format( - output_width, output_height, - width_half_pad, height_half_pad, - overscan_color_value - ), - "setsar=1" + # defining image ratios + resolution_ratio = ( + (float(slate_width) * pixel_aspect) / slate_height + ) + delivery_ratio = float(to_width) / float(to_height) + self.log.debug("resolution_ratio: `{}`".format(resolution_ratio)) + self.log.debug("delivery_ratio: `{}`".format(delivery_ratio)) + + # get scale factor + scale_factor_by_height = float(to_height) / slate_height + scale_factor_by_width = float(to_width) / ( + slate_width * pixel_aspect + ) + + # shorten two decimals long float number for testing conditions + resolution_ratio_test = float("{:0.2f}".format(resolution_ratio)) + delivery_ratio_test = float("{:0.2f}".format(delivery_ratio)) + + self.log.debug("__ scale_factor_by_width: `{}`".format( + scale_factor_by_width + )) + self.log.debug("__ scale_factor_by_height: `{}`".format( + scale_factor_by_height + )) + + _remove_at_end = [] + + ext = os.path.splitext(input_file)[1] + output_file = input_file.replace(ext, "") + suffix + ext + + _remove_at_end.append(input_path) + + output_path = os.path.join( + os.path.normpath(stagingdir), output_file) + self.log.debug("__ output_path: {}".format(output_path)) + + input_args = [] + output_args = [] + + # preset's input data + if use_legacy_code: + input_args.extend(repre["_profile"].get('input', [])) + else: + input_args.extend(repre["outputDef"].get('input', [])) + + input_args.append("-loop 1 -i {}".format( + openpype.lib.path_to_subprocess_arg(slate_path))) + # if input has an audio, add silent audio to the slate + if input_audio: + input_args.extend( + ["-f lavfi -i anullsrc=r={}:cl={}:d={}".format( + audio_sample_rate, + audio_channel_layout, + one_frame_duration + )] + ) + + input_args.extend(["-r {}".format(input_frame_rate)]) + input_args.extend(["-frames:v 1"]) + # add timecode from source to the slate, substract one frame + if input_timecode: + offset_timecode = self._tc_offset( + str(input_timecode), + framerate=fps, + frame_offset=-1 + ) + self.log.debug("Slate Timecode: `{}`".format( + offset_timecode + )) + if offset_timecode: + input_args.extend(["-timecode {}".format(offset_timecode)]) + else: + # fall back to input timecode if offset fails + input_args.extend(["-timecode {}".format(input_timecode)]) + if use_legacy_code: + codec_args = repre["_profile"].get('codec', []) + output_args.extend(codec_args) + # preset's output data + output_args.extend(repre["_profile"].get('output', [])) + else: + # Codecs are copied from source for whole input + codec_args = self._get_codec_args(repre) + output_args.extend(codec_args) + + # make sure colors are correct + output_args.extend([ + "-vf scale=out_color_matrix=bt709", + "-color_primaries bt709", + "-color_trc bt709", + "-colorspace bt709" ]) - # letter_box - if letter_box_enabled: - filters.extend( - self.get_letterbox_filters( - letter_box_def, - output_width, - output_height + # scaling none square pixels and 1920 width + if ( + # Always scale slate if not legacy + not use_legacy_code or + # Legacy code required reformat tag + (use_legacy_code and "reformat" in p_tags) + ): + if resolution_ratio_test < delivery_ratio_test: + self.log.debug("lower then delivery") + width_scale = int(slate_width * scale_factor_by_height) + width_half_pad = int((to_width - width_scale) / 2) + height_scale = to_height + height_half_pad = 0 + else: + self.log.debug("heigher then delivery") + width_scale = to_width + width_half_pad = 0 + height_scale = int(slate_height * scale_factor_by_width) + height_half_pad = int((to_height - height_scale) / 2) + + self.log.debug( + "__ width_scale: `{}`".format(width_scale) ) + self.log.debug( + "__ width_half_pad: `{}`".format(width_half_pad) + ) + self.log.debug( + "__ height_scale: `{}`".format(height_scale) + ) + self.log.debug( + "__ height_half_pad: `{}`".format(height_half_pad) + ) + + scaling_arg = ("scale={0}x{1}:flags=lanczos," + "pad={2}:{3}:{4}:{5}:black,setsar=1").format( + width_scale, height_scale, to_width, to_height, + width_half_pad, height_half_pad + ) + # add output frame rate as a filter, just in case + scaling_arg += ",fps={}".format(input_frame_rate) + vf_back = self.add_video_filter_args(output_args, scaling_arg) + # add it to output_args + output_args.insert(0, vf_back) + + # overrides output file + output_args.append("-y") + + slate_v_path = slate_path.replace(".png", ext) + output_args.append( + path_to_subprocess_arg(slate_v_path) + ) + _remove_at_end.append(slate_v_path) + + slate_args = [ + path_to_subprocess_arg(ffmpeg_path), + " ".join(input_args), + " ".join(output_args) + ] + slate_subprocess_cmd = " ".join(slate_args) + + # run slate generation subprocess + self.log.debug( + "Slate Executing: {}".format(slate_subprocess_cmd) + ) + openpype.api.run_subprocess( + slate_subprocess_cmd, shell=True, logger=self.log ) - new_repre["resolutionWidth"] = output_width - new_repre["resolutionHeight"] = output_height + # create ffmpeg concat text file path + conc_text_file = input_file.replace(ext, "") + "_concat" + ".txt" + conc_text_path = os.path.join( + os.path.normpath(stagingdir), conc_text_file) + _remove_at_end.append(conc_text_path) + self.log.debug("__ conc_text_path: {}".format(conc_text_path)) - return filters + new_line = "\n" + with open(conc_text_path, "w") as conc_text_f: + conc_text_f.writelines([ + "file {}".format( + slate_v_path.replace("\\", "/")), + new_line, + "file {}".format(input_path.replace("\\", "/")) + ]) - def lut_filters(self, new_repre, instance, input_args): - """Add lut file to output ffmpeg filters.""" - filters = [] - # baking lut file application - lut_path = instance.data.get("lutPath") - if not lut_path or "bake-lut" not in new_repre["tags"]: - return filters - - # Prepare path for ffmpeg argument - lut_path = lut_path.replace("\\", "/").replace(":", "\\:") - - # Remove gamma from input arguments - if "-gamma" in input_args: - input_args.remove("-gamme") - - # Prepare filters - filters.append("lut3d=file='{}'".format(lut_path)) - # QUESTION hardcoded colormatrix? - filters.append("colormatrix=bt601:bt709") - - self.log.info("Added Lut to ffmpeg command.") - - return filters - - def main_family_from_instance(self, instance): - """Returns main family of entered instance.""" - family = instance.data.get("family") - if not family: - family = instance.data["families"][0] - return family - - def families_from_instance(self, instance): - """Returns all families of entered instance.""" - families = [] - family = instance.data.get("family") - if family: - families.append(family) - - for family in (instance.data.get("families") or tuple()): - if family not in families: - families.append(family) - return families - - def compile_list_of_regexes(self, in_list): - """Convert strings in entered list to compiled regex objects.""" - regexes = [] - if not in_list: - return regexes - - for item in in_list: - if not item: - continue - - try: - regexes.append(re.compile(item)) - except TypeError: - self.log.warning(( - "Invalid type \"{}\" value \"{}\"." - " Expected string based object. Skipping." - ).format(str(type(item)), str(item))) - - return regexes - - def validate_value_by_regexes(self, value, in_list): - """Validates in any regex from list match entered value. - - Args: - in_list (list): List with regexes. - value (str): String where regexes is checked. - - Returns: - int: Returns `0` when list is not set or is empty. Returns `1` when - any regex match value and returns `-1` when none of regexes - match value entered. - """ - if not in_list: - return 0 - - output = -1 - regexes = self.compile_list_of_regexes(in_list) - for regex in regexes: - if re.match(regex, value): - output = 1 - break - return output - - def profile_exclusion(self, matching_profiles): - """Find out most matching profile byt host, task and family match. - - Profiles are selectively filtered. Each profile should have - "__value__" key with list of booleans. Each boolean represents - existence of filter for specific key (host, tasks, family). - Profiles are looped in sequence. In each sequence are split into - true_list and false_list. For next sequence loop are used profiles in - true_list if there are any profiles else false_list is used. - - Filtering ends when only one profile left in true_list. Or when all - existence booleans loops passed, in that case first profile from left - profiles is returned. - - Args: - matching_profiles (list): Profiles with same values. - - Returns: - dict: Most matching profile. - """ - self.log.info( - "Search for first most matching profile in match order:" - " Host name -> Task name -> Family." - ) - # Filter all profiles with highest points value. First filter profiles - # with matching host if there are any then filter profiles by task - # name if there are any and lastly filter by family. Else use first in - # list. - idx = 0 - final_profile = None - while True: - profiles_true = [] - profiles_false = [] - for profile in matching_profiles: - value = profile["__value__"] - # Just use first profile when idx is greater than values. - if not idx < len(value): - final_profile = profile - break - - if value[idx]: - profiles_true.append(profile) - else: - profiles_false.append(profile) - - if final_profile is not None: - break - - if profiles_true: - matching_profiles = profiles_true - else: - matching_profiles = profiles_false - - if len(matching_profiles) == 1: - final_profile = matching_profiles[0] - break - idx += 1 - - final_profile.pop("__value__") - return final_profile - - def find_matching_profile(self, host_name, task_name, family): - """ Filter profiles by Host name, Task name and main Family. - - Filtering keys are "hosts" (list), "tasks" (list), "families" (list). - If key is not find or is empty than it's expected to match. - - Args: - profiles (list): Profiles definition from presets. - host_name (str): Current running host name. - task_name (str): Current context task name. - family (str): Main family of current Instance. - - Returns: - dict/None: Return most matching profile or None if none of profiles - match at least one criteria. - """ - - matching_profiles = None - if not self.profiles: - return matching_profiles - - highest_profile_points = -1 - # Each profile get 1 point for each matching filter. Profile with most - # points is returned. For cases when more than one profile will match - # are also stored ordered lists of matching values. - for profile in self.profiles: - profile_points = 0 - profile_value = [] - - # Host filtering - host_names = profile.get("hosts") - match = self.validate_value_by_regexes(host_name, host_names) - if match == -1: - self.log.debug( - "\"{}\" not found in {}".format(host_name, host_names) - ) - continue - profile_points += match - profile_value.append(bool(match)) - - # Task filtering - task_names = profile.get("tasks") - match = self.validate_value_by_regexes(task_name, task_names) - if match == -1: - self.log.debug( - "\"{}\" not found in {}".format(task_name, task_names) - ) - continue - profile_points += match - profile_value.append(bool(match)) - - # Family filtering - families = profile.get("families") - match = self.validate_value_by_regexes(family, families) - if match == -1: - self.log.debug( - "\"{}\" not found in {}".format(family, families) - ) - continue - profile_points += match - profile_value.append(bool(match)) - - if profile_points < highest_profile_points: - continue - - if profile_points > highest_profile_points: - matching_profiles = [] - highest_profile_points = profile_points - - if profile_points == highest_profile_points: - profile["__value__"] = profile_value - matching_profiles.append(profile) - - if not matching_profiles: - self.log.warning(( - "None of profiles match your setup." - " Host \"{}\" | Task: \"{}\" | Family: \"{}\"" - ).format(host_name, task_name, family)) - return - - if len(matching_profiles) == 1: - # Pop temporary key `__value__` - matching_profiles[0].pop("__value__") - return matching_profiles[0] - - self.log.warning(( - "More than one profile match your setup." - " Host \"{}\" | Task: \"{}\" | Family: \"{}\"" - ).format(host_name, task_name, family)) - - return self.profile_exclusion(matching_profiles) - - def families_filter_validation(self, families, output_families_filter): - """Determines if entered families intersect with families filters. - - All family values are lowered to avoid unexpected results. - """ - if not output_families_filter: - return True - - single_families = [] - combination_families = [] - for family_filter in output_families_filter: - if not family_filter: - continue - if isinstance(family_filter, (list, tuple)): - _family_filter = [] - for family in family_filter: - if family: - _family_filter.append(family.lower()) - combination_families.append(_family_filter) - else: - single_families.append(family_filter.lower()) - - for family in single_families: - if family in families: - return True - - for family_combination in combination_families: - valid = True - for family in family_combination: - if family not in families: - valid = False - break - - if valid: - return True - return False - - def filter_output_defs(self, profile, subset_name, families): - """Return outputs matching input instance families. - - Output definitions without families filter are marked as valid. - - Args: - profile (dict): Profile from presets matching current context. - families (list): All families of current instance. - - Returns: - list: Containg all output definitions matching entered families. - """ - outputs = profile.get("outputs") or [] - if not outputs: - return outputs - - # lower values - # QUESTION is this valid operation? - families = [family.lower() for family in families] - - filtered_outputs = {} - for filename_suffix, output_def in outputs.items(): - output_filters = output_def.get("filter") - # If no filter on output preset, skip filtering and add output - # profile for farther processing - if not output_filters: - filtered_outputs[filename_suffix] = output_def - continue - - families_filters = output_filters.get("families") - if not self.families_filter_validation(families, families_filters): - continue - - # Subsets name filters - subset_filters = [ - subset_filter - for subset_filter in output_filters.get("subsets", []) - # Skip empty strings - if subset_filter + # concat slate and videos together + concat_args = [ + ffmpeg_path, + "-y", + "-f", "concat", + "-safe", "0", + "-i", conc_text_path, + "-c:v", "copy", + output_path ] - if subset_name and subset_filters: - match = False - for subset_filter in subset_filters: - compiled = re.compile(subset_filter) - if compiled.search(subset_name): - match = True - break + if not input_audio: + # ffmpeg concat subprocess + self.log.debug( + "Executing concat: {}".format(" ".join(concat_args)) + ) + openpype.api.run_subprocess( + concat_args, logger=self.log + ) + else: + self.log.warning( + "Audio found. Creating slate with audio" + " is not supported at this time. Outputing slate-less" + ":\n{}".format(input_file)) + # skip concatenating slate, use slate-less file instead + shutil.copyfile(input_path, output_path) - if not match: - continue + self.log.debug("__ repre[tags]: {}".format(repre["tags"])) + repre_update = { + "files": output_file, + "name": repre["name"], + "tags": [x for x in repre["tags"] if x != "delete"] + } + inst_data["representations"][idx].update(repre_update) + self.log.debug( + "_ representation {}: `{}`".format( + idx, inst_data["representations"][idx])) - filtered_outputs[filename_suffix] = output_def + # removing temp files + for f in _remove_at_end: + os.remove(f) + self.log.debug("Removed: `{}`".format(f)) - return filtered_outputs + # Remove any representations tagged for deletion. + for repre in inst_data.get("representations", []): + if "delete" in repre.get("tags", []): + self.log.debug("Removing representation: {}".format(repre)) + inst_data["representations"].remove(repre) - def filter_outputs_by_tags(self, outputs, tags): - """Filter output definitions by entered representation tags. - - Output definitions without tags filter are marked as valid. - - Args: - outputs (list): Contain list of output definitions from presets. - tags (list): Tags of processed representation. - - Returns: - list: Containg all output definitions matching entered tags. - """ - filtered_outputs = [] - repre_tags_low = [tag.lower() for tag in tags] - for output_def in outputs: - valid = True - output_filters = output_def.get("filter") - if output_filters: - # Check tag filters - tag_filters = output_filters.get("tags") - if tag_filters: - tag_filters_low = [tag.lower() for tag in tag_filters] - valid = False - for tag in repre_tags_low: - if tag in tag_filters_low: - valid = True - break - - if not valid: - continue - - if valid: - filtered_outputs.append(output_def) - - return filtered_outputs + self.log.debug(inst_data["representations"]) def add_video_filter_args(self, args, inserting_arg): """ - Fixing video filter arguments to be one long string + Fixing video filter argumets to be one long string Args: args (list): list of string arguments @@ -1784,299 +416,74 @@ class ExtractReview(pyblish.api.InstancePlugin): return vf_back + def _get_codec_args(self, repre): + """Detect possible codec arguments from representation.""" + codec_args = [] -@six.add_metaclass(ABCMeta) -class _OverscanValue: - def __repr__(self): - return "<{}> {}".format(self.__class__.__name__, str(self)) + # Get one filename of representation files + filename = repre["files"] + # If files is list then pick first filename in list + if isinstance(filename, (tuple, list)): + filename = filename[0] + # Get full path to the file + full_input_path = os.path.join(repre["stagingDir"], filename) - @abstractmethod - def copy(self): - """Create a copy of object.""" - pass - - @abstractmethod - def size_for(self, value): - """Calculate new value for passed value.""" - pass - - -class PixValueExplicit(_OverscanValue): - def __init__(self, value): - self._value = int(value) - - def __str__(self): - return "{}px".format(self._value) - - def copy(self): - return PixValueExplicit(self._value) - - def size_for(self, value): - if self._value == 0: - return value - return self._value - - -class PercentValueExplicit(_OverscanValue): - def __init__(self, value): - self._value = float(value) - - def __str__(self): - return "{}%".format(abs(self._value)) - - def copy(self): - return PercentValueExplicit(self._value) - - def size_for(self, value): - if self._value == 0: - return value - return int((value / 100) * self._value) - - -class PixValueRelative(_OverscanValue): - def __init__(self, value): - self._value = int(value) - - def __str__(self): - sign = "-" if self._value < 0 else "+" - return "{}{}px".format(sign, abs(self._value)) - - def copy(self): - return PixValueRelative(self._value) - - def size_for(self, value): - return value + self._value - - -class PercentValueRelative(_OverscanValue): - def __init__(self, value): - self._value = float(value) - - def __str__(self): - return "{}%".format(self._value) - - def copy(self): - return PercentValueRelative(self._value) - - def size_for(self, value): - if self._value == 0: - return value - - offset = int((value / 100) * self._value) - - return value + offset - - -class PercentValueRelativeSource(_OverscanValue): - def __init__(self, value, source_sign): - self._value = float(value) - if source_sign not in ("-", "+"): - raise ValueError( - "Invalid sign value \"{}\" expected \"-\" or \"+\"".format( - source_sign - ) + try: + # Get information about input file via ffprobe tool + ffprobe_data = get_ffprobe_data(full_input_path, self.log) + except Exception: + self.log.warning( + "Could not get codec data from input.", + exc_info=True ) - self._source_sign = source_sign + return codec_args - def __str__(self): - return "{}%{}".format(self._value, self._source_sign) - - def copy(self): - return PercentValueRelativeSource(self._value, self._source_sign) - - def size_for(self, value): - if self._value == 0: - return value - return int((value * 100) / (100 - self._value)) - - -class OverscanCrop: - """Helper class to read overscan string and calculate output resolution. - - It is possible to enter single value for both width and heigh or two values - for width and height. Overscan string may have a few variants. Each variant - define output size for input size. - - ### Example - For input size: 2200px - - | String | Output | Description | - |----------|--------|-------------------------------------------------| - | "" | 2200px | Empty string does nothing. | - | "10%" | 220px | Explicit percent size. | - | "-10%" | 1980px | Relative percent size (decrease). | - | "+10%" | 2420px | Relative percent size (increase). | - | "-10%+" | 2000px | Relative percent size to output size. | - | "300px" | 300px | Explicit output size cropped or expanded. | - | "-300px" | 1900px | Relative pixel size (decrease). | - | "+300px" | 2500px | Relative pixel size (increase). | - | "300" | 300px | Value without "%" and "px" is used as has "px". | - - Value without sign (+/-) in is always explicit and value with sign is - relative. Output size for "200px" and "+200px" are not the same. - Values "0", "0px" or "0%" are ignored. - - All values that cause output resolution smaller than 1 pixel are invalid. - - Value "-10%+" is a special case which says that input's resolution is - bigger by 10% than expected output. - - It is possible to combine these variants to define different output for - width and height. - - Resolution: 2000px 1000px - - | String | Output | - |---------------|---------------| - | "100px 120px" | 2100px 1120px | - | "-10% -200px" | 1800px 800px | - """ - - item_regex = re.compile(r"([\+\-])?([0-9]+)(.+)?") - relative_source_regex = re.compile(r"%([\+\-])") - - def __init__( - self, input_width, input_height, string_value, overscal_color=None - ): - # Make sure that is not None - string_value = string_value or "" - - self.input_width = input_width - self.input_height = input_height - self.overscal_color = overscal_color - - width, height = self._convert_string_to_values(string_value) - self._width_value = width - self._height_value = height - - self._string_value = string_value - - def __str__(self): - return "{}".format(self._string_value) - - def __repr__(self): - return "<{}>".format(self.__class__.__name__) - - def width(self): - """Calculated width.""" - return self._width_value.size_for(self.input_width) - - def height(self): - """Calculated height.""" - return self._height_value.size_for(self.input_height) - - def video_filters(self): - """FFmpeg video filters to achieve expected result. - - Filter may be empty, use "crop" filter, "pad" filter or combination of - "crop" and "pad". - - Returns: - list: FFmpeg video filters. - """ - # crop=width:height:x:y - explicit start x, y position - # crop=width:height - x, y are related to center by width/height - # pad=width:heigth:x:y - explicit start x, y position - # pad=width:heigth - x, y are set to 0 by default - - width = self.width() - height = self.height() - - output = [] - if self.input_width == width and self.input_height == height: - return output - - # Make sure resolution has odd numbers - if width % 2 == 1: - width -= 1 - - if height % 2 == 1: - height -= 1 - - if width <= self.input_width and height <= self.input_height: - output.append("crop={}:{}".format(width, height)) - - elif width >= self.input_width and height >= self.input_height: - output.append( - "pad={}:{}:(iw-ow)/2:(ih-oh)/2:{}".format( - width, height, self.overscal_color - ) + source_ffmpeg_cmd = repre.get("ffmpeg_cmd") + codec_args.extend( + get_ffmpeg_format_args(ffprobe_data, source_ffmpeg_cmd) + ) + codec_args.extend( + get_ffmpeg_codec_args( + ffprobe_data, source_ffmpeg_cmd, logger=self.log ) - - elif width > self.input_width and height < self.input_height: - output.append("crop=iw:{}".format(height)) - output.append("pad={}:ih:(iw-ow)/2:(ih-oh)/2:{}".format( - width, self.overscal_color - )) - - elif width < self.input_width and height > self.input_height: - output.append("crop={}:ih".format(width)) - output.append("pad=iw:{}:(iw-ow)/2:(ih-oh)/2:{}".format( - height, self.overscal_color - )) - - return output - - def _convert_string_to_values(self, orig_string_value): - string_value = orig_string_value.strip().lower() - if not string_value: - return [PixValueRelative(0), PixValueRelative(0)] - - # Replace "px" (and spaces before) with single space - string_value = re.sub(r"([ ]+)?px", " ", string_value) - string_value = re.sub(r"([ ]+)%", "%", string_value) - # Make sure +/- sign at the beggining of string is next to number - string_value = re.sub(r"^([\+\-])[ ]+", "\g<1>", string_value) - # Make sure +/- sign in the middle has zero spaces before number under - # which belongs - string_value = re.sub( - r"[ ]([\+\-])[ ]+([0-9])", - r" \g<1>\g<2>", - string_value ) - string_parts = [ - part - for part in string_value.split(" ") - if part - ] - error_msg = "Invalid string for rescaling \"{}\"".format( - orig_string_value - ) - if 1 > len(string_parts) > 2: - raise ValueError(error_msg) + return codec_args - output = [] - for item in string_parts: - groups = self.item_regex.findall(item) - if not groups: - raise ValueError(error_msg) - - relative_sign, value, ending = groups[0] - if not relative_sign: - if not ending: - output.append(PixValueExplicit(value)) - else: - output.append(PercentValueExplicit(value)) + def _tc_offset(self, timecode, framerate=24.0, frame_offset=-1): + """Offsets timecode by frame""" + def _seconds(value, framerate): + if isinstance(value, str): + _zip_ft = zip((3600, 60, 1, 1/framerate), value.split(':')) + _s = sum(f * float(t) for f,t in _zip_ft) + elif isinstance(value, (int, float)): + _s = value / framerate else: - source_sign_group = self.relative_source_regex.findall(ending) - if not ending: - output.append(PixValueRelative(int(relative_sign + value))) + _s = 0 + return _s - elif source_sign_group: - source_sign = source_sign_group[0] - output.append(PercentValueRelativeSource( - float(relative_sign + value), source_sign - )) - else: - output.append( - PercentValueRelative(float(relative_sign + value)) - ) + def _frames(seconds, framerate, frame_offset): + _f = seconds * framerate + frame_offset + if _f < 0: + _f = framerate * 60 * 60 * 24 + _f + return _f - if len(output) == 1: - width = output.pop(0) - height = width.copy() - else: - width, height = output - - return width, height + def _timecode(seconds, framerate): + return '{h:02d}:{m:02d}:{s:02d}:{f:02d}'.format( + h = int(seconds / 3600), + m = int(seconds / 60 % 60), + s = int(seconds % 60), + f = int(round((seconds - int(seconds)) * framerate))) + drop = False + if ';' in timecode: + timecode = timecode.replace(';', ':') + drop = True + frames = _frames( + _seconds(timecode, framerate), + framerate, + frame_offset + ) + tc = _timecode(_seconds(frames, framerate), framerate) + if drop: + tc = ';'.join(tc.rsplit(':', 1)) + return tc From 8abc3ff7953001b687af2d860e0892a3d968c0a6 Mon Sep 17 00:00:00 2001 From: Jiri Sindelar <45896205+jrsndl@users.noreply.github.com> Date: Thu, 14 Apr 2022 19:19:28 +0200 Subject: [PATCH 016/350] hound --- openpype/plugins/publish/extract_review_slate.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index c8ee2ec7ed..13526ece66 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -454,8 +454,8 @@ class ExtractReviewSlate(openpype.api.Extractor): """Offsets timecode by frame""" def _seconds(value, framerate): if isinstance(value, str): - _zip_ft = zip((3600, 60, 1, 1/framerate), value.split(':')) - _s = sum(f * float(t) for f,t in _zip_ft) + _zip_ft = zip((3600, 60, 1, 1 / framerate), value.split(':')) + _s = sum(f * float(t) for f, t in _zip_ft) elif isinstance(value, (int, float)): _s = value / framerate else: @@ -470,10 +470,10 @@ class ExtractReviewSlate(openpype.api.Extractor): def _timecode(seconds, framerate): return '{h:02d}:{m:02d}:{s:02d}:{f:02d}'.format( - h = int(seconds / 3600), - m = int(seconds / 60 % 60), - s = int(seconds % 60), - f = int(round((seconds - int(seconds)) * framerate))) + h=int(seconds / 3600), + m=int(seconds / 60 % 60), + s=int(seconds % 60), + f=int(round((seconds - int(seconds)) * framerate))) drop = False if ';' in timecode: timecode = timecode.replace(';', ':') From ddddb86e77939214d818a54efc7a0eda5587588d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Mon, 25 Apr 2022 18:56:20 +0200 Subject: [PATCH 017/350] wip on ue5 support --- openpype/hosts/unreal/lib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/unreal/lib.py b/openpype/hosts/unreal/lib.py index d4a776e892..c0b4c7061c 100644 --- a/openpype/hosts/unreal/lib.py +++ b/openpype/hosts/unreal/lib.py @@ -74,7 +74,7 @@ def get_editor_executable_path(engine_path: Path) -> Path: """Get UE4 Editor executable path.""" ue4_path = engine_path / "Engine/Binaries" if platform.system().lower() == "windows": - ue4_path /= "Win64/UE4Editor.exe" + ue4_path /= "Win64/UnrealEditor.exe" elif platform.system().lower() == "linux": ue4_path /= "Linux/UE4Editor" @@ -420,7 +420,7 @@ class {1}_API A{0}GameModeBase : public AGameModeBase f.write(game_mode_h) u_build_tool = Path( - engine_path / "Engine/Binaries/DotNET/UnrealBuildTool.exe") + engine_path / "Engine/Binaries/DotNET/UnrealBuildTool/UnrealBuildTool.exe") u_header_tool = None arch = "Win64" From faff541bc73529f1a2ebe16ff4b496d01d77f1af Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 26 Apr 2022 16:43:19 +0200 Subject: [PATCH 018/350] Removed submodule repos/avalon-core --- .gitmodules | 0 repos/avalon-core | 1 - 2 files changed, 1 deletion(-) delete mode 100644 .gitmodules delete mode 160000 repos/avalon-core diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/repos/avalon-core b/repos/avalon-core deleted file mode 160000 index 2fa14cea6f..0000000000 --- a/repos/avalon-core +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2fa14cea6f6a9d86eec70bbb96860cbe4c75c8eb From fb2327ad3b6a71278def4632de287b16560b7142 Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Fri, 29 Apr 2022 13:25:23 +0200 Subject: [PATCH 019/350] concat timecode fix --- .../plugins/publish/extract_review_slate.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 13526ece66..71a1fccf53 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -213,7 +213,9 @@ class ExtractReviewSlate(openpype.api.Extractor): input_args.extend(["-r {}".format(input_frame_rate)]) input_args.extend(["-frames:v 1"]) # add timecode from source to the slate, substract one frame + offset_timecode = "00:00:00:00" if input_timecode: + offset_timecode = str(input_timecode) offset_timecode = self._tc_offset( str(input_timecode), framerate=fps, @@ -222,11 +224,7 @@ class ExtractReviewSlate(openpype.api.Extractor): self.log.debug("Slate Timecode: `{}`".format( offset_timecode )) - if offset_timecode: - input_args.extend(["-timecode {}".format(offset_timecode)]) - else: - # fall back to input timecode if offset fails - input_args.extend(["-timecode {}".format(input_timecode)]) + input_args.extend(["-timecode {}".format(offset_timecode)]) if use_legacy_code: codec_args = repre["_profile"].get('codec', []) output_args.extend(codec_args) @@ -283,11 +281,12 @@ class ExtractReviewSlate(openpype.api.Extractor): width_scale, height_scale, to_width, to_height, width_half_pad, height_half_pad ) - # add output frame rate as a filter, just in case - scaling_arg += ",fps={}".format(input_frame_rate) - vf_back = self.add_video_filter_args(output_args, scaling_arg) - # add it to output_args - output_args.insert(0, vf_back) + # add output frame rate as a filter, just in case + scaling_arg += ",fps={}".format(input_frame_rate) + + vf_back = self.add_video_filter_args(output_args, scaling_arg) + # add it to output_args + output_args.insert(0, vf_back) # overrides output file output_args.append("-y") @@ -336,7 +335,8 @@ class ExtractReviewSlate(openpype.api.Extractor): "-f", "concat", "-safe", "0", "-i", conc_text_path, - "-c:v", "copy", + "-c", "copy", + "-timecode", offset_timecode, output_path ] if not input_audio: From 5d8cea50461e9190ca1838fca55779235010333a Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Fri, 29 Apr 2022 13:27:14 +0200 Subject: [PATCH 020/350] hound --- openpype/plugins/publish/extract_review_slate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 71a1fccf53..46bd4f3a7b 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -336,7 +336,7 @@ class ExtractReviewSlate(openpype.api.Extractor): "-safe", "0", "-i", conc_text_path, "-c", "copy", - "-timecode", offset_timecode, + "-timecode", offset_timecode, output_path ] if not input_audio: From 49725781f4e8afc97f43f711dc3effb8d3ded7e0 Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Fri, 29 Apr 2022 17:43:02 +0200 Subject: [PATCH 021/350] Fix concatenating metadata Slate concatenation didn't pass metadata to output --- .../plugins/publish/extract_review_slate.py | 19 +++++++++++++++++-- openpype/scripts/otio_burnin.py | 1 + 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 46bd4f3a7b..d5741273a8 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -77,7 +77,7 @@ class ExtractReviewSlate(openpype.api.Extractor): streams = get_ffprobe_streams( input_path, self.log ) - # get video metadata + # Get video metadata for stream in streams: input_timecode = None input_width = None @@ -337,8 +337,23 @@ class ExtractReviewSlate(openpype.api.Extractor): "-i", conc_text_path, "-c", "copy", "-timecode", offset_timecode, - output_path ] + # Use arguments from ffmpeg preset + source_ffmpeg_cmd = repre.get("ffmpeg_cmd") + if source_ffmpeg_cmd: + copy_args = ( + "-metadata", + "-metadata:s:v:0", + ) + args = source_ffmpeg_cmd.split(" ") + for indx, arg in enumerate(args): + if arg in copy_args: + concat_args.append(arg) + # assumes arg has one parameter + concat_args.append(args[indx + 1]) + # add output + concat_args.append(output_path) + if not input_audio: # ffmpeg concat subprocess self.log.debug( diff --git a/openpype/scripts/otio_burnin.py b/openpype/scripts/otio_burnin.py index 1f57891b84..4c3a5de2ec 100644 --- a/openpype/scripts/otio_burnin.py +++ b/openpype/scripts/otio_burnin.py @@ -568,6 +568,7 @@ def burnins_from_data( if source_ffmpeg_cmd: copy_args = ( "-metadata", + "-metadata:s:v:0", ) args = source_ffmpeg_cmd.split(" ") for idx, arg in enumerate(args): From a80d37847dad918a0b8f401a0432a9c9f5faf1b5 Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Fri, 29 Apr 2022 17:46:34 +0200 Subject: [PATCH 022/350] hound --- openpype/plugins/publish/extract_review_slate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index d5741273a8..59150e9d4a 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -353,7 +353,7 @@ class ExtractReviewSlate(openpype.api.Extractor): concat_args.append(args[indx + 1]) # add output concat_args.append(output_path) - + if not input_audio: # ffmpeg concat subprocess self.log.debug( From 25fd05df9ea82f4698cc03d113b3b149d9bf2536 Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Tue, 3 May 2022 16:29:45 +0100 Subject: [PATCH 023/350] Updated plugin for UE5 --- .../Source/OpenPype/OpenPype.Build.cs | 2 + .../Source/OpenPype/Private/OpenPype.cpp | 110 ++++++++---------- .../OpenPype/Private/OpenPypeCommands.cpp | 13 +++ .../Source/OpenPype/Private/OpenPypeStyle.cpp | 53 ++++----- .../Source/OpenPype/Public/OpenPype.h | 8 +- .../Source/OpenPype/Public/OpenPypeCommands.h | 24 ++++ .../Source/OpenPype/Public/OpenPypeStyle.h | 12 +- 7 files changed, 116 insertions(+), 106 deletions(-) create mode 100644 openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypeCommands.cpp create mode 100644 openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypeCommands.h diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/OpenPype.Build.cs b/openpype/hosts/unreal/integration/Source/OpenPype/OpenPype.Build.cs index c30835b63d..fcfd268234 100644 --- a/openpype/hosts/unreal/integration/Source/OpenPype/OpenPype.Build.cs +++ b/openpype/hosts/unreal/integration/Source/OpenPype/OpenPype.Build.cs @@ -36,7 +36,9 @@ public class OpenPype : ModuleRules { "Projects", "InputCore", + "EditorFramework", "UnrealEd", + "ToolMenus", "LevelEditor", "CoreUObject", "Engine", diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPype.cpp b/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPype.cpp index 15c46b3862..b3bd9a81b3 100644 --- a/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPype.cpp +++ b/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPype.cpp @@ -1,7 +1,10 @@ #include "OpenPype.h" -#include "LevelEditor.h" -#include "OpenPypePythonBridge.h" #include "OpenPypeStyle.h" +#include "OpenPypeCommands.h" +#include "OpenPypePythonBridge.h" +#include "LevelEditor.h" +#include "Misc/MessageDialog.h" +#include "ToolMenus.h" static const FName OpenPypeTabName("OpenPype"); @@ -11,82 +14,61 @@ static const FName OpenPypeTabName("OpenPype"); // This function is triggered when the plugin is staring up void FOpenPypeModule::StartupModule() { - FOpenPypeStyle::Initialize(); - FOpenPypeStyle::SetIcon("Logo", "openpype40"); + FOpenPypeStyle::ReloadTextures(); + FOpenPypeCommands::Register(); - // Create the Extender that will add content to the menu - FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked("LevelEditor"); - - TSharedPtr MenuExtender = MakeShareable(new FExtender()); - TSharedPtr ToolbarExtender = MakeShareable(new FExtender()); + PluginCommands = MakeShareable(new FUICommandList); - MenuExtender->AddMenuExtension( - "LevelEditor", - EExtensionHook::After, - NULL, - FMenuExtensionDelegate::CreateRaw(this, &FOpenPypeModule::AddMenuEntry) - ); - ToolbarExtender->AddToolBarExtension( - "Settings", - EExtensionHook::After, - NULL, - FToolBarExtensionDelegate::CreateRaw(this, &FOpenPypeModule::AddToobarEntry)); - - - LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender); - LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender); + PluginCommands->MapAction( + FOpenPypeCommands::Get().OpenPypeTools, + FExecuteAction::CreateRaw(this, &FOpenPypeModule::MenuPopup), + FCanExecuteAction()); + PluginCommands->MapAction( + FOpenPypeCommands::Get().OpenPypeToolsDialog, + FExecuteAction::CreateRaw(this, &FOpenPypeModule::MenuDialog), + FCanExecuteAction()); + UToolMenus::RegisterStartupCallback(FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FOpenPypeModule::RegisterMenus)); } void FOpenPypeModule::ShutdownModule() { + UToolMenus::UnRegisterStartupCallback(this); + + UToolMenus::UnregisterOwner(this); + FOpenPypeStyle::Shutdown(); + + FOpenPypeCommands::Unregister(); } - -void FOpenPypeModule::AddMenuEntry(FMenuBuilder& MenuBuilder) +void FOpenPypeModule::RegisterMenus() { - // Create Section - MenuBuilder.BeginSection("OpenPype", TAttribute(FText::FromString("OpenPype"))); + // Owner will be used for cleanup in call to UToolMenus::UnregisterOwner + FToolMenuOwnerScoped OwnerScoped(this); + { - // Create a Submenu inside of the Section - MenuBuilder.AddMenuEntry( - FText::FromString("Tools..."), - FText::FromString("Pipeline tools"), - FSlateIcon(FOpenPypeStyle::GetStyleSetName(), "OpenPype.Logo"), - FUIAction(FExecuteAction::CreateRaw(this, &FOpenPypeModule::MenuPopup)) - ); - - MenuBuilder.AddMenuEntry( - FText::FromString("Tools dialog..."), - FText::FromString("Pipeline tools dialog"), - FSlateIcon(FOpenPypeStyle::GetStyleSetName(), "OpenPype.Logo"), - FUIAction(FExecuteAction::CreateRaw(this, &FOpenPypeModule::MenuDialog)) - ); - + UToolMenu* Menu = UToolMenus::Get()->ExtendMenu("LevelEditor.MainMenu.Tools"); + { + // FToolMenuSection& Section = Menu->FindOrAddSection("OpenPype"); + FToolMenuSection& Section = Menu->AddSection( + "OpenPype", + TAttribute(FText::FromString("OpenPype")), + FToolMenuInsert("Programming", EToolMenuInsertType::Before) + ); + Section.AddMenuEntryWithCommandList(FOpenPypeCommands::Get().OpenPypeTools, PluginCommands); + Section.AddMenuEntryWithCommandList(FOpenPypeCommands::Get().OpenPypeToolsDialog, PluginCommands); + } + UToolMenu* ToolbarMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.LevelEditorToolBar.PlayToolBar"); + { + FToolMenuSection& Section = ToolbarMenu->FindOrAddSection("PluginTools"); + { + FToolMenuEntry& Entry = Section.AddEntry(FToolMenuEntry::InitToolBarButton(FOpenPypeCommands::Get().OpenPypeTools)); + Entry.SetCommandList(PluginCommands); + } + } } - MenuBuilder.EndSection(); -} - -void FOpenPypeModule::AddToobarEntry(FToolBarBuilder& ToolbarBuilder) -{ - ToolbarBuilder.BeginSection(TEXT("OpenPype")); - { - ToolbarBuilder.AddToolBarButton( - FUIAction( - FExecuteAction::CreateRaw(this, &FOpenPypeModule::MenuPopup), - NULL, - FIsActionChecked() - - ), - NAME_None, - LOCTEXT("OpenPype_label", "OpenPype"), - LOCTEXT("OpenPype_tooltip", "OpenPype Tools"), - FSlateIcon(FOpenPypeStyle::GetStyleSetName(), "OpenPype.Logo") - ); - } - ToolbarBuilder.EndSection(); } diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypeCommands.cpp b/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypeCommands.cpp new file mode 100644 index 0000000000..6187bd7c7e --- /dev/null +++ b/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypeCommands.cpp @@ -0,0 +1,13 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OpenPypeCommands.h" + +#define LOCTEXT_NAMESPACE "FOpenPypeModule" + +void FOpenPypeCommands::RegisterCommands() +{ + UI_COMMAND(OpenPypeTools, "OpenPype Tools", "Pipeline tools", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(OpenPypeToolsDialog, "OpenPype Tools Dialog", "Pipeline tools dialog", EUserInterfaceActionType::Button, FInputChord()); +} + +#undef LOCTEXT_NAMESPACE diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypeStyle.cpp b/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypeStyle.cpp index a51c2d6aa5..4a53af26b5 100644 --- a/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypeStyle.cpp +++ b/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypeStyle.cpp @@ -1,10 +1,14 @@ +#include "OpenPype.h" #include "OpenPypeStyle.h" #include "Framework/Application/SlateApplication.h" -#include "Styling/SlateStyle.h" #include "Styling/SlateStyleRegistry.h" +#include "Slate/SlateGameResources.h" +#include "Interfaces/IPluginManager.h" +#include "Styling/SlateStyleMacros.h" +#define RootToContentDir Style->RootToContentDir -TUniquePtr< FSlateStyleSet > FOpenPypeStyle::OpenPypeStyleInstance = nullptr; +TSharedPtr FOpenPypeStyle::OpenPypeStyleInstance = nullptr; void FOpenPypeStyle::Initialize() { @@ -17,11 +21,9 @@ void FOpenPypeStyle::Initialize() void FOpenPypeStyle::Shutdown() { - if (OpenPypeStyleInstance.IsValid()) - { - FSlateStyleRegistry::UnRegisterSlateStyle(*OpenPypeStyleInstance); - OpenPypeStyleInstance.Reset(); - } + FSlateStyleRegistry::UnRegisterSlateStyle(*OpenPypeStyleInstance); + ensure(OpenPypeStyleInstance.IsUnique()); + OpenPypeStyleInstance.Reset(); } FName FOpenPypeStyle::GetStyleSetName() @@ -30,41 +32,30 @@ FName FOpenPypeStyle::GetStyleSetName() return StyleSetName; } -FName FOpenPypeStyle::GetContextName() -{ - static FName ContextName(TEXT("OpenPype")); - return ContextName; -} - -#define IMAGE_BRUSH(RelativePath, ...) FSlateImageBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ ) - +const FVector2D Icon16x16(16.0f, 16.0f); +const FVector2D Icon20x20(20.0f, 20.0f); const FVector2D Icon40x40(40.0f, 40.0f); -TUniquePtr< FSlateStyleSet > FOpenPypeStyle::Create() +TSharedRef< FSlateStyleSet > FOpenPypeStyle::Create() { - TUniquePtr< FSlateStyleSet > Style = MakeUnique(GetStyleSetName()); - Style->SetContentRoot(FPaths::ProjectPluginsDir() / TEXT("OpenPype/Resources")); + TSharedRef< FSlateStyleSet > Style = MakeShareable(new FSlateStyleSet("OpenPypeStyle")); + Style->SetContentRoot(IPluginManager::Get().FindPlugin("OpenPype")->GetBaseDir() / TEXT("Resources")); + + Style->Set("OpenPype.OpenPypeTools", new IMAGE_BRUSH(TEXT("openpype40"), Icon40x40)); + Style->Set("OpenPype.OpenPypeToolsDialog", new IMAGE_BRUSH(TEXT("openpype40"), Icon40x40)); return Style; } -void FOpenPypeStyle::SetIcon(const FString& StyleName, const FString& ResourcePath) +void FOpenPypeStyle::ReloadTextures() { - FSlateStyleSet* Style = OpenPypeStyleInstance.Get(); - - FString Name(GetContextName().ToString()); - Name = Name + "." + StyleName; - Style->Set(*Name, new FSlateImageBrush(Style->RootToContentDir(ResourcePath, TEXT(".png")), Icon40x40)); - - - FSlateApplication::Get().GetRenderer()->ReloadTextureResources(); + if (FSlateApplication::IsInitialized()) + { + FSlateApplication::Get().GetRenderer()->ReloadTextureResources(); + } } -#undef IMAGE_BRUSH - const ISlateStyle& FOpenPypeStyle::Get() { - check(OpenPypeStyleInstance); - return *OpenPypeStyleInstance; return *OpenPypeStyleInstance; } diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPype.h b/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPype.h index db3f299354..3ee5eaa65f 100644 --- a/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPype.h +++ b/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPype.h @@ -2,7 +2,8 @@ #pragma once -#include "Engine.h" +#include "CoreMinimal.h" +#include "Modules/ModuleManager.h" class FOpenPypeModule : public IModuleInterface @@ -12,10 +13,11 @@ public: virtual void ShutdownModule() override; private: + void RegisterMenus(); - void AddMenuEntry(FMenuBuilder& MenuBuilder); - void AddToobarEntry(FToolBarBuilder& ToolbarBuilder); void MenuPopup(); void MenuDialog(); +private: + TSharedPtr PluginCommands; }; diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypeCommands.h b/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypeCommands.h new file mode 100644 index 0000000000..62ffb8de33 --- /dev/null +++ b/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypeCommands.h @@ -0,0 +1,24 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Framework/Commands/Commands.h" +#include "OpenPypeStyle.h" + +class FOpenPypeCommands : public TCommands +{ +public: + + FOpenPypeCommands() + : TCommands(TEXT("OpenPype"), NSLOCTEXT("Contexts", "OpenPype", "OpenPype Tools"), NAME_None, FOpenPypeStyle::GetStyleSetName()) + { + } + + // TCommands<> interface + virtual void RegisterCommands() override; + +public: + TSharedPtr< FUICommandInfo > OpenPypeTools; + TSharedPtr< FUICommandInfo > OpenPypeToolsDialog; +}; diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypeStyle.h b/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypeStyle.h index fbc8bcdd5b..ae704251e1 100644 --- a/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypeStyle.h +++ b/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypeStyle.h @@ -1,22 +1,18 @@ #pragma once #include "CoreMinimal.h" - -class FSlateStyleSet; -class ISlateStyle; - +#include "Styling/SlateStyle.h" class FOpenPypeStyle { public: static void Initialize(); static void Shutdown(); + static void ReloadTextures(); static const ISlateStyle& Get(); static FName GetStyleSetName(); - static FName GetContextName(); - static void SetIcon(const FString& StyleName, const FString& ResourcePath); private: - static TUniquePtr< FSlateStyleSet > Create(); - static TUniquePtr< FSlateStyleSet > OpenPypeStyleInstance; + static TSharedRef< class FSlateStyleSet > Create(); + static TSharedPtr< class FSlateStyleSet > OpenPypeStyleInstance; }; \ No newline at end of file From e2076c0f2fa264f4dc7ae6959c3292b60616ca91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Thu, 3 Feb 2022 19:03:16 +0100 Subject: [PATCH 024/350] Module: Kitsu module --- .../modules/default_modules/kitsu/__init__.py | 15 ++ .../default_modules/kitsu/kitsu_module.py | 147 ++++++++++++++++++ .../kitsu/plugins/publish/example_plugin.py | 9 ++ .../schemas/project_schemas/main.json | 30 ++++ .../schemas/project_schemas/the_template.json | 30 ++++ .../modules/default_modules/kitsu/widgets.py | 31 ++++ .../defaults/project_settings/kitsu.json | 3 + .../defaults/system_settings/modules.json | 4 + .../schemas/projects_schema/schema_main.json | 4 + .../projects_schema/schema_project_kitsu.json | 17 ++ .../module_settings/schema_kitsu.json | 23 +++ .../schemas/system_schema/schema_modules.json | 4 + 12 files changed, 317 insertions(+) create mode 100644 openpype/modules/default_modules/kitsu/__init__.py create mode 100644 openpype/modules/default_modules/kitsu/kitsu_module.py create mode 100644 openpype/modules/default_modules/kitsu/plugins/publish/example_plugin.py create mode 100644 openpype/modules/default_modules/kitsu/settings/schemas/project_schemas/main.json create mode 100644 openpype/modules/default_modules/kitsu/settings/schemas/project_schemas/the_template.json create mode 100644 openpype/modules/default_modules/kitsu/widgets.py create mode 100644 openpype/settings/defaults/project_settings/kitsu.json create mode 100644 openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json create mode 100644 openpype/settings/entities/schemas/system_schema/module_settings/schema_kitsu.json diff --git a/openpype/modules/default_modules/kitsu/__init__.py b/openpype/modules/default_modules/kitsu/__init__.py new file mode 100644 index 0000000000..cd0c2ea8af --- /dev/null +++ b/openpype/modules/default_modules/kitsu/__init__.py @@ -0,0 +1,15 @@ +""" Addon class definition and Settings definition must be imported here. + +If addon class or settings definition won't be here their definition won't +be found by OpenPype discovery. +""" + +from .kitsu_module import ( + AddonSettingsDef, + KitsuModule +) + +__all__ = ( + "AddonSettingsDef", + "KitsuModule" +) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py new file mode 100644 index 0000000000..81d7e56a81 --- /dev/null +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -0,0 +1,147 @@ +"""Addon definition is located here. + +Import of python packages that may not be available should not be imported +in global space here until are required or used. +- Qt related imports +- imports of Python 3 packages + - we still support Python 2 hosts where addon definition should available +""" + +import os +import click + +from openpype.modules import ( + JsonFilesSettingsDef, + OpenPypeModule, + ModulesManager +) +# Import interface defined by this addon to be able find other addons using it +from openpype_interfaces import ( + IPluginPaths, + ITrayAction +) + + +# Settings definition of this addon using `JsonFilesSettingsDef` +# - JsonFilesSettingsDef is prepared settings definition using json files +# to define settings and store default values +class AddonSettingsDef(JsonFilesSettingsDef): + # This will add prefixes to every schema and template from `schemas` + # subfolder. + # - it is not required to fill the prefix but it is highly + # recommended as schemas and templates may have name clashes across + # multiple addons + # - it is also recommended that prefix has addon name in it + schema_prefix = "kitsu" + + def get_settings_root_path(self): + """Implemented abstract class of JsonFilesSettingsDef. + + Return directory path where json files defying addon settings are + located. + """ + return os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "settings" + ) + + +class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): + """This Addon has defined it's settings and interface. + + This example has system settings with an enabled option. And use + few other interfaces: + - `IPluginPaths` to define custom plugin paths + - `ITrayAction` to be shown in tray tool + """ + label = "Kitsu" + name = "kitsu" + + def initialize(self, settings): + """Initialization of addon.""" + module_settings = settings[self.name] + # Enabled by settings + self.enabled = module_settings.get("enabled", False) + + # Prepare variables that can be used or set afterwards + self._connected_modules = None + # UI which must not be created at this time + self._dialog = None + + def tray_init(self): + """Implementation of abstract method for `ITrayAction`. + + We're definitely in tray tool so we can pre create dialog. + """ + + self._create_dialog() + + def _create_dialog(self): + # Don't recreate dialog if already exists + if self._dialog is not None: + return + + from .widgets import MyExampleDialog + + self._dialog = MyExampleDialog() + + def show_dialog(self): + """Show dialog with connected modules. + + This can be called from anywhere but can also crash in headless mode. + There is no way to prevent addon to do invalid operations if he's + not handling them. + """ + # Make sure dialog is created + self._create_dialog() + # Show dialog + self._dialog.open() + + def get_connected_modules(self): + """Custom implementation of addon.""" + names = set() + if self._connected_modules is not None: + for module in self._connected_modules: + names.add(module.name) + return names + + def on_action_trigger(self): + """Implementation of abstract method for `ITrayAction`.""" + self.show_dialog() + + def get_plugin_paths(self): + """Implementation of abstract method for `IPluginPaths`.""" + current_dir = os.path.dirname(os.path.abspath(__file__)) + + return { + "publish": [os.path.join(current_dir, "plugins", "publish")] + } + + def cli(self, click_group): + click_group.add_command(cli_main) + + +@click.group(KitsuModule.name, help="Kitsu dynamic cli commands.") +def cli_main(): + pass + + +@cli_main.command() +def nothing(): + """Does nothing but print a message.""" + print("You've triggered \"nothing\" command.") + + +@cli_main.command() +def show_dialog(): + """Show ExampleAddon dialog. + + We don't have access to addon directly through cli so we have to create + it again. + """ + from openpype.tools.utils.lib import qt_app_context + + manager = ModulesManager() + example_addon = manager.modules_by_name[KitsuModule.name] + with qt_app_context(): + example_addon.show_dialog() diff --git a/openpype/modules/default_modules/kitsu/plugins/publish/example_plugin.py b/openpype/modules/default_modules/kitsu/plugins/publish/example_plugin.py new file mode 100644 index 0000000000..61602f4e78 --- /dev/null +++ b/openpype/modules/default_modules/kitsu/plugins/publish/example_plugin.py @@ -0,0 +1,9 @@ +import pyblish.api + + +class CollectExampleAddon(pyblish.api.ContextPlugin): + order = pyblish.api.CollectorOrder + 0.4 + label = "Collect Kitsu" + + def process(self, context): + self.log.info("I'm in Kitsu's plugin!") diff --git a/openpype/modules/default_modules/kitsu/settings/schemas/project_schemas/main.json b/openpype/modules/default_modules/kitsu/settings/schemas/project_schemas/main.json new file mode 100644 index 0000000000..82e58ce9ab --- /dev/null +++ b/openpype/modules/default_modules/kitsu/settings/schemas/project_schemas/main.json @@ -0,0 +1,30 @@ +{ + "type": "dict", + "key": "kitsu", + "label": " Kitsu", + "collapsible": true, + "children": [ + { + "type": "number", + "key": "number", + "label": "This is your lucky number:", + "minimum": 7, + "maximum": 7, + "decimals": 0 + }, + { + "type": "template", + "name": "kitsu/the_template", + "template_data": [ + { + "name": "color_1", + "label": "Color 1" + }, + { + "name": "color_2", + "label": "Color 2" + } + ] + } + ] +} diff --git a/openpype/modules/default_modules/kitsu/settings/schemas/project_schemas/the_template.json b/openpype/modules/default_modules/kitsu/settings/schemas/project_schemas/the_template.json new file mode 100644 index 0000000000..af8fd9dae4 --- /dev/null +++ b/openpype/modules/default_modules/kitsu/settings/schemas/project_schemas/the_template.json @@ -0,0 +1,30 @@ +[ + { + "type": "list-strict", + "key": "{name}", + "label": "{label}", + "object_types": [ + { + "label": "Red", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + }, + { + "label": "Green", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + }, + { + "label": "Blue", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + } + ] + } +] diff --git a/openpype/modules/default_modules/kitsu/widgets.py b/openpype/modules/default_modules/kitsu/widgets.py new file mode 100644 index 0000000000..de232113fe --- /dev/null +++ b/openpype/modules/default_modules/kitsu/widgets.py @@ -0,0 +1,31 @@ +from Qt import QtWidgets + +from openpype.style import load_stylesheet + + +class MyExampleDialog(QtWidgets.QDialog): + def __init__(self, parent=None): + super(MyExampleDialog, self).__init__(parent) + + self.setWindowTitle("Connected modules") + + msg = "This is example dialog of Kitsu." + label_widget = QtWidgets.QLabel(msg, self) + + ok_btn = QtWidgets.QPushButton("OK", self) + btns_layout = QtWidgets.QHBoxLayout() + btns_layout.addStretch(1) + btns_layout.addWidget(ok_btn) + + layout = QtWidgets.QVBoxLayout(self) + layout.addWidget(label_widget) + layout.addLayout(btns_layout) + + ok_btn.clicked.connect(self._on_ok_clicked) + + self._label_widget = label_widget + + self.setStyleSheet(load_stylesheet()) + + def _on_ok_clicked(self): + self.done(1) diff --git a/openpype/settings/defaults/project_settings/kitsu.json b/openpype/settings/defaults/project_settings/kitsu.json new file mode 100644 index 0000000000..b4d2ccc611 --- /dev/null +++ b/openpype/settings/defaults/project_settings/kitsu.json @@ -0,0 +1,3 @@ +{ + "number": 0 +} \ No newline at end of file diff --git a/openpype/settings/defaults/system_settings/modules.json b/openpype/settings/defaults/system_settings/modules.json index d74269922f..9cfaddecbe 100644 --- a/openpype/settings/defaults/system_settings/modules.json +++ b/openpype/settings/defaults/system_settings/modules.json @@ -137,6 +137,10 @@ } } }, + "kitsu": { + "enabled": false, + "kitsu_server": "" + }, "timers_manager": { "enabled": true, "auto_stop": true, diff --git a/openpype/settings/entities/schemas/projects_schema/schema_main.json b/openpype/settings/entities/schemas/projects_schema/schema_main.json index dbddd18c80..6c07209de3 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_main.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_main.json @@ -62,6 +62,10 @@ "type": "schema", "name": "schema_project_ftrack" }, + { + "type": "schema", + "name": "schema_project_kitsu" + }, { "type": "schema", "name": "schema_project_deadline" diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json b/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json new file mode 100644 index 0000000000..93976cc03b --- /dev/null +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json @@ -0,0 +1,17 @@ +{ + "type": "dict", + "key": "kitsu", + "label": "Kitsu", + "collapsible": true, + "is_file": true, + "children": [ + { + "type": "number", + "key": "number", + "label": "This is your lucky number:", + "minimum": 7, + "maximum": 7, + "decimals": 0 + } + ] +} diff --git a/openpype/settings/entities/schemas/system_schema/module_settings/schema_kitsu.json b/openpype/settings/entities/schemas/system_schema/module_settings/schema_kitsu.json new file mode 100644 index 0000000000..8e496dc783 --- /dev/null +++ b/openpype/settings/entities/schemas/system_schema/module_settings/schema_kitsu.json @@ -0,0 +1,23 @@ +{ + "type": "dict", + "key": "kitsu", + "label": "Kitsu", + "collapsible": true, + "require_restart": true, + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "text", + "key": "kitsu_server", + "label": "Server" + }, + { + "type": "splitter" + } + ] +} diff --git a/openpype/settings/entities/schemas/system_schema/schema_modules.json b/openpype/settings/entities/schemas/system_schema/schema_modules.json index 52595914ed..d22b9016a7 100644 --- a/openpype/settings/entities/schemas/system_schema/schema_modules.json +++ b/openpype/settings/entities/schemas/system_schema/schema_modules.json @@ -44,6 +44,10 @@ "type": "schema", "name": "schema_ftrack" }, + { + "type": "schema", + "name": "schema_kitsu" + }, { "type": "dict", "key": "timers_manager", From 70440290cafcf02753f8c499951cc164b011c132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Tue, 8 Feb 2022 15:38:02 +0100 Subject: [PATCH 025/350] Fist step to sync from Zou to local --- .../default_modules/kitsu/kitsu_module.py | 125 +++++++++++++++++- .../defaults/system_settings/modules.json | 4 +- .../module_settings/schema_kitsu.json | 12 +- 3 files changed, 135 insertions(+), 6 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index 81d7e56a81..55e4640fa2 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -6,20 +6,27 @@ in global space here until are required or used. - imports of Python 3 packages - we still support Python 2 hosts where addon definition should available """ - +import collections import os import click +from avalon.api import AvalonMongoDB +import gazu +from openpype.api import get_project_basic_paths, create_project_folders +from openpype.lib import create_project +from openpype.lib.anatomy import Anatomy from openpype.modules import ( JsonFilesSettingsDef, OpenPypeModule, ModulesManager ) +from openpype.tools.project_manager.project_manager.model import AssetItem, ProjectItem, TaskItem # Import interface defined by this addon to be able find other addons using it from openpype_interfaces import ( IPluginPaths, ITrayAction ) +from pymongo import UpdateOne, DeleteOne # Settings definition of this addon using `JsonFilesSettingsDef` @@ -60,9 +67,27 @@ class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): def initialize(self, settings): """Initialization of addon.""" module_settings = settings[self.name] + # Enabled by settings self.enabled = module_settings.get("enabled", False) + # Add API URL schema + kitsu_url = module_settings["server"].strip() + if kitsu_url: + # Ensure web url + if not kitsu_url.startswith("http"): + kitsu_url = "https://" + kitsu_url + + # Check for "/api" url validity + if not kitsu_url.endswith("api"): + kitsu_url = f"{kitsu_url}{'' if kitsu_url.endswith('/') else '/'}api" + + self.server_url = kitsu_url + + # Set credentials + self.script_login = module_settings["script_login"] + self.script_pwd = module_settings["script_pwd"] + # Prepare variables that can be used or set afterwards self._connected_modules = None # UI which must not be created at this time @@ -76,6 +101,14 @@ class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): self._create_dialog() + def get_global_environments(self): + """Kitsu's global environments.""" + return { + "KITSU_SERVER": self.server_url, + "KITSU_LOGIN": self.script_login, + "KITSU_PWD": self.script_pwd + } + def _create_dialog(self): # Don't recreate dialog if already exists if self._dialog is not None: @@ -127,10 +160,94 @@ def cli_main(): @cli_main.command() -def nothing(): - """Does nothing but print a message.""" - print("You've triggered \"nothing\" command.") +def sync_local(): + """Synchronize local database from Zou sever database.""" + # Connect to server + gazu.client.set_host(os.environ["KITSU_SERVER"]) + + # Authenticate + gazu.log_in(os.environ["KITSU_LOGIN"], os.environ["KITSU_PWD"]) + + # Iterate projects + dbcon = AvalonMongoDB() + dbcon.install() + all_projects = gazu.project.all_projects() + for project in all_projects: + # Create project locally + # Try to find project document + project_name = project["name"] + project_code = project_name + dbcon.Session["AVALON_PROJECT"] = project_name + project_doc = dbcon.find_one({ + "type": "project" + }) + + # Get all assets from zou + all_assets = gazu.asset.all_assets_for_project(project) + + # Query all assets of the local project + project_col = dbcon.database[project_code] + asset_docs_zou_ids = { + asset_doc["data"]["zou_id"] + for asset_doc in project_col.find({"type": "asset"}) + } + + # Create project if is not available + # - creation is required to be able set project anatomy and attributes + if not project_doc: + print(f"Creating project '{project_name}'") + project_doc = create_project(project_name, project_code, dbcon=dbcon) + + # Create project item + insert_list = [] + + bulk_writes = [] + for zou_asset in all_assets: + doc_data = {"zou_id": zou_asset["id"]} + + # Create Asset + new_doc = { + "name": zou_asset["name"], + "type": "asset", + "schema": "openpype:asset-3.0", + "data": doc_data, + "parent": project_doc["_id"] + } + + if zou_asset["id"] not in asset_docs_zou_ids: # Item is new + insert_list.append(new_doc) + + # TODO tasks + + # elif item.data(REMOVED_ROLE): # TODO removal + # if item.data(HIERARCHY_CHANGE_ABLE_ROLE): + # bulk_writes.append(DeleteOne( + # {"_id": item.asset_id} + # )) + # else: + # bulk_writes.append(UpdateOne( + # {"_id": item.asset_id}, + # {"$set": {"type": "archived_asset"}} + # )) + + # else: TODO update data + # update_data = new_item.update_data() + # if update_data: + # bulk_writes.append(UpdateOne( + # {"_id": new_item.asset_id}, + # update_data + # )) + + # Insert new docs if created + if insert_list: + project_col.insert_many(insert_list) + + # Write into DB TODO + # if bulk_writes: + # project_col.bulk_write(bulk_writes) + + dbcon.uninstall() @cli_main.command() def show_dialog(): diff --git a/openpype/settings/defaults/system_settings/modules.json b/openpype/settings/defaults/system_settings/modules.json index 9cfaddecbe..ddb2edc360 100644 --- a/openpype/settings/defaults/system_settings/modules.json +++ b/openpype/settings/defaults/system_settings/modules.json @@ -139,7 +139,9 @@ }, "kitsu": { "enabled": false, - "kitsu_server": "" + "server": "", + "script_login": "", + "script_pwd": "" }, "timers_manager": { "enabled": true, diff --git a/openpype/settings/entities/schemas/system_schema/module_settings/schema_kitsu.json b/openpype/settings/entities/schemas/system_schema/module_settings/schema_kitsu.json index 8e496dc783..ae2b52df0d 100644 --- a/openpype/settings/entities/schemas/system_schema/module_settings/schema_kitsu.json +++ b/openpype/settings/entities/schemas/system_schema/module_settings/schema_kitsu.json @@ -13,9 +13,19 @@ }, { "type": "text", - "key": "kitsu_server", + "key": "server", "label": "Server" }, + { + "type": "text", + "key": "script_login", + "label": "Script Login" + }, + { + "type": "text", + "key": "script_pwd", + "label": "Script Password" + }, { "type": "splitter" } From 719afdcc8ae5f8710537d55da24040bd7ccfcd95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Tue, 8 Feb 2022 15:41:02 +0100 Subject: [PATCH 026/350] black --- .../default_modules/kitsu/kitsu_module.py | 37 ++++++------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index 55e4640fa2..6eb37dfaed 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -6,27 +6,17 @@ in global space here until are required or used. - imports of Python 3 packages - we still support Python 2 hosts where addon definition should available """ -import collections import os import click from avalon.api import AvalonMongoDB import gazu -from openpype.api import get_project_basic_paths, create_project_folders from openpype.lib import create_project from openpype.lib.anatomy import Anatomy -from openpype.modules import ( - JsonFilesSettingsDef, - OpenPypeModule, - ModulesManager -) -from openpype.tools.project_manager.project_manager.model import AssetItem, ProjectItem, TaskItem +from openpype.modules import JsonFilesSettingsDef, OpenPypeModule, ModulesManager + # Import interface defined by this addon to be able find other addons using it -from openpype_interfaces import ( - IPluginPaths, - ITrayAction -) -from pymongo import UpdateOne, DeleteOne +from openpype_interfaces import IPluginPaths, ITrayAction # Settings definition of this addon using `JsonFilesSettingsDef` @@ -47,10 +37,7 @@ class AddonSettingsDef(JsonFilesSettingsDef): Return directory path where json files defying addon settings are located. """ - return os.path.join( - os.path.dirname(os.path.abspath(__file__)), - "settings" - ) + return os.path.join(os.path.dirname(os.path.abspath(__file__)), "settings") class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): @@ -61,6 +48,7 @@ class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): - `IPluginPaths` to define custom plugin paths - `ITrayAction` to be shown in tray tool """ + label = "Kitsu" name = "kitsu" @@ -106,7 +94,7 @@ class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): return { "KITSU_SERVER": self.server_url, "KITSU_LOGIN": self.script_login, - "KITSU_PWD": self.script_pwd + "KITSU_PWD": self.script_pwd, } def _create_dialog(self): @@ -146,9 +134,7 @@ class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): """Implementation of abstract method for `IPluginPaths`.""" current_dir = os.path.dirname(os.path.abspath(__file__)) - return { - "publish": [os.path.join(current_dir, "plugins", "publish")] - } + return {"publish": [os.path.join(current_dir, "plugins", "publish")]} def cli(self, click_group): click_group.add_command(cli_main) @@ -179,10 +165,8 @@ def sync_local(): project_name = project["name"] project_code = project_name dbcon.Session["AVALON_PROJECT"] = project_name - project_doc = dbcon.find_one({ - "type": "project" - }) - + project_doc = dbcon.find_one({"type": "project"}) + # Get all assets from zou all_assets = gazu.asset.all_assets_for_project(project) @@ -212,7 +196,7 @@ def sync_local(): "type": "asset", "schema": "openpype:asset-3.0", "data": doc_data, - "parent": project_doc["_id"] + "parent": project_doc["_id"], } if zou_asset["id"] not in asset_docs_zou_ids: # Item is new @@ -249,6 +233,7 @@ def sync_local(): dbcon.uninstall() + @cli_main.command() def show_dialog(): """Show ExampleAddon dialog. From 7c63d3a374637ee8630d293b8ac8dcc8a34ffb95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Tue, 8 Feb 2022 16:28:06 +0100 Subject: [PATCH 027/350] Add tasks to asset --- .../default_modules/kitsu/kitsu_module.py | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index 6eb37dfaed..9730437ec2 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -187,22 +187,43 @@ def sync_local(): insert_list = [] bulk_writes = [] - for zou_asset in all_assets: - doc_data = {"zou_id": zou_asset["id"]} + for asset in all_assets: + asset_data = {"zou_id": asset["id"]} + + # Set tasks + asset_tasks = gazu.task.all_tasks_for_asset(asset) + asset_data["tasks"] = { + t["task_type_name"]: {"type": t["task_type_name"]} for t in asset_tasks + } # Create Asset - new_doc = { - "name": zou_asset["name"], + asset_doc = { + "name": asset["name"], "type": "asset", "schema": "openpype:asset-3.0", - "data": doc_data, + "data": asset_data, "parent": project_doc["_id"], } - if zou_asset["id"] not in asset_docs_zou_ids: # Item is new - insert_list.append(new_doc) + if asset["id"] not in asset_docs_zou_ids: # Item is new + insert_list.append(asset_doc) + else: + asset_doc = project_col.find_one({"data": {"zou_id": asset["id"]}}) - # TODO tasks + # TODO update + # for task in asset_tasks: + # # print(task) + # task_data = {"zou_id": task["id"]} + + # # Create Task + # task_doc = { + # "name": task["name"], + # "type": "task", + # "schema": "openpype:asset-3.0", + # "data": task_data, + # "parent": asset_doc["_id"], + # } + # insert_list.append(task_doc) # elif item.data(REMOVED_ROLE): # TODO removal # if item.data(HIERARCHY_CHANGE_ABLE_ROLE): From 9a1dd4fc0630f94cff1ef554fd31ede714b8ad49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Tue, 8 Feb 2022 19:26:26 +0100 Subject: [PATCH 028/350] All bulk write. Updating assets --- .../default_modules/kitsu/kitsu_module.py | 68 ++++++++----------- 1 file changed, 29 insertions(+), 39 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index 9730437ec2..1a71a05a7e 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -12,10 +12,8 @@ import click from avalon.api import AvalonMongoDB import gazu from openpype.lib import create_project -from openpype.lib.anatomy import Anatomy from openpype.modules import JsonFilesSettingsDef, OpenPypeModule, ModulesManager - -# Import interface defined by this addon to be able find other addons using it +from pymongo import DeleteOne, InsertOne, UpdateOne from openpype_interfaces import IPluginPaths, ITrayAction @@ -183,9 +181,6 @@ def sync_local(): print(f"Creating project '{project_name}'") project_doc = create_project(project_name, project_code, dbcon=dbcon) - # Create project item - insert_list = [] - bulk_writes = [] for asset in all_assets: asset_data = {"zou_id": asset["id"]} @@ -196,34 +191,33 @@ def sync_local(): t["task_type_name"]: {"type": t["task_type_name"]} for t in asset_tasks } - # Create Asset - asset_doc = { - "name": asset["name"], - "type": "asset", - "schema": "openpype:asset-3.0", - "data": asset_data, - "parent": project_doc["_id"], - } + # Update or create asset + if asset["id"] in asset_docs_zou_ids: # Update asset + asset_doc = project_col.find_one({"data.zou_id": asset["id"]}) - if asset["id"] not in asset_docs_zou_ids: # Item is new - insert_list.append(asset_doc) - else: - asset_doc = project_col.find_one({"data": {"zou_id": asset["id"]}}) + # Override all 'data' TODO filter data to update? + diff_data = { + k: asset_data[k] + for k in asset_data.keys() + if asset_doc["data"].get(k) != asset_data[k] + } + if diff_data: + bulk_writes.append( + UpdateOne( + {"_id": asset_doc["_id"]}, {"$set": {"data": asset_data}} + ) + ) + else: # Create + asset_doc = { + "name": asset["name"], + "type": "asset", + "schema": "openpype:asset-3.0", + "data": asset_data, + "parent": project_doc["_id"], + } - # TODO update - # for task in asset_tasks: - # # print(task) - # task_data = {"zou_id": task["id"]} - - # # Create Task - # task_doc = { - # "name": task["name"], - # "type": "task", - # "schema": "openpype:asset-3.0", - # "data": task_data, - # "parent": asset_doc["_id"], - # } - # insert_list.append(task_doc) + # Insert new doc + bulk_writes.append(InsertOne(asset_doc)) # elif item.data(REMOVED_ROLE): # TODO removal # if item.data(HIERARCHY_CHANGE_ABLE_ROLE): @@ -244,13 +238,9 @@ def sync_local(): # update_data # )) - # Insert new docs if created - if insert_list: - project_col.insert_many(insert_list) - - # Write into DB TODO - # if bulk_writes: - # project_col.bulk_write(bulk_writes) + # Write into DB + if bulk_writes: + project_col.bulk_write(bulk_writes) dbcon.uninstall() From 206bf9f3c18873a6f81734841779eeab4f8829d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 9 Feb 2022 09:45:11 +0100 Subject: [PATCH 029/350] Delete assets --- .../default_modules/kitsu/kitsu_module.py | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index 1a71a05a7e..1ce1bef6a2 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -170,10 +170,13 @@ def sync_local(): # Query all assets of the local project project_col = dbcon.database[project_code] - asset_docs_zou_ids = { - asset_doc["data"]["zou_id"] + asset_doc_ids = { + asset_doc["_id"]: asset_doc for asset_doc in project_col.find({"type": "asset"}) } + asset_docs_zou_ids = { + asset_doc["data"]["zou_id"] for asset_doc in asset_doc_ids.values() + } # Create project if is not available # - creation is required to be able set project anatomy and attributes @@ -182,6 +185,7 @@ def sync_local(): project_doc = create_project(project_name, project_code, dbcon=dbcon) bulk_writes = [] + sync_assets = set() for asset in all_assets: asset_data = {"zou_id": asset["id"]} @@ -195,13 +199,13 @@ def sync_local(): if asset["id"] in asset_docs_zou_ids: # Update asset asset_doc = project_col.find_one({"data.zou_id": asset["id"]}) - # Override all 'data' TODO filter data to update? - diff_data = { + # Override all 'data' + updated_data = { k: asset_data[k] for k in asset_data.keys() if asset_doc["data"].get(k) != asset_data[k] } - if diff_data: + if updated_data: bulk_writes.append( UpdateOne( {"_id": asset_doc["_id"]}, {"$set": {"data": asset_data}} @@ -219,24 +223,16 @@ def sync_local(): # Insert new doc bulk_writes.append(InsertOne(asset_doc)) - # elif item.data(REMOVED_ROLE): # TODO removal - # if item.data(HIERARCHY_CHANGE_ABLE_ROLE): - # bulk_writes.append(DeleteOne( - # {"_id": item.asset_id} - # )) - # else: - # bulk_writes.append(UpdateOne( - # {"_id": item.asset_id}, - # {"$set": {"type": "archived_asset"}} - # )) + # Keep synchronized asset for diff + sync_assets.add(asset_doc["_id"]) - # else: TODO update data - # update_data = new_item.update_data() - # if update_data: - # bulk_writes.append(UpdateOne( - # {"_id": new_item.asset_id}, - # update_data - # )) + # Delete from diff of assets in OP and synchronized assets to detect deleted assets + diff_assets = set(asset_doc_ids.keys()) - sync_assets + if diff_assets: + # Delete doc + bulk_writes.extend( + [DeleteOne(asset_doc_ids[asset_id]) for asset_id in diff_assets] + ) # Write into DB if bulk_writes: From e882de52f04d2ca79e30fb23801257cefd085e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Thu, 10 Feb 2022 17:35:03 +0100 Subject: [PATCH 030/350] Assets hierarchy --- .../default_modules/kitsu/kitsu_module.py | 165 ++++++++++++------ 1 file changed, 114 insertions(+), 51 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index 1ce1bef6a2..92d724be67 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -7,13 +7,15 @@ in global space here until are required or used. - we still support Python 2 hosts where addon definition should available """ import os +from typing import Dict, List, Set import click from avalon.api import AvalonMongoDB import gazu from openpype.lib import create_project from openpype.modules import JsonFilesSettingsDef, OpenPypeModule, ModulesManager -from pymongo import DeleteOne, InsertOne, UpdateOne +from pymongo import DeleteOne, UpdateOne +from pymongo.collection import Collection from openpype_interfaces import IPluginPaths, ITrayAction @@ -144,8 +146,8 @@ def cli_main(): @cli_main.command() -def sync_local(): - """Synchronize local database from Zou sever database.""" +def sync_openpype(): + """Synchronize openpype database from Zou sever database.""" # Connect to server gazu.client.set_host(os.environ["KITSU_SERVER"]) @@ -167,69 +169,61 @@ def sync_local(): # Get all assets from zou all_assets = gazu.asset.all_assets_for_project(project) - - # Query all assets of the local project - project_col = dbcon.database[project_code] - asset_doc_ids = { - asset_doc["_id"]: asset_doc - for asset_doc in project_col.find({"type": "asset"}) - } - asset_docs_zou_ids = { - asset_doc["data"]["zou_id"] for asset_doc in asset_doc_ids.values() - } + all_episodes = gazu.shot.all_episodes_for_project(project) + all_seqs = gazu.shot.all_sequences_for_project(project) + all_shots = gazu.shot.all_shots_for_project(project) # Create project if is not available # - creation is required to be able set project anatomy and attributes + to_insert = [] if not project_doc: print(f"Creating project '{project_name}'") project_doc = create_project(project_name, project_code, dbcon=dbcon) - bulk_writes = [] - sync_assets = set() - for asset in all_assets: - asset_data = {"zou_id": asset["id"]} + # Query all assets of the local project + project_col = dbcon.database[project_code] + asset_doc_ids = { + asset_doc["data"]["zou_id"]: asset_doc + for asset_doc in project_col.find({"type": "asset"}) + if asset_doc["data"].get("zou_id") + } + asset_doc_ids[project["id"]] = project_doc - # Set tasks - asset_tasks = gazu.task.all_tasks_for_asset(asset) - asset_data["tasks"] = { - t["task_type_name"]: {"type": t["task_type_name"]} for t in asset_tasks - } - - # Update or create asset - if asset["id"] in asset_docs_zou_ids: # Update asset - asset_doc = project_col.find_one({"data.zou_id": asset["id"]}) - - # Override all 'data' - updated_data = { - k: asset_data[k] - for k in asset_data.keys() - if asset_doc["data"].get(k) != asset_data[k] - } - if updated_data: - bulk_writes.append( - UpdateOne( - {"_id": asset_doc["_id"]}, {"$set": {"data": asset_data}} - ) - ) - else: # Create - asset_doc = { - "name": asset["name"], + # Create + to_insert.extend( + [ + { + "name": item["name"], "type": "asset", "schema": "openpype:asset-3.0", - "data": asset_data, - "parent": project_doc["_id"], + "data": {"zou_id": item["id"], "tasks": {}}, } + for item in all_episodes + all_assets + all_seqs + all_shots + if item["id"] not in asset_doc_ids.keys() + ] + ) + if to_insert: + # Insert in doc + project_col.insert_many(to_insert) - # Insert new doc - bulk_writes.append(InsertOne(asset_doc)) + # Update existing docs + asset_doc_ids.update( + { + asset_doc["data"]["zou_id"]: asset_doc + for asset_doc in project_col.find({"type": "asset"}) + if asset_doc["data"].get("zou_id") + } + ) - # Keep synchronized asset for diff - sync_assets.add(asset_doc["_id"]) + # Update + all_entities = all_assets + all_episodes + all_seqs + all_shots + bulk_writes = update_op_assets(project_col, all_entities, asset_doc_ids) - # Delete from diff of assets in OP and synchronized assets to detect deleted assets - diff_assets = set(asset_doc_ids.keys()) - sync_assets + # Delete + diff_assets = set(asset_doc_ids.keys()) - { + e["id"] for e in all_entities + [project] + } if diff_assets: - # Delete doc bulk_writes.extend( [DeleteOne(asset_doc_ids[asset_id]) for asset_id in diff_assets] ) @@ -241,6 +235,75 @@ def sync_local(): dbcon.uninstall() +def update_op_assets( + project_col: Collection, items_list: List[dict], asset_doc_ids: Dict[str, dict] +) -> List[UpdateOne]: + """Update OpenPype assets. + Set 'data' and 'parent' fields. + + :param project_col: Project collection to query data from + :param items_list: List of zou items to update + :param asset_doc_ids: Dicts of [{zou_id: asset_doc}, ...] + :return: List of UpdateOne objects + """ + bulk_writes = [] + for item in items_list: + # Update asset + item_doc = project_col.find_one({"data.zou_id": item["id"]}) + item_data = item_doc["data"].copy() + + # Tasks + tasks_list = None + if item["type"] == "Asset": + tasks_list = gazu.task.all_tasks_for_asset(item) + elif item["type"] == "Shot": + tasks_list = gazu.task.all_tasks_for_shot(item) + if tasks_list: + item_data["tasks"] = { + t["task_type_name"]: {"type": t["task_type_name"]} for t in tasks_list + } + + # Visual parent for hierarchy + direct_parent_id = item["parent_id"] or item["source_id"] + if direct_parent_id: + visual_parent_doc = asset_doc_ids[direct_parent_id] + item_data["visualParent"] = visual_parent_doc["_id"] + + # Add parents for hierarchy + parent_zou_id = item["parent_id"] + item_data["parents"] = [] + while parent_zou_id is not None: + parent_doc = asset_doc_ids[parent_zou_id] + item_data["parents"].insert(0, parent_doc["name"]) + + parent_zou_id = next( + i for i in items_list if i["id"] == parent_doc["data"]["zou_id"] + )["parent_id"] + + # TODO create missing tasks before + + # Update 'data' different in zou DB + updated_data = { + k: item_data[k] + for k in item_data.keys() + if item_doc["data"].get(k) != item_data[k] + } + if updated_data or not item_doc.get("parent"): + bulk_writes.append( + UpdateOne( + {"_id": item_doc["_id"]}, + { + "$set": { + "data": item_data, + "parent": asset_doc_ids[item["project_id"]]["_id"], + } + }, + ) + ) + + return bulk_writes + + @cli_main.command() def show_dialog(): """Show ExampleAddon dialog. From ee281f740d58821ab4d5e190e6b4863af5c2ac44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Thu, 10 Feb 2022 18:03:27 +0100 Subject: [PATCH 031/350] Project tasks --- .../default_modules/kitsu/kitsu_module.py | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index 92d724be67..84709bc0a2 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -160,6 +160,8 @@ def sync_openpype(): dbcon.install() all_projects = gazu.project.all_projects() for project in all_projects: + bulk_writes = [] + # Create project locally # Try to find project document project_name = project["name"] @@ -180,6 +182,23 @@ def sync_openpype(): print(f"Creating project '{project_name}'") project_doc = create_project(project_name, project_code, dbcon=dbcon) + # Project tasks + bulk_writes.append( + UpdateOne( + {"_id": project_doc["_id"]}, + { + "$set": { + "config.tasks": { + t["name"]: { + "short_name": t.get("short_name", t["name"]) + } + for t in gazu.task.all_task_types_for_project(project) + } + } + }, + ) + ) + # Query all assets of the local project project_col = dbcon.database[project_code] asset_doc_ids = { @@ -217,7 +236,7 @@ def sync_openpype(): # Update all_entities = all_assets + all_episodes + all_seqs + all_shots - bulk_writes = update_op_assets(project_col, all_entities, asset_doc_ids) + bulk_writes.extend(update_op_assets(project_col, all_entities, asset_doc_ids)) # Delete diff_assets = set(asset_doc_ids.keys()) - { @@ -228,7 +247,7 @@ def sync_openpype(): [DeleteOne(asset_doc_ids[asset_id]) for asset_id in diff_assets] ) - # Write into DB + # Write into DB # TODO make it common for all projects if bulk_writes: project_col.bulk_write(bulk_writes) From d63c5fcae8ec1ee8c49c4a21dea86b3e9da157d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Fri, 11 Feb 2022 09:29:08 +0100 Subject: [PATCH 032/350] Optim: bulkwrite and queries mutualization --- .../default_modules/kitsu/kitsu_module.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index 84709bc0a2..89312a344c 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -159,9 +159,8 @@ def sync_openpype(): dbcon = AvalonMongoDB() dbcon.install() all_projects = gazu.project.all_projects() + bulk_writes = [] for project in all_projects: - bulk_writes = [] - # Create project locally # Try to find project document project_name = project["name"] @@ -236,7 +235,7 @@ def sync_openpype(): # Update all_entities = all_assets + all_episodes + all_seqs + all_shots - bulk_writes.extend(update_op_assets(project_col, all_entities, asset_doc_ids)) + bulk_writes.extend(update_op_assets(all_entities, asset_doc_ids)) # Delete diff_assets = set(asset_doc_ids.keys()) - { @@ -247,20 +246,19 @@ def sync_openpype(): [DeleteOne(asset_doc_ids[asset_id]) for asset_id in diff_assets] ) - # Write into DB # TODO make it common for all projects - if bulk_writes: - project_col.bulk_write(bulk_writes) + # Write into DB + if bulk_writes: + project_col.bulk_write(bulk_writes) dbcon.uninstall() def update_op_assets( - project_col: Collection, items_list: List[dict], asset_doc_ids: Dict[str, dict] + items_list: List[dict], asset_doc_ids: Dict[str, dict] ) -> List[UpdateOne]: """Update OpenPype assets. Set 'data' and 'parent' fields. - :param project_col: Project collection to query data from :param items_list: List of zou items to update :param asset_doc_ids: Dicts of [{zou_id: asset_doc}, ...] :return: List of UpdateOne objects @@ -268,7 +266,7 @@ def update_op_assets( bulk_writes = [] for item in items_list: # Update asset - item_doc = project_col.find_one({"data.zou_id": item["id"]}) + item_doc = asset_doc_ids[item["id"]] item_data = item_doc["data"].copy() # Tasks @@ -299,8 +297,6 @@ def update_op_assets( i for i in items_list if i["id"] == parent_doc["data"]["zou_id"] )["parent_id"] - # TODO create missing tasks before - # Update 'data' different in zou DB updated_data = { k: item_data[k] From 4e68bcf55fd2552f53904dcd0a6c47b56946c927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Fri, 11 Feb 2022 09:31:14 +0100 Subject: [PATCH 033/350] cleaning --- openpype/modules/default_modules/kitsu/kitsu_module.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index 89312a344c..e52d18b84b 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -15,7 +15,6 @@ import gazu from openpype.lib import create_project from openpype.modules import JsonFilesSettingsDef, OpenPypeModule, ModulesManager from pymongo import DeleteOne, UpdateOne -from pymongo.collection import Collection from openpype_interfaces import IPluginPaths, ITrayAction From 294b93f65a97d17f503a82962f121c3202002a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Sat, 12 Feb 2022 15:06:22 +0100 Subject: [PATCH 034/350] Create episode --- .../default_modules/kitsu/kitsu_module.py | 226 +++++++++++++++++- .../defaults/project_settings/kitsu.json | 6 +- .../projects_schema/schema_project_kitsu.json | 26 +- 3 files changed, 243 insertions(+), 15 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index e52d18b84b..c4f627d5ad 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -6,12 +6,14 @@ in global space here until are required or used. - imports of Python 3 packages - we still support Python 2 hosts where addon definition should available """ -import os -from typing import Dict, List, Set import click +import os +import re +from typing import Dict, List from avalon.api import AvalonMongoDB import gazu +from openpype.api import get_project_settings from openpype.lib import create_project from openpype.modules import JsonFilesSettingsDef, OpenPypeModule, ModulesManager from pymongo import DeleteOne, UpdateOne @@ -145,8 +147,8 @@ def cli_main(): @cli_main.command() -def sync_openpype(): - """Synchronize openpype database from Zou sever database.""" +def sync_zou(): + """Synchronize Zou server database (Kitsu backend) with openpype database.""" # Connect to server gazu.client.set_host(os.environ["KITSU_SERVER"]) @@ -157,8 +159,108 @@ def sync_openpype(): # Iterate projects dbcon = AvalonMongoDB() dbcon.install() - all_projects = gazu.project.all_projects() + + op_projects = [p for p in dbcon.projects()] bulk_writes = [] + for op_project in op_projects: + # Create project locally + # Try to find project document + project_name = op_project["name"] + project_code = op_project["data"]["code"] + dbcon.Session["AVALON_PROJECT"] = project_name + + # Get all entities from zou + zou_project = gazu.project.get_project_by_name(project_name) + + # Create project + if zou_project is None: + raise RuntimeError( + f"Project '{project_name}' doesn't exist in Zou database, please create it in Kitsu and add logged user to it before running synchronization." + ) + + # Update project settings and data + zou_project.update( + { + "code": op_project["data"]["code"], + "fps": op_project["data"]["fps"], + "resolution": f"{op_project['data']['resolutionWidth']}x{op_project['data']['resolutionHeight']}", + } + ) + gazu.project.update_project(zou_project) + gazu.project.update_project_data(zou_project, data=op_project["data"]) + + all_assets = gazu.asset.all_assets_for_project(zou_project) + all_episodes = gazu.shot.all_episodes_for_project(zou_project) + all_seqs = gazu.shot.all_sequences_for_project(zou_project) + all_shots = gazu.shot.all_shots_for_project(zou_project) + print(zou_project["name"]) + all_entities_ids = { + e["id"] for e in all_episodes + all_seqs + all_shots + all_assets + } + + project_module_settings = get_project_settings(project_name)["kitsu"] + + # Create new assets + # Query all assets of the local project + project_col = dbcon.database[project_name] + asset_docs = [asset_doc for asset_doc in project_col.find({"type": "asset"})] + + new_assets_docs = [ + doc + for doc in asset_docs + if doc["data"].get("zou_id") not in all_entities_ids + ] + naming_pattern = project_module_settings["entities_naming_pattern"] + regex_ep = re.compile( + r"({})|({})|({})".format( + naming_pattern["episode"].replace("#", "\d"), + naming_pattern["sequence"].replace("#", "\d"), + naming_pattern["shot"].replace("#", "\d"), + ), + re.IGNORECASE, + ) + for doc in new_assets_docs: + match = regex_ep.match(doc["name"]) + if not match: + # TODO asset + continue + + print(doc) + if match.group(1): # Episode + new_episode = gazu.shot.new_episode(zou_project, doc["name"]) + + # Update doc with zou id + bulk_writes.append( + UpdateOne( + {"_id": doc["_id"]}, + {"$set": {"data.zou_id": new_episode["id"]}}, + ) + ) + elif match.group(2): # Sequence + # TODO match zou episode + new_sequence = gazu.shot.new_sequence(zou_project, doc["name"]) + + # Update doc with zou id + bulk_writes.append( + UpdateOne( + {"_id": doc["_id"]}, + {"$set": {"data.zou_id": new_sequence["id"]}}, + ) + ) + elif match.group(3): # Shot + pass + + # Delete + # if gazu. + + # Write into DB + if bulk_writes: + project_col.bulk_write(bulk_writes) + + dbcon.uninstall() + + return + for project in all_projects: # Create project locally # Try to find project document @@ -245,9 +347,117 @@ def sync_openpype(): [DeleteOne(asset_doc_ids[asset_id]) for asset_id in diff_assets] ) - # Write into DB - if bulk_writes: - project_col.bulk_write(bulk_writes) + +@cli_main.command() +def sync_openpype(): + """Synchronize openpype database from Zou sever database.""" + + # Connect to server + gazu.client.set_host(os.environ["KITSU_SERVER"]) + + # Authenticate + gazu.log_in(os.environ["KITSU_LOGIN"], os.environ["KITSU_PWD"]) + + # Iterate projects + dbcon = AvalonMongoDB() + dbcon.install() + all_projects = gazu.project.all_projects() + bulk_writes = [] + for project in all_projects: + # Create project locally + # Try to find project document + project_name = project["name"] + project_code = project_name + dbcon.Session["AVALON_PROJECT"] = project_name + project_doc = dbcon.find_one({"type": "project"}) + + # Get all assets from zou + all_assets = gazu.asset.all_assets_for_project(project) + all_episodes = gazu.shot.all_episodes_for_project(project) + all_seqs = gazu.shot.all_sequences_for_project(project) + all_shots = gazu.shot.all_shots_for_project(project) + + # Create project if is not available + # - creation is required to be able set project anatomy and attributes + to_insert = [] + if not project_doc: + print(f"Creating project '{project_name}'") + project_doc = create_project(project_name, project_code, dbcon=dbcon) + + # Project data and tasks + bulk_writes.append( + UpdateOne( + {"_id": project_doc["_id"]}, + { + "$set": { + "config.tasks": { + t["name"]: {"short_name": t.get("short_name", t["name"])} + for t in gazu.task.all_task_types_for_project(project) + }, + "data": project["data"].update( + { + "code": project["code"], + "fps": project_code["fps"], + "resolutionWidth": project["resolution"].split("x")[0], + "resolutionHeight": project["resolution"].split("x")[1], + } + ), + } + }, + ) + ) + + # Query all assets of the local project + project_col = dbcon.database[project_code] + asset_doc_ids = { + asset_doc["data"]["zou_id"]: asset_doc + for asset_doc in project_col.find({"type": "asset"}) + if asset_doc["data"].get("zou_id") + } + asset_doc_ids[project["id"]] = project_doc + + # Create + to_insert.extend( + [ + { + "name": item["name"], + "type": "asset", + "schema": "openpype:asset-3.0", + "data": {"zou_id": item["id"], "tasks": {}}, + } + for item in all_episodes + all_assets + all_seqs + all_shots + if item["id"] not in asset_doc_ids.keys() + ] + ) + if to_insert: + # Insert in doc + project_col.insert_many(to_insert) + + # Update existing docs + asset_doc_ids.update( + { + asset_doc["data"]["zou_id"]: asset_doc + for asset_doc in project_col.find({"type": "asset"}) + if asset_doc["data"].get("zou_id") + } + ) + + # Update + all_entities = all_assets + all_episodes + all_seqs + all_shots + bulk_writes.extend(update_op_assets(all_entities, asset_doc_ids)) + + # Delete + diff_assets = set(asset_doc_ids.keys()) - { + e["id"] for e in all_entities + [project] + } + if diff_assets: + bulk_writes.extend( + [DeleteOne(asset_doc_ids[asset_id]) for asset_id in diff_assets] + ) + + # Write into DB + if bulk_writes: + project_col.bulk_write(bulk_writes) dbcon.uninstall() diff --git a/openpype/settings/defaults/project_settings/kitsu.json b/openpype/settings/defaults/project_settings/kitsu.json index b4d2ccc611..435814a9d1 100644 --- a/openpype/settings/defaults/project_settings/kitsu.json +++ b/openpype/settings/defaults/project_settings/kitsu.json @@ -1,3 +1,7 @@ { - "number": 0 + "entities_naming_pattern": { + "episode": "E##", + "sequence": "SQ##", + "shot": "SH##" + } } \ No newline at end of file diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json b/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json index 93976cc03b..a504959001 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json @@ -6,12 +6,26 @@ "is_file": true, "children": [ { - "type": "number", - "key": "number", - "label": "This is your lucky number:", - "minimum": 7, - "maximum": 7, - "decimals": 0 + "type": "dict", + "key": "entities_naming_pattern", + "label": "Entities naming pattern", + "children": [ + { + "type": "text", + "key": "episode", + "label": "Episode:" + }, + { + "type": "text", + "key": "sequence", + "label": "Sequence:" + }, + { + "type": "text", + "key": "shot", + "label": "Shot:" + } + ] } ] } From bad16651e1b2ed2d307496941ac95adb1224040a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Mon, 14 Feb 2022 17:58:06 +0100 Subject: [PATCH 035/350] Create asset, ep, seq and shot in zou --- .../default_modules/kitsu/kitsu_module.py | 123 +++++++++++++----- 1 file changed, 93 insertions(+), 30 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index c4f627d5ad..453d1c5315 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -189,6 +189,7 @@ def sync_zou(): gazu.project.update_project(zou_project) gazu.project.update_project_data(zou_project, data=op_project["data"]) + all_asset_types = gazu.asset.all_asset_types() all_assets = gazu.asset.all_assets_for_project(zou_project) all_episodes = gazu.shot.all_episodes_for_project(zou_project) all_seqs = gazu.shot.all_sequences_for_project(zou_project) @@ -199,15 +200,17 @@ def sync_zou(): } project_module_settings = get_project_settings(project_name)["kitsu"] + project_col = dbcon.database[project_name] + asset_docs = { + asset_doc["_id"]: asset_doc + for asset_doc in project_col.find({"type": "asset"}) + } # Create new assets # Query all assets of the local project - project_col = dbcon.database[project_name] - asset_docs = [asset_doc for asset_doc in project_col.find({"type": "asset"})] - new_assets_docs = [ doc - for doc in asset_docs + for doc in asset_docs.values() if doc["data"].get("zou_id") not in all_entities_ids ] naming_pattern = project_module_settings["entities_naming_pattern"] @@ -220,37 +223,95 @@ def sync_zou(): re.IGNORECASE, ) for doc in new_assets_docs: + visual_parent_id = doc["data"]["visualParent"] + match = regex_ep.match(doc["name"]) - if not match: - # TODO asset - continue - - print(doc) - if match.group(1): # Episode - new_episode = gazu.shot.new_episode(zou_project, doc["name"]) - - # Update doc with zou id - bulk_writes.append( - UpdateOne( - {"_id": doc["_id"]}, - {"$set": {"data.zou_id": new_episode["id"]}}, - ) + if not match: # Asset + new_entity = gazu.asset.new_asset( + zou_project, all_asset_types[0], doc["name"] ) + + elif match.group(1): # Episode + new_entity = gazu.shot.new_episode(zou_project, doc["name"]) + elif match.group(2): # Sequence - # TODO match zou episode - new_sequence = gazu.shot.new_sequence(zou_project, doc["name"]) - - # Update doc with zou id - bulk_writes.append( - UpdateOne( - {"_id": doc["_id"]}, - {"$set": {"data.zou_id": new_sequence["id"]}}, - ) + parent_doc = asset_docs[visual_parent_id] + new_entity = gazu.shot.new_sequence( + zou_project, doc["name"], episode=parent_doc["data"]["zou_id"] ) - elif match.group(3): # Shot - pass - # Delete + elif match.group(3): # Shot + # Match and check parent doc + parent_doc = asset_docs[visual_parent_id] + zou_parent_id = parent_doc["data"]["zou_id"] + if parent_doc["data"].get("zou", {}).get("type") != "Sequence": + # Warn + print( + f"Shot {doc['name']} must be parented to a Sequence in Kitsu. Creating automatically one substitute sequence..." + ) + + # Create new sequence + digits_padding = naming_pattern["sequence"].count("#") + substitute_sequence_name = f'{naming_pattern["sequence"].replace("#" * digits_padding, "1".zfill(digits_padding))}' + new_sequence = gazu.shot.new_sequence( + zou_project, substitute_sequence_name, episode=zou_parent_id + ) + + # Insert doc + inserted = project_col.insert_one( + { + "name": substitute_sequence_name, + "type": "asset", + "schema": "openpype:asset-3.0", + "data": { + "zou_id": new_sequence["id"], + "tasks": {}, + "parents": parent_doc["data"]["parents"] + + [parent_doc["name"]], + "visualParent": parent_doc["_id"], + }, + "parent": parent_doc["_id"], + } + ) + visual_parent_id = inserted.inserted_id + + # Update parent ID + zou_parent_id = new_sequence["id"] + + # Create shot + new_entity = gazu.shot.new_shot( + zou_project, + zou_parent_id, + doc["name"], + frame_in=doc["data"]["frameStart"], + frame_out=doc["data"]["frameEnd"], + nb_frames=doc["data"]["frameEnd"] - doc["data"]["frameStart"], + ) + + # Update doc with zou id + doc["data"].update( + { + "zou_id": new_entity["id"], + "visualParent": visual_parent_id, + "zou": new_entity, + } + ) + bulk_writes.append( + UpdateOne( + {"_id": doc["_id"]}, + { + "$set": { + "data.zou_id": new_entity["id"], + "data.visualParent": visual_parent_id, + "data.zou": new_entity, + } + }, + ) + ) + + # TODO update / tasks + + # Delete TODO # if gazu. # Write into DB @@ -477,6 +538,7 @@ def update_op_assets( # Update asset item_doc = asset_doc_ids[item["id"]] item_data = item_doc["data"].copy() + item_data["zou"] = item # Tasks tasks_list = None @@ -484,6 +546,7 @@ def update_op_assets( tasks_list = gazu.task.all_tasks_for_asset(item) elif item["type"] == "Shot": tasks_list = gazu.task.all_tasks_for_shot(item) + # TODO frame in and out if tasks_list: item_data["tasks"] = { t["task_type_name"]: {"type": t["task_type_name"]} for t in tasks_list From 9af6264d1e02f92244d678964da5c5902428016f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Tue, 15 Feb 2022 18:21:26 +0100 Subject: [PATCH 036/350] Update and delete in zou --- .../default_modules/kitsu/kitsu_module.py | 146 +++++++----------- 1 file changed, 53 insertions(+), 93 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index 453d1c5315..e42edbc52b 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -6,6 +6,8 @@ in global space here until are required or used. - imports of Python 3 packages - we still support Python 2 hosts where addon definition should available """ +from asyncio import all_tasks +from turtle import update import click import os import re @@ -170,6 +172,7 @@ def sync_zou(): dbcon.Session["AVALON_PROJECT"] = project_name # Get all entities from zou + print(f"Synchronizing {project_name}...") zou_project = gazu.project.get_project_by_name(project_name) # Create project @@ -194,11 +197,11 @@ def sync_zou(): all_episodes = gazu.shot.all_episodes_for_project(zou_project) all_seqs = gazu.shot.all_sequences_for_project(zou_project) all_shots = gazu.shot.all_shots_for_project(zou_project) - print(zou_project["name"]) all_entities_ids = { e["id"] for e in all_episodes + all_seqs + all_shots + all_assets } + # Query all assets of the local project project_module_settings = get_project_settings(project_name)["kitsu"] project_col = dbcon.database[project_name] asset_docs = { @@ -207,7 +210,6 @@ def sync_zou(): } # Create new assets - # Query all assets of the local project new_assets_docs = [ doc for doc in asset_docs.values() @@ -225,6 +227,7 @@ def sync_zou(): for doc in new_assets_docs: visual_parent_id = doc["data"]["visualParent"] + # Match asset type by it's name match = regex_ep.match(doc["name"]) if not match: # Asset new_entity = gazu.asset.new_asset( @@ -269,6 +272,7 @@ def sync_zou(): "parents": parent_doc["data"]["parents"] + [parent_doc["name"]], "visualParent": parent_doc["_id"], + "zou": new_sequence, }, "parent": parent_doc["_id"], } @@ -309,10 +313,54 @@ def sync_zou(): ) ) - # TODO update / tasks + # Update assets + all_tasks_types = {t["name"]: t for t in gazu.task.all_task_types()} + assets_docs_to_update = [ + doc + for doc in asset_docs.values() + if doc["data"].get("zou_id") in all_entities_ids + ] + for doc in assets_docs_to_update: + zou_id = doc["data"].get("zou", {}).get("id") + if zou_id: + # Data + entity_data = {} + frame_in = doc["data"].get("frameStart") + frame_out = doc["data"].get("frameEnd") + if frame_in or frame_out: + entity_data.update( + { + "data": {"frame_in": frame_in, "frame_out": frame_out}, + "nb_frames": frame_out - frame_in, + } + ) + entity = gazu.raw.update("entities", zou_id, entity_data) - # Delete TODO - # if gazu. + # Tasks + all_tasks_func = getattr( + gazu.task, f"all_tasks_for_{entity['type'].lower()}" + ) + entity_tasks = {t["name"] for t in all_tasks_func(entity)} + for task_name in doc["data"]["tasks"].keys(): + # Create only if new + if task_name not in entity_tasks: + task_type = all_tasks_types.get(task_name) + + # Create non existing task + if not task_type: + task_type = gazu.task.new_task_type(task_name) + all_tasks_types[task_name] = task_type + + # New task for entity + gazu.task.new_task(entity, task_type) + + # Delete + deleted_entities = all_entities_ids - { + asset_doc["data"].get("zou", {}).get("id") + for asset_doc in asset_docs.values() + } + for entity_id in deleted_entities: + gazu.raw.delete(f"data/entities/{entity_id}") # Write into DB if bulk_writes: @@ -320,94 +368,6 @@ def sync_zou(): dbcon.uninstall() - return - - for project in all_projects: - # Create project locally - # Try to find project document - project_name = project["name"] - project_code = project_name - dbcon.Session["AVALON_PROJECT"] = project_name - project_doc = dbcon.find_one({"type": "project"}) - - # Get all assets from zou - all_assets = gazu.asset.all_assets_for_project(project) - all_episodes = gazu.shot.all_episodes_for_project(project) - all_seqs = gazu.shot.all_sequences_for_project(project) - all_shots = gazu.shot.all_shots_for_project(project) - - # Create project if is not available - # - creation is required to be able set project anatomy and attributes - to_insert = [] - if not project_doc: - print(f"Creating project '{project_name}'") - project_doc = create_project(project_name, project_code, dbcon=dbcon) - - # Project tasks - bulk_writes.append( - UpdateOne( - {"_id": project_doc["_id"]}, - { - "$set": { - "config.tasks": { - t["name"]: { - "short_name": t.get("short_name", t["name"]) - } - for t in gazu.task.all_task_types_for_project(project) - } - } - }, - ) - ) - - # Query all assets of the local project - project_col = dbcon.database[project_code] - asset_doc_ids = { - asset_doc["data"]["zou_id"]: asset_doc - for asset_doc in project_col.find({"type": "asset"}) - if asset_doc["data"].get("zou_id") - } - asset_doc_ids[project["id"]] = project_doc - - # Create - to_insert.extend( - [ - { - "name": item["name"], - "type": "asset", - "schema": "openpype:asset-3.0", - "data": {"zou_id": item["id"], "tasks": {}}, - } - for item in all_episodes + all_assets + all_seqs + all_shots - if item["id"] not in asset_doc_ids.keys() - ] - ) - if to_insert: - # Insert in doc - project_col.insert_many(to_insert) - - # Update existing docs - asset_doc_ids.update( - { - asset_doc["data"]["zou_id"]: asset_doc - for asset_doc in project_col.find({"type": "asset"}) - if asset_doc["data"].get("zou_id") - } - ) - - # Update - all_entities = all_assets + all_episodes + all_seqs + all_shots - bulk_writes.extend(update_op_assets(all_entities, asset_doc_ids)) - - # Delete - diff_assets = set(asset_doc_ids.keys()) - { - e["id"] for e in all_entities + [project] - } - if diff_assets: - bulk_writes.extend( - [DeleteOne(asset_doc_ids[asset_id]) for asset_id in diff_assets] - ) - @cli_main.command() def sync_openpype(): From b2ce0ac07a04ebdc2e61b4289ec2c2fcde624c63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Tue, 15 Feb 2022 18:29:43 +0100 Subject: [PATCH 037/350] Shot naming matching --- .../default_modules/kitsu/kitsu_module.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index e42edbc52b..a67f0e2d58 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -233,16 +233,7 @@ def sync_zou(): new_entity = gazu.asset.new_asset( zou_project, all_asset_types[0], doc["name"] ) - - elif match.group(1): # Episode - new_entity = gazu.shot.new_episode(zou_project, doc["name"]) - - elif match.group(2): # Sequence - parent_doc = asset_docs[visual_parent_id] - new_entity = gazu.shot.new_sequence( - zou_project, doc["name"], episode=parent_doc["data"]["zou_id"] - ) - + # Match case in shot Date: Tue, 15 Feb 2022 18:30:06 +0100 Subject: [PATCH 038/350] cleaning --- openpype/modules/default_modules/kitsu/kitsu_module.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index a67f0e2d58..47af25ce60 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -6,8 +6,6 @@ in global space here until are required or used. - imports of Python 3 packages - we still support Python 2 hosts where addon definition should available """ -from asyncio import all_tasks -from turtle import update import click import os import re From a8611c07a8d56942950a2294a95f06f07aa87d94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 16 Feb 2022 15:42:23 +0100 Subject: [PATCH 039/350] Clean sync zou --- .../default_modules/kitsu/kitsu_module.py | 138 +++++++++--------- 1 file changed, 72 insertions(+), 66 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index 47af25ce60..ce4c579607 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -13,6 +13,24 @@ from typing import Dict, List from avalon.api import AvalonMongoDB import gazu +from gazu.asset import all_assets_for_project, all_asset_types, new_asset +from gazu.shot import ( + all_episodes_for_project, + all_sequences_for_project, + all_shots_for_project, + new_episode, + new_sequence, + new_shot, + update_sequence, +) +from gazu.task import ( + all_tasks_for_asset, + all_tasks_for_shot, + all_task_types, + all_task_types_for_project, + new_task, + new_task_type, +) from openpype.api import get_project_settings from openpype.lib import create_project from openpype.modules import JsonFilesSettingsDef, OpenPypeModule, ModulesManager @@ -176,7 +194,7 @@ def sync_zou(): # Create project if zou_project is None: raise RuntimeError( - f"Project '{project_name}' doesn't exist in Zou database, please create it in Kitsu and add logged user to it before running synchronization." + f"Project '{project_name}' doesn't exist in Zou database, please create it in Kitsu and add OpenPype user to it before running synchronization." ) # Update project settings and data @@ -190,11 +208,11 @@ def sync_zou(): gazu.project.update_project(zou_project) gazu.project.update_project_data(zou_project, data=op_project["data"]) - all_asset_types = gazu.asset.all_asset_types() - all_assets = gazu.asset.all_assets_for_project(zou_project) - all_episodes = gazu.shot.all_episodes_for_project(zou_project) - all_seqs = gazu.shot.all_sequences_for_project(zou_project) - all_shots = gazu.shot.all_shots_for_project(zou_project) + asset_types = all_asset_types() + all_assets = all_assets_for_project(zou_project) + all_episodes = all_episodes_for_project(zou_project) + all_seqs = all_sequences_for_project(zou_project) + all_shots = all_shots_for_project(zou_project) all_entities_ids = { e["id"] for e in all_episodes + all_seqs + all_shots + all_assets } @@ -211,14 +229,14 @@ def sync_zou(): new_assets_docs = [ doc for doc in asset_docs.values() - if doc["data"].get("zou_id") not in all_entities_ids + if doc["data"].get("zou", {}).get("id") not in all_entities_ids ] naming_pattern = project_module_settings["entities_naming_pattern"] regex_ep = re.compile( - r"({})|({})|({})".format( - naming_pattern["episode"].replace("#", "\d"), - naming_pattern["sequence"].replace("#", "\d"), - naming_pattern["shot"].replace("#", "\d"), + r"(.*{}.*)|(.*{}.*)|(.*{}.*)".format( + naming_pattern["shot"].replace("#", ""), + naming_pattern["sequence"].replace("#", ""), + naming_pattern["episode"].replace("#", ""), ), re.IGNORECASE, ) @@ -228,51 +246,38 @@ def sync_zou(): # Match asset type by it's name match = regex_ep.match(doc["name"]) if not match: # Asset - new_entity = gazu.asset.new_asset( - zou_project, all_asset_types[0], doc["name"] - ) + new_entity = new_asset(zou_project, asset_types[0], doc["name"]) # Match case in shot Date: Wed, 16 Feb 2022 17:30:35 +0100 Subject: [PATCH 040/350] Fix sync --- .../default_modules/kitsu/kitsu_module.py | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index ce4c579607..266aaa9139 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -184,7 +184,6 @@ def sync_zou(): # Create project locally # Try to find project document project_name = op_project["name"] - project_code = op_project["data"]["code"] dbcon.Session["AVALON_PROJECT"] = project_name # Get all entities from zou @@ -198,15 +197,16 @@ def sync_zou(): ) # Update project settings and data - zou_project.update( - { - "code": op_project["data"]["code"], - "fps": op_project["data"]["fps"], - "resolution": f"{op_project['data']['resolutionWidth']}x{op_project['data']['resolutionHeight']}", - } - ) + if op_project["data"]: + zou_project.update( + { + "code": op_project["data"]["code"], + "fps": op_project["data"]["fps"], + "resolution": f"{op_project['data']['resolutionWidth']}x{op_project['data']['resolutionHeight']}", + } + ) + gazu.project.update_project_data(zou_project, data=op_project["data"]) gazu.project.update_project(zou_project) - gazu.project.update_project_data(zou_project, data=op_project["data"]) asset_types = all_asset_types() all_assets = all_assets_for_project(zou_project) @@ -270,8 +270,9 @@ def sync_zou(): created_sequence = new_sequence( zou_project, substitute_sequence_name, episode=zou_parent_id ) - created_sequence["is_substitute"] = True - update_sequence(created_sequence) + gazu.shot.update_sequence_data( + created_sequence, {"is_substitute": True} + ) # Update parent ID zou_parent_id = created_sequence["id"] @@ -395,11 +396,18 @@ def sync_openpype(): dbcon.Session["AVALON_PROJECT"] = project_name project_doc = dbcon.find_one({"type": "project"}) + print(f"Synchronizing {project_name}...") + # Get all assets from zou all_assets = all_assets_for_project(project) all_episodes = all_episodes_for_project(project) all_seqs = all_sequences_for_project(project) all_shots = all_shots_for_project(project) + all_entities = [ + e + for e in all_assets + all_episodes + all_seqs + all_shots + if not e["data"].get("is_substitute") + ] # Create project if is not available # - creation is required to be able set project anatomy and attributes @@ -421,7 +429,7 @@ def sync_openpype(): "data": project["data"].update( { "code": project["code"], - "fps": project_code["fps"], + "fps": project["fps"], "resolutionWidth": project["resolution"].split("x")[0], "resolutionHeight": project["resolution"].split("x")[1], } @@ -449,9 +457,8 @@ def sync_openpype(): "schema": "openpype:asset-3.0", "data": {"zou": item, "tasks": {}}, } - for item in all_episodes + all_assets + all_seqs + all_shots + for item in all_entities if item["id"] not in asset_doc_ids.keys() - and not item.get("is_substitute") ] ) if to_insert: @@ -468,7 +475,6 @@ def sync_openpype(): ) # Update - all_entities = all_assets + all_episodes + all_seqs + all_shots bulk_writes.extend(update_op_assets(all_entities, asset_doc_ids)) # Delete From 93fb1ac0f1331439852104189733671386366861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Thu, 17 Feb 2022 11:12:13 +0100 Subject: [PATCH 041/350] Use substitutes id --- .../default_modules/kitsu/kitsu_module.py | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index 266aaa9139..0529d38a0e 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -242,6 +242,7 @@ def sync_zou(): ) for doc in new_assets_docs: visual_parent_id = doc["data"]["visualParent"] + parent_substitutes = [] # Match asset type by it's name match = regex_ep.match(doc["name"]) @@ -273,6 +274,7 @@ def sync_zou(): gazu.shot.update_sequence_data( created_sequence, {"is_substitute": True} ) + parent_substitutes.append(created_sequence) # Update parent ID zou_parent_id = created_sequence["id"] @@ -310,6 +312,7 @@ def sync_zou(): "$set": { "data.visualParent": visual_parent_id, "data.zou": new_entity, + "data.parent_substitutes": parent_substitutes, } }, ) @@ -494,17 +497,17 @@ def sync_openpype(): def update_op_assets( - items_list: List[dict], asset_doc_ids: Dict[str, dict] + entities_list: List[dict], asset_doc_ids: Dict[str, dict] ) -> List[UpdateOne]: """Update OpenPype assets. Set 'data' and 'parent' fields. - :param items_list: List of zou items to update + :param entities_list: List of zou entities to update :param asset_doc_ids: Dicts of [{zou_id: asset_doc}, ...] :return: List of UpdateOne objects """ bulk_writes = [] - for item in items_list: + for item in entities_list: # Update asset item_doc = asset_doc_ids[item["id"]] item_data = item_doc["data"].copy() @@ -523,20 +526,28 @@ def update_op_assets( } # Visual parent for hierarchy - direct_parent_id = item["parent_id"] or item["source_id"] - if direct_parent_id: - visual_parent_doc = asset_doc_ids[direct_parent_id] + substitute_parent_item = ( + item_data["parent_substitutes"][0] + if item_data.get("parent_substitutes") + else None + ) + parent_zou_id = item["parent_id"] or item["source_id"] + if substitute_parent_item: + parent_zou_id = ( + substitute_parent_item["parent_id"] + or substitute_parent_item["source_id"] + ) + visual_parent_doc = asset_doc_ids[parent_zou_id] item_data["visualParent"] = visual_parent_doc["_id"] # Add parents for hierarchy - parent_zou_id = item["parent_id"] item_data["parents"] = [] while parent_zou_id is not None: parent_doc = asset_doc_ids[parent_zou_id] item_data["parents"].insert(0, parent_doc["name"]) parent_zou_id = next( - i for i in items_list if i["id"] == parent_doc["data"]["zou"]["id"] + i for i in entities_list if i["id"] == parent_doc["data"]["zou"]["id"] )["parent_id"] # Update 'data' different in zou DB From c058ba54c2763b4563f5912f8a8a8930cceafc1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Tue, 22 Feb 2022 18:27:06 +0100 Subject: [PATCH 042/350] Project sync and code DRYing --- .../modules/default_modules/kitsu/__init__.py | 10 +-- .../default_modules/kitsu/kitsu_module.py | 52 ++++++---------- .../default_modules/kitsu/listeners.py | 61 +++++++++++++++++++ .../default_modules/kitsu/utils/__init__.py | 0 .../default_modules/kitsu/utils/openpype.py | 47 ++++++++++++++ 5 files changed, 128 insertions(+), 42 deletions(-) create mode 100644 openpype/modules/default_modules/kitsu/listeners.py create mode 100644 openpype/modules/default_modules/kitsu/utils/__init__.py create mode 100644 openpype/modules/default_modules/kitsu/utils/openpype.py diff --git a/openpype/modules/default_modules/kitsu/__init__.py b/openpype/modules/default_modules/kitsu/__init__.py index cd0c2ea8af..dc7c2dad50 100644 --- a/openpype/modules/default_modules/kitsu/__init__.py +++ b/openpype/modules/default_modules/kitsu/__init__.py @@ -4,12 +4,6 @@ If addon class or settings definition won't be here their definition won't be found by OpenPype discovery. """ -from .kitsu_module import ( - AddonSettingsDef, - KitsuModule -) +from .kitsu_module import AddonSettingsDef, KitsuModule -__all__ = ( - "AddonSettingsDef", - "KitsuModule" -) +__all__ = ("AddonSettingsDef", "KitsuModule") diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index 0529d38a0e..3fddc48ee9 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -11,7 +11,6 @@ import os import re from typing import Dict, List -from avalon.api import AvalonMongoDB import gazu from gazu.asset import all_assets_for_project, all_asset_types, new_asset from gazu.shot import ( @@ -21,7 +20,6 @@ from gazu.shot import ( new_episode, new_sequence, new_shot, - update_sequence, ) from gazu.task import ( all_tasks_for_asset, @@ -31,11 +29,15 @@ from gazu.task import ( new_task, new_task_type, ) +from pymongo import DeleteOne, UpdateOne + +from avalon.api import AvalonMongoDB from openpype.api import get_project_settings from openpype.lib import create_project from openpype.modules import JsonFilesSettingsDef, OpenPypeModule, ModulesManager -from pymongo import DeleteOne, UpdateOne +from openpype.modules.default_modules.kitsu.utils.openpype import sync_project from openpype_interfaces import IPluginPaths, ITrayAction +from .listeners import add_listeners # Settings definition of this addon using `JsonFilesSettingsDef` @@ -371,8 +373,6 @@ def sync_zou(): if bulk_writes: project_col.bulk_write(bulk_writes) - # TODO Create events daemons - dbcon.uninstall() @@ -412,35 +412,8 @@ def sync_openpype(): if not e["data"].get("is_substitute") ] - # Create project if is not available - # - creation is required to be able set project anatomy and attributes - to_insert = [] - if not project_doc: - print(f"Creating project '{project_name}'") - project_doc = create_project(project_name, project_code, dbcon=dbcon) - - # Project data and tasks - bulk_writes.append( - UpdateOne( - {"_id": project_doc["_id"]}, - { - "$set": { - "config.tasks": { - t["name"]: {"short_name": t.get("short_name", t["name"])} - for t in all_task_types_for_project(project) - }, - "data": project["data"].update( - { - "code": project["code"], - "fps": project["fps"], - "resolutionWidth": project["resolution"].split("x")[0], - "resolutionHeight": project["resolution"].split("x")[1], - } - ), - } - }, - ) - ) + # Sync project. Create if doesn't exist + bulk_writes.append(sync_project(project, dbcon)) # Query all assets of the local project project_col = dbcon.database[project_code] @@ -452,6 +425,7 @@ def sync_openpype(): asset_doc_ids[project["id"]] = project_doc # Create + to_insert = [] to_insert.extend( [ { @@ -572,6 +546,16 @@ def update_op_assets( return bulk_writes +@cli_main.command() +def listen(): + """Show ExampleAddon dialog. + + We don't have access to addon directly through cli so we have to create + it again. + """ + add_listeners() + + @cli_main.command() def show_dialog(): """Show ExampleAddon dialog. diff --git a/openpype/modules/default_modules/kitsu/listeners.py b/openpype/modules/default_modules/kitsu/listeners.py new file mode 100644 index 0000000000..5303933bce --- /dev/null +++ b/openpype/modules/default_modules/kitsu/listeners.py @@ -0,0 +1,61 @@ +from turtle import update +import gazu +import os + +from pymongo import DeleteOne, UpdateOne + +from avalon.api import AvalonMongoDB +from openpype.modules.default_modules.kitsu.utils.openpype import sync_project + + +def add_listeners(): + # Connect to server + gazu.client.set_host(os.environ["KITSU_SERVER"]) + + # Authenticate + gazu.log_in(os.environ["KITSU_LOGIN"], os.environ["KITSU_PWD"]) + gazu.set_event_host(os.environ["KITSU_SERVER"].replace("api", "socket.io")) + + # Connect to DB + dbcon = AvalonMongoDB() + dbcon.install() + + def new_project(data): + """Create new project into DB.""" + + # Use update process to avoid duplicating code + update_project(data) + + def update_project(data): + """Update project into DB.""" + # Get project entity + project = gazu.project.get_project(data["project_id"]) + project_name = project["name"] + dbcon.Session["AVALON_PROJECT"] = project_name + + update_project = sync_project(project, dbcon) + + # Write into DB + if update_project: + project_col = dbcon.database[project_name] + project_col.bulk_write([update_project]) + + def delete_project(data): + # Get project entity + print(data) # TODO check bugfix + project = gazu.project.get_project(data["project_id"]) + + # Delete project collection + project_col = dbcon.database[project["name"]] + project_col.drop() + + def new_asset(data): + print("Asset created %s" % data) + + event_client = gazu.events.init() + gazu.events.add_listener(event_client, "project:new", new_project) + gazu.events.add_listener(event_client, "project:update", update_project) + gazu.events.add_listener(event_client, "project:delete", delete_project) + gazu.events.add_listener(event_client, "asset:new", new_asset) + gazu.events.run_client(event_client) + print("ll") diff --git a/openpype/modules/default_modules/kitsu/utils/__init__.py b/openpype/modules/default_modules/kitsu/utils/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openpype/modules/default_modules/kitsu/utils/openpype.py b/openpype/modules/default_modules/kitsu/utils/openpype.py new file mode 100644 index 0000000000..9e795bb8ca --- /dev/null +++ b/openpype/modules/default_modules/kitsu/utils/openpype.py @@ -0,0 +1,47 @@ +import gazu + +from pymongo import DeleteOne, UpdateOne + +from avalon.api import AvalonMongoDB +from openpype.lib import create_project + + +def sync_project(project: dict, dbcon: AvalonMongoDB) -> UpdateOne: + """Sync project with database. + Create project if doesn't exist. + + :param project: Gazu project + :param dbcon: DB to create project in + :return: Update instance for the project + """ + project_name = project["name"] + project_doc = dbcon.find_one({"type": "project"}) + if not project_doc: + print(f"Creating project '{project_name}'") + project_doc = create_project(project_name, project_name, dbcon=dbcon) + + print(f"Synchronizing {project_name}...") + + # Project data and tasks + if not project["data"]: # Sentinel + project["data"] = {} + + return UpdateOne( + {"_id": project_doc["_id"]}, + { + "$set": { + "config.tasks": { + t["name"]: {"short_name": t.get("short_name", t["name"])} + for t in gazu.task.all_task_types_for_project(project) + }, + "data": project["data"].update( + { + "code": project["code"], + "fps": project["fps"], + "resolutionWidth": project["resolution"].split("x")[0], + "resolutionHeight": project["resolution"].split("x")[1], + } + ), + } + }, + ) From 0d38ccc5127bd00157aa9d19157f5d7c3ec3e20f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 23 Feb 2022 15:14:38 +0100 Subject: [PATCH 043/350] Listen asset and DRY --- .../default_modules/kitsu/kitsu_module.py | 117 ++++-------------- .../default_modules/kitsu/listeners.py | 70 +++++++++-- .../default_modules/kitsu/utils/openpype.py | 114 +++++++++++++++++ 3 files changed, 198 insertions(+), 103 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index 3fddc48ee9..0bdd4b12e6 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -22,10 +22,7 @@ from gazu.shot import ( new_shot, ) from gazu.task import ( - all_tasks_for_asset, - all_tasks_for_shot, all_task_types, - all_task_types_for_project, new_task, new_task_type, ) @@ -33,9 +30,12 @@ from pymongo import DeleteOne, UpdateOne from avalon.api import AvalonMongoDB from openpype.api import get_project_settings -from openpype.lib import create_project from openpype.modules import JsonFilesSettingsDef, OpenPypeModule, ModulesManager -from openpype.modules.default_modules.kitsu.utils.openpype import sync_project +from openpype.modules.default_modules.kitsu.utils.openpype import ( + create_op_asset, + sync_project, + update_op_assets, +) from openpype_interfaces import IPluginPaths, ITrayAction from .listeners import add_listeners @@ -417,33 +417,28 @@ def sync_openpype(): # Query all assets of the local project project_col = dbcon.database[project_code] - asset_doc_ids = { + zou_ids_and_asset_docs = { asset_doc["data"]["zou"]["id"]: asset_doc for asset_doc in project_col.find({"type": "asset"}) if asset_doc["data"].get("zou", {}).get("id") } - asset_doc_ids[project["id"]] = project_doc + zou_ids_and_asset_docs[project["id"]] = project_doc # Create to_insert = [] to_insert.extend( [ - { - "name": item["name"], - "type": "asset", - "schema": "openpype:asset-3.0", - "data": {"zou": item, "tasks": {}}, - } + create_op_asset(item) for item in all_entities - if item["id"] not in asset_doc_ids.keys() + if item["id"] not in zou_ids_and_asset_docs.keys() ] ) if to_insert: - # Insert in doc + # Insert doc in DB project_col.insert_many(to_insert) # Update existing docs - asset_doc_ids.update( + zou_ids_and_asset_docs.update( { asset_doc["data"]["zou"]["id"]: asset_doc for asset_doc in project_col.find({"type": "asset"}) @@ -452,15 +447,23 @@ def sync_openpype(): ) # Update - bulk_writes.extend(update_op_assets(all_entities, asset_doc_ids)) + bulk_writes.extend( + [ + UpdateOne({"_id": id}, update) + for id, update in update_op_assets(all_entities, zou_ids_and_asset_docs) + ] + ) # Delete - diff_assets = set(asset_doc_ids.keys()) - { + diff_assets = set(zou_ids_and_asset_docs.keys()) - { e["id"] for e in all_entities + [project] } if diff_assets: bulk_writes.extend( - [DeleteOne(asset_doc_ids[asset_id]) for asset_id in diff_assets] + [ + DeleteOne(zou_ids_and_asset_docs[asset_id]) + for asset_id in diff_assets + ] ) # Write into DB @@ -470,82 +473,6 @@ def sync_openpype(): dbcon.uninstall() -def update_op_assets( - entities_list: List[dict], asset_doc_ids: Dict[str, dict] -) -> List[UpdateOne]: - """Update OpenPype assets. - Set 'data' and 'parent' fields. - - :param entities_list: List of zou entities to update - :param asset_doc_ids: Dicts of [{zou_id: asset_doc}, ...] - :return: List of UpdateOne objects - """ - bulk_writes = [] - for item in entities_list: - # Update asset - item_doc = asset_doc_ids[item["id"]] - item_data = item_doc["data"].copy() - item_data["zou"] = item - - # Tasks - tasks_list = None - if item["type"] == "Asset": - tasks_list = all_tasks_for_asset(item) - elif item["type"] == "Shot": - tasks_list = all_tasks_for_shot(item) - # TODO frame in and out - if tasks_list: - item_data["tasks"] = { - t["task_type_name"]: {"type": t["task_type_name"]} for t in tasks_list - } - - # Visual parent for hierarchy - substitute_parent_item = ( - item_data["parent_substitutes"][0] - if item_data.get("parent_substitutes") - else None - ) - parent_zou_id = item["parent_id"] or item["source_id"] - if substitute_parent_item: - parent_zou_id = ( - substitute_parent_item["parent_id"] - or substitute_parent_item["source_id"] - ) - visual_parent_doc = asset_doc_ids[parent_zou_id] - item_data["visualParent"] = visual_parent_doc["_id"] - - # Add parents for hierarchy - item_data["parents"] = [] - while parent_zou_id is not None: - parent_doc = asset_doc_ids[parent_zou_id] - item_data["parents"].insert(0, parent_doc["name"]) - - parent_zou_id = next( - i for i in entities_list if i["id"] == parent_doc["data"]["zou"]["id"] - )["parent_id"] - - # Update 'data' different in zou DB - updated_data = { - k: item_data[k] - for k in item_data.keys() - if item_doc["data"].get(k) != item_data[k] - } - if updated_data or not item_doc.get("parent"): - bulk_writes.append( - UpdateOne( - {"_id": item_doc["_id"]}, - { - "$set": { - "data": item_data, - "parent": asset_doc_ids[item["project_id"]]["_id"], - } - }, - ) - ) - - return bulk_writes - - @cli_main.command() def listen(): """Show ExampleAddon dialog. diff --git a/openpype/modules/default_modules/kitsu/listeners.py b/openpype/modules/default_modules/kitsu/listeners.py index 5303933bce..fd4cf6dd3d 100644 --- a/openpype/modules/default_modules/kitsu/listeners.py +++ b/openpype/modules/default_modules/kitsu/listeners.py @@ -5,7 +5,12 @@ import os from pymongo import DeleteOne, UpdateOne from avalon.api import AvalonMongoDB -from openpype.modules.default_modules.kitsu.utils.openpype import sync_project +from openpype.modules.default_modules.kitsu.utils.openpype import ( + create_op_asset, + set_op_project, + sync_project, + update_op_assets, +) def add_listeners(): @@ -15,19 +20,22 @@ def add_listeners(): # Authenticate gazu.log_in(os.environ["KITSU_LOGIN"], os.environ["KITSU_PWD"]) gazu.set_event_host(os.environ["KITSU_SERVER"].replace("api", "socket.io")) + event_client = gazu.events.init() # Connect to DB dbcon = AvalonMongoDB() dbcon.install() + # == Project == + def new_project(data): - """Create new project into DB.""" + """Create new project into OP DB.""" # Use update process to avoid duplicating code update_project(data) def update_project(data): - """Update project into DB.""" + """Update project into OP DB.""" # Get project entity project = gazu.project.get_project(data["project_id"]) project_name = project["name"] @@ -41,6 +49,7 @@ def add_listeners(): project_col.bulk_write([update_project]) def delete_project(data): + """Delete project.""" # Get project entity print(data) # TODO check bugfix project = gazu.project.get_project(data["project_id"]) @@ -49,13 +58,58 @@ def add_listeners(): project_col = dbcon.database[project["name"]] project_col.drop() - def new_asset(data): - print("Asset created %s" % data) - - event_client = gazu.events.init() gazu.events.add_listener(event_client, "project:new", new_project) gazu.events.add_listener(event_client, "project:update", update_project) gazu.events.add_listener(event_client, "project:delete", delete_project) + + # == Asset == + + def new_asset(data): + """Create new asset into OP DB.""" + # Get project entity + project_col = set_op_project(dbcon, data["project_id"]) + + # Get gazu entity + asset = gazu.asset.get_asset(data["asset_id"]) + + # Insert doc in DB + project_col.insert_one(create_op_asset(asset)) + + # Update + update_asset(data) + + def update_asset(data): + """Update asset into OP DB.""" + project_col = set_op_project(dbcon, data["project_id"]) + project_doc = dbcon.find_one({"type": "project"}) + + # Get gazu entity + asset = gazu.asset.get_asset(data["asset_id"]) + + # Find asset doc + # Query all assets of the local project + zou_ids_and_asset_docs = { + asset_doc["data"]["zou"]["id"]: asset_doc + for asset_doc in project_col.find({"type": "asset"}) + if asset_doc["data"].get("zou", {}).get("id") + } + zou_ids_and_asset_docs[asset["project_id"]] = project_doc + + # Update + asset_doc_id, asset_update = update_op_assets([asset], zou_ids_and_asset_docs)[ + 0 + ] + project_col.update_one({"_id": asset_doc_id}, asset_update) + + def delete_asset(data): + """Delete asset of OP DB.""" + project_col = set_op_project(dbcon, data["project_id"]) + + # Delete + project_col.delete_one({"type": "asset", "data.zou.id": data["asset_id"]}) + gazu.events.add_listener(event_client, "asset:new", new_asset) + gazu.events.add_listener(event_client, "asset:update", update_asset) + gazu.events.add_listener(event_client, "asset:delete", delete_asset) + gazu.events.run_client(event_client) - print("ll") diff --git a/openpype/modules/default_modules/kitsu/utils/openpype.py b/openpype/modules/default_modules/kitsu/utils/openpype.py index 9e795bb8ca..8ef987898d 100644 --- a/openpype/modules/default_modules/kitsu/utils/openpype.py +++ b/openpype/modules/default_modules/kitsu/utils/openpype.py @@ -1,11 +1,125 @@ +from typing import Dict, List import gazu from pymongo import DeleteOne, UpdateOne +from pymongo.collection import Collection + +from gazu.task import ( + all_tasks_for_asset, + all_tasks_for_shot, +) from avalon.api import AvalonMongoDB from openpype.lib import create_project +def create_op_asset(gazu_entity: dict) -> dict: + """Create OP asset dict from gazu entity. + + :param gazu_entity: + """ + return { + "name": gazu_entity["name"], + "type": "asset", + "schema": "openpype:asset-3.0", + "data": {"zou": gazu_entity, "tasks": {}}, + } + + +def set_op_project(dbcon, project_id) -> Collection: + """Set project context. + + :param dbcon: Connection to DB. + :param project_id: Project zou ID + """ + project = gazu.project.get_project(project_id) + project_name = project["name"] + dbcon.Session["AVALON_PROJECT"] = project_name + + return dbcon.database[project_name] + + +def update_op_assets( + entities_list: List[dict], asset_doc_ids: Dict[str, dict] +) -> List[Dict[str, dict]]: + """Update OpenPype assets. + Set 'data' and 'parent' fields. + + :param entities_list: List of zou entities to update + :param asset_doc_ids: Dicts of [{zou_id: asset_doc}, ...] + :return: List of (doc_id, update_dict) tuples + """ + assets_with_update = [] + for item in entities_list: + # Update asset + item_doc = asset_doc_ids[item["id"]] + item_data = item_doc["data"].copy() + item_data["zou"] = item + + # Tasks + tasks_list = [] + if item["type"] == "Asset": + tasks_list = all_tasks_for_asset(item) + elif item["type"] == "Shot": + tasks_list = all_tasks_for_shot(item) + # TODO frame in and out + item_data["tasks"] = { + t["task_type_name"]: {"type": t["task_type_name"]} for t in tasks_list + } + + # Get zou parent id for correct hierarchy + # Use parent substitutes if existing + substitute_parent_item = ( + item_data["parent_substitutes"][0] + if item_data.get("parent_substitutes") + else None + ) + if substitute_parent_item: + parent_zou_id = substitute_parent_item["id"] + else: + parent_zou_id = ( + item.get("parent_id") or item.get("episode_id") or item.get("source_id") + ) # TODO check consistency + + # Visual parent for hierarchy + visual_parent_doc_id = ( + asset_doc_ids[parent_zou_id]["_id"] if parent_zou_id else None + ) + item_data["visualParent"] = visual_parent_doc_id + + # Add parents for hierarchy + item_data["parents"] = [] + while parent_zou_id is not None: + parent_doc = asset_doc_ids[parent_zou_id] + item_data["parents"].insert(0, parent_doc["name"]) + + # Get parent entity + parent_entity = parent_doc["data"]["zou"] + parent_zou_id = parent_entity["parent_id"] + + # Update 'data' different in zou DB + updated_data = { + k: item_data[k] + for k in item_data.keys() + if item_doc["data"].get(k) != item_data[k] + } + if updated_data or not item_doc.get("parent"): + assets_with_update.append( + ( + item_doc["_id"], + { + "$set": { + "name": item["name"], + "data": item_data, + "parent": asset_doc_ids[item["project_id"]]["_id"], + } + }, + ) + ) + + return assets_with_update + + def sync_project(project: dict, dbcon: AvalonMongoDB) -> UpdateOne: """Sync project with database. Create project if doesn't exist. From fe5486886712a77cd40f37cac6ec41d329c17748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 23 Feb 2022 17:04:21 +0100 Subject: [PATCH 044/350] Listen Episode, Sequence and Shot --- .../default_modules/kitsu/listeners.py | 147 ++++++++++++++++++ .../default_modules/kitsu/utils/openpype.py | 2 +- 2 files changed, 148 insertions(+), 1 deletion(-) diff --git a/openpype/modules/default_modules/kitsu/listeners.py b/openpype/modules/default_modules/kitsu/listeners.py index fd4cf6dd3d..bb217452df 100644 --- a/openpype/modules/default_modules/kitsu/listeners.py +++ b/openpype/modules/default_modules/kitsu/listeners.py @@ -112,4 +112,151 @@ def add_listeners(): gazu.events.add_listener(event_client, "asset:update", update_asset) gazu.events.add_listener(event_client, "asset:delete", delete_asset) + # == Episode == + def new_episode(data): + """Create new episode into OP DB.""" + # Get project entity + project_col = set_op_project(dbcon, data["project_id"]) + + # Get gazu entity + episode = gazu.shot.get_episode(data["episode_id"]) + + # Insert doc in DB + project_col.insert_one(create_op_asset(episode)) + + # Update + update_episode(data) + + def update_episode(data): + """Update episode into OP DB.""" + project_col = set_op_project(dbcon, data["project_id"]) + project_doc = dbcon.find_one({"type": "project"}) + + # Get gazu entity + episode = gazu.shot.get_episode(data["episode_id"]) + + # Find asset doc + # Query all assets of the local project + zou_ids_and_asset_docs = { + asset_doc["data"]["zou"]["id"]: asset_doc + for asset_doc in project_col.find({"type": "asset"}) + if asset_doc["data"].get("zou", {}).get("id") + } + zou_ids_and_asset_docs[episode["project_id"]] = project_doc + + # Update + asset_doc_id, asset_update = update_op_assets( + [episode], zou_ids_and_asset_docs + )[0] + project_col.update_one({"_id": asset_doc_id}, asset_update) + + def delete_episode(data): + """Delete shot of OP DB.""" + project_col = set_op_project(dbcon, data["project_id"]) + print("delete episode") # TODO check bugfix + + # Delete + project_col.delete_one({"type": "asset", "data.zou.id": data["episode_id"]}) + + gazu.events.add_listener(event_client, "episode:new", new_episode) + gazu.events.add_listener(event_client, "episode:update", update_episode) + gazu.events.add_listener(event_client, "episode:delete", delete_episode) + + # == Sequence == + def new_sequence(data): + """Create new sequnce into OP DB.""" + # Get project entity + project_col = set_op_project(dbcon, data["project_id"]) + + # Get gazu entity + sequence = gazu.shot.get_sequence(data["sequence_id"]) + + # Insert doc in DB + project_col.insert_one(create_op_asset(sequence)) + + # Update + update_sequence(data) + + def update_sequence(data): + """Update sequence into OP DB.""" + project_col = set_op_project(dbcon, data["project_id"]) + project_doc = dbcon.find_one({"type": "project"}) + + # Get gazu entity + sequence = gazu.shot.get_sequence(data["sequence_id"]) + + # Find asset doc + # Query all assets of the local project + zou_ids_and_asset_docs = { + asset_doc["data"]["zou"]["id"]: asset_doc + for asset_doc in project_col.find({"type": "asset"}) + if asset_doc["data"].get("zou", {}).get("id") + } + zou_ids_and_asset_docs[sequence["project_id"]] = project_doc + + # Update + asset_doc_id, asset_update = update_op_assets( + [sequence], zou_ids_and_asset_docs + )[0] + project_col.update_one({"_id": asset_doc_id}, asset_update) + + def delete_sequence(data): + """Delete sequence of OP DB.""" + project_col = set_op_project(dbcon, data["project_id"]) + print("delete sequence") # TODO check bugfix + + # Delete + project_col.delete_one({"type": "asset", "data.zou.id": data["sequence_id"]}) + + gazu.events.add_listener(event_client, "sequence:new", new_sequence) + gazu.events.add_listener(event_client, "sequence:update", update_sequence) + gazu.events.add_listener(event_client, "sequence:delete", delete_sequence) + + # == Shot == + def new_shot(data): + """Create new shot into OP DB.""" + # Get project entity + project_col = set_op_project(dbcon, data["project_id"]) + + # Get gazu entity + shot = gazu.shot.get_shot(data["shot_id"]) + + # Insert doc in DB + project_col.insert_one(create_op_asset(shot)) + + # Update + update_shot(data) + + def update_shot(data): + """Update shot into OP DB.""" + project_col = set_op_project(dbcon, data["project_id"]) + project_doc = dbcon.find_one({"type": "project"}) + + # Get gazu entity + shot = gazu.shot.get_shot(data["shot_id"]) + + # Find asset doc + # Query all assets of the local project + zou_ids_and_asset_docs = { + asset_doc["data"]["zou"]["id"]: asset_doc + for asset_doc in project_col.find({"type": "asset"}) + if asset_doc["data"].get("zou", {}).get("id") + } + zou_ids_and_asset_docs[shot["project_id"]] = project_doc + + # Update + asset_doc_id, asset_update = update_op_assets([shot], zou_ids_and_asset_docs)[0] + project_col.update_one({"_id": asset_doc_id}, asset_update) + + def delete_shot(data): + """Delete shot of OP DB.""" + project_col = set_op_project(dbcon, data["project_id"]) + + # Delete + project_col.delete_one({"type": "asset", "data.zou.id": data["shot_id"]}) + + gazu.events.add_listener(event_client, "shot:new", new_shot) + gazu.events.add_listener(event_client, "shot:update", update_shot) + gazu.events.add_listener(event_client, "shot:delete", delete_shot) + gazu.events.run_client(event_client) diff --git a/openpype/modules/default_modules/kitsu/utils/openpype.py b/openpype/modules/default_modules/kitsu/utils/openpype.py index 8ef987898d..809748fa78 100644 --- a/openpype/modules/default_modules/kitsu/utils/openpype.py +++ b/openpype/modules/default_modules/kitsu/utils/openpype.py @@ -75,7 +75,7 @@ def update_op_assets( else None ) if substitute_parent_item: - parent_zou_id = substitute_parent_item["id"] + parent_zou_id = substitute_parent_item["parent_id"] else: parent_zou_id = ( item.get("parent_id") or item.get("episode_id") or item.get("source_id") From de153a0450d9cbdcf9229775fa8fa9afa94eef79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Thu, 24 Feb 2022 15:53:03 +0100 Subject: [PATCH 045/350] Listen tasks, clean code --- .../default_modules/kitsu/kitsu_module.py | 1 - .../default_modules/kitsu/listeners.py | 55 ++++++++++++++++++- .../default_modules/kitsu/utils/openpype.py | 2 +- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index 0bdd4b12e6..10cbe76db2 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -9,7 +9,6 @@ in global space here until are required or used. import click import os import re -from typing import Dict, List import gazu from gazu.asset import all_assets_for_project, all_asset_types, new_asset diff --git a/openpype/modules/default_modules/kitsu/listeners.py b/openpype/modules/default_modules/kitsu/listeners.py index bb217452df..16c4e0e69e 100644 --- a/openpype/modules/default_modules/kitsu/listeners.py +++ b/openpype/modules/default_modules/kitsu/listeners.py @@ -1,9 +1,6 @@ -from turtle import update import gazu import os -from pymongo import DeleteOne, UpdateOne - from avalon.api import AvalonMongoDB from openpype.modules.default_modules.kitsu.utils.openpype import ( create_op_asset, @@ -259,4 +256,56 @@ def add_listeners(): gazu.events.add_listener(event_client, "shot:update", update_shot) gazu.events.add_listener(event_client, "shot:delete", delete_shot) + # == Task == + def new_task(data): + """Create new task into OP DB.""" + print("new", data) + # Get project entity + project_col = set_op_project(dbcon, data["project_id"]) + + # Get gazu entity + task = gazu.task.get_task(data["task_id"]) + + # Find asset doc + asset_doc = project_col.find_one( + {"type": "asset", "data.zou.id": task["entity"]["id"]} + ) + + # Update asset tasks with new one + asset_tasks = asset_doc["data"].get("tasks") + task_type_name = task["task_type"]["name"] + asset_tasks[task_type_name] = {"type": task_type_name, "zou": task} + project_col.update_one( + {"_id": asset_doc["_id"]}, {"$set": {"data.tasks": asset_tasks}} + ) + + def update_task(data): + """Update task into OP DB.""" + # TODO is it necessary? + pass + + def delete_task(data): + """Delete task of OP DB.""" + project_col = set_op_project(dbcon, data["project_id"]) + + # Find asset doc + asset_docs = [doc for doc in project_col.find({"type": "asset"})] + for doc in asset_docs: + # Match task + for name, task in doc["data"]["tasks"].items(): + if task.get("zou") and data["task_id"] == task["zou"]["id"]: + # Pop task + asset_tasks = doc["data"].get("tasks") + asset_tasks.pop(name) + + # Delete task in DB + project_col.update_one( + {"_id": doc["_id"]}, {"$set": {"data.tasks": asset_tasks}} + ) + return + + gazu.events.add_listener(event_client, "task:new", new_task) + gazu.events.add_listener(event_client, "task:update", update_task) + gazu.events.add_listener(event_client, "task:delete", delete_task) + gazu.events.run_client(event_client) diff --git a/openpype/modules/default_modules/kitsu/utils/openpype.py b/openpype/modules/default_modules/kitsu/utils/openpype.py index 809748fa78..edcf233ea8 100644 --- a/openpype/modules/default_modules/kitsu/utils/openpype.py +++ b/openpype/modules/default_modules/kitsu/utils/openpype.py @@ -1,7 +1,7 @@ from typing import Dict, List import gazu -from pymongo import DeleteOne, UpdateOne +from pymongo import UpdateOne from pymongo.collection import Collection from gazu.task import ( From 6cf38e1a35ba73a5df64969befb71728ffec4813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Fri, 25 Feb 2022 16:23:14 +0100 Subject: [PATCH 046/350] Publish comment to kitsu --- .../default_modules/kitsu/kitsu_module.py | 2 +- .../kitsu/plugins/publish/example_plugin.py | 40 +++++++++++++++++++ .../default_modules/kitsu/utils/openpype.py | 24 +++++------ 3 files changed, 53 insertions(+), 13 deletions(-) diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index 10cbe76db2..f62a86f04d 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -408,7 +408,7 @@ def sync_openpype(): all_entities = [ e for e in all_assets + all_episodes + all_seqs + all_shots - if not e["data"].get("is_substitute") + if e["data"] and not e["data"].get("is_substitute") ] # Sync project. Create if doesn't exist diff --git a/openpype/modules/default_modules/kitsu/plugins/publish/example_plugin.py b/openpype/modules/default_modules/kitsu/plugins/publish/example_plugin.py index 61602f4e78..614d9ecc38 100644 --- a/openpype/modules/default_modules/kitsu/plugins/publish/example_plugin.py +++ b/openpype/modules/default_modules/kitsu/plugins/publish/example_plugin.py @@ -1,9 +1,49 @@ +import os + +import gazu + import pyblish.api +import debugpy + class CollectExampleAddon(pyblish.api.ContextPlugin): order = pyblish.api.CollectorOrder + 0.4 label = "Collect Kitsu" def process(self, context): + debugpy.breakpoint() self.log.info("I'm in Kitsu's plugin!") + + +class IntegrateRig(pyblish.api.InstancePlugin): + """Copy files to an appropriate location where others may reach it""" + + order = pyblish.api.IntegratorOrder + families = ["model"] + + def process(self, instance): + print(instance.data["version"]) + + # Connect to server + gazu.client.set_host(os.environ["KITSU_SERVER"]) + + # Authenticate + gazu.log_in(os.environ["KITSU_LOGIN"], os.environ["KITSU_PWD"]) + + asset_data = instance.data["assetEntity"]["data"] + + # TODO Set local settings for login and password + + # Get task + task_type = gazu.task.get_task_type_by_name(instance.data["task"]) + entity_task = gazu.task.get_task_by_entity(asset_data["zou"], task_type) + + # Comment entity + gazu.task.add_comment( + entity_task, + entity_task["task_status_id"], + comment=f"Version {instance.data['version']} has been published!", + ) + + self.log.info("Copied successfully!") diff --git a/openpype/modules/default_modules/kitsu/utils/openpype.py b/openpype/modules/default_modules/kitsu/utils/openpype.py index edcf233ea8..518872a71c 100644 --- a/openpype/modules/default_modules/kitsu/utils/openpype.py +++ b/openpype/modules/default_modules/kitsu/utils/openpype.py @@ -134,11 +134,18 @@ def sync_project(project: dict, dbcon: AvalonMongoDB) -> UpdateOne: print(f"Creating project '{project_name}'") project_doc = create_project(project_name, project_name, dbcon=dbcon) - print(f"Synchronizing {project_name}...") - # Project data and tasks - if not project["data"]: # Sentinel - project["data"] = {} + project_data = project["data"] or {} + + # Update data + project_data.update( + { + "code": project["code"], + "fps": project["fps"], + "resolutionWidth": project["resolution"].split("x")[0], + "resolutionHeight": project["resolution"].split("x")[1], + } + ) return UpdateOne( {"_id": project_doc["_id"]}, @@ -148,14 +155,7 @@ def sync_project(project: dict, dbcon: AvalonMongoDB) -> UpdateOne: t["name"]: {"short_name": t.get("short_name", t["name"])} for t in gazu.task.all_task_types_for_project(project) }, - "data": project["data"].update( - { - "code": project["code"], - "fps": project["fps"], - "resolutionWidth": project["resolution"].split("x")[0], - "resolutionHeight": project["resolution"].split("x")[1], - } - ), + "data": project_data, } }, ) From cb01f8338c3b651897d626479a1a1bd306a7e05f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Tue, 1 Mar 2022 17:56:08 +0100 Subject: [PATCH 047/350] Sign in dialog, credentials as local setting and cleaning --- .../default_modules/kitsu/kitsu_module.py | 72 +++---- .../default_modules/kitsu/kitsu_widgets.py | 193 ++++++++++++++++++ .../{example_plugin.py => kitsu_plugin.py} | 8 +- .../schemas/project_schemas/main.json | 30 --- .../schemas/project_schemas/the_template.json | 30 --- .../kitsu/{ => utils}/listeners.py | 2 +- .../modules/default_modules/kitsu/widgets.py | 31 --- .../defaults/system_settings/modules.json | 4 +- .../module_settings/schema_kitsu.json | 10 - pyproject.toml | 3 +- 10 files changed, 224 insertions(+), 159 deletions(-) create mode 100644 openpype/modules/default_modules/kitsu/kitsu_widgets.py rename openpype/modules/default_modules/kitsu/plugins/publish/{example_plugin.py => kitsu_plugin.py} (85%) delete mode 100644 openpype/modules/default_modules/kitsu/settings/schemas/project_schemas/main.json delete mode 100644 openpype/modules/default_modules/kitsu/settings/schemas/project_schemas/the_template.json rename openpype/modules/default_modules/kitsu/{ => utils}/listeners.py (99%) delete mode 100644 openpype/modules/default_modules/kitsu/widgets.py diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/default_modules/kitsu/kitsu_module.py index f62a86f04d..51ab8aaa42 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/default_modules/kitsu/kitsu_module.py @@ -1,11 +1,5 @@ -"""Addon definition is located here. +"""Kitsu module.""" -Import of python packages that may not be available should not be imported -in global space here until are required or used. -- Qt related imports -- imports of Python 3 packages - - we still support Python 2 hosts where addon definition should available -""" import click import os import re @@ -35,20 +29,12 @@ from openpype.modules.default_modules.kitsu.utils.openpype import ( sync_project, update_op_assets, ) +from openpype.settings.lib import get_local_settings from openpype_interfaces import IPluginPaths, ITrayAction -from .listeners import add_listeners +from .utils.listeners import start_listeners -# Settings definition of this addon using `JsonFilesSettingsDef` -# - JsonFilesSettingsDef is prepared settings definition using json files -# to define settings and store default values class AddonSettingsDef(JsonFilesSettingsDef): - # This will add prefixes to every schema and template from `schemas` - # subfolder. - # - it is not required to fill the prefix but it is highly - # recommended as schemas and templates may have name clashes across - # multiple addons - # - it is also recommended that prefix has addon name in it schema_prefix = "kitsu" def get_settings_root_path(self): @@ -61,20 +47,15 @@ class AddonSettingsDef(JsonFilesSettingsDef): class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): - """This Addon has defined it's settings and interface. - - This example has system settings with an enabled option. And use - few other interfaces: - - `IPluginPaths` to define custom plugin paths - - `ITrayAction` to be shown in tray tool - """ + """Kitsu module class.""" label = "Kitsu" name = "kitsu" def initialize(self, settings): - """Initialization of addon.""" + """Initialization of module.""" module_settings = settings[self.name] + local_kitsu_settings = get_local_settings().get("kitsu", {}) # Enabled by settings self.enabled = module_settings.get("enabled", False) @@ -93,8 +74,8 @@ class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): self.server_url = kitsu_url # Set credentials - self.script_login = module_settings["script_login"] - self.script_pwd = module_settings["script_pwd"] + self.kitsu_login = local_kitsu_settings["login"] + self.kitsu_password = local_kitsu_settings["password"] # Prepare variables that can be used or set afterwards self._connected_modules = None @@ -113,8 +94,8 @@ class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): """Kitsu's global environments.""" return { "KITSU_SERVER": self.server_url, - "KITSU_LOGIN": self.script_login, - "KITSU_PWD": self.script_pwd, + "KITSU_LOGIN": self.kitsu_login, + "KITSU_PWD": self.kitsu_password, } def _create_dialog(self): @@ -122,9 +103,9 @@ class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): if self._dialog is not None: return - from .widgets import MyExampleDialog + from .kitsu_widgets import PasswordDialog - self._dialog = MyExampleDialog() + self._dialog = PasswordDialog() def show_dialog(self): """Show dialog with connected modules. @@ -376,7 +357,10 @@ def sync_zou(): @cli_main.command() -def sync_openpype(): +@click.option( + "-l", "--listen", is_flag=True, help="Listen Kitsu server after synchronization." +) +def sync_openpype(listen: bool): """Synchronize openpype database from Zou sever database.""" # Connect to server @@ -471,27 +455,23 @@ def sync_openpype(): dbcon.uninstall() + # Run listening + if listen: + start_listeners() + @cli_main.command() def listen(): - """Show ExampleAddon dialog. - - We don't have access to addon directly through cli so we have to create - it again. - """ - add_listeners() + """Listen to Kitsu server.""" + start_listeners() @cli_main.command() -def show_dialog(): - """Show ExampleAddon dialog. - - We don't have access to addon directly through cli so we have to create - it again. - """ +def sign_in(): + """Show credentials dialog.""" from openpype.tools.utils.lib import qt_app_context manager = ModulesManager() - example_addon = manager.modules_by_name[KitsuModule.name] + kitsu_addon = manager.modules_by_name[KitsuModule.name] with qt_app_context(): - example_addon.show_dialog() + kitsu_addon.show_dialog() diff --git a/openpype/modules/default_modules/kitsu/kitsu_widgets.py b/openpype/modules/default_modules/kitsu/kitsu_widgets.py new file mode 100644 index 0000000000..6bd436f460 --- /dev/null +++ b/openpype/modules/default_modules/kitsu/kitsu_widgets.py @@ -0,0 +1,193 @@ +import os + +import gazu +from Qt import QtWidgets, QtCore, QtGui + +from openpype import style +from openpype.resources import get_resource +from openpype.settings.lib import ( + get_local_settings, + get_system_settings, + save_local_settings, +) + +from openpype.widgets.password_dialog import PressHoverButton + + +class PasswordDialog(QtWidgets.QDialog): + """Stupidly simple dialog to compare password from general settings.""" + + finished = QtCore.Signal(bool) + + def __init__(self, parent=None): + super(PasswordDialog, self).__init__(parent) + + self.setWindowTitle("Kitsu Credentials") + self.resize(300, 120) + + system_settings = get_system_settings() + kitsu_settings = get_local_settings().get("kitsu", {}) + remembered = kitsu_settings.get("remember") + + self._final_result = None + self._connectable = bool( + system_settings["modules"].get("kitsu", {}).get("server") + ) + + # Server label + server_label = QtWidgets.QLabel( + f"Server: {system_settings['modules']['kitsu']['server'] if self._connectable else 'no server url set in Studio Settings...'}", + self, + ) + + # Login input + login_widget = QtWidgets.QWidget(self) + + login_label = QtWidgets.QLabel("Login:", login_widget) + + login_input = QtWidgets.QLineEdit( + login_widget, text=kitsu_settings.get("login") if remembered else None + ) + login_input.setPlaceholderText("Your Kitsu account login...") + + login_layout = QtWidgets.QHBoxLayout(login_widget) + login_layout.setContentsMargins(0, 0, 0, 0) + login_layout.addWidget(login_label) + login_layout.addWidget(login_input) + + # Password input + password_widget = QtWidgets.QWidget(self) + + password_label = QtWidgets.QLabel("Password:", password_widget) + + password_input = QtWidgets.QLineEdit( + password_widget, text=kitsu_settings.get("password") if remembered else None + ) + password_input.setPlaceholderText("Your password...") + password_input.setEchoMode(QtWidgets.QLineEdit.Password) + + show_password_icon_path = get_resource("icons", "eye.png") + show_password_icon = QtGui.QIcon(show_password_icon_path) + show_password_btn = PressHoverButton(password_widget) + show_password_btn.setObjectName("PasswordBtn") + show_password_btn.setIcon(show_password_icon) + show_password_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + + password_layout = QtWidgets.QHBoxLayout(password_widget) + password_layout.setContentsMargins(0, 0, 0, 0) + password_layout.addWidget(password_label) + password_layout.addWidget(password_input) + password_layout.addWidget(show_password_btn) + + # Message label + message_label = QtWidgets.QLabel("", self) + + # Buttons + buttons_widget = QtWidgets.QWidget(self) + + remember_checkbox = QtWidgets.QCheckBox("Remember", buttons_widget) + remember_checkbox.setObjectName("RememberCheckbox") + remember_checkbox.setChecked(remembered if remembered is not None else True) + + ok_btn = QtWidgets.QPushButton("Ok", buttons_widget) + cancel_btn = QtWidgets.QPushButton("Cancel", buttons_widget) + + buttons_layout = QtWidgets.QHBoxLayout(buttons_widget) + buttons_layout.setContentsMargins(0, 0, 0, 0) + buttons_layout.addWidget(remember_checkbox) + buttons_layout.addStretch(1) + buttons_layout.addWidget(ok_btn) + buttons_layout.addWidget(cancel_btn) + + # Main layout + layout = QtWidgets.QVBoxLayout(self) + layout.addSpacing(5) + layout.addWidget(server_label, 0) + layout.addSpacing(5) + layout.addWidget(login_widget, 0) + layout.addWidget(password_widget, 0) + layout.addWidget(message_label, 0) + layout.addStretch(1) + layout.addWidget(buttons_widget, 0) + + ok_btn.clicked.connect(self._on_ok_click) + cancel_btn.clicked.connect(self._on_cancel_click) + show_password_btn.change_state.connect(self._on_show_password) + + self.login_input = login_input + self.password_input = password_input + self.remember_checkbox = remember_checkbox + self.message_label = message_label + + self.setStyleSheet(style.load_stylesheet()) + + def result(self): + return self._final_result + + def keyPressEvent(self, event): + if event.key() in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter): + self._on_ok_click() + return event.accept() + super(PasswordDialog, self).keyPressEvent(event) + + def closeEvent(self, event): + super(PasswordDialog, self).closeEvent(event) + self.finished.emit(self.result()) + + def _on_ok_click(self): + # Check if is connectable + if not self._connectable: + self.message_label.setText("Please set server url in Studio Settings!") + return + + # Collect values + login_value = self.login_input.text() + pwd_value = self.password_input.text() + remember = self.remember_checkbox.isChecked() + + # Connect to server + gazu.client.set_host(os.environ["KITSU_SERVER"]) + + # Authenticate + gazu.log_in(login_value, pwd_value) + + # Set logging-in env vars + os.environ["KITSU_LOGIN"] = login_value + os.environ["KITSU_PWD"] = pwd_value + + # Get settings + local_settings = get_local_settings() + local_settings.setdefault("kitsu", {}) + + # Remember password cases + if remember: + # Set local settings + local_settings["kitsu"]["login"] = login_value + local_settings["kitsu"]["password"] = pwd_value + else: + # Clear local settings + local_settings["kitsu"]["login"] = None + local_settings["kitsu"]["password"] = None + + # Clear input fields + self.login_input.clear() + self.password_input.clear() + + # Keep 'remember' parameter + local_settings["kitsu"]["remember"] = remember + + # Save settings + save_local_settings(local_settings) + + self._final_result = True + self.close() + + def _on_show_password(self, show_password): + if show_password: + echo_mode = QtWidgets.QLineEdit.Normal + else: + echo_mode = QtWidgets.QLineEdit.Password + self.password_input.setEchoMode(echo_mode) + + def _on_cancel_click(self): + self.close() diff --git a/openpype/modules/default_modules/kitsu/plugins/publish/example_plugin.py b/openpype/modules/default_modules/kitsu/plugins/publish/kitsu_plugin.py similarity index 85% rename from openpype/modules/default_modules/kitsu/plugins/publish/example_plugin.py rename to openpype/modules/default_modules/kitsu/plugins/publish/kitsu_plugin.py index 614d9ecc38..86ba40a5f4 100644 --- a/openpype/modules/default_modules/kitsu/plugins/publish/example_plugin.py +++ b/openpype/modules/default_modules/kitsu/plugins/publish/kitsu_plugin.py @@ -4,15 +4,12 @@ import gazu import pyblish.api -import debugpy - class CollectExampleAddon(pyblish.api.ContextPlugin): order = pyblish.api.CollectorOrder + 0.4 label = "Collect Kitsu" def process(self, context): - debugpy.breakpoint() self.log.info("I'm in Kitsu's plugin!") @@ -23,7 +20,6 @@ class IntegrateRig(pyblish.api.InstancePlugin): families = ["model"] def process(self, instance): - print(instance.data["version"]) # Connect to server gazu.client.set_host(os.environ["KITSU_SERVER"]) @@ -33,8 +29,6 @@ class IntegrateRig(pyblish.api.InstancePlugin): asset_data = instance.data["assetEntity"]["data"] - # TODO Set local settings for login and password - # Get task task_type = gazu.task.get_task_type_by_name(instance.data["task"]) entity_task = gazu.task.get_task_by_entity(asset_data["zou"], task_type) @@ -46,4 +40,4 @@ class IntegrateRig(pyblish.api.InstancePlugin): comment=f"Version {instance.data['version']} has been published!", ) - self.log.info("Copied successfully!") + self.log.info("Version published to Kitsu successfully!") diff --git a/openpype/modules/default_modules/kitsu/settings/schemas/project_schemas/main.json b/openpype/modules/default_modules/kitsu/settings/schemas/project_schemas/main.json deleted file mode 100644 index 82e58ce9ab..0000000000 --- a/openpype/modules/default_modules/kitsu/settings/schemas/project_schemas/main.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "type": "dict", - "key": "kitsu", - "label": " Kitsu", - "collapsible": true, - "children": [ - { - "type": "number", - "key": "number", - "label": "This is your lucky number:", - "minimum": 7, - "maximum": 7, - "decimals": 0 - }, - { - "type": "template", - "name": "kitsu/the_template", - "template_data": [ - { - "name": "color_1", - "label": "Color 1" - }, - { - "name": "color_2", - "label": "Color 2" - } - ] - } - ] -} diff --git a/openpype/modules/default_modules/kitsu/settings/schemas/project_schemas/the_template.json b/openpype/modules/default_modules/kitsu/settings/schemas/project_schemas/the_template.json deleted file mode 100644 index af8fd9dae4..0000000000 --- a/openpype/modules/default_modules/kitsu/settings/schemas/project_schemas/the_template.json +++ /dev/null @@ -1,30 +0,0 @@ -[ - { - "type": "list-strict", - "key": "{name}", - "label": "{label}", - "object_types": [ - { - "label": "Red", - "type": "number", - "minimum": 0, - "maximum": 1, - "decimal": 3 - }, - { - "label": "Green", - "type": "number", - "minimum": 0, - "maximum": 1, - "decimal": 3 - }, - { - "label": "Blue", - "type": "number", - "minimum": 0, - "maximum": 1, - "decimal": 3 - } - ] - } -] diff --git a/openpype/modules/default_modules/kitsu/listeners.py b/openpype/modules/default_modules/kitsu/utils/listeners.py similarity index 99% rename from openpype/modules/default_modules/kitsu/listeners.py rename to openpype/modules/default_modules/kitsu/utils/listeners.py index 16c4e0e69e..c99870fa36 100644 --- a/openpype/modules/default_modules/kitsu/listeners.py +++ b/openpype/modules/default_modules/kitsu/utils/listeners.py @@ -2,7 +2,7 @@ import gazu import os from avalon.api import AvalonMongoDB -from openpype.modules.default_modules.kitsu.utils.openpype import ( +from .openpype import ( create_op_asset, set_op_project, sync_project, diff --git a/openpype/modules/default_modules/kitsu/widgets.py b/openpype/modules/default_modules/kitsu/widgets.py deleted file mode 100644 index de232113fe..0000000000 --- a/openpype/modules/default_modules/kitsu/widgets.py +++ /dev/null @@ -1,31 +0,0 @@ -from Qt import QtWidgets - -from openpype.style import load_stylesheet - - -class MyExampleDialog(QtWidgets.QDialog): - def __init__(self, parent=None): - super(MyExampleDialog, self).__init__(parent) - - self.setWindowTitle("Connected modules") - - msg = "This is example dialog of Kitsu." - label_widget = QtWidgets.QLabel(msg, self) - - ok_btn = QtWidgets.QPushButton("OK", self) - btns_layout = QtWidgets.QHBoxLayout() - btns_layout.addStretch(1) - btns_layout.addWidget(ok_btn) - - layout = QtWidgets.QVBoxLayout(self) - layout.addWidget(label_widget) - layout.addLayout(btns_layout) - - ok_btn.clicked.connect(self._on_ok_clicked) - - self._label_widget = label_widget - - self.setStyleSheet(load_stylesheet()) - - def _on_ok_clicked(self): - self.done(1) diff --git a/openpype/settings/defaults/system_settings/modules.json b/openpype/settings/defaults/system_settings/modules.json index ddb2edc360..537e287366 100644 --- a/openpype/settings/defaults/system_settings/modules.json +++ b/openpype/settings/defaults/system_settings/modules.json @@ -139,9 +139,7 @@ }, "kitsu": { "enabled": false, - "server": "", - "script_login": "", - "script_pwd": "" + "server": "" }, "timers_manager": { "enabled": true, diff --git a/openpype/settings/entities/schemas/system_schema/module_settings/schema_kitsu.json b/openpype/settings/entities/schemas/system_schema/module_settings/schema_kitsu.json index ae2b52df0d..15a2ccc58d 100644 --- a/openpype/settings/entities/schemas/system_schema/module_settings/schema_kitsu.json +++ b/openpype/settings/entities/schemas/system_schema/module_settings/schema_kitsu.json @@ -16,16 +16,6 @@ "key": "server", "label": "Server" }, - { - "type": "text", - "key": "script_login", - "label": "Script Login" - }, - { - "type": "text", - "key": "script_pwd", - "label": "Script Password" - }, { "type": "splitter" } diff --git a/pyproject.toml b/pyproject.toml index f32e385e80..93caa5ca70 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,6 +40,7 @@ clique = "1.6.*" Click = "^7" dnspython = "^2.1.0" ftrack-python-api = "2.0.*" +gazu = "^0.8" google-api-python-client = "^1.12.8" # sync server google support (should be separate?) jsonschema = "^2.6.0" keyring = "^22.0.1" @@ -64,7 +65,7 @@ jinxed = [ python3-xlib = { version="*", markers = "sys_platform == 'linux'"} enlighten = "^1.9.0" slack-sdk = "^3.6.0" -requests = "2.25.1" +requests = "^2.25.1" pysftp = "^0.2.9" dropbox = "^11.20.0" From 6b3987708711e72d984b39096efec9a0421ffd0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Tue, 1 Mar 2022 18:11:42 +0100 Subject: [PATCH 048/350] Moved to modules --- openpype/modules/{default_modules => }/kitsu/__init__.py | 0 openpype/modules/{default_modules => }/kitsu/kitsu_module.py | 2 +- openpype/modules/{default_modules => }/kitsu/kitsu_widgets.py | 0 .../kitsu/plugins/publish/kitsu_plugin.py | 0 openpype/modules/{default_modules => }/kitsu/utils/__init__.py | 0 .../modules/{default_modules => }/kitsu/utils/listeners.py | 3 ++- openpype/modules/{default_modules => }/kitsu/utils/openpype.py | 0 7 files changed, 3 insertions(+), 2 deletions(-) rename openpype/modules/{default_modules => }/kitsu/__init__.py (100%) rename openpype/modules/{default_modules => }/kitsu/kitsu_module.py (99%) rename openpype/modules/{default_modules => }/kitsu/kitsu_widgets.py (100%) rename openpype/modules/{default_modules => }/kitsu/plugins/publish/kitsu_plugin.py (100%) rename openpype/modules/{default_modules => }/kitsu/utils/__init__.py (100%) rename openpype/modules/{default_modules => }/kitsu/utils/listeners.py (99%) rename openpype/modules/{default_modules => }/kitsu/utils/openpype.py (100%) diff --git a/openpype/modules/default_modules/kitsu/__init__.py b/openpype/modules/kitsu/__init__.py similarity index 100% rename from openpype/modules/default_modules/kitsu/__init__.py rename to openpype/modules/kitsu/__init__.py diff --git a/openpype/modules/default_modules/kitsu/kitsu_module.py b/openpype/modules/kitsu/kitsu_module.py similarity index 99% rename from openpype/modules/default_modules/kitsu/kitsu_module.py rename to openpype/modules/kitsu/kitsu_module.py index 51ab8aaa42..a17b509047 100644 --- a/openpype/modules/default_modules/kitsu/kitsu_module.py +++ b/openpype/modules/kitsu/kitsu_module.py @@ -24,7 +24,7 @@ from pymongo import DeleteOne, UpdateOne from avalon.api import AvalonMongoDB from openpype.api import get_project_settings from openpype.modules import JsonFilesSettingsDef, OpenPypeModule, ModulesManager -from openpype.modules.default_modules.kitsu.utils.openpype import ( +from openpype.modules.kitsu.utils.openpype import ( create_op_asset, sync_project, update_op_assets, diff --git a/openpype/modules/default_modules/kitsu/kitsu_widgets.py b/openpype/modules/kitsu/kitsu_widgets.py similarity index 100% rename from openpype/modules/default_modules/kitsu/kitsu_widgets.py rename to openpype/modules/kitsu/kitsu_widgets.py diff --git a/openpype/modules/default_modules/kitsu/plugins/publish/kitsu_plugin.py b/openpype/modules/kitsu/plugins/publish/kitsu_plugin.py similarity index 100% rename from openpype/modules/default_modules/kitsu/plugins/publish/kitsu_plugin.py rename to openpype/modules/kitsu/plugins/publish/kitsu_plugin.py diff --git a/openpype/modules/default_modules/kitsu/utils/__init__.py b/openpype/modules/kitsu/utils/__init__.py similarity index 100% rename from openpype/modules/default_modules/kitsu/utils/__init__.py rename to openpype/modules/kitsu/utils/__init__.py diff --git a/openpype/modules/default_modules/kitsu/utils/listeners.py b/openpype/modules/kitsu/utils/listeners.py similarity index 99% rename from openpype/modules/default_modules/kitsu/utils/listeners.py rename to openpype/modules/kitsu/utils/listeners.py index c99870fa36..961aa1691b 100644 --- a/openpype/modules/default_modules/kitsu/utils/listeners.py +++ b/openpype/modules/kitsu/utils/listeners.py @@ -10,7 +10,8 @@ from .openpype import ( ) -def add_listeners(): +def start_listeners(): + """Start listeners to keep OpenPype up-to-date with Kitsu.""" # Connect to server gazu.client.set_host(os.environ["KITSU_SERVER"]) diff --git a/openpype/modules/default_modules/kitsu/utils/openpype.py b/openpype/modules/kitsu/utils/openpype.py similarity index 100% rename from openpype/modules/default_modules/kitsu/utils/openpype.py rename to openpype/modules/kitsu/utils/openpype.py From a33b3d3b5cdfa37204da8570d175997be3544001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 2 Mar 2022 09:30:33 +0100 Subject: [PATCH 049/350] Remove AddonSettingsDef --- openpype/modules/kitsu/__init__.py | 4 ++-- openpype/modules/kitsu/kitsu_module.py | 12 ------------ 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/openpype/modules/kitsu/__init__.py b/openpype/modules/kitsu/__init__.py index dc7c2dad50..6cb62bbb15 100644 --- a/openpype/modules/kitsu/__init__.py +++ b/openpype/modules/kitsu/__init__.py @@ -4,6 +4,6 @@ If addon class or settings definition won't be here their definition won't be found by OpenPype discovery. """ -from .kitsu_module import AddonSettingsDef, KitsuModule +from .kitsu_module import KitsuModule -__all__ = ("AddonSettingsDef", "KitsuModule") +__all__ = "KitsuModule" diff --git a/openpype/modules/kitsu/kitsu_module.py b/openpype/modules/kitsu/kitsu_module.py index a17b509047..9efcac9714 100644 --- a/openpype/modules/kitsu/kitsu_module.py +++ b/openpype/modules/kitsu/kitsu_module.py @@ -34,18 +34,6 @@ from openpype_interfaces import IPluginPaths, ITrayAction from .utils.listeners import start_listeners -class AddonSettingsDef(JsonFilesSettingsDef): - schema_prefix = "kitsu" - - def get_settings_root_path(self): - """Implemented abstract class of JsonFilesSettingsDef. - - Return directory path where json files defying addon settings are - located. - """ - return os.path.join(os.path.dirname(os.path.abspath(__file__)), "settings") - - class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): """Kitsu module class.""" From 4907ce1362602efef2692253d9b93fbc79d2e522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 2 Mar 2022 09:31:02 +0100 Subject: [PATCH 050/350] Moved up module 'base' changes --- openpype/modules/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/modules/base.py b/openpype/modules/base.py index 0dd512ee8b..d77189be6c 100644 --- a/openpype/modules/base.py +++ b/openpype/modules/base.py @@ -860,6 +860,7 @@ class TrayModulesManager(ModulesManager): modules_menu_order = ( "user", "ftrack", + "kitsu", "muster", "launcher_tool", "avalon", From a15c4d2895a5eaf433ec9d3912200a271cac16a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 2 Mar 2022 09:48:39 +0100 Subject: [PATCH 051/350] import gazu only at start --- openpype/modules/kitsu/kitsu_module.py | 63 ++++++++++------------- openpype/modules/kitsu/utils/listeners.py | 3 +- openpype/modules/kitsu/utils/openpype.py | 13 ++--- 3 files changed, 35 insertions(+), 44 deletions(-) diff --git a/openpype/modules/kitsu/kitsu_module.py b/openpype/modules/kitsu/kitsu_module.py index 9efcac9714..502ed8ff96 100644 --- a/openpype/modules/kitsu/kitsu_module.py +++ b/openpype/modules/kitsu/kitsu_module.py @@ -4,34 +4,19 @@ import click import os import re -import gazu -from gazu.asset import all_assets_for_project, all_asset_types, new_asset -from gazu.shot import ( - all_episodes_for_project, - all_sequences_for_project, - all_shots_for_project, - new_episode, - new_sequence, - new_shot, -) -from gazu.task import ( - all_task_types, - new_task, - new_task_type, -) from pymongo import DeleteOne, UpdateOne from avalon.api import AvalonMongoDB from openpype.api import get_project_settings -from openpype.modules import JsonFilesSettingsDef, OpenPypeModule, ModulesManager -from openpype.modules.kitsu.utils.openpype import ( +from openpype.modules import OpenPypeModule, ModulesManager +from openpype.settings.lib import get_local_settings +from openpype_interfaces import IPluginPaths, ITrayAction +from .utils.listeners import start_listeners +from .utils.openpype import ( create_op_asset, sync_project, update_op_assets, ) -from openpype.settings.lib import get_local_settings -from openpype_interfaces import IPluginPaths, ITrayAction -from .utils.listeners import start_listeners class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): @@ -137,6 +122,7 @@ def cli_main(): @cli_main.command() def sync_zou(): """Synchronize Zou server database (Kitsu backend) with openpype database.""" + import gazu # Connect to server gazu.client.set_host(os.environ["KITSU_SERVER"]) @@ -178,11 +164,11 @@ def sync_zou(): gazu.project.update_project_data(zou_project, data=op_project["data"]) gazu.project.update_project(zou_project) - asset_types = all_asset_types() - all_assets = all_assets_for_project(zou_project) - all_episodes = all_episodes_for_project(zou_project) - all_seqs = all_sequences_for_project(zou_project) - all_shots = all_shots_for_project(zou_project) + asset_types = gazu.asset.all_asset_types() + all_assets = gazu.asset.all_assets_for_project(zou_project) + all_episodes = gazu.shot.all_episodes_for_project(zou_project) + all_seqs = gazu.shot.all_sequences_for_project(zou_project) + all_shots = gazu.shot.all_shots_for_project(zou_project) all_entities_ids = { e["id"] for e in all_episodes + all_seqs + all_shots + all_assets } @@ -217,7 +203,9 @@ def sync_zou(): # Match asset type by it's name match = regex_ep.match(doc["name"]) if not match: # Asset - new_entity = new_asset(zou_project, asset_types[0], doc["name"]) + new_entity = gazu.asset.new_asset( + zou_project, asset_types[0], doc["name"] + ) # Match case in shot Collection: :param dbcon: Connection to DB. :param project_id: Project zou ID """ + import gazu + project = gazu.project.get_project(project_id) project_name = project["name"] dbcon.Session["AVALON_PROJECT"] = project_name @@ -49,6 +45,11 @@ def update_op_assets( :param asset_doc_ids: Dicts of [{zou_id: asset_doc}, ...] :return: List of (doc_id, update_dict) tuples """ + from gazu.task import ( + all_tasks_for_asset, + all_tasks_for_shot, + ) + assets_with_update = [] for item in entities_list: # Update asset From 44100b0da7d30bc34af0635b5e577e2a6df03c01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 2 Mar 2022 09:52:26 +0100 Subject: [PATCH 052/350] line length to 79 --- openpype/modules/kitsu/kitsu_module.py | 33 ++++++++++++++----- openpype/modules/kitsu/kitsu_widgets.py | 14 +++++--- .../kitsu/plugins/publish/kitsu_plugin.py | 4 ++- openpype/modules/kitsu/utils/listeners.py | 29 +++++++++++----- openpype/modules/kitsu/utils/openpype.py | 7 ++-- 5 files changed, 63 insertions(+), 24 deletions(-) diff --git a/openpype/modules/kitsu/kitsu_module.py b/openpype/modules/kitsu/kitsu_module.py index 502ed8ff96..a7b3b17eb5 100644 --- a/openpype/modules/kitsu/kitsu_module.py +++ b/openpype/modules/kitsu/kitsu_module.py @@ -42,7 +42,9 @@ class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): # Check for "/api" url validity if not kitsu_url.endswith("api"): - kitsu_url = f"{kitsu_url}{'' if kitsu_url.endswith('/') else '/'}api" + kitsu_url = ( + f"{kitsu_url}{'' if kitsu_url.endswith('/') else '/'}api" + ) self.server_url = kitsu_url @@ -161,7 +163,9 @@ def sync_zou(): "resolution": f"{op_project['data']['resolutionWidth']}x{op_project['data']['resolutionHeight']}", } ) - gazu.project.update_project_data(zou_project, data=op_project["data"]) + gazu.project.update_project_data( + zou_project, data=op_project["data"] + ) gazu.project.update_project(zou_project) asset_types = gazu.asset.all_asset_types() @@ -227,7 +231,9 @@ def sync_zou(): # Create new sequence and set it as substitute created_sequence = gazu.shot.new_sequence( - zou_project, substitute_sequence_name, episode=zou_parent_id + zou_project, + substitute_sequence_name, + episode=zou_parent_id, ) gazu.shot.update_sequence_data( created_sequence, {"is_substitute": True} @@ -244,13 +250,16 @@ def sync_zou(): doc["name"], frame_in=doc["data"]["frameStart"], frame_out=doc["data"]["frameEnd"], - nb_frames=doc["data"]["frameEnd"] - doc["data"]["frameStart"], + nb_frames=doc["data"]["frameEnd"] + - doc["data"]["frameStart"], ) elif match.group(2): # Sequence parent_doc = asset_docs[visual_parent_id] new_entity = gazu.shot.new_sequence( - zou_project, doc["name"], episode=parent_doc["data"]["zou"]["id"] + zou_project, + doc["name"], + episode=parent_doc["data"]["zou"]["id"], ) elif match.group(3): # Episode @@ -293,7 +302,10 @@ def sync_zou(): if frame_in or frame_out: entity_data.update( { - "data": {"frame_in": frame_in, "frame_out": frame_out}, + "data": { + "frame_in": frame_in, + "frame_out": frame_out, + }, "nb_frames": frame_out - frame_in, } ) @@ -334,7 +346,10 @@ def sync_zou(): @cli_main.command() @click.option( - "-l", "--listen", is_flag=True, help="Listen Kitsu server after synchronization." + "-l", + "--listen", + is_flag=True, + help="Listen Kitsu server after synchronization.", ) def sync_openpype(listen: bool): """Synchronize openpype database from Zou sever database.""" @@ -410,7 +425,9 @@ def sync_openpype(listen: bool): bulk_writes.extend( [ UpdateOne({"_id": id}, update) - for id, update in update_op_assets(all_entities, zou_ids_and_asset_docs) + for id, update in update_op_assets( + all_entities, zou_ids_and_asset_docs + ) ] ) diff --git a/openpype/modules/kitsu/kitsu_widgets.py b/openpype/modules/kitsu/kitsu_widgets.py index 6bd436f460..1a32182795 100644 --- a/openpype/modules/kitsu/kitsu_widgets.py +++ b/openpype/modules/kitsu/kitsu_widgets.py @@ -46,7 +46,8 @@ class PasswordDialog(QtWidgets.QDialog): login_label = QtWidgets.QLabel("Login:", login_widget) login_input = QtWidgets.QLineEdit( - login_widget, text=kitsu_settings.get("login") if remembered else None + login_widget, + text=kitsu_settings.get("login") if remembered else None, ) login_input.setPlaceholderText("Your Kitsu account login...") @@ -61,7 +62,8 @@ class PasswordDialog(QtWidgets.QDialog): password_label = QtWidgets.QLabel("Password:", password_widget) password_input = QtWidgets.QLineEdit( - password_widget, text=kitsu_settings.get("password") if remembered else None + password_widget, + text=kitsu_settings.get("password") if remembered else None, ) password_input.setPlaceholderText("Your password...") password_input.setEchoMode(QtWidgets.QLineEdit.Password) @@ -87,7 +89,9 @@ class PasswordDialog(QtWidgets.QDialog): remember_checkbox = QtWidgets.QCheckBox("Remember", buttons_widget) remember_checkbox.setObjectName("RememberCheckbox") - remember_checkbox.setChecked(remembered if remembered is not None else True) + remember_checkbox.setChecked( + remembered if remembered is not None else True + ) ok_btn = QtWidgets.QPushButton("Ok", buttons_widget) cancel_btn = QtWidgets.QPushButton("Cancel", buttons_widget) @@ -137,7 +141,9 @@ class PasswordDialog(QtWidgets.QDialog): def _on_ok_click(self): # Check if is connectable if not self._connectable: - self.message_label.setText("Please set server url in Studio Settings!") + self.message_label.setText( + "Please set server url in Studio Settings!" + ) return # Collect values diff --git a/openpype/modules/kitsu/plugins/publish/kitsu_plugin.py b/openpype/modules/kitsu/plugins/publish/kitsu_plugin.py index 86ba40a5f4..24f1e4e80c 100644 --- a/openpype/modules/kitsu/plugins/publish/kitsu_plugin.py +++ b/openpype/modules/kitsu/plugins/publish/kitsu_plugin.py @@ -31,7 +31,9 @@ class IntegrateRig(pyblish.api.InstancePlugin): # Get task task_type = gazu.task.get_task_type_by_name(instance.data["task"]) - entity_task = gazu.task.get_task_by_entity(asset_data["zou"], task_type) + entity_task = gazu.task.get_task_by_entity( + asset_data["zou"], task_type + ) # Comment entity gazu.task.add_comment( diff --git a/openpype/modules/kitsu/utils/listeners.py b/openpype/modules/kitsu/utils/listeners.py index 18f67b13e3..3768b4e8e6 100644 --- a/openpype/modules/kitsu/utils/listeners.py +++ b/openpype/modules/kitsu/utils/listeners.py @@ -95,9 +95,9 @@ def start_listeners(): zou_ids_and_asset_docs[asset["project_id"]] = project_doc # Update - asset_doc_id, asset_update = update_op_assets([asset], zou_ids_and_asset_docs)[ - 0 - ] + asset_doc_id, asset_update = update_op_assets( + [asset], zou_ids_and_asset_docs + )[0] project_col.update_one({"_id": asset_doc_id}, asset_update) def delete_asset(data): @@ -105,7 +105,9 @@ def start_listeners(): project_col = set_op_project(dbcon, data["project_id"]) # Delete - project_col.delete_one({"type": "asset", "data.zou.id": data["asset_id"]}) + project_col.delete_one( + {"type": "asset", "data.zou.id": data["asset_id"]} + ) gazu.events.add_listener(event_client, "asset:new", new_asset) gazu.events.add_listener(event_client, "asset:update", update_asset) @@ -155,7 +157,9 @@ def start_listeners(): print("delete episode") # TODO check bugfix # Delete - project_col.delete_one({"type": "asset", "data.zou.id": data["episode_id"]}) + project_col.delete_one( + {"type": "asset", "data.zou.id": data["episode_id"]} + ) gazu.events.add_listener(event_client, "episode:new", new_episode) gazu.events.add_listener(event_client, "episode:update", update_episode) @@ -205,7 +209,9 @@ def start_listeners(): print("delete sequence") # TODO check bugfix # Delete - project_col.delete_one({"type": "asset", "data.zou.id": data["sequence_id"]}) + project_col.delete_one( + {"type": "asset", "data.zou.id": data["sequence_id"]} + ) gazu.events.add_listener(event_client, "sequence:new", new_sequence) gazu.events.add_listener(event_client, "sequence:update", update_sequence) @@ -244,7 +250,9 @@ def start_listeners(): zou_ids_and_asset_docs[shot["project_id"]] = project_doc # Update - asset_doc_id, asset_update = update_op_assets([shot], zou_ids_and_asset_docs)[0] + asset_doc_id, asset_update = update_op_assets( + [shot], zou_ids_and_asset_docs + )[0] project_col.update_one({"_id": asset_doc_id}, asset_update) def delete_shot(data): @@ -252,7 +260,9 @@ def start_listeners(): project_col = set_op_project(dbcon, data["project_id"]) # Delete - project_col.delete_one({"type": "asset", "data.zou.id": data["shot_id"]}) + project_col.delete_one( + {"type": "asset", "data.zou.id": data["shot_id"]} + ) gazu.events.add_listener(event_client, "shot:new", new_shot) gazu.events.add_listener(event_client, "shot:update", update_shot) @@ -302,7 +312,8 @@ def start_listeners(): # Delete task in DB project_col.update_one( - {"_id": doc["_id"]}, {"$set": {"data.tasks": asset_tasks}} + {"_id": doc["_id"]}, + {"$set": {"data.tasks": asset_tasks}}, ) return diff --git a/openpype/modules/kitsu/utils/openpype.py b/openpype/modules/kitsu/utils/openpype.py index 2443323893..8aabba6de0 100644 --- a/openpype/modules/kitsu/utils/openpype.py +++ b/openpype/modules/kitsu/utils/openpype.py @@ -65,7 +65,8 @@ def update_op_assets( tasks_list = all_tasks_for_shot(item) # TODO frame in and out item_data["tasks"] = { - t["task_type_name"]: {"type": t["task_type_name"]} for t in tasks_list + t["task_type_name"]: {"type": t["task_type_name"]} + for t in tasks_list } # Get zou parent id for correct hierarchy @@ -79,7 +80,9 @@ def update_op_assets( parent_zou_id = substitute_parent_item["parent_id"] else: parent_zou_id = ( - item.get("parent_id") or item.get("episode_id") or item.get("source_id") + item.get("parent_id") + or item.get("episode_id") + or item.get("source_id") ) # TODO check consistency # Visual parent for hierarchy From c26c2f09a8f271419e76cd7407f35b19d579d851 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 2 Mar 2022 09:54:47 +0100 Subject: [PATCH 053/350] fix import --- openpype/modules/kitsu/utils/openpype.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/modules/kitsu/utils/openpype.py b/openpype/modules/kitsu/utils/openpype.py index 8aabba6de0..56c99effff 100644 --- a/openpype/modules/kitsu/utils/openpype.py +++ b/openpype/modules/kitsu/utils/openpype.py @@ -132,6 +132,8 @@ def sync_project(project: dict, dbcon: AvalonMongoDB) -> UpdateOne: :param dbcon: DB to create project in :return: Update instance for the project """ + import gazu + project_name = project["name"] project_doc = dbcon.find_one({"type": "project"}) if not project_doc: From e8831947e6c2de902470e0fffdb69cad6429ce32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 2 Mar 2022 09:57:00 +0100 Subject: [PATCH 054/350] Fix __all__ --- openpype/modules/kitsu/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/kitsu/__init__.py b/openpype/modules/kitsu/__init__.py index 6cb62bbb15..9737a054f6 100644 --- a/openpype/modules/kitsu/__init__.py +++ b/openpype/modules/kitsu/__init__.py @@ -6,4 +6,4 @@ be found by OpenPype discovery. from .kitsu_module import KitsuModule -__all__ = "KitsuModule" +__all__ = ("KitsuModule", ) From cde925c09b06130f6b4e1f36d993d21aba0fd7bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 2 Mar 2022 11:38:47 +0100 Subject: [PATCH 055/350] Use OpenPypeSecureRegistry for authentication --- openpype/modules/kitsu/__init__.py | 2 +- openpype/modules/kitsu/kitsu_module.py | 22 ++++++++++++++--- openpype/modules/kitsu/kitsu_widgets.py | 33 +++++++++++-------------- 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/openpype/modules/kitsu/__init__.py b/openpype/modules/kitsu/__init__.py index 9737a054f6..9220cb1762 100644 --- a/openpype/modules/kitsu/__init__.py +++ b/openpype/modules/kitsu/__init__.py @@ -6,4 +6,4 @@ be found by OpenPype discovery. from .kitsu_module import KitsuModule -__all__ = ("KitsuModule", ) +__all__ = ("KitsuModule",) diff --git a/openpype/modules/kitsu/kitsu_module.py b/openpype/modules/kitsu/kitsu_module.py index a7b3b17eb5..ebfa0dbeea 100644 --- a/openpype/modules/kitsu/kitsu_module.py +++ b/openpype/modules/kitsu/kitsu_module.py @@ -8,6 +8,7 @@ from pymongo import DeleteOne, UpdateOne from avalon.api import AvalonMongoDB from openpype.api import get_project_settings +from openpype.lib.local_settings import OpenPypeSecureRegistry from openpype.modules import OpenPypeModule, ModulesManager from openpype.settings.lib import get_local_settings from openpype_interfaces import IPluginPaths, ITrayAction @@ -28,7 +29,9 @@ class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): def initialize(self, settings): """Initialization of module.""" module_settings = settings[self.name] - local_kitsu_settings = get_local_settings().get("kitsu", {}) + + # Get user registry + user_registry = OpenPypeSecureRegistry("kitsu_user") # Enabled by settings self.enabled = module_settings.get("enabled", False) @@ -49,8 +52,8 @@ class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): self.server_url = kitsu_url # Set credentials - self.kitsu_login = local_kitsu_settings["login"] - self.kitsu_password = local_kitsu_settings["password"] + self.kitsu_login = user_registry.get_item("login", None) + self.kitsu_password = user_registry.get_item("password", None) # Prepare variables that can be used or set afterwards self._connected_modules = None @@ -359,7 +362,13 @@ def sync_openpype(listen: bool): gazu.client.set_host(os.environ["KITSU_SERVER"]) # Authenticate - gazu.log_in(os.environ["KITSU_LOGIN"], os.environ["KITSU_PWD"]) + kitsu_login = os.environ.get("KITSU_LOGIN") + kitsu_pwd = os.environ.get("KITSU_PWD") + if not kitsu_login or not kitsu_pwd: # Sentinel to log-in + log_in_dialog() + return + + gazu.log_in(kitsu_login, kitsu_pwd) # Iterate projects dbcon = AvalonMongoDB() @@ -462,6 +471,11 @@ def listen(): @cli_main.command() def sign_in(): + """Sign-in command.""" + log_in_dialog() + + +def log_in_dialog(): """Show credentials dialog.""" from openpype.tools.utils.lib import qt_app_context diff --git a/openpype/modules/kitsu/kitsu_widgets.py b/openpype/modules/kitsu/kitsu_widgets.py index 1a32182795..1a48e6dbc0 100644 --- a/openpype/modules/kitsu/kitsu_widgets.py +++ b/openpype/modules/kitsu/kitsu_widgets.py @@ -4,11 +4,10 @@ import gazu from Qt import QtWidgets, QtCore, QtGui from openpype import style +from openpype.lib.local_settings import OpenPypeSecureRegistry from openpype.resources import get_resource from openpype.settings.lib import ( - get_local_settings, get_system_settings, - save_local_settings, ) from openpype.widgets.password_dialog import PressHoverButton @@ -26,8 +25,11 @@ class PasswordDialog(QtWidgets.QDialog): self.resize(300, 120) system_settings = get_system_settings() - kitsu_settings = get_local_settings().get("kitsu", {}) - remembered = kitsu_settings.get("remember") + user_registry = OpenPypeSecureRegistry("kitsu_user") + remembered = bool( + user_registry.get_item("login", None) + or user_registry.get_item("password", None) + ) self._final_result = None self._connectable = bool( @@ -47,7 +49,7 @@ class PasswordDialog(QtWidgets.QDialog): login_input = QtWidgets.QLineEdit( login_widget, - text=kitsu_settings.get("login") if remembered else None, + text=user_registry.get_item("login") if remembered else None, ) login_input.setPlaceholderText("Your Kitsu account login...") @@ -63,7 +65,7 @@ class PasswordDialog(QtWidgets.QDialog): password_input = QtWidgets.QLineEdit( password_widget, - text=kitsu_settings.get("password") if remembered else None, + text=user_registry.get_item("password") if remembered else None, ) password_input.setPlaceholderText("Your password...") password_input.setEchoMode(QtWidgets.QLineEdit.Password) @@ -161,30 +163,23 @@ class PasswordDialog(QtWidgets.QDialog): os.environ["KITSU_LOGIN"] = login_value os.environ["KITSU_PWD"] = pwd_value - # Get settings - local_settings = get_local_settings() - local_settings.setdefault("kitsu", {}) + # Get user registry + user_registry = OpenPypeSecureRegistry("kitsu_user") # Remember password cases if remember: # Set local settings - local_settings["kitsu"]["login"] = login_value - local_settings["kitsu"]["password"] = pwd_value + user_registry.set_item("login", login_value) + user_registry.set_item("password", pwd_value) else: # Clear local settings - local_settings["kitsu"]["login"] = None - local_settings["kitsu"]["password"] = None + user_registry.delete_item("login") + user_registry.delete_item("password") # Clear input fields self.login_input.clear() self.password_input.clear() - # Keep 'remember' parameter - local_settings["kitsu"]["remember"] = remember - - # Save settings - save_local_settings(local_settings) - self._final_result = True self.close() From c9ea0b3bb262484b43ebd5c1c5d649dcdaf75d7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 2 Mar 2022 11:49:49 +0100 Subject: [PATCH 056/350] Line length max 79 --- openpype/modules/kitsu/kitsu_module.py | 28 +++++++++++++++++-------- openpype/modules/kitsu/kitsu_widgets.py | 7 ++++++- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/openpype/modules/kitsu/kitsu_module.py b/openpype/modules/kitsu/kitsu_module.py index ebfa0dbeea..6a2e517832 100644 --- a/openpype/modules/kitsu/kitsu_module.py +++ b/openpype/modules/kitsu/kitsu_module.py @@ -10,7 +10,6 @@ from avalon.api import AvalonMongoDB from openpype.api import get_project_settings from openpype.lib.local_settings import OpenPypeSecureRegistry from openpype.modules import OpenPypeModule, ModulesManager -from openpype.settings.lib import get_local_settings from openpype_interfaces import IPluginPaths, ITrayAction from .utils.listeners import start_listeners from .utils.openpype import ( @@ -126,7 +125,7 @@ def cli_main(): @cli_main.command() def sync_zou(): - """Synchronize Zou server database (Kitsu backend) with openpype database.""" + """Synchronize Zou database (Kitsu backend) with openpype database.""" import gazu # Connect to server @@ -154,7 +153,9 @@ def sync_zou(): # Create project if zou_project is None: raise RuntimeError( - f"Project '{project_name}' doesn't exist in Zou database, please create it in Kitsu and add OpenPype user to it before running synchronization." + f"Project '{project_name}' doesn't exist in Zou database, " + "please create it in Kitsu and add OpenPype user to it before " + "running synchronization." ) # Update project settings and data @@ -163,7 +164,8 @@ def sync_zou(): { "code": op_project["data"]["code"], "fps": op_project["data"]["fps"], - "resolution": f"{op_project['data']['resolutionWidth']}x{op_project['data']['resolutionHeight']}", + "resolution": f"{op_project['data']['resolutionWidth']}" + f"x{op_project['data']['resolutionHeight']}", } ) gazu.project.update_project_data( @@ -213,7 +215,8 @@ def sync_zou(): new_entity = gazu.asset.new_asset( zou_project, asset_types[0], doc["name"] ) - # Match case in shot Date: Wed, 2 Mar 2022 12:11:05 +0100 Subject: [PATCH 057/350] Rename module to Kitsu Connect --- openpype/modules/kitsu/kitsu_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/kitsu/kitsu_module.py b/openpype/modules/kitsu/kitsu_module.py index 6a2e517832..d5e744ceb5 100644 --- a/openpype/modules/kitsu/kitsu_module.py +++ b/openpype/modules/kitsu/kitsu_module.py @@ -22,7 +22,7 @@ from .utils.openpype import ( class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): """Kitsu module class.""" - label = "Kitsu" + label = "Kitsu Connect" name = "kitsu" def initialize(self, settings): From c39bdee4330b1578cfe821d0506dbc7b59373621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Thu, 3 Mar 2022 15:50:35 +0100 Subject: [PATCH 058/350] Refactor for login system following recommendations. --- openpype/modules/kitsu/kitsu_module.py | 457 ++---------------- openpype/modules/kitsu/kitsu_widgets.py | 59 +-- .../kitsu/plugins/publish/kitsu_plugin.py | 2 +- openpype/modules/kitsu/utils/credentials.py | 92 ++++ .../utils/{listeners.py => sync_service.py} | 238 +++++---- .../{openpype.py => update_op_with_zou.py} | 153 +++++- .../modules/kitsu/utils/update_zou_with_op.py | 262 ++++++++++ 7 files changed, 717 insertions(+), 546 deletions(-) create mode 100644 openpype/modules/kitsu/utils/credentials.py rename openpype/modules/kitsu/utils/{listeners.py => sync_service.py} (54%) rename openpype/modules/kitsu/utils/{openpype.py => update_op_with_zou.py} (52%) create mode 100644 openpype/modules/kitsu/utils/update_zou_with_op.py diff --git a/openpype/modules/kitsu/kitsu_module.py b/openpype/modules/kitsu/kitsu_module.py index d5e744ceb5..dca6133e88 100644 --- a/openpype/modules/kitsu/kitsu_module.py +++ b/openpype/modules/kitsu/kitsu_module.py @@ -2,21 +2,9 @@ import click import os -import re -from pymongo import DeleteOne, UpdateOne - -from avalon.api import AvalonMongoDB -from openpype.api import get_project_settings -from openpype.lib.local_settings import OpenPypeSecureRegistry -from openpype.modules import OpenPypeModule, ModulesManager +from openpype.modules import OpenPypeModule from openpype_interfaces import IPluginPaths, ITrayAction -from .utils.listeners import start_listeners -from .utils.openpype import ( - create_op_asset, - sync_project, - update_op_assets, -) class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): @@ -29,9 +17,6 @@ class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): """Initialization of module.""" module_settings = settings[self.name] - # Get user registry - user_registry = OpenPypeSecureRegistry("kitsu_user") - # Enabled by settings self.enabled = module_settings.get("enabled", False) @@ -44,66 +29,58 @@ class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): # Check for "/api" url validity if not kitsu_url.endswith("api"): - kitsu_url = ( - f"{kitsu_url}{'' if kitsu_url.endswith('/') else '/'}api" + kitsu_url = "{}{}api".format( + kitsu_url, "" if kitsu_url.endswith("/") else "/" ) self.server_url = kitsu_url - # Set credentials - self.kitsu_login = user_registry.get_item("login", None) - self.kitsu_password = user_registry.get_item("password", None) - - # Prepare variables that can be used or set afterwards - self._connected_modules = None # UI which must not be created at this time self._dialog = None def tray_init(self): - """Implementation of abstract method for `ITrayAction`. - - We're definitely in tray tool so we can pre create dialog. - """ + """Tray init.""" self._create_dialog() + def tray_start(self): + """Tray start.""" + from .utils.credentials import ( + load_credentials, + validate_credentials, + set_credentials_envs, + ) + + username, password = load_credentials() + + # Check credentials, ask them if needed + if validate_credentials(username, password): + set_credentials_envs(username, password) + else: + self.show_dialog() + def get_global_environments(self): """Kitsu's global environments.""" - return { - "KITSU_SERVER": self.server_url, - "KITSU_LOGIN": self.kitsu_login, - "KITSU_PWD": self.kitsu_password, - } + return {"KITSU_SERVER": self.server_url} def _create_dialog(self): # Don't recreate dialog if already exists if self._dialog is not None: return - from .kitsu_widgets import PasswordDialog + from .kitsu_widgets import KitsuPasswordDialog - self._dialog = PasswordDialog() + self._dialog = KitsuPasswordDialog() def show_dialog(self): - """Show dialog with connected modules. + """Show dialog to log-in.""" - This can be called from anywhere but can also crash in headless mode. - There is no way to prevent addon to do invalid operations if he's - not handling them. - """ # Make sure dialog is created self._create_dialog() + # Show dialog self._dialog.open() - def get_connected_modules(self): - """Custom implementation of addon.""" - names = set() - if self._connected_modules is not None: - for module in self._connected_modules: - names.add(module.name) - return names - def on_action_trigger(self): """Implementation of abstract method for `ITrayAction`.""" self.show_dialog() @@ -124,372 +101,36 @@ def cli_main(): @cli_main.command() -def sync_zou(): - """Synchronize Zou database (Kitsu backend) with openpype database.""" - import gazu - - # Connect to server - gazu.client.set_host(os.environ["KITSU_SERVER"]) - - # Authenticate - gazu.log_in(os.environ["KITSU_LOGIN"], os.environ["KITSU_PWD"]) - - # Iterate projects - dbcon = AvalonMongoDB() - dbcon.install() - - op_projects = [p for p in dbcon.projects()] - bulk_writes = [] - for op_project in op_projects: - # Create project locally - # Try to find project document - project_name = op_project["name"] - dbcon.Session["AVALON_PROJECT"] = project_name - - # Get all entities from zou - print(f"Synchronizing {project_name}...") - zou_project = gazu.project.get_project_by_name(project_name) - - # Create project - if zou_project is None: - raise RuntimeError( - f"Project '{project_name}' doesn't exist in Zou database, " - "please create it in Kitsu and add OpenPype user to it before " - "running synchronization." - ) - - # Update project settings and data - if op_project["data"]: - zou_project.update( - { - "code": op_project["data"]["code"], - "fps": op_project["data"]["fps"], - "resolution": f"{op_project['data']['resolutionWidth']}" - f"x{op_project['data']['resolutionHeight']}", - } - ) - gazu.project.update_project_data( - zou_project, data=op_project["data"] - ) - gazu.project.update_project(zou_project) - - asset_types = gazu.asset.all_asset_types() - all_assets = gazu.asset.all_assets_for_project(zou_project) - all_episodes = gazu.shot.all_episodes_for_project(zou_project) - all_seqs = gazu.shot.all_sequences_for_project(zou_project) - all_shots = gazu.shot.all_shots_for_project(zou_project) - all_entities_ids = { - e["id"] for e in all_episodes + all_seqs + all_shots + all_assets - } - - # Query all assets of the local project - project_module_settings = get_project_settings(project_name)["kitsu"] - project_col = dbcon.database[project_name] - asset_docs = { - asset_doc["_id"]: asset_doc - for asset_doc in project_col.find({"type": "asset"}) - } - - # Create new assets - new_assets_docs = [ - doc - for doc in asset_docs.values() - if doc["data"].get("zou", {}).get("id") not in all_entities_ids - ] - naming_pattern = project_module_settings["entities_naming_pattern"] - regex_ep = re.compile( - r"(.*{}.*)|(.*{}.*)|(.*{}.*)".format( - naming_pattern["shot"].replace("#", ""), - naming_pattern["sequence"].replace("#", ""), - naming_pattern["episode"].replace("#", ""), - ), - re.IGNORECASE, - ) - for doc in new_assets_docs: - visual_parent_id = doc["data"]["visualParent"] - parent_substitutes = [] - - # Match asset type by it's name - match = regex_ep.match(doc["name"]) - if not match: # Asset - new_entity = gazu.asset.new_asset( - zou_project, asset_types[0], doc["name"] - ) - # Match case in shot bool: + """Validate credentials by trying to connect to Kitsu host URL. + + :param login: Kitsu Login + :param password: Kitsu Password + :param kitsu_url: Kitsu host URL + :return: Are credentials valid? + """ + # Connect to server + validate_host(kitsu_url) + + # Authenticate + try: + gazu.log_in(login, password) + except gazu.exception.AuthFailedException: + return False + + return True + + +def validate_host(kitsu_url: str) -> bool: + """Validate credentials by trying to connect to Kitsu host URL. + + :param kitsu_url: Kitsu host URL + :return: Is host valid? + """ + # Connect to server + gazu.set_host(kitsu_url) + + # Test host + if gazu.client.host_is_valid(): + return True + else: + raise gazu.exception.HostException(f"Host '{kitsu_url}' is invalid.") + + +def clear_credentials(): + """Clear credentials in Secure Registry.""" + # Get user registry + user_registry = OpenPypeSecureRegistry("kitsu_user") + + # Set local settings + user_registry.delete_item("login") + user_registry.delete_item("password") + + +def save_credentials(login: str, password: str): + """Save credentials in Secure Registry. + + :param login: Kitsu Login + :param password: Kitsu Password + """ + # Get user registry + user_registry = OpenPypeSecureRegistry("kitsu_user") + + # Set local settings + user_registry.set_item("login", login) + user_registry.set_item("password", password) + + +def load_credentials() -> Tuple[str, str]: + """Load registered credentials. + + :return: Login, Password + """ + # Get user registry + user_registry = OpenPypeSecureRegistry("kitsu_user") + + return user_registry.get_item("login", None), user_registry.get_item( + "password", None + ) + + +def set_credentials_envs(login: str, password: str): + """Set environment variables with Kitsu login and password. + + :param login: Kitsu Login + :param password: Kitsu Password + """ + os.environ["KITSU_LOGIN"] = login + os.environ["KITSU_PWD"] = password diff --git a/openpype/modules/kitsu/utils/listeners.py b/openpype/modules/kitsu/utils/sync_service.py similarity index 54% rename from openpype/modules/kitsu/utils/listeners.py rename to openpype/modules/kitsu/utils/sync_service.py index 3768b4e8e6..831673ec0d 100644 --- a/openpype/modules/kitsu/utils/listeners.py +++ b/openpype/modules/kitsu/utils/sync_service.py @@ -1,72 +1,143 @@ import os +import gazu + from avalon.api import AvalonMongoDB -from .openpype import ( +from .credentials import load_credentials, validate_credentials +from .update_op_with_zou import ( create_op_asset, set_op_project, - sync_project, + write_project_to_op, update_op_assets, ) -def start_listeners(): - """Start listeners to keep OpenPype up-to-date with Kitsu.""" - import gazu +class Listener: + """Host Kitsu listener.""" - # Connect to server - gazu.client.set_host(os.environ["KITSU_SERVER"]) + def __init__(self, login, password): + """Create client and add listeners to events without starting it. - # Authenticate - gazu.log_in(os.environ["KITSU_LOGIN"], os.environ["KITSU_PWD"]) - gazu.set_event_host(os.environ["KITSU_SERVER"].replace("api", "socket.io")) - event_client = gazu.events.init() + Run `listener.start()` to actually start the service. - # Connect to DB - dbcon = AvalonMongoDB() - dbcon.install() + Args: + login (str): Kitsu user login + password (str): Kitsu user password + + Raises: + AuthFailedException: Wrong user login and/or password + """ + self.dbcon = AvalonMongoDB() + self.dbcon.install() + + gazu.client.set_host(os.environ["KITSU_SERVER"]) + + # Authenticate + if not validate_credentials(login, password): + raise gazu.exception.AuthFailedException( + f"Kitsu authentication failed for login: '{login}'..." + ) + + gazu.set_event_host( + os.environ["KITSU_SERVER"].replace("api", "socket.io") + ) + self.event_client = gazu.events.init() + + gazu.events.add_listener( + self.event_client, "project:new", self._new_project + ) + gazu.events.add_listener( + self.event_client, "project:update", self._update_project + ) + gazu.events.add_listener( + self.event_client, "project:delete", self._delete_project + ) + + gazu.events.add_listener( + self.event_client, "asset:new", self._new_asset + ) + gazu.events.add_listener( + self.event_client, "asset:update", self._update_asset + ) + gazu.events.add_listener( + self.event_client, "asset:delete", self._delete_asset + ) + + gazu.events.add_listener( + self.event_client, "episode:new", self._new_episode + ) + gazu.events.add_listener( + self.event_client, "episode:update", self._update_episode + ) + gazu.events.add_listener( + self.event_client, "episode:delete", self._delete_episode + ) + + gazu.events.add_listener( + self.event_client, "sequence:new", self._new_sequence + ) + gazu.events.add_listener( + self.event_client, "sequence:update", self._update_sequence + ) + gazu.events.add_listener( + self.event_client, "sequence:delete", self._delete_sequence + ) + + gazu.events.add_listener(self.event_client, "shot:new", self._new_shot) + gazu.events.add_listener( + self.event_client, "shot:update", self._update_shot + ) + gazu.events.add_listener( + self.event_client, "shot:delete", self._delete_shot + ) + + gazu.events.add_listener(self.event_client, "task:new", self._new_task) + gazu.events.add_listener( + self.event_client, "task:update", self._update_task + ) + gazu.events.add_listener( + self.event_client, "task:delete", self._delete_task + ) + + def start(self): + gazu.events.run_client(self.event_client) # == Project == - - def new_project(data): + def _new_project(self, data): """Create new project into OP DB.""" # Use update process to avoid duplicating code - update_project(data) + self._update_project(data) - def update_project(data): + def _update_project(self, data): """Update project into OP DB.""" # Get project entity project = gazu.project.get_project(data["project_id"]) project_name = project["name"] - dbcon.Session["AVALON_PROJECT"] = project_name - update_project = sync_project(project, dbcon) + update_project = write_project_to_op(project, self.dbcon) # Write into DB if update_project: - project_col = dbcon.database[project_name] + project_col = self.dbcon.database[project_name] project_col.bulk_write([update_project]) - def delete_project(data): + def _delete_project(self, data): """Delete project.""" # Get project entity print(data) # TODO check bugfix project = gazu.project.get_project(data["project_id"]) # Delete project collection - project_col = dbcon.database[project["name"]] + project_col = self.dbcon.database[project["name"]] project_col.drop() - gazu.events.add_listener(event_client, "project:new", new_project) - gazu.events.add_listener(event_client, "project:update", update_project) - gazu.events.add_listener(event_client, "project:delete", delete_project) - # == Asset == - def new_asset(data): + def _new_asset(self, data): """Create new asset into OP DB.""" # Get project entity - project_col = set_op_project(dbcon, data["project_id"]) + project_col = set_op_project(self.dbcon, data["project_id"]) # Get gazu entity asset = gazu.asset.get_asset(data["asset_id"]) @@ -75,12 +146,12 @@ def start_listeners(): project_col.insert_one(create_op_asset(asset)) # Update - update_asset(data) + self._update_asset(data) - def update_asset(data): + def _update_asset(self, data): """Update asset into OP DB.""" - project_col = set_op_project(dbcon, data["project_id"]) - project_doc = dbcon.find_one({"type": "project"}) + project_col = set_op_project(self.dbcon, data["project_id"]) + project_doc = self.dbcon.find_one({"type": "project"}) # Get gazu entity asset = gazu.asset.get_asset(data["asset_id"]) @@ -100,24 +171,20 @@ def start_listeners(): )[0] project_col.update_one({"_id": asset_doc_id}, asset_update) - def delete_asset(data): + def _delete_asset(self, data): """Delete asset of OP DB.""" - project_col = set_op_project(dbcon, data["project_id"]) + project_col = set_op_project(self.dbcon, data["project_id"]) # Delete project_col.delete_one( {"type": "asset", "data.zou.id": data["asset_id"]} ) - gazu.events.add_listener(event_client, "asset:new", new_asset) - gazu.events.add_listener(event_client, "asset:update", update_asset) - gazu.events.add_listener(event_client, "asset:delete", delete_asset) - # == Episode == - def new_episode(data): + def _new_episode(self, data): """Create new episode into OP DB.""" # Get project entity - project_col = set_op_project(dbcon, data["project_id"]) + project_col = set_op_project(self.dbcon, data["project_id"]) # Get gazu entity episode = gazu.shot.get_episode(data["episode_id"]) @@ -126,12 +193,12 @@ def start_listeners(): project_col.insert_one(create_op_asset(episode)) # Update - update_episode(data) + self._update_episode(data) - def update_episode(data): + def _update_episode(self, data): """Update episode into OP DB.""" - project_col = set_op_project(dbcon, data["project_id"]) - project_doc = dbcon.find_one({"type": "project"}) + project_col = set_op_project(self.dbcon, data["project_id"]) + project_doc = self.dbcon.find_one({"type": "project"}) # Get gazu entity episode = gazu.shot.get_episode(data["episode_id"]) @@ -151,9 +218,9 @@ def start_listeners(): )[0] project_col.update_one({"_id": asset_doc_id}, asset_update) - def delete_episode(data): + def _delete_episode(self, data): """Delete shot of OP DB.""" - project_col = set_op_project(dbcon, data["project_id"]) + project_col = set_op_project(self.dbcon, data["project_id"]) print("delete episode") # TODO check bugfix # Delete @@ -161,15 +228,11 @@ def start_listeners(): {"type": "asset", "data.zou.id": data["episode_id"]} ) - gazu.events.add_listener(event_client, "episode:new", new_episode) - gazu.events.add_listener(event_client, "episode:update", update_episode) - gazu.events.add_listener(event_client, "episode:delete", delete_episode) - # == Sequence == - def new_sequence(data): + def _new_sequence(self, data): """Create new sequnce into OP DB.""" # Get project entity - project_col = set_op_project(dbcon, data["project_id"]) + project_col = set_op_project(self.dbcon, data["project_id"]) # Get gazu entity sequence = gazu.shot.get_sequence(data["sequence_id"]) @@ -178,12 +241,12 @@ def start_listeners(): project_col.insert_one(create_op_asset(sequence)) # Update - update_sequence(data) + self._update_sequence(data) - def update_sequence(data): + def _update_sequence(self, data): """Update sequence into OP DB.""" - project_col = set_op_project(dbcon, data["project_id"]) - project_doc = dbcon.find_one({"type": "project"}) + project_col = set_op_project(self.dbcon, data["project_id"]) + project_doc = self.dbcon.find_one({"type": "project"}) # Get gazu entity sequence = gazu.shot.get_sequence(data["sequence_id"]) @@ -203,9 +266,9 @@ def start_listeners(): )[0] project_col.update_one({"_id": asset_doc_id}, asset_update) - def delete_sequence(data): + def _delete_sequence(self, data): """Delete sequence of OP DB.""" - project_col = set_op_project(dbcon, data["project_id"]) + project_col = set_op_project(self.dbcon, data["project_id"]) print("delete sequence") # TODO check bugfix # Delete @@ -213,15 +276,11 @@ def start_listeners(): {"type": "asset", "data.zou.id": data["sequence_id"]} ) - gazu.events.add_listener(event_client, "sequence:new", new_sequence) - gazu.events.add_listener(event_client, "sequence:update", update_sequence) - gazu.events.add_listener(event_client, "sequence:delete", delete_sequence) - # == Shot == - def new_shot(data): + def _new_shot(self, data): """Create new shot into OP DB.""" # Get project entity - project_col = set_op_project(dbcon, data["project_id"]) + project_col = set_op_project(self.dbcon, data["project_id"]) # Get gazu entity shot = gazu.shot.get_shot(data["shot_id"]) @@ -230,12 +289,12 @@ def start_listeners(): project_col.insert_one(create_op_asset(shot)) # Update - update_shot(data) + self._update_shot(data) - def update_shot(data): + def _update_shot(self, data): """Update shot into OP DB.""" - project_col = set_op_project(dbcon, data["project_id"]) - project_doc = dbcon.find_one({"type": "project"}) + project_col = set_op_project(self.dbcon, data["project_id"]) + project_doc = self.dbcon.find_one({"type": "project"}) # Get gazu entity shot = gazu.shot.get_shot(data["shot_id"]) @@ -255,25 +314,20 @@ def start_listeners(): )[0] project_col.update_one({"_id": asset_doc_id}, asset_update) - def delete_shot(data): + def _delete_shot(self, data): """Delete shot of OP DB.""" - project_col = set_op_project(dbcon, data["project_id"]) + project_col = set_op_project(self.dbcon, data["project_id"]) # Delete project_col.delete_one( {"type": "asset", "data.zou.id": data["shot_id"]} ) - gazu.events.add_listener(event_client, "shot:new", new_shot) - gazu.events.add_listener(event_client, "shot:update", update_shot) - gazu.events.add_listener(event_client, "shot:delete", delete_shot) - # == Task == - def new_task(data): + def _new_task(self, data): """Create new task into OP DB.""" - print("new", data) # Get project entity - project_col = set_op_project(dbcon, data["project_id"]) + project_col = set_op_project(self.dbcon, data["project_id"]) # Get gazu entity task = gazu.task.get_task(data["task_id"]) @@ -291,14 +345,14 @@ def start_listeners(): {"_id": asset_doc["_id"]}, {"$set": {"data.tasks": asset_tasks}} ) - def update_task(data): + def _update_task(self, data): """Update task into OP DB.""" # TODO is it necessary? pass - def delete_task(data): + def _delete_task(self, data): """Delete task of OP DB.""" - project_col = set_op_project(dbcon, data["project_id"]) + project_col = set_op_project(self.dbcon, data["project_id"]) # Find asset doc asset_docs = [doc for doc in project_col.find({"type": "asset"})] @@ -307,7 +361,7 @@ def start_listeners(): for name, task in doc["data"]["tasks"].items(): if task.get("zou") and data["task_id"] == task["zou"]["id"]: # Pop task - asset_tasks = doc["data"].get("tasks") + asset_tasks = doc["data"].get("tasks", {}) asset_tasks.pop(name) # Delete task in DB @@ -317,8 +371,20 @@ def start_listeners(): ) return - gazu.events.add_listener(event_client, "task:new", new_task) - gazu.events.add_listener(event_client, "task:update", update_task) - gazu.events.add_listener(event_client, "task:delete", delete_task) - gazu.events.run_client(event_client) +def start_listeners(login: str, password: str): + """Start listeners to keep OpenPype up-to-date with Kitsu. + + Args: + login (str): Kitsu user login + password (str): Kitsu user password + """ + + # Connect to server + listener = Listener(login, password) + listener.start() + + +if __name__ == "__main__": + # TODO not sure when this can be run and if this system is reliable + start_listeners(load_credentials()) diff --git a/openpype/modules/kitsu/utils/openpype.py b/openpype/modules/kitsu/utils/update_op_with_zou.py similarity index 52% rename from openpype/modules/kitsu/utils/openpype.py rename to openpype/modules/kitsu/utils/update_op_with_zou.py index 56c99effff..eb675ad09e 100644 --- a/openpype/modules/kitsu/utils/openpype.py +++ b/openpype/modules/kitsu/utils/update_op_with_zou.py @@ -1,10 +1,17 @@ +"""Functions to update OpenPype data using Kitsu DB (a.k.a Zou).""" from typing import Dict, List -from pymongo import UpdateOne +from pymongo import DeleteOne, UpdateOne from pymongo.collection import Collection +import gazu +from gazu.task import ( + all_tasks_for_asset, + all_tasks_for_shot, +) from avalon.api import AvalonMongoDB from openpype.lib import create_project +from openpype.modules.kitsu.utils.credentials import validate_credentials def create_op_asset(gazu_entity: dict) -> dict: @@ -26,8 +33,6 @@ def set_op_project(dbcon, project_id) -> Collection: :param dbcon: Connection to DB. :param project_id: Project zou ID """ - import gazu - project = gazu.project.get_project(project_id) project_name = project["name"] dbcon.Session["AVALON_PROJECT"] = project_name @@ -45,11 +50,6 @@ def update_op_assets( :param asset_doc_ids: Dicts of [{zou_id: asset_doc}, ...] :return: List of (doc_id, update_dict) tuples """ - from gazu.task import ( - all_tasks_for_asset, - all_tasks_for_shot, - ) - assets_with_update = [] for item in entities_list: # Update asset @@ -124,18 +124,19 @@ def update_op_assets( return assets_with_update -def sync_project(project: dict, dbcon: AvalonMongoDB) -> UpdateOne: - """Sync project with database. +def write_project_to_op(project: dict, dbcon: AvalonMongoDB) -> UpdateOne: + """Write gazu project to OP database. Create project if doesn't exist. - :param project: Gazu project - :param dbcon: DB to create project in - :return: Update instance for the project - """ - import gazu + Args: + project (dict): Gazu project + dbcon (AvalonMongoDB): DB to create project in + Returns: + UpdateOne: Update instance for the project + """ project_name = project["name"] - project_doc = dbcon.find_one({"type": "project"}) + project_doc = dbcon.database[project_name].find_one({"type": "project"}) if not project_doc: print(f"Creating project '{project_name}'") project_doc = create_project(project_name, project_name, dbcon=dbcon) @@ -165,3 +166,123 @@ def sync_project(project: dict, dbcon: AvalonMongoDB) -> UpdateOne: } }, ) + + +def sync_all_project(login: str, password: str): + """Update all OP projects in DB with Zou data. + + Args: + login (str): Kitsu user login + password (str): Kitsu user password + + Raises: + gazu.exception.AuthFailedException: Wrong user login and/or password + """ + + # Authenticate + if not validate_credentials(login, password): + raise gazu.exception.AuthFailedException( + f"Kitsu authentication failed for login: '{login}'..." + ) + + # Iterate projects + dbcon = AvalonMongoDB() + dbcon.install() + all_projects = gazu.project.all_projects() + for project in all_projects: + sync_project_from_kitsu(project["name"], dbcon, project) + + +def sync_project_from_kitsu( + project_name: str, dbcon: AvalonMongoDB, project: dict = None +): + """Update OP project in DB with Zou data. + + Args: + project_name (str): Name of project to sync + dbcon (AvalonMongoDB): MongoDB connection + project (dict, optional): Project dict got using gazu. + Defaults to None. + """ + bulk_writes = [] + + # Get project from zou + if not project: + project = gazu.project.get_project_by_name(project_name) + project_code = project_name + + # Try to find project document + project_col = dbcon.database[project_code] + project_doc = project_col.find_one({"type": "project"}) + + print(f"Synchronizing {project_name}...") + + # Get all assets from zou + all_assets = gazu.asset.all_assets_for_project(project) + all_episodes = gazu.shot.all_episodes_for_project(project) + all_seqs = gazu.shot.all_sequences_for_project(project) + all_shots = gazu.shot.all_shots_for_project(project) + all_entities = [ + e + for e in all_assets + all_episodes + all_seqs + all_shots + if e["data"] and not e["data"].get("is_substitute") + ] + + # Sync project. Create if doesn't exist + bulk_writes.append(write_project_to_op(project, dbcon)) + + # Query all assets of the local project + zou_ids_and_asset_docs = { + asset_doc["data"]["zou"]["id"]: asset_doc + for asset_doc in project_col.find({"type": "asset"}) + if asset_doc["data"].get("zou", {}).get("id") + } + zou_ids_and_asset_docs[project["id"]] = project_doc + + # Create + to_insert = [] + to_insert.extend( + [ + create_op_asset(item) + for item in all_entities + if item["id"] not in zou_ids_and_asset_docs.keys() + ] + ) + if to_insert: + # Insert doc in DB + project_col.insert_many(to_insert) + + # Update existing docs + zou_ids_and_asset_docs.update( + { + asset_doc["data"]["zou"]["id"]: asset_doc + for asset_doc in project_col.find({"type": "asset"}) + if asset_doc["data"].get("zou") + } + ) + + # Update + bulk_writes.extend( + [ + UpdateOne({"_id": id}, update) + for id, update in update_op_assets( + all_entities, zou_ids_and_asset_docs + ) + ] + ) + + # Delete + diff_assets = set(zou_ids_and_asset_docs.keys()) - { + e["id"] for e in all_entities + [project] + } + if diff_assets: + bulk_writes.extend( + [ + DeleteOne(zou_ids_and_asset_docs[asset_id]) + for asset_id in diff_assets + ] + ) + + # Write into DB + if bulk_writes: + project_col.bulk_write(bulk_writes) diff --git a/openpype/modules/kitsu/utils/update_zou_with_op.py b/openpype/modules/kitsu/utils/update_zou_with_op.py new file mode 100644 index 0000000000..d1fcde5601 --- /dev/null +++ b/openpype/modules/kitsu/utils/update_zou_with_op.py @@ -0,0 +1,262 @@ +"""Functions to update Kitsu DB (a.k.a Zou) using OpenPype Data.""" + +import re +from typing import List + +import gazu +from pymongo import UpdateOne + +from avalon.api import AvalonMongoDB +from openpype.api import get_project_settings +from openpype.modules.kitsu.utils.credentials import validate_credentials + + +def sync_zou(login: str, password: str): + """Synchronize Zou database (Kitsu backend) with openpype database. + This is an utility function to help updating zou data with OP's, it may not + handle correctly all cases, a human intervention might + be required after all. + Will work better if OP DB has been previously synchronized from zou/kitsu. + + Args: + login (str): Kitsu user login + password (str): Kitsu user password + + Raises: + gazu.exception.AuthFailedException: Wrong user login and/or password + """ + + # Authenticate + if not validate_credentials(login, password): + raise gazu.exception.AuthFailedException( + f"Kitsu authentication failed for login: '{login}'..." + ) + + # Iterate projects + dbcon = AvalonMongoDB() + dbcon.install() + + op_projects = [p for p in dbcon.projects()] + for project_doc in op_projects: + sync_zou_from_op_project(project_doc["name"], dbcon, project_doc) + + +def sync_zou_from_op_project( + project_name: str, dbcon: AvalonMongoDB, project_doc: dict = None +) -> List[UpdateOne]: + """Update OP project in DB with Zou data. + + Args: + project_name (str): Name of project to sync + dbcon (AvalonMongoDB): MongoDB connection + project_doc (str, optional): Project doc to sync + """ + # Get project doc if not provided + if not project_doc: + project_doc = dbcon.database[project_name].find_one( + {"type": "project"} + ) + + # Get all entities from zou + print(f"Synchronizing {project_name}...") + zou_project = gazu.project.get_project_by_name(project_name) + + # Create project + if zou_project is None: + raise RuntimeError( + f"Project '{project_name}' doesn't exist in Zou database, " + "please create it in Kitsu and add OpenPype user to it before " + "running synchronization." + ) + + # Update project settings and data + if project_doc["data"]: + zou_project.update( + { + "code": project_doc["data"]["code"], + "fps": project_doc["data"]["fps"], + "resolution": f"{project_doc['data']['resolutionWidth']}" + f"x{project_doc['data']['resolutionHeight']}", + } + ) + gazu.project.update_project_data(zou_project, data=project_doc["data"]) + gazu.project.update_project(zou_project) + + asset_types = gazu.asset.all_asset_types() + all_assets = gazu.asset.all_assets_for_project(zou_project) + all_episodes = gazu.shot.all_episodes_for_project(zou_project) + all_seqs = gazu.shot.all_sequences_for_project(zou_project) + all_shots = gazu.shot.all_shots_for_project(zou_project) + all_entities_ids = { + e["id"] for e in all_episodes + all_seqs + all_shots + all_assets + } + + # Query all assets of the local project + project_module_settings = get_project_settings(project_name)["kitsu"] + project_col = dbcon.database[project_name] + asset_docs = { + asset_doc["_id"]: asset_doc + for asset_doc in project_col.find({"type": "asset"}) + } + + # Create new assets + new_assets_docs = [ + doc + for doc in asset_docs.values() + if doc["data"].get("zou", {}).get("id") not in all_entities_ids + ] + naming_pattern = project_module_settings["entities_naming_pattern"] + regex_ep = re.compile( + r"(.*{}.*)|(.*{}.*)|(.*{}.*)".format( + naming_pattern["shot"].replace("#", ""), + naming_pattern["sequence"].replace("#", ""), + naming_pattern["episode"].replace("#", ""), + ), + re.IGNORECASE, + ) + bulk_writes = [] + for doc in new_assets_docs: + visual_parent_id = doc["data"]["visualParent"] + parent_substitutes = [] + + # Match asset type by it's name + match = regex_ep.match(doc["name"]) + if not match: # Asset + new_entity = gazu.asset.new_asset( + zou_project, asset_types[0], doc["name"] + ) + # Match case in shot Date: Thu, 3 Mar 2022 15:55:56 +0100 Subject: [PATCH 059/350] Cleaning. --- openpype/modules/kitsu/utils/credentials.py | 36 ++++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/openpype/modules/kitsu/utils/credentials.py b/openpype/modules/kitsu/utils/credentials.py index b4dd5ee4a2..0529380d6d 100644 --- a/openpype/modules/kitsu/utils/credentials.py +++ b/openpype/modules/kitsu/utils/credentials.py @@ -8,15 +8,21 @@ from openpype.lib.local_settings import OpenPypeSecureRegistry def validate_credentials( - login: str, password: str, kitsu_url: str = os.environ.get("KITSU_SERVER") + login: str, password: str, kitsu_url: str = None ) -> bool: """Validate credentials by trying to connect to Kitsu host URL. - :param login: Kitsu Login - :param password: Kitsu Password - :param kitsu_url: Kitsu host URL - :return: Are credentials valid? + Args: + login (str): Kitsu user login + password (str): Kitsu user password + kitsu_url (str, optional): Kitsu host URL. Defaults to None. + + Returns: + bool: Are credentials valid? """ + if kitsu_url is None: + kitsu_url = os.environ.get("KITSU_SERVER") + # Connect to server validate_host(kitsu_url) @@ -32,8 +38,11 @@ def validate_credentials( def validate_host(kitsu_url: str) -> bool: """Validate credentials by trying to connect to Kitsu host URL. - :param kitsu_url: Kitsu host URL - :return: Is host valid? + Args: + kitsu_url (str, optional): Kitsu host URL. + + Returns: + bool: Is host valid? """ # Connect to server gazu.set_host(kitsu_url) @@ -58,8 +67,9 @@ def clear_credentials(): def save_credentials(login: str, password: str): """Save credentials in Secure Registry. - :param login: Kitsu Login - :param password: Kitsu Password + Args: + login (str): Kitsu user login + password (str): Kitsu user password """ # Get user registry user_registry = OpenPypeSecureRegistry("kitsu_user") @@ -72,7 +82,8 @@ def save_credentials(login: str, password: str): def load_credentials() -> Tuple[str, str]: """Load registered credentials. - :return: Login, Password + Returns: + Tuple[str, str]: (Login, Password) """ # Get user registry user_registry = OpenPypeSecureRegistry("kitsu_user") @@ -85,8 +96,9 @@ def load_credentials() -> Tuple[str, str]: def set_credentials_envs(login: str, password: str): """Set environment variables with Kitsu login and password. - :param login: Kitsu Login - :param password: Kitsu Password + Args: + login (str): Kitsu user login + password (str): Kitsu user password """ os.environ["KITSU_LOGIN"] = login os.environ["KITSU_PWD"] = password From 5db0c1dfa7cbf483976b6e52f6d4cde5813daedc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Fri, 4 Mar 2022 10:12:08 +0100 Subject: [PATCH 060/350] Python 2 compat and cleaning --- openpype/modules/kitsu/kitsu_module.py | 4 ++-- openpype/modules/kitsu/utils/sync_service.py | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/openpype/modules/kitsu/kitsu_module.py b/openpype/modules/kitsu/kitsu_module.py index dca6133e88..53edfddf9a 100644 --- a/openpype/modules/kitsu/kitsu_module.py +++ b/openpype/modules/kitsu/kitsu_module.py @@ -105,7 +105,7 @@ def cli_main(): @click.option( "--password", envvar="KITSU_PWD", help="Password for kitsu username" ) -def push_to_zou(login: str, password: str): +def push_to_zou(login, password): """Synchronize Zou database (Kitsu backend) with openpype database. Args: @@ -122,7 +122,7 @@ def push_to_zou(login: str, password: str): @click.option( "-p", "--password", envvar="KITSU_PWD", help="Password for kitsu username" ) -def sync_service(login: str, password: str): +def sync_service(login, password): """Synchronize openpype database from Zou sever database. Args: diff --git a/openpype/modules/kitsu/utils/sync_service.py b/openpype/modules/kitsu/utils/sync_service.py index 831673ec0d..6bf98cf308 100644 --- a/openpype/modules/kitsu/utils/sync_service.py +++ b/openpype/modules/kitsu/utils/sync_service.py @@ -383,8 +383,3 @@ def start_listeners(login: str, password: str): # Connect to server listener = Listener(login, password) listener.start() - - -if __name__ == "__main__": - # TODO not sure when this can be run and if this system is reliable - start_listeners(load_credentials()) From 8c3b510887564d52d7230c7114a17f9044157be5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Fri, 4 Mar 2022 10:12:58 +0100 Subject: [PATCH 061/350] Cleaning --- openpype/modules/kitsu/utils/sync_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/kitsu/utils/sync_service.py b/openpype/modules/kitsu/utils/sync_service.py index 6bf98cf308..2e8fbf77f5 100644 --- a/openpype/modules/kitsu/utils/sync_service.py +++ b/openpype/modules/kitsu/utils/sync_service.py @@ -3,7 +3,7 @@ import os import gazu from avalon.api import AvalonMongoDB -from .credentials import load_credentials, validate_credentials +from .credentials import validate_credentials from .update_op_with_zou import ( create_op_asset, set_op_project, From e5ae5459e135d10d01e1549f8ac3f8a8cb83e689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Fri, 4 Mar 2022 15:58:06 +0100 Subject: [PATCH 062/350] Kitsu docs --- website/docs/artist_kitsu.md | 17 ++++++++ .../docs/assets/kitsu/kitsu_credentials.png | Bin 0 -> 15798 bytes website/docs/module_kitsu.md | 37 ++++++++++++++++++ website/sidebars.js | 2 + 4 files changed, 56 insertions(+) create mode 100644 website/docs/artist_kitsu.md create mode 100644 website/docs/assets/kitsu/kitsu_credentials.png create mode 100644 website/docs/module_kitsu.md diff --git a/website/docs/artist_kitsu.md b/website/docs/artist_kitsu.md new file mode 100644 index 0000000000..9ef782c297 --- /dev/null +++ b/website/docs/artist_kitsu.md @@ -0,0 +1,17 @@ +--- +id: artist_kitsu +title: Kitsu +sidebar_label: Kitsu +--- + +# How to use Kitsu in OpenPype + +## Login to Kitsu module in OpenPype +1. Launch OpenPype, the `Kitsu Credentials` window will open automatically, if not, or if you want to log-in with another account, go to systray OpenPype icon and click on `Kitsu Connect`. +2. Enter your credentials and press *Ok*: + + ![kitsu-login](assets/kitsu/kitsu_credentials.png) + +:::tip +In Kitsu, All the publish actions executed by `pyblish` will be attributed to the currently logged-in user. +::: \ No newline at end of file diff --git a/website/docs/assets/kitsu/kitsu_credentials.png b/website/docs/assets/kitsu/kitsu_credentials.png new file mode 100644 index 0000000000000000000000000000000000000000..25c1ad93c4d966a083d1fbdcd15e78a54e659b76 GIT binary patch literal 15798 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 literal 0 HcmV?d00001 diff --git a/website/docs/module_kitsu.md b/website/docs/module_kitsu.md new file mode 100644 index 0000000000..ec38cce5e1 --- /dev/null +++ b/website/docs/module_kitsu.md @@ -0,0 +1,37 @@ +--- +id: module_kitsu +title: Kitsu Administration +sidebar_label: Kitsu +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Kitsu is a great open source production tracker and can be used for project management instead of Ftrack. This documentation assumes that you are familiar with Kitsu and it's basic principles. If you're new to Kitsu, we recommend having a thorough look at [Kitsu Official Documentation](https://kitsu.cg-wire.com/). + +## Prepare Kitsu for OpenPype + +### Server URL +If you want to connect Kitsu to OpenPype you have to set the `Server` url in Kitsu settings. And that's all! +This setting is available for all the users of the OpenPype instance. + +## Synchronize +Updating OP with Kitsu data is executed running the `sync-service`, which requires to provide your Kitsu credentials with `-l, --login` and `-p, --password` or by setting the environment variables `KITSU_LOGIN` and `KITSU_PWD`. This process will request data from Kitsu and create/delete/update OP assets. +Once this sync is done, the thread will automatically start a loop to listen to Kitsu events. + +```bash +openpype_console module kitsu sync-service -l me@domain.ext -p my_password +``` + +### Events listening +Listening to Kitsu events is the key to automation of many tasks like _project/episode/sequence/shot/asset/task create/update/delete_ and some more. Events listening should run at all times to perform the required processing as it is not possible to catch some of them retrospectively with strong reliability. If such timeout has been encountered, you must relaunch the `sync-service` command to run the synchronization step again. + +### Push to Kitsu +An utility function is provided to help update Kitsu data (a.k.a Zou database) with OpenPype data if the publishing to the production tracker hasn't been possible for some time. Running `push-to-zou` will create the data on behalf of the user. +:::caution +This functionality cannot deal with all cases and is not error proof, some intervention by a human being might be required. +::: + +```bash +openpype_console module kitsu push-to-zou -l me@domain.ext -p my_password +``` diff --git a/website/sidebars.js b/website/sidebars.js index 105afc30eb..eecdcc6e9a 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -28,6 +28,7 @@ module.exports = { "artist_hosts_photoshop", "artist_hosts_tvpaint", "artist_hosts_unreal", + "artist_kitsu", { type: "category", label: "Ftrack", @@ -75,6 +76,7 @@ module.exports = { label: "Modules", items: [ "module_ftrack", + "module_kitsu", "module_site_sync", "module_deadline", "module_muster", From 05158585c778a3bed91c023626bcf5ee3baf29a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Tue, 8 Mar 2022 09:22:16 +0100 Subject: [PATCH 063/350] Add pyblish comment to kitsu --- openpype/modules/kitsu/kitsu_module.py | 6 +++--- openpype/modules/kitsu/plugins/publish/kitsu_plugin.py | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/openpype/modules/kitsu/kitsu_module.py b/openpype/modules/kitsu/kitsu_module.py index 53edfddf9a..8e7ab6f78c 100644 --- a/openpype/modules/kitsu/kitsu_module.py +++ b/openpype/modules/kitsu/kitsu_module.py @@ -51,11 +51,11 @@ class KitsuModule(OpenPypeModule, IPluginPaths, ITrayAction): set_credentials_envs, ) - username, password = load_credentials() + login, password = load_credentials() # Check credentials, ask them if needed - if validate_credentials(username, password): - set_credentials_envs(username, password) + if validate_credentials(login, password): + set_credentials_envs(login, password) else: self.show_dialog() diff --git a/openpype/modules/kitsu/plugins/publish/kitsu_plugin.py b/openpype/modules/kitsu/plugins/publish/kitsu_plugin.py index b556f2b91f..5fce123d7e 100644 --- a/openpype/modules/kitsu/plugins/publish/kitsu_plugin.py +++ b/openpype/modules/kitsu/plugins/publish/kitsu_plugin.py @@ -39,7 +39,9 @@ class IntegrateRig(pyblish.api.InstancePlugin): gazu.task.add_comment( entity_task, entity_task["task_status_id"], - comment=f"Version {instance.data['version']} has been published!", - ) # TODO add comment from pyblish + comment=f"Version {instance.data['version']} has been published!\n" + "\n" # Add written comment in Pyblish + f"{instance.data['versionEntity']['data']['comment']}".strip(), + ) self.log.info("Version published to Kitsu successfully!") From 1591b91c54611e2bfe55902ad31929e72416515f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Tue, 8 Mar 2022 09:57:37 +0100 Subject: [PATCH 064/350] Python2 compat --- openpype/modules/kitsu/plugins/publish/kitsu_plugin.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/openpype/modules/kitsu/plugins/publish/kitsu_plugin.py b/openpype/modules/kitsu/plugins/publish/kitsu_plugin.py index 5fce123d7e..5d6c76bc3f 100644 --- a/openpype/modules/kitsu/plugins/publish/kitsu_plugin.py +++ b/openpype/modules/kitsu/plugins/publish/kitsu_plugin.py @@ -39,9 +39,11 @@ class IntegrateRig(pyblish.api.InstancePlugin): gazu.task.add_comment( entity_task, entity_task["task_status_id"], - comment=f"Version {instance.data['version']} has been published!\n" - "\n" # Add written comment in Pyblish - f"{instance.data['versionEntity']['data']['comment']}".strip(), + comment="Version {} has been published!\n".format( + instance.data["version"] + ) + # Add written comment in Pyblish + + "\n{}".format(instance.data["versionEntity"]["data"]["comment"]), ) self.log.info("Version published to Kitsu successfully!") From 9c0c43a0612c70fa7fa26e71c1f91b7605b3792d Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Tue, 15 Mar 2022 18:01:04 +0100 Subject: [PATCH 065/350] fix first sync crash --- .../modules/kitsu/utils/update_op_with_zou.py | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/openpype/modules/kitsu/utils/update_op_with_zou.py b/openpype/modules/kitsu/utils/update_op_with_zou.py index eb675ad09e..e76d54d1ad 100644 --- a/openpype/modules/kitsu/utils/update_op_with_zou.py +++ b/openpype/modules/kitsu/utils/update_op_with_zou.py @@ -145,14 +145,15 @@ def write_project_to_op(project: dict, dbcon: AvalonMongoDB) -> UpdateOne: project_data = project["data"] or {} # Update data - project_data.update( - { - "code": project["code"], - "fps": project["fps"], - "resolutionWidth": project["resolution"].split("x")[0], - "resolutionHeight": project["resolution"].split("x")[1], - } - ) + if project_data: + project_data.update( + { + "code": project["code"], + "fps": project["fps"], + "resolutionWidth": project["resolution"].split("x")[0], + "resolutionHeight": project["resolution"].split("x")[1], + } + ) return UpdateOne( {"_id": project_doc["_id"]}, @@ -211,10 +212,6 @@ def sync_project_from_kitsu( project = gazu.project.get_project_by_name(project_name) project_code = project_name - # Try to find project document - project_col = dbcon.database[project_code] - project_doc = project_col.find_one({"type": "project"}) - print(f"Synchronizing {project_name}...") # Get all assets from zou @@ -222,15 +219,15 @@ def sync_project_from_kitsu( all_episodes = gazu.shot.all_episodes_for_project(project) all_seqs = gazu.shot.all_sequences_for_project(project) all_shots = gazu.shot.all_shots_for_project(project) - all_entities = [ - e - for e in all_assets + all_episodes + all_seqs + all_shots - if e["data"] and not e["data"].get("is_substitute") - ] + all_entities = all_assets + all_episodes + all_seqs + all_shots # Sync project. Create if doesn't exist bulk_writes.append(write_project_to_op(project, dbcon)) + # Try to find project document + project_col = dbcon.database[project_code] + project_doc = project_col.find_one({"type": "project"}) + # Query all assets of the local project zou_ids_and_asset_docs = { asset_doc["data"]["zou"]["id"]: asset_doc From 17dd018aa060f8fbaf043e19e86a9a0e318f14dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 16 Mar 2022 17:01:30 +0100 Subject: [PATCH 066/350] Build project code --- openpype/modules/kitsu/utils/update_op_with_zou.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/openpype/modules/kitsu/utils/update_op_with_zou.py b/openpype/modules/kitsu/utils/update_op_with_zou.py index e76d54d1ad..98f263efe1 100644 --- a/openpype/modules/kitsu/utils/update_op_with_zou.py +++ b/openpype/modules/kitsu/utils/update_op_with_zou.py @@ -144,11 +144,20 @@ def write_project_to_op(project: dict, dbcon: AvalonMongoDB) -> UpdateOne: # Project data and tasks project_data = project["data"] or {} + # Build project code and update Kitsu + project_code = project.get("code") + if not project_code: + project_code = project["name"].replace(" ", "_").lower() + project["code"] = project_code + + # Update Zou + gazu.project.update_project(project) + # Update data if project_data: project_data.update( { - "code": project["code"], + "code": project_code, "fps": project["fps"], "resolutionWidth": project["resolution"].split("x")[0], "resolutionHeight": project["resolution"].split("x")[1], From 093e801b0b02074e4d5bd7ecd0ff6d791ba6ea92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 16 Mar 2022 17:31:22 +0100 Subject: [PATCH 067/350] Sync project FPS and resolution --- .../modules/kitsu/utils/update_op_with_zou.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/openpype/modules/kitsu/utils/update_op_with_zou.py b/openpype/modules/kitsu/utils/update_op_with_zou.py index 98f263efe1..cb2c79b942 100644 --- a/openpype/modules/kitsu/utils/update_op_with_zou.py +++ b/openpype/modules/kitsu/utils/update_op_with_zou.py @@ -154,15 +154,14 @@ def write_project_to_op(project: dict, dbcon: AvalonMongoDB) -> UpdateOne: gazu.project.update_project(project) # Update data - if project_data: - project_data.update( - { - "code": project_code, - "fps": project["fps"], - "resolutionWidth": project["resolution"].split("x")[0], - "resolutionHeight": project["resolution"].split("x")[1], - } - ) + project_data.update( + { + "code": project_code, + "fps": project["fps"], + "resolutionWidth": project["resolution"].split("x")[0], + "resolutionHeight": project["resolution"].split("x")[1], + } + ) return UpdateOne( {"_id": project_doc["_id"]}, From bd06809ffaf8ff8ae8bde463a5ad990b486288c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 16 Mar 2022 18:44:26 +0100 Subject: [PATCH 068/350] Fix shot syncs --- openpype/modules/kitsu/utils/update_op_with_zou.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/openpype/modules/kitsu/utils/update_op_with_zou.py b/openpype/modules/kitsu/utils/update_op_with_zou.py index cb2c79b942..6aea2e3930 100644 --- a/openpype/modules/kitsu/utils/update_op_with_zou.py +++ b/openpype/modules/kitsu/utils/update_op_with_zou.py @@ -1,4 +1,5 @@ """Functions to update OpenPype data using Kitsu DB (a.k.a Zou).""" +from copy import deepcopy from typing import Dict, List from pymongo import DeleteOne, UpdateOne @@ -54,9 +55,14 @@ def update_op_assets( for item in entities_list: # Update asset item_doc = asset_doc_ids[item["id"]] - item_data = item_doc["data"].copy() + item_data = deepcopy(item_doc["data"]) + item_data.update(item.get("data") or {}) item_data["zou"] = item + # Asset settings + item_data["frameStart"] = item_data.get("frame_in") + item_data["frameEnd"] = item_data.get("frame_out") + # Tasks tasks_list = [] if item["type"] == "Asset": @@ -103,9 +109,7 @@ def update_op_assets( # Update 'data' different in zou DB updated_data = { - k: item_data[k] - for k in item_data.keys() - if item_doc["data"].get(k) != item_data[k] + k: v for k, v in item_data.items() if item_doc["data"].get(k) != v } if updated_data or not item_doc.get("parent"): assets_with_update.append( From 84a13e4eb6ff99b433ea1d2fddce32d106381e61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Thu, 17 Mar 2022 15:52:14 +0100 Subject: [PATCH 069/350] shots and assets custom folders root --- openpype/modules/kitsu/utils/sync_service.py | 8 +- .../modules/kitsu/utils/update_op_with_zou.py | 82 +++++++++++++++++-- .../defaults/project_settings/kitsu.json | 4 + .../projects_schema/schema_project_kitsu.json | 17 ++++ 4 files changed, 99 insertions(+), 12 deletions(-) diff --git a/openpype/modules/kitsu/utils/sync_service.py b/openpype/modules/kitsu/utils/sync_service.py index 2e8fbf77f5..746cb843e9 100644 --- a/openpype/modules/kitsu/utils/sync_service.py +++ b/openpype/modules/kitsu/utils/sync_service.py @@ -167,7 +167,7 @@ class Listener: # Update asset_doc_id, asset_update = update_op_assets( - [asset], zou_ids_and_asset_docs + project_col[asset], zou_ids_and_asset_docs )[0] project_col.update_one({"_id": asset_doc_id}, asset_update) @@ -214,7 +214,7 @@ class Listener: # Update asset_doc_id, asset_update = update_op_assets( - [episode], zou_ids_and_asset_docs + project_col, [episode], zou_ids_and_asset_docs )[0] project_col.update_one({"_id": asset_doc_id}, asset_update) @@ -262,7 +262,7 @@ class Listener: # Update asset_doc_id, asset_update = update_op_assets( - [sequence], zou_ids_and_asset_docs + project_col, [sequence], zou_ids_and_asset_docs )[0] project_col.update_one({"_id": asset_doc_id}, asset_update) @@ -310,7 +310,7 @@ class Listener: # Update asset_doc_id, asset_update = update_op_assets( - [shot], zou_ids_and_asset_docs + project_col, [shot], zou_ids_and_asset_docs )[0] project_col.update_one({"_id": asset_doc_id}, asset_update) diff --git a/openpype/modules/kitsu/utils/update_op_with_zou.py b/openpype/modules/kitsu/utils/update_op_with_zou.py index 6aea2e3930..e2ad29bfa0 100644 --- a/openpype/modules/kitsu/utils/update_op_with_zou.py +++ b/openpype/modules/kitsu/utils/update_op_with_zou.py @@ -11,6 +11,7 @@ from gazu.task import ( ) from avalon.api import AvalonMongoDB +from openpype.api import get_project_settings from openpype.lib import create_project from openpype.modules.kitsu.utils.credentials import validate_credentials @@ -42,15 +43,23 @@ def set_op_project(dbcon, project_id) -> Collection: def update_op_assets( - entities_list: List[dict], asset_doc_ids: Dict[str, dict] + project_col: Collection, + entities_list: List[dict], + asset_doc_ids: Dict[str, dict], ) -> List[Dict[str, dict]]: """Update OpenPype assets. Set 'data' and 'parent' fields. - :param entities_list: List of zou entities to update - :param asset_doc_ids: Dicts of [{zou_id: asset_doc}, ...] - :return: List of (doc_id, update_dict) tuples + Args: + project_col (Collection): Mongo project collection to sync + entities_list (List[dict]): List of zou entities to update + asset_doc_ids (Dict[str, dict]): Dicts of [{zou_id: asset_doc}, ...] + + Returns: + List[Dict[str, dict]]: List of (doc_id, update_dict) tuples """ + project_name = project_col.name + assets_with_update = [] for item in entities_list: # Update asset @@ -65,9 +74,10 @@ def update_op_assets( # Tasks tasks_list = [] - if item["type"] == "Asset": + item_type = item["type"] + if item_type == "Asset": tasks_list = all_tasks_for_asset(item) - elif item["type"] == "Shot": + elif item_type == "Shot": tasks_list = all_tasks_for_shot(item) # TODO frame in and out item_data["tasks"] = { @@ -91,10 +101,39 @@ def update_op_assets( or item.get("source_id") ) # TODO check consistency - # Visual parent for hierarchy + # Substitute Episode and Sequence by Shot + project_module_settings = get_project_settings(project_name)["kitsu"] + substitute_item_type = ( + "shots" + if item_type in ["Episode", "Sequence"] + else f"{item_type.lower()}s" + ) + entity_parent_folders = [ + f + for f in project_module_settings["entities_root"] + .get(substitute_item_type) + .split("/") + if f + ] + + # Root parent folder if exist visual_parent_doc_id = ( asset_doc_ids[parent_zou_id]["_id"] if parent_zou_id else None ) + if visual_parent_doc_id is None: + # Find root folder doc + root_folder_doc = project_col.find_one( + { + "type": "asset", + "name": entity_parent_folders[-1], + "data.root_of": substitute_item_type, + }, + ["_id"], + ) + if root_folder_doc: + visual_parent_doc_id = root_folder_doc["_id"] + + # Visual parent for hierarchy item_data["visualParent"] = visual_parent_doc_id # Add parents for hierarchy @@ -107,6 +146,9 @@ def update_op_assets( parent_entity = parent_doc["data"]["zou"] parent_zou_id = parent_entity["parent_id"] + # Set root folders parents + item_data["parents"] = entity_parent_folders + item_data["parents"] + # Update 'data' different in zou DB updated_data = { k: v for k, v in item_data.items() if item_doc["data"].get(k) != v @@ -248,6 +290,30 @@ def sync_project_from_kitsu( } zou_ids_and_asset_docs[project["id"]] = project_doc + # Create entities root folders + project_module_settings = get_project_settings(project_name)["kitsu"] + for entity_type, root in project_module_settings["entities_root"].items(): + parent_folders = root.split("/") + direct_parent_doc = None + for i, folder in enumerate(parent_folders, 1): + parent_doc = project_col.find_one( + {"type": "asset", "name": folder, "data.root_of": entity_type} + ) + if not parent_doc: + direct_parent_doc = project_col.insert_one( + { + "name": folder, + "type": "asset", + "schema": "openpype:asset-3.0", + "data": { + "root_of": entity_type, + "parents": parent_folders[:i], + "visualParent": direct_parent_doc, + "tasks": {}, + }, + } + ) + # Create to_insert = [] to_insert.extend( @@ -275,7 +341,7 @@ def sync_project_from_kitsu( [ UpdateOne({"_id": id}, update) for id, update in update_op_assets( - all_entities, zou_ids_and_asset_docs + project_col, all_entities, zou_ids_and_asset_docs ) ] ) diff --git a/openpype/settings/defaults/project_settings/kitsu.json b/openpype/settings/defaults/project_settings/kitsu.json index 435814a9d1..a37146e1d2 100644 --- a/openpype/settings/defaults/project_settings/kitsu.json +++ b/openpype/settings/defaults/project_settings/kitsu.json @@ -1,4 +1,8 @@ { + "entities_root": { + "assets": "Assets", + "shots": "Shots" + }, "entities_naming_pattern": { "episode": "E##", "sequence": "SQ##", diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json b/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json index a504959001..8d71d0ecd6 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json @@ -5,6 +5,23 @@ "collapsible": true, "is_file": true, "children": [ + { + "type": "dict", + "key": "entities_root", + "label": "Entities root folder", + "children": [ + { + "type": "text", + "key": "assets", + "label": "Assets:" + }, + { + "type": "text", + "key": "shots", + "label": "Shots (includes Episodes & Sequences if any):" + } + ] + }, { "type": "dict", "key": "entities_naming_pattern", From 3970229ce5908abfd62c90a88b656f08f232dbfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Thu, 17 Mar 2022 16:09:15 +0100 Subject: [PATCH 070/350] Fix fps fallback to project's value --- openpype/modules/kitsu/utils/update_op_with_zou.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openpype/modules/kitsu/utils/update_op_with_zou.py b/openpype/modules/kitsu/utils/update_op_with_zou.py index e2ad29bfa0..288efe30da 100644 --- a/openpype/modules/kitsu/utils/update_op_with_zou.py +++ b/openpype/modules/kitsu/utils/update_op_with_zou.py @@ -71,6 +71,10 @@ def update_op_assets( # Asset settings item_data["frameStart"] = item_data.get("frame_in") item_data["frameEnd"] = item_data.get("frame_out") + # Sentinel for fps, fallback to project's value when entity fps is deleted + if not item_data.get("fps") and item_doc["data"].get("fps"): + project_doc = project_col.find_one({"type": "project"}) + item_data["fps"] = project_doc["data"]["fps"] # Tasks tasks_list = [] From 78bda28da4ec26cf4b8b8673cabc01316f578678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Thu, 17 Mar 2022 16:49:13 +0100 Subject: [PATCH 071/350] frame_in/out fallbacks --- .../modules/kitsu/utils/update_op_with_zou.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/openpype/modules/kitsu/utils/update_op_with_zou.py b/openpype/modules/kitsu/utils/update_op_with_zou.py index 288efe30da..f5c6406722 100644 --- a/openpype/modules/kitsu/utils/update_op_with_zou.py +++ b/openpype/modules/kitsu/utils/update_op_with_zou.py @@ -68,10 +68,19 @@ def update_op_assets( item_data.update(item.get("data") or {}) item_data["zou"] = item - # Asset settings - item_data["frameStart"] = item_data.get("frame_in") - item_data["frameEnd"] = item_data.get("frame_out") - # Sentinel for fps, fallback to project's value when entity fps is deleted + # == Asset settings == + # Frame in, fallback on 0 + frame_in = int(item_data.get("frame_in") or 0) + item_data["frameStart"] = frame_in + # Frame out, fallback on frame_in + duration + frames_duration = int(item.get("nb_frames") or 1) + frame_out = ( + item_data["frame_out"] + if item_data.get("frame_out") + else frame_in + frames_duration + ) + item_data["frameEnd"] = int(frame_out) + # Fps, fallback to project's value when entity fps is deleted if not item_data.get("fps") and item_doc["data"].get("fps"): project_doc = project_col.find_one({"type": "project"}) item_data["fps"] = project_doc["data"]["fps"] From 527f4a710dbddd21feac630bdafb7b986a354c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Fri, 25 Mar 2022 10:03:22 +0100 Subject: [PATCH 072/350] Sync only open projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Clément Hector --- openpype/modules/kitsu/utils/update_op_with_zou.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/kitsu/utils/update_op_with_zou.py b/openpype/modules/kitsu/utils/update_op_with_zou.py index f5c6406722..f43223cdf7 100644 --- a/openpype/modules/kitsu/utils/update_op_with_zou.py +++ b/openpype/modules/kitsu/utils/update_op_with_zou.py @@ -256,7 +256,7 @@ def sync_all_project(login: str, password: str): # Iterate projects dbcon = AvalonMongoDB() dbcon.install() - all_projects = gazu.project.all_projects() + all_projects = gazu.project.all_open_projects() for project in all_projects: sync_project_from_kitsu(project["name"], dbcon, project) From 63096b4e6b819081bfc3ea962ea82ab8d2ef507e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 4 May 2022 18:26:58 +0200 Subject: [PATCH 073/350] change avalon API --- openpype/modules/kitsu/utils/sync_service.py | 2 +- openpype/modules/kitsu/utils/update_op_with_zou.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/modules/kitsu/utils/sync_service.py b/openpype/modules/kitsu/utils/sync_service.py index 746cb843e9..01596e2667 100644 --- a/openpype/modules/kitsu/utils/sync_service.py +++ b/openpype/modules/kitsu/utils/sync_service.py @@ -2,7 +2,7 @@ import os import gazu -from avalon.api import AvalonMongoDB +from openpype.pipeline import AvalonMongoDB from .credentials import validate_credentials from .update_op_with_zou import ( create_op_asset, diff --git a/openpype/modules/kitsu/utils/update_op_with_zou.py b/openpype/modules/kitsu/utils/update_op_with_zou.py index f43223cdf7..25c89800d4 100644 --- a/openpype/modules/kitsu/utils/update_op_with_zou.py +++ b/openpype/modules/kitsu/utils/update_op_with_zou.py @@ -10,7 +10,7 @@ from gazu.task import ( all_tasks_for_shot, ) -from avalon.api import AvalonMongoDB +from openpype.pipeline import AvalonMongoDB from openpype.api import get_project_settings from openpype.lib import create_project from openpype.modules.kitsu.utils.credentials import validate_credentials From 0359ec6da4e03bf9c7df49060a423c028195d86c Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Thu, 7 Apr 2022 15:46:40 +0200 Subject: [PATCH 074/350] create kitsu collector --- .../publish/collect_kitsu_credential.py | 18 ++++++ .../plugins/publish/collect_kitsu_entities.py | 64 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 openpype/modules/kitsu/plugins/publish/collect_kitsu_credential.py create mode 100644 openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py diff --git a/openpype/modules/kitsu/plugins/publish/collect_kitsu_credential.py b/openpype/modules/kitsu/plugins/publish/collect_kitsu_credential.py new file mode 100644 index 0000000000..bd0af16c8b --- /dev/null +++ b/openpype/modules/kitsu/plugins/publish/collect_kitsu_credential.py @@ -0,0 +1,18 @@ +import os + +import gazu + +import pyblish.api + + +class CollectKitsuSession(pyblish.api.ContextPlugin): + """Collect Kitsu session using user credentials""" + + order = pyblish.api.CollectorOrder + label = "Kitsu user session" + + + def process(self, context): + + gazu.client.set_host(os.environ["KITSU_SERVER"]) + gazu.log_in(os.environ["KITSU_LOGIN"], os.environ["KITSU_PWD"]) \ No newline at end of file diff --git a/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py new file mode 100644 index 0000000000..e4773f7b2a --- /dev/null +++ b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py @@ -0,0 +1,64 @@ +import os + +import gazu + +import pyblish.api + + +class CollectKitsuEntities(pyblish.api.ContextPlugin): + """Collect Kitsu entities according to the current context""" + + order = pyblish.api.CollectorOrder + 0.499 + label = "Kitsu entities" + + def process(self, context): + + os.environ["AVALON_PROJECT"], + os.environ["AVALON_ASSET"], + os.environ["AVALON_TASK"], + os.environ["AVALON_APP_NAME"] + + asset_data = context.data["assetEntity"]["data"] + zoo_asset_data = asset_data.get("zou") + if not zoo_asset_data: + raise + + kitsu_project = gazu.project.get_project(zoo_asset_data["project_id"]) + if not kitsu_project: + raise + context.data["kitsu_project"] = kitsu_project + + kitsu_asset = gazu.asset.get_asset(zoo_asset_data["entity_type_id"]) + if not kitsu_asset: + raise + context.data["kitsu_asset"] = kitsu_asset + + # kitsu_task_type = gazu.task.get_task_type_by_name(instance.data["task"]) + # if not kitsu_task_type: + # raise + # context.data["kitsu_task_type"] = kitsu_task_type + + zoo_task_data = asset_data["tasks"][os.environ["AVALON_TASK"]].get("zou") + kitsu_task = gazu.task.get_task( + asset_data["zou"], + kitsu_task_type + ) + if not kitsu_task: + raise + context.data["kitsu_task"] = kitsu_task + + wip = gazu.task.get_task_status_by_short_name("wip") + + task = gazu.task.get_task_by_name(asset, modeling) + comment = gazu.task.add_comment(task, wip, "Change status to work in progress") + + person = gazu.person.get_person_by_desktop_login("john.doe") + + # task_type = gazu.task.get_task_type_by_name(instance.data["task"]) + + # entity_task = gazu.task.get_task_by_entity( + # asset_data["zou"], + # task_type + # ) + + raise \ No newline at end of file From 196c81ab78dffdafcca28c00657d11c799a9d7f4 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Fri, 8 Apr 2022 12:03:43 +0200 Subject: [PATCH 075/350] collect all kitsu entities in context --- .../plugins/publish/collect_kitsu_entities.py | 51 ++++++------------- 1 file changed, 15 insertions(+), 36 deletions(-) diff --git a/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py index e4773f7b2a..f599fd0c14 100644 --- a/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py +++ b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py @@ -13,52 +13,31 @@ class CollectKitsuEntities(pyblish.api.ContextPlugin): def process(self, context): - os.environ["AVALON_PROJECT"], - os.environ["AVALON_ASSET"], - os.environ["AVALON_TASK"], - os.environ["AVALON_APP_NAME"] - asset_data = context.data["assetEntity"]["data"] zoo_asset_data = asset_data.get("zou") if not zoo_asset_data: - raise + raise AssertionError("Zoo asset data not found in OpenPype!") + self.log.debug("Collected zoo asset data: {}".format(zoo_asset_data)) + + zoo_task_data = asset_data["tasks"][os.environ["AVALON_TASK"]].get("zou") + if not zoo_task_data: + raise AssertionError("Zoo task data not found in OpenPype!") + self.log.debug("Collected zoo task data: {}".format(zoo_task_data)) kitsu_project = gazu.project.get_project(zoo_asset_data["project_id"]) if not kitsu_project: - raise + raise AssertionError("Project not not found in kitsu!") context.data["kitsu_project"] = kitsu_project + self.log.debug("Collect kitsu project: {}".format(kitsu_project)) - kitsu_asset = gazu.asset.get_asset(zoo_asset_data["entity_type_id"]) + kitsu_asset = gazu.asset.get_asset(zoo_asset_data["id"]) if not kitsu_asset: - raise + raise AssertionError("Asset not not found in kitsu!") context.data["kitsu_asset"] = kitsu_asset + self.log.debug("Collect kitsu asset: {}".format(kitsu_asset)) - # kitsu_task_type = gazu.task.get_task_type_by_name(instance.data["task"]) - # if not kitsu_task_type: - # raise - # context.data["kitsu_task_type"] = kitsu_task_type - - zoo_task_data = asset_data["tasks"][os.environ["AVALON_TASK"]].get("zou") - kitsu_task = gazu.task.get_task( - asset_data["zou"], - kitsu_task_type - ) + kitsu_task = gazu.task.get_task(zoo_task_data["id"]) if not kitsu_task: - raise + raise AssertionError("Task not not found in kitsu!") context.data["kitsu_task"] = kitsu_task - - wip = gazu.task.get_task_status_by_short_name("wip") - - task = gazu.task.get_task_by_name(asset, modeling) - comment = gazu.task.add_comment(task, wip, "Change status to work in progress") - - person = gazu.person.get_person_by_desktop_login("john.doe") - - # task_type = gazu.task.get_task_type_by_name(instance.data["task"]) - - # entity_task = gazu.task.get_task_by_entity( - # asset_data["zou"], - # task_type - # ) - - raise \ No newline at end of file + self.log.debug("Collect kitsu task: {}".format(kitsu_task)) From eb288959f50666e0c9a4751d7908decd540de9de Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Sat, 9 Apr 2022 11:13:48 +0200 Subject: [PATCH 076/350] integrate note and status --- .../publish/collect_kitsu_credential.py | 2 +- .../plugins/publish/integrate_kitsu_note.py | 36 +++++++++++++++++++ .../plugins/publish/integrate_kitsu_review.py | 16 +++++++++ .../plugins/publish/validate_kitsu_intent.py | 27 ++++++++++++++ 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py create mode 100644 openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py create mode 100644 openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py diff --git a/openpype/modules/kitsu/plugins/publish/collect_kitsu_credential.py b/openpype/modules/kitsu/plugins/publish/collect_kitsu_credential.py index bd0af16c8b..c9d94d128a 100644 --- a/openpype/modules/kitsu/plugins/publish/collect_kitsu_credential.py +++ b/openpype/modules/kitsu/plugins/publish/collect_kitsu_credential.py @@ -10,7 +10,7 @@ class CollectKitsuSession(pyblish.api.ContextPlugin): order = pyblish.api.CollectorOrder label = "Kitsu user session" - + # families = ["kitsu"] def process(self, context): diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py new file mode 100644 index 0000000000..5601dea586 --- /dev/null +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py @@ -0,0 +1,36 @@ +import gazu +import pyblish.api + + +class IntegrateKitsuNote(pyblish.api.ContextPlugin): + """Integrate Kitsu Note""" + + order = pyblish.api.IntegratorOrder + label = "Kitsu Note and Status" + # families = ["kitsu"] + optional = True + + def process(self, context): + + publish_comment = context.data.get("comment") + if not publish_comment: + self.log.info("Comment is not set.") + + publish_status = context.data.get("intent", {}).get("value") + if not publish_status: + self.log.info("Status is not set.") + + self.log.debug("Comment is `{}`".format(publish_comment)) + self.log.debug("Status is `{}`".format(publish_status)) + + kitsu_status = context.data.get("kitsu_status") + if not kitsu_status: + self.log.info("The status will not be changed") + kitsu_status = context.data["kitsu_task"].get("task_status") + self.log.debug("Kitsu status: {}".format(kitsu_status)) + + gazu.task.add_comment( + context.data["kitsu_task"], + kitsu_status, + comment = publish_comment + ) \ No newline at end of file diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py new file mode 100644 index 0000000000..1853bf569f --- /dev/null +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py @@ -0,0 +1,16 @@ +# import gazu +import pyblish.api + + +class IntegrateKitsuVersion(pyblish.api.InstancePlugin): + """Integrate Kitsu Review""" + + order = pyblish.api.IntegratorOrder + label = "Kitsu Review" + # families = ["kitsu"] + + def process(self, instance): + pass + + # gazu.task.upload_preview_file(preview, file_path, normalize_movie=True, client=) + # gazu.task.add_preview(task, comment, preview_file_path, normalize_movie=True, client=) \ No newline at end of file diff --git a/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py b/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py new file mode 100644 index 0000000000..9708ebb0dd --- /dev/null +++ b/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py @@ -0,0 +1,27 @@ +from typing import Optional +import pyblish.api +import gazu + + +class IntegrateKitsuNote(pyblish.api.ContextPlugin): + """Integrate Kitsu Note""" + + order = pyblish.api.ValidatorOrder + label = "Kitsu Intent/Status" + # families = ["kitsu"] + optional = True + + def process(self, context): + + publish_status = context.data.get("intent", {}).get("value") + if not publish_status: + self.log.info("Status is not set.") + + kitsu_status = gazu.task.get_task_status_by_short_name(publish_status) + if not kitsu_status: + raise AssertionError( + "Status `{}` not not found in kitsu!".format(kitsu_status) + ) + self.log.debug("Collect kitsu status: {}".format(kitsu_status)) + + context.data["kitsu_status"] = kitsu_status \ No newline at end of file From ff6c8a6a54b2146fce11b78ea7dccf048536d1e8 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Sun, 10 Apr 2022 10:47:11 +0200 Subject: [PATCH 077/350] Add kitsu log out --- .../plugins/publish/collect_kitsu_credential.py | 4 ++-- .../plugins/publish/collect_kitsu_entities.py | 2 +- .../plugins/publish/integrate_kitsu_file.py | 1 + .../plugins/publish/integrate_kitsu_note.py | 1 + .../plugins/publish/integrate_kitsu_review.py | 3 ++- .../kitsu/plugins/publish/other_kitsu_log_out.py | 16 ++++++++++++++++ 6 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 openpype/modules/kitsu/plugins/publish/integrate_kitsu_file.py create mode 100644 openpype/modules/kitsu/plugins/publish/other_kitsu_log_out.py diff --git a/openpype/modules/kitsu/plugins/publish/collect_kitsu_credential.py b/openpype/modules/kitsu/plugins/publish/collect_kitsu_credential.py index c9d94d128a..4a27117e03 100644 --- a/openpype/modules/kitsu/plugins/publish/collect_kitsu_credential.py +++ b/openpype/modules/kitsu/plugins/publish/collect_kitsu_credential.py @@ -1,11 +1,11 @@ +# -*- coding: utf-8 -*- import os import gazu - import pyblish.api -class CollectKitsuSession(pyblish.api.ContextPlugin): +class CollectKitsuSession(pyblish.api.ContextPlugin): #rename log in """Collect Kitsu session using user credentials""" order = pyblish.api.CollectorOrder diff --git a/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py index f599fd0c14..c5df20b349 100644 --- a/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py +++ b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py @@ -1,7 +1,7 @@ +# -*- coding: utf-8 -*- import os import gazu - import pyblish.api diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_file.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_file.py new file mode 100644 index 0000000000..7c68785e9d --- /dev/null +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_file.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- \ No newline at end of file diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py index 5601dea586..8844581237 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- import gazu import pyblish.api diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py index 1853bf569f..a800ca9b57 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py @@ -1,4 +1,5 @@ -# import gazu +# -*- coding: utf-8 -*- +import gazu import pyblish.api diff --git a/openpype/modules/kitsu/plugins/publish/other_kitsu_log_out.py b/openpype/modules/kitsu/plugins/publish/other_kitsu_log_out.py new file mode 100644 index 0000000000..ff76d9c4f6 --- /dev/null +++ b/openpype/modules/kitsu/plugins/publish/other_kitsu_log_out.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +""".""" +import gazu +import pyblish.api + + +class KitsuLogOut(pyblish.api.ContextPlugin): + """ + Log out from Kitsu API + """ + + order = pyblish.api.IntegratorOrder + 10 + label = "Kitsu Log Out" + + def process(self, context): + gazu.client.log_out() From ed8c01c2639321126b43d84ad83bd06496cb1bad Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Wed, 20 Apr 2022 11:57:33 +0200 Subject: [PATCH 078/350] upload file to kitsu --- .../plugins/publish/integrate_kitsu_note.py | 8 ++++--- .../plugins/publish/integrate_kitsu_review.py | 24 +++++++++++++++---- .../plugins/publish/validate_kitsu_intent.py | 5 ++-- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py index 8844581237..afe388fd82 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py @@ -9,7 +9,7 @@ class IntegrateKitsuNote(pyblish.api.ContextPlugin): order = pyblish.api.IntegratorOrder label = "Kitsu Note and Status" # families = ["kitsu"] - optional = True + # optional = True def process(self, context): @@ -30,8 +30,10 @@ class IntegrateKitsuNote(pyblish.api.ContextPlugin): kitsu_status = context.data["kitsu_task"].get("task_status") self.log.debug("Kitsu status: {}".format(kitsu_status)) - gazu.task.add_comment( + kitsu_comment = gazu.task.add_comment( context.data["kitsu_task"], kitsu_status, comment = publish_comment - ) \ No newline at end of file + ) + + context.data["kitsu_comment"] = kitsu_comment \ No newline at end of file diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py index a800ca9b57..e69937e9bf 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import os import gazu import pyblish.api @@ -6,12 +7,27 @@ import pyblish.api class IntegrateKitsuVersion(pyblish.api.InstancePlugin): """Integrate Kitsu Review""" - order = pyblish.api.IntegratorOrder + order = pyblish.api.IntegratorOrder + 0.01 label = "Kitsu Review" # families = ["kitsu"] def process(self, instance): - pass - # gazu.task.upload_preview_file(preview, file_path, normalize_movie=True, client=) - # gazu.task.add_preview(task, comment, preview_file_path, normalize_movie=True, client=) \ No newline at end of file + context = instance.context + task = context.data["kitsu_task"] + comment = context.data["kitsu_comment"] + + for representation in instance.data.get("representations", []): + + local_path = representation.get("published_path") + self.log.info("*"*40) + self.log.info(local_path) + self.log.info(representation.get("tags", [])) + + # code = os.path.basename(local_path) + + if representation.get("tags", []): + continue + + # gazu.task.upload_preview_file(preview, file_path, normalize_movie=True) + gazu.task.add_preview(task, comment, local_path, normalize_movie=True) \ No newline at end of file diff --git a/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py b/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py index 9708ebb0dd..0597e8546a 100644 --- a/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py +++ b/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py @@ -1,10 +1,9 @@ -from typing import Optional import pyblish.api import gazu -class IntegrateKitsuNote(pyblish.api.ContextPlugin): - """Integrate Kitsu Note""" +class ValidateKitsuIntent(pyblish.api.ContextPlugin): + """Validate Kitsu Status""" order = pyblish.api.ValidatorOrder label = "Kitsu Intent/Status" From 2e0f6ce42d631674d910dc3caffc1654b6d781f2 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Wed, 20 Apr 2022 17:47:17 +0200 Subject: [PATCH 079/350] use task type if no task data in OP --- .../plugins/publish/collect_kitsu_entities.py | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py index c5df20b349..c907c22e0f 100644 --- a/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py +++ b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py @@ -21,7 +21,7 @@ class CollectKitsuEntities(pyblish.api.ContextPlugin): zoo_task_data = asset_data["tasks"][os.environ["AVALON_TASK"]].get("zou") if not zoo_task_data: - raise AssertionError("Zoo task data not found in OpenPype!") + self.log.warning("Zoo task data not found in OpenPype!") self.log.debug("Collected zoo task data: {}".format(zoo_task_data)) kitsu_project = gazu.project.get_project(zoo_asset_data["project_id"]) @@ -36,8 +36,29 @@ class CollectKitsuEntities(pyblish.api.ContextPlugin): context.data["kitsu_asset"] = kitsu_asset self.log.debug("Collect kitsu asset: {}".format(kitsu_asset)) - kitsu_task = gazu.task.get_task(zoo_task_data["id"]) - if not kitsu_task: - raise AssertionError("Task not not found in kitsu!") - context.data["kitsu_task"] = kitsu_task - self.log.debug("Collect kitsu task: {}".format(kitsu_task)) + if zoo_task_data: + kitsu_task = gazu.task.get_task(zoo_task_data["id"]) + if not kitsu_task: + raise AssertionError("Task not not found in kitsu!") + context.data["kitsu_task"] = kitsu_task + self.log.debug("Collect kitsu task: {}".format(kitsu_task)) + + else: + kitsu_task_type = gazu.task.get_task_type_by_name( + os.environ["AVALON_TASK"] + ) + if not kitsu_task_type: + raise AssertionError( + "Task type {} not found in Kitsu!".format( + os.environ["AVALON_TASK"] + ) + ) + + kitsu_task = gazu.task.get_task_by_name( + kitsu_asset, + kitsu_task_type + ) + if not kitsu_task: + raise AssertionError("Task not not found in kitsu!") + context.data["kitsu_task"] = kitsu_task + self.log.debug("Collect kitsu task: {}".format(kitsu_task)) \ No newline at end of file From f72cb8ba9e6201be23f09515e3e3190408fc30a0 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Wed, 20 Apr 2022 17:56:39 +0200 Subject: [PATCH 080/350] fix log out --- openpype/modules/kitsu/plugins/publish/other_kitsu_log_out.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/kitsu/plugins/publish/other_kitsu_log_out.py b/openpype/modules/kitsu/plugins/publish/other_kitsu_log_out.py index ff76d9c4f6..d7e1616f8d 100644 --- a/openpype/modules/kitsu/plugins/publish/other_kitsu_log_out.py +++ b/openpype/modules/kitsu/plugins/publish/other_kitsu_log_out.py @@ -13,4 +13,4 @@ class KitsuLogOut(pyblish.api.ContextPlugin): label = "Kitsu Log Out" def process(self, context): - gazu.client.log_out() + gazu.log_out() From 3d6a6fcbf065c5ed000aea43c7ce4b5db91cd47a Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Wed, 20 Apr 2022 18:10:58 +0200 Subject: [PATCH 081/350] upload review --- .../plugins/publish/integrate_kitsu_review.py | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py index e69937e9bf..23ee4a668e 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py @@ -1,15 +1,17 @@ # -*- coding: utf-8 -*- import os +from typing import Optional import gazu import pyblish.api -class IntegrateKitsuVersion(pyblish.api.InstancePlugin): +class IntegrateKitsuReview(pyblish.api.InstancePlugin): """Integrate Kitsu Review""" order = pyblish.api.IntegratorOrder + 0.01 label = "Kitsu Review" # families = ["kitsu"] + optional = True def process(self, instance): @@ -20,14 +22,16 @@ class IntegrateKitsuVersion(pyblish.api.InstancePlugin): for representation in instance.data.get("representations", []): local_path = representation.get("published_path") - self.log.info("*"*40) - self.log.info(local_path) - self.log.info(representation.get("tags", [])) - # code = os.path.basename(local_path) - - if representation.get("tags", []): + if 'review' not in representation.get("tags", []): continue - # gazu.task.upload_preview_file(preview, file_path, normalize_movie=True) - gazu.task.add_preview(task, comment, local_path, normalize_movie=True) \ No newline at end of file + self.log.debug("Found review at: {}".format(local_path)) + + gazu.task.add_preview( + task, + comment, + local_path, + normalize_movie=True + ) + self.log.info("Review upload on comment") From db8719b895cf553de6f24ad80f610fff28acfc21 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Wed, 20 Apr 2022 18:11:38 +0200 Subject: [PATCH 082/350] remove unused import --- .../modules/kitsu/plugins/publish/integrate_kitsu_review.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py index 23ee4a668e..59b3bcf53e 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py @@ -1,6 +1,4 @@ # -*- coding: utf-8 -*- -import os -from typing import Optional import gazu import pyblish.api From 7787056c969b0ca91f2f1eee1d58c6c92de2e4f8 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Wed, 20 Apr 2022 18:14:14 +0200 Subject: [PATCH 083/350] Do some cleanup --- .../plugins/publish/collect_kitsu_entities.py | 37 +++++++------- .../plugins/publish/integrate_kitsu_file.py | 1 - .../plugins/publish/integrate_kitsu_note.py | 5 +- .../plugins/publish/integrate_kitsu_review.py | 8 +-- .../kitsu/plugins/publish/kitsu_plugin.py | 49 ------------------- .../plugins/publish/other_kitsu_log_out.py | 1 - .../plugins/publish/validate_kitsu_intent.py | 5 +- 7 files changed, 28 insertions(+), 78 deletions(-) delete mode 100644 openpype/modules/kitsu/plugins/publish/integrate_kitsu_file.py delete mode 100644 openpype/modules/kitsu/plugins/publish/kitsu_plugin.py diff --git a/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py index c907c22e0f..935b020641 100644 --- a/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py +++ b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py @@ -14,35 +14,36 @@ class CollectKitsuEntities(pyblish.api.ContextPlugin): def process(self, context): asset_data = context.data["assetEntity"]["data"] - zoo_asset_data = asset_data.get("zou") - if not zoo_asset_data: - raise AssertionError("Zoo asset data not found in OpenPype!") - self.log.debug("Collected zoo asset data: {}".format(zoo_asset_data)) + zou_asset_data = asset_data.get("zou") + if not zou_asset_data: + raise AssertionError("Zou asset data not found in OpenPype!") + self.log.debug("Collected zou asset data: {}".format(zou_asset_data)) - zoo_task_data = asset_data["tasks"][os.environ["AVALON_TASK"]].get("zou") - if not zoo_task_data: - self.log.warning("Zoo task data not found in OpenPype!") - self.log.debug("Collected zoo task data: {}".format(zoo_task_data)) + zou_task_data = asset_data["tasks"][ + os.environ["AVALON_TASK"]].get("zou") + if not zou_task_data: + self.log.warning("Zou task data not found in OpenPype!") + self.log.debug("Collected zou task data: {}".format(zou_task_data)) - kitsu_project = gazu.project.get_project(zoo_asset_data["project_id"]) + kitsu_project = gazu.project.get_project(zou_asset_data["project_id"]) if not kitsu_project: - raise AssertionError("Project not not found in kitsu!") + raise AssertionError("Project not found in kitsu!") context.data["kitsu_project"] = kitsu_project self.log.debug("Collect kitsu project: {}".format(kitsu_project)) - kitsu_asset = gazu.asset.get_asset(zoo_asset_data["id"]) + kitsu_asset = gazu.asset.get_asset(zou_asset_data["id"]) if not kitsu_asset: - raise AssertionError("Asset not not found in kitsu!") + raise AssertionError("Asset not found in kitsu!") context.data["kitsu_asset"] = kitsu_asset self.log.debug("Collect kitsu asset: {}".format(kitsu_asset)) - if zoo_task_data: - kitsu_task = gazu.task.get_task(zoo_task_data["id"]) + if zou_task_data: + kitsu_task = gazu.task.get_task(zou_task_data["id"]) if not kitsu_task: - raise AssertionError("Task not not found in kitsu!") + raise AssertionError("Task not found in kitsu!") context.data["kitsu_task"] = kitsu_task self.log.debug("Collect kitsu task: {}".format(kitsu_task)) - + else: kitsu_task_type = gazu.task.get_task_type_by_name( os.environ["AVALON_TASK"] @@ -59,6 +60,6 @@ class CollectKitsuEntities(pyblish.api.ContextPlugin): kitsu_task_type ) if not kitsu_task: - raise AssertionError("Task not not found in kitsu!") + raise AssertionError("Task not found in kitsu!") context.data["kitsu_task"] = kitsu_task - self.log.debug("Collect kitsu task: {}".format(kitsu_task)) \ No newline at end of file + self.log.debug("Collect kitsu task: {}".format(kitsu_task)) diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_file.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_file.py deleted file mode 100644 index 7c68785e9d..0000000000 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_file.py +++ /dev/null @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- \ No newline at end of file diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py index afe388fd82..61e4d2454c 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py @@ -9,7 +9,6 @@ class IntegrateKitsuNote(pyblish.api.ContextPlugin): order = pyblish.api.IntegratorOrder label = "Kitsu Note and Status" # families = ["kitsu"] - # optional = True def process(self, context): @@ -31,8 +30,8 @@ class IntegrateKitsuNote(pyblish.api.ContextPlugin): self.log.debug("Kitsu status: {}".format(kitsu_status)) kitsu_comment = gazu.task.add_comment( - context.data["kitsu_task"], - kitsu_status, + context.data["kitsu_task"], + kitsu_status, comment = publish_comment ) diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py index 59b3bcf53e..c38f14e8a4 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py @@ -19,17 +19,17 @@ class IntegrateKitsuReview(pyblish.api.InstancePlugin): for representation in instance.data.get("representations", []): - local_path = representation.get("published_path") + review_path = representation.get("published_path") if 'review' not in representation.get("tags", []): continue - - self.log.debug("Found review at: {}".format(local_path)) + + self.log.debug("Found review at: {}".format(review_path)) gazu.task.add_preview( task, comment, - local_path, + review_path, normalize_movie=True ) self.log.info("Review upload on comment") diff --git a/openpype/modules/kitsu/plugins/publish/kitsu_plugin.py b/openpype/modules/kitsu/plugins/publish/kitsu_plugin.py deleted file mode 100644 index 5d6c76bc3f..0000000000 --- a/openpype/modules/kitsu/plugins/publish/kitsu_plugin.py +++ /dev/null @@ -1,49 +0,0 @@ -import os - -import gazu - -import pyblish.api - - -class CollectExampleAddon(pyblish.api.ContextPlugin): - order = pyblish.api.CollectorOrder + 0.4 - label = "Collect Kitsu" - - def process(self, context): - self.log.info("I'm in Kitsu's plugin!") - - -class IntegrateRig(pyblish.api.InstancePlugin): - """Copy files to an appropriate location where others may reach it""" - - order = pyblish.api.IntegratorOrder - families = ["model"] - - def process(self, instance): - - # Connect to server - gazu.client.set_host(os.environ["KITSU_SERVER"]) - - # Authenticate - gazu.log_in(os.environ["KITSU_LOGIN"], os.environ["KITSU_PWD"]) - - asset_data = instance.data["assetEntity"]["data"] - - # Get task - task_type = gazu.task.get_task_type_by_name(instance.data["task"]) - entity_task = gazu.task.get_task_by_entity( - asset_data["zou"], task_type - ) - - # Comment entity - gazu.task.add_comment( - entity_task, - entity_task["task_status_id"], - comment="Version {} has been published!\n".format( - instance.data["version"] - ) - # Add written comment in Pyblish - + "\n{}".format(instance.data["versionEntity"]["data"]["comment"]), - ) - - self.log.info("Version published to Kitsu successfully!") diff --git a/openpype/modules/kitsu/plugins/publish/other_kitsu_log_out.py b/openpype/modules/kitsu/plugins/publish/other_kitsu_log_out.py index d7e1616f8d..c4a5b390e0 100644 --- a/openpype/modules/kitsu/plugins/publish/other_kitsu_log_out.py +++ b/openpype/modules/kitsu/plugins/publish/other_kitsu_log_out.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -""".""" import gazu import pyblish.api diff --git a/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py b/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py index 0597e8546a..c82130b33b 100644 --- a/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py +++ b/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- import pyblish.api import gazu @@ -9,7 +10,7 @@ class ValidateKitsuIntent(pyblish.api.ContextPlugin): label = "Kitsu Intent/Status" # families = ["kitsu"] optional = True - + def process(self, context): publish_status = context.data.get("intent", {}).get("value") @@ -19,7 +20,7 @@ class ValidateKitsuIntent(pyblish.api.ContextPlugin): kitsu_status = gazu.task.get_task_status_by_short_name(publish_status) if not kitsu_status: raise AssertionError( - "Status `{}` not not found in kitsu!".format(kitsu_status) + "Status `{}` not found in kitsu!".format(kitsu_status) ) self.log.debug("Collect kitsu status: {}".format(kitsu_status)) From d9062b762ab82b85fb048084ef27ebf863a92366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Thu, 5 May 2022 11:49:16 +0200 Subject: [PATCH 084/350] Update openpype/modules/kitsu/utils/update_zou_with_op.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/modules/kitsu/utils/update_zou_with_op.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/kitsu/utils/update_zou_with_op.py b/openpype/modules/kitsu/utils/update_zou_with_op.py index d1fcde5601..526159d101 100644 --- a/openpype/modules/kitsu/utils/update_zou_with_op.py +++ b/openpype/modules/kitsu/utils/update_zou_with_op.py @@ -6,7 +6,7 @@ from typing import List import gazu from pymongo import UpdateOne -from avalon.api import AvalonMongoDB +from openpype.pipeline import AvalonMongoDB from openpype.api import get_project_settings from openpype.modules.kitsu.utils.credentials import validate_credentials From 19b6cb7b6cbee03b60cf3d152af322a914f35514 Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Thu, 5 May 2022 18:05:22 +0200 Subject: [PATCH 085/350] concatenation output formats fix --- .../plugins/publish/extract_review_slate.py | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 59150e9d4a..77b40b785d 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -226,13 +226,15 @@ class ExtractReviewSlate(openpype.api.Extractor): )) input_args.extend(["-timecode {}".format(offset_timecode)]) if use_legacy_code: + format_args = [] codec_args = repre["_profile"].get('codec', []) output_args.extend(codec_args) # preset's output data output_args.extend(repre["_profile"].get('output', [])) else: # Codecs are copied from source for whole input - codec_args = self._get_codec_args(repre) + format_args, codec_args = self._get_format_codec_args(repre) + output_args.extend(format_args) output_args.extend(codec_args) # make sure colors are correct @@ -338,6 +340,11 @@ class ExtractReviewSlate(openpype.api.Extractor): "-c", "copy", "-timecode", offset_timecode, ] + # NOTE: Added because of OP Atom demuxers + # Add format arguments if there are any + # - keep format of output + if format_args: + concat_args.extend(format_args) # Use arguments from ffmpeg preset source_ffmpeg_cmd = repre.get("ffmpeg_cmd") if source_ffmpeg_cmd: @@ -351,7 +358,7 @@ class ExtractReviewSlate(openpype.api.Extractor): concat_args.append(arg) # assumes arg has one parameter concat_args.append(args[indx + 1]) - # add output + # add final output path concat_args.append(output_path) if not input_audio: @@ -431,7 +438,7 @@ class ExtractReviewSlate(openpype.api.Extractor): return vf_back - def _get_codec_args(self, repre): +def _get_format_codec_args(self, repre): """Detect possible codec arguments from representation.""" codec_args = [] @@ -454,16 +461,12 @@ class ExtractReviewSlate(openpype.api.Extractor): return codec_args source_ffmpeg_cmd = repre.get("ffmpeg_cmd") - codec_args.extend( - get_ffmpeg_format_args(ffprobe_data, source_ffmpeg_cmd) - ) - codec_args.extend( - get_ffmpeg_codec_args( - ffprobe_data, source_ffmpeg_cmd, logger=self.log - ) + format_args = get_ffmpeg_format_args(ffprobe_data, source_ffmpeg_cmd) + codec_args = get_ffmpeg_codec_args( + ffprobe_data, source_ffmpeg_cmd, logger=self.log ) - return codec_args + return format_args, codec_args def _tc_offset(self, timecode, framerate=24.0, frame_offset=-1): """Offsets timecode by frame""" From 2e7c82316a24d98c152d5571e20bcde512a1924e Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Thu, 5 May 2022 18:06:43 +0200 Subject: [PATCH 086/350] mad dog fix --- openpype/plugins/publish/extract_review_slate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 77b40b785d..17ac4b68bc 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -438,6 +438,7 @@ class ExtractReviewSlate(openpype.api.Extractor): return vf_back + def _get_format_codec_args(self, repre): """Detect possible codec arguments from representation.""" codec_args = [] From fe514cf385bf99683ef87d0fa78bd022f9fa69dd Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Thu, 5 May 2022 19:30:38 +0200 Subject: [PATCH 087/350] more fixes --- openpype/plugins/publish/extract_review_slate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 17ac4b68bc..832799601c 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -439,7 +439,7 @@ class ExtractReviewSlate(openpype.api.Extractor): return vf_back -def _get_format_codec_args(self, repre): + def _get_format_codec_args(self, repre): """Detect possible codec arguments from representation.""" codec_args = [] From 40d487221aa0ff0c60e89132db6aad7b95a31aa4 Mon Sep 17 00:00:00 2001 From: DMO Date: Sat, 7 May 2022 08:05:59 +0900 Subject: [PATCH 088/350] OP/MV: Export correct node , export composition with absolute path. --- .../maya/plugins/publish/extract_multiverse_usd.py | 6 ------ .../plugins/publish/extract_multiverse_usd_comp.py | 12 ++++++------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py index 4e4efdc32c..9726c7e14c 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py @@ -149,12 +149,6 @@ class ExtractMultiverseUsd(openpype.api.Extractor): with maintained_selection(): members = instance.data("setMembers") - members = cmds.ls(members, - dag=True, - shapes=True, - type=("mesh"), - noIntermediate=True, - long=True) self.log.info('Collected object {}'.format(members)) import multiverse diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py index 8fccc412e6..685e3d4592 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py @@ -90,12 +90,6 @@ class ExtractMultiverseUsdComposition(openpype.api.Extractor): with maintained_selection(): members = instance.data("setMembers") - members = cmds.ls(members, - dag=True, - shapes=True, - type="mvUsdCompoundShape", - noIntermediate=True, - long=True) self.log.info('Collected object {}'.format(members)) import multiverse @@ -119,6 +113,12 @@ class ExtractMultiverseUsdComposition(openpype.api.Extractor): time_opts.framePerSecond = fps comp_write_opts = multiverse.CompositionWriteOptions() + if not hasattr(comp_write_opts,"forceAbsolutePaths"): + self.log.warning("multiverse.CompositionWriteOptions is " + + "missing forceAbsolutePaths', extract will yield " + + "inccorect reference paths.") + else: + comp_write_opts.forceAbsolutePaths = True options_discard_keys = { 'numTimeSamples', 'timeSamplesSpan', From b796c2563decaf953f130e93df75d79d8dae54d2 Mon Sep 17 00:00:00 2001 From: DMO Date: Mon, 9 May 2022 16:52:51 +0900 Subject: [PATCH 089/350] PEP Formatting and typo fixing. --- .../maya/plugins/publish/extract_multiverse_usd_comp.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py index 685e3d4592..7bd7768da6 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py @@ -113,10 +113,10 @@ class ExtractMultiverseUsdComposition(openpype.api.Extractor): time_opts.framePerSecond = fps comp_write_opts = multiverse.CompositionWriteOptions() - if not hasattr(comp_write_opts,"forceAbsolutePaths"): + if not hasattr(comp_write_opts, "forceAbsolutePaths"): self.log.warning("multiverse.CompositionWriteOptions is " + - "missing forceAbsolutePaths', extract will yield " + - "inccorect reference paths.") + "missing 'forceAbsolutePaths', extract " + + "will yield incorrect reference paths.") else: comp_write_opts.forceAbsolutePaths = True options_discard_keys = { From 8bb0c2779113aaa4ec1b8681a3d89232912fface Mon Sep 17 00:00:00 2001 From: DMO Date: Mon, 9 May 2022 17:21:47 +0900 Subject: [PATCH 090/350] Removing attr check and explaining in a comment. --- .../publish/extract_multiverse_usd_comp.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py index 7bd7768da6..e6bc0c68b5 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py @@ -113,12 +113,18 @@ class ExtractMultiverseUsdComposition(openpype.api.Extractor): time_opts.framePerSecond = fps comp_write_opts = multiverse.CompositionWriteOptions() - if not hasattr(comp_write_opts, "forceAbsolutePaths"): - self.log.warning("multiverse.CompositionWriteOptions is " + - "missing 'forceAbsolutePaths', extract " + - "will yield incorrect reference paths.") - else: - comp_write_opts.forceAbsolutePaths = True + + """ + OP tells MV to write to a staging directory, and then moves the + file to it's final publish directory. By default, MV write relative + paths, but these paths will break when the referencing file moves. + This option forces writes to absolute paths, which is ok within OP + because all published assets have static paths, and MV can only + reference published assets. When a proper UsdAssetResolver is used, + this won't be needed. + """ + comp_write_opts.forceAbsolutePaths = True + options_discard_keys = { 'numTimeSamples', 'timeSamplesSpan', From 7cf7f5ee7434c0a818a161de74677422f0a4f667 Mon Sep 17 00:00:00 2001 From: DMO Date: Tue, 10 May 2022 12:18:52 +0900 Subject: [PATCH 091/350] Adding support for choosing .usd/.usda/.usdz. Fix a bug in extract override where it was selecting a locator that shouldn't be selected. --- .../plugins/create/create_multiverse_usd.py | 3 ++- .../create/create_multiverse_usd_comp.py | 1 + .../create/create_multiverse_usd_over.py | 3 ++- .../plugins/publish/extract_multiverse_usd.py | 18 ++++++++++----- .../publish/extract_multiverse_usd_comp.py | 18 ++++++++++----- .../publish/extract_multiverse_usd_over.py | 22 +++++++++++++------ 6 files changed, 46 insertions(+), 19 deletions(-) diff --git a/openpype/hosts/maya/plugins/create/create_multiverse_usd.py b/openpype/hosts/maya/plugins/create/create_multiverse_usd.py index b2266e5a57..e64d7d90b8 100644 --- a/openpype/hosts/maya/plugins/create/create_multiverse_usd.py +++ b/openpype/hosts/maya/plugins/create/create_multiverse_usd.py @@ -2,7 +2,7 @@ from openpype.hosts.maya.api import plugin, lib class CreateMultiverseUsd(plugin.Creator): - """Multiverse USD data""" + """Create Multiverse USD Asset""" name = "usdMain" label = "Multiverse USD" @@ -15,6 +15,7 @@ class CreateMultiverseUsd(plugin.Creator): # Add animation data first, since it maintains order. self.data.update(lib.collect_animation_data(True)) + self.data["fileFormat"] = ["usd", "usda", "usdz"] self.data["stripNamespaces"] = False self.data["mergeTransformAndShape"] = False self.data["writeAncestors"] = True diff --git a/openpype/hosts/maya/plugins/create/create_multiverse_usd_comp.py b/openpype/hosts/maya/plugins/create/create_multiverse_usd_comp.py index 77b808c459..accdffad46 100644 --- a/openpype/hosts/maya/plugins/create/create_multiverse_usd_comp.py +++ b/openpype/hosts/maya/plugins/create/create_multiverse_usd_comp.py @@ -15,6 +15,7 @@ class CreateMultiverseUsdComp(plugin.Creator): # Add animation data first, since it maintains order. self.data.update(lib.collect_animation_data(True)) + self.data["fileFormat"] = ["usd", "usda"] self.data["stripNamespaces"] = False self.data["mergeTransformAndShape"] = False self.data["flattenContent"] = False diff --git a/openpype/hosts/maya/plugins/create/create_multiverse_usd_over.py b/openpype/hosts/maya/plugins/create/create_multiverse_usd_over.py index bb82ab2039..25892f68bb 100644 --- a/openpype/hosts/maya/plugins/create/create_multiverse_usd_over.py +++ b/openpype/hosts/maya/plugins/create/create_multiverse_usd_over.py @@ -2,7 +2,7 @@ from openpype.hosts.maya.api import plugin, lib class CreateMultiverseUsdOver(plugin.Creator): - """Multiverse USD data""" + """Create Multiverse USD Override""" name = "usdOverrideMain" label = "Multiverse USD Override" @@ -15,6 +15,7 @@ class CreateMultiverseUsdOver(plugin.Creator): # Add animation data first, since it maintains order. self.data.update(lib.collect_animation_data(True)) + self.data["fileFormat"] = ["usd", "usda"] self.data["writeAll"] = False self.data["writeTransforms"] = True self.data["writeVisibility"] = True diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py index 9726c7e14c..74fcf2bee7 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py @@ -13,6 +13,8 @@ class ExtractMultiverseUsd(openpype.api.Extractor): label = "Extract Multiverse USD" hosts = ["maya"] families = ["usd"] + scene_type = "usd" + file_formats = ["usd", "usda", "usdz"] @property def options(self): @@ -129,13 +131,19 @@ class ExtractMultiverseUsd(openpype.api.Extractor): return options + def get_file_format(self, instance): + fileFormat = instance.data["fileFormat"] + if fileFormat in range(len(self.file_formats)): + self.scene_type = self.file_formats[fileFormat] + def process(self, instance): - # Load plugin firstly + # Load plugin first cmds.loadPlugin("MultiverseForMaya", quiet=True) # Define output file path staging_dir = self.staging_dir(instance) - file_name = "{}.usd".format(instance.name) + self.get_file_format(instance) + file_name = "{0}.{1}".format(instance.name, self.scene_type) file_path = os.path.join(staging_dir, file_name) file_path = file_path.replace('\\', '/') @@ -193,10 +201,10 @@ class ExtractMultiverseUsd(openpype.api.Extractor): instance.data["representations"] = [] representation = { - 'name': 'usd', - 'ext': 'usd', + 'name': self.scene_type, + 'ext': self.scene_type, 'files': file_name, - "stagingDir": staging_dir + 'stagingDir': staging_dir } instance.data["representations"].append(representation) diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py index e6bc0c68b5..c686b2a600 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py @@ -12,6 +12,8 @@ class ExtractMultiverseUsdComposition(openpype.api.Extractor): label = "Extract Multiverse USD Composition" hosts = ["maya"] families = ["usdComposition"] + scene_type = "usd" + file_formats = ["usd", "usda"] @property def options(self): @@ -70,13 +72,19 @@ class ExtractMultiverseUsdComposition(openpype.api.Extractor): return options + def get_file_format(self, instance): + fileFormat = instance.data["fileFormat"] + if fileFormat in range(len(self.file_formats)): + self.scene_type = self.file_formats[fileFormat] + def process(self, instance): - # Load plugin firstly + # Load plugin first cmds.loadPlugin("MultiverseForMaya", quiet=True) # Define output file path staging_dir = self.staging_dir(instance) - file_name = "{}.usd".format(instance.name) + self.get_file_format(instance) + file_name = "{0}.{1}".format(instance.name, self.scene_type) file_path = os.path.join(staging_dir, file_name) file_path = file_path.replace('\\', '/') @@ -146,10 +154,10 @@ class ExtractMultiverseUsdComposition(openpype.api.Extractor): instance.data["representations"] = [] representation = { - 'name': 'usd', - 'ext': 'usd', + 'name': self.scene_type, + 'ext': self.scene_type, 'files': file_name, - "stagingDir": staging_dir + 'stagingDir': staging_dir } instance.data["representations"].append(representation) diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py index ce0e8a392a..77680d09f9 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py @@ -12,6 +12,8 @@ class ExtractMultiverseUsdOverride(openpype.api.Extractor): label = "Extract Multiverse USD Override" hosts = ["maya"] families = ["usdOverride"] + scene_type = "usd" + file_formats = ["usd", "usda"] @property def options(self): @@ -57,13 +59,19 @@ class ExtractMultiverseUsdOverride(openpype.api.Extractor): "timeSamplesSpan": 0.0 } + def get_file_format(self, instance): + fileFormat = instance.data["fileFormat"] + if fileFormat in range(len(self.file_formats)): + self.scene_type = self.file_formats[fileFormat] + def process(self, instance): - # Load plugin firstly + # Load plugin first cmds.loadPlugin("MultiverseForMaya", quiet=True) # Define output file path staging_dir = self.staging_dir(instance) - file_name = "{}.usda".format(instance.name) + self.get_file_format(instance) + file_name = "{0}.{1}".format(instance.name, self.scene_type) file_path = os.path.join(staging_dir, file_name) file_path = file_path.replace("\\", "/") @@ -78,7 +86,7 @@ class ExtractMultiverseUsdOverride(openpype.api.Extractor): members = instance.data("setMembers") members = cmds.ls(members, dag=True, - shapes=True, + shapes=False, type="mvUsdCompoundShape", noIntermediate=True, long=True) @@ -128,10 +136,10 @@ class ExtractMultiverseUsdOverride(openpype.api.Extractor): instance.data["representations"] = [] representation = { - "name": "usd", - "ext": "usd", - "files": file_name, - "stagingDir": staging_dir + 'name': self.scene_type, + 'ext': self.scene_type, + 'files': file_name, + 'stagingDir': staging_dir } instance.data["representations"].append(representation) From f7fc6a3e7007d80d0f75ccedcf381267c676f089 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 10 May 2022 16:52:13 +0200 Subject: [PATCH 092/350] flame: fixing attr_name issue --- openpype/hosts/flame/api/lib.py | 2 +- openpype/hosts/flame/otio/flame_export.py | 91 +++++------------------ 2 files changed, 21 insertions(+), 72 deletions(-) diff --git a/openpype/hosts/flame/api/lib.py b/openpype/hosts/flame/api/lib.py index c7c444c1fb..2e9b535764 100644 --- a/openpype/hosts/flame/api/lib.py +++ b/openpype/hosts/flame/api/lib.py @@ -560,7 +560,7 @@ def get_segment_attributes(segment): if not hasattr(segment, attr_name): continue attr = getattr(segment, attr_name) - segment_attrs_data[attr] = str(attr).replace("+", ":") + segment_attrs_data[attr_name] = str(attr).replace("+", ":") if attr_name in ["record_in", "record_out"]: clip_data[attr_name] = attr.relative_frame diff --git a/openpype/hosts/flame/otio/flame_export.py b/openpype/hosts/flame/otio/flame_export.py index 4fe05ec1d8..d84ee98256 100644 --- a/openpype/hosts/flame/otio/flame_export.py +++ b/openpype/hosts/flame/otio/flame_export.py @@ -94,83 +94,30 @@ def create_otio_time_range(start_frame, frame_duration, fps): def _get_metadata(item): if hasattr(item, 'metadata'): - if not item.metadata: - return {} - return {key: value for key, value in dict(item.metadata)} + return dict(dict(item.metadata)) if item.metadata else {} return {} -def create_time_effects(otio_clip, item): - # todo #2426: add retiming effects to export - # get all subtrack items - # subTrackItems = flatten(track_item.parent().subTrackItems()) - # speed = track_item.playbackSpeed() +# def create_time_effects(otio_clip, clip_data): +# otio_effect = None - # otio_effect = None - # # retime on track item - # if speed != 1.: - # # make effect - # otio_effect = otio.schema.LinearTimeWarp() - # otio_effect.name = "Speed" - # otio_effect.time_scalar = speed - # otio_effect.metadata = {} +# # retime on track item +# if speed != 1.: +# # make effect +# otio_effect = otio.schema.LinearTimeWarp() +# otio_effect.name = "Speed" +# otio_effect.time_scalar = speed +# otio_effect.metadata = {} - # # freeze frame effect - # if speed == 0.: - # otio_effect = otio.schema.FreezeFrame() - # otio_effect.name = "FreezeFrame" - # otio_effect.metadata = {} +# # freeze frame effect +# if speed == 0.: +# otio_effect = otio.schema.FreezeFrame() +# otio_effect.name = "FreezeFrame" +# otio_effect.metadata = {} - # if otio_effect: - # # add otio effect to clip effects - # otio_clip.effects.append(otio_effect) - - # # loop through and get all Timewarps - # for effect in subTrackItems: - # if ((track_item not in effect.linkedItems()) - # and (len(effect.linkedItems()) > 0)): - # continue - # # avoid all effect which are not TimeWarp and disabled - # if "TimeWarp" not in effect.name(): - # continue - - # if not effect.isEnabled(): - # continue - - # node = effect.node() - # name = node["name"].value() - - # # solve effect class as effect name - # _name = effect.name() - # if "_" in _name: - # effect_name = re.sub(r"(?:_)[_0-9]+", "", _name) # more numbers - # else: - # effect_name = re.sub(r"\d+", "", _name) # one number - - # metadata = {} - # # add knob to metadata - # for knob in ["lookup", "length"]: - # value = node[knob].value() - # animated = node[knob].isAnimated() - # if animated: - # value = [ - # ((node[knob].getValueAt(i)) - i) - # for i in range( - # track_item.timelineIn(), - # track_item.timelineOut() + 1) - # ] - - # metadata[knob] = value - - # # make effect - # otio_effect = otio.schema.TimeEffect() - # otio_effect.name = name - # otio_effect.effect_name = effect_name - # otio_effect.metadata = metadata - - # # add otio effect to clip effects - # otio_clip.effects.append(otio_effect) - pass +# if otio_effect: +# # add otio effect to clip effects +# otio_clip.effects.append(otio_effect) def _get_marker_color(flame_colour): @@ -363,6 +310,8 @@ def create_otio_clip(clip_data): if MARKERS_INCLUDE: create_otio_markers(otio_clip, segment) + create_time_effects(otio_clip, clip_data) + return otio_clip From 21b83e341b754506d982c8ec05cb28d647c296cd Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 10 May 2022 16:59:20 +0200 Subject: [PATCH 093/350] flame" adding empty families to workfile instance --- openpype/hosts/flame/plugins/publish/collect_timeline_otio.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/flame/plugins/publish/collect_timeline_otio.py b/openpype/hosts/flame/plugins/publish/collect_timeline_otio.py index f2ae1f62a9..0a9b0db334 100644 --- a/openpype/hosts/flame/plugins/publish/collect_timeline_otio.py +++ b/openpype/hosts/flame/plugins/publish/collect_timeline_otio.py @@ -39,7 +39,8 @@ class CollecTimelineOTIO(pyblish.api.ContextPlugin): "name": subset_name, "asset": asset_doc["name"], "subset": subset_name, - "family": "workfile" + "family": "workfile", + "families": [] } # create instance with workfile From 9483adc91eaa0958f14090ba8af3e773b80247f9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 10 May 2022 16:59:39 +0200 Subject: [PATCH 094/350] Flame: commenting out effects - not yet implemented --- openpype/hosts/flame/otio/flame_export.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/flame/otio/flame_export.py b/openpype/hosts/flame/otio/flame_export.py index d84ee98256..fc960b670c 100644 --- a/openpype/hosts/flame/otio/flame_export.py +++ b/openpype/hosts/flame/otio/flame_export.py @@ -310,7 +310,7 @@ def create_otio_clip(clip_data): if MARKERS_INCLUDE: create_otio_markers(otio_clip, segment) - create_time_effects(otio_clip, clip_data) + # create_time_effects(otio_clip, clip_data) return otio_clip From de31b8d1df9458f1daa1ac9a385e648f588f4cf6 Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Tue, 10 May 2022 20:14:02 +0200 Subject: [PATCH 095/350] add silent audio to slate --- .../plugins/publish/extract_review_slate.py | 74 ++++++++++++------- 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 832799601c..2ef5308225 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -1,5 +1,4 @@ import os -import shutil import openpype.api import pyblish from openpype.lib import ( @@ -11,6 +10,7 @@ from openpype.lib import ( get_ffmpeg_format_args, ) + class ExtractReviewSlate(openpype.api.Extractor): """ Will add slate frame at the start of the video files @@ -122,10 +122,14 @@ class ExtractReviewSlate(openpype.api.Extractor): if stream["channel_layout"]: audio_channel_layout = str( stream.get("channel_layout")) + if stream["codec_name"]: + audio_codec = str( + stream.get("codec_name")) if ( audio_channels and audio_sample_rate and audio_channel_layout + and audio_codec ): input_audio = True break @@ -200,16 +204,6 @@ class ExtractReviewSlate(openpype.api.Extractor): input_args.append("-loop 1 -i {}".format( openpype.lib.path_to_subprocess_arg(slate_path))) - # if input has an audio, add silent audio to the slate - if input_audio: - input_args.extend( - ["-f lavfi -i anullsrc=r={}:cl={}:d={}".format( - audio_sample_rate, - audio_channel_layout, - one_frame_duration - )] - ) - input_args.extend(["-r {}".format(input_frame_rate)]) input_args.extend(["-frames:v 1"]) # add timecode from source to the slate, substract one frame @@ -314,6 +308,41 @@ class ExtractReviewSlate(openpype.api.Extractor): slate_subprocess_cmd, shell=True, logger=self.log ) + # Create slate with silent audio track + if input_audio: + # silent slate output path + slate_silent_path = slate_path.replace(".png", "Silent" + ext) + _remove_at_end.append(slate_silent_path) + + slate_silent_args = [ + ffmpeg_path, + "-i", slate_v_path, + "-f", "lavfi", "-i", + "anullsrc=r={}:cl={}:d={}".format( + audio_sample_rate, + audio_channel_layout, + one_frame_duration + ), + "-c:v", "copy", + "-c:a", audio_codec, + "-map", "0:v", + "-map", "1:a", + "-shortest", + "-y", + slate_silent_path + ] + slate_silent_subprocess_cmd = " ".join(slate_silent_args) + # run slate generation subprocess + self.log.debug( + "Silent Slate Executing: {}".format(slate_silent_subprocess_cmd) + ) + openpype.api.run_subprocess( + slate_silent_subprocess_cmd, shell=True, logger=self.log + ) + + # replace slate with silent slate for concat + slate_v_path = slate_silent_path + # create ffmpeg concat text file path conc_text_file = input_file.replace(ext, "") + "_concat" + ".txt" conc_text_path = os.path.join( @@ -361,21 +390,13 @@ class ExtractReviewSlate(openpype.api.Extractor): # add final output path concat_args.append(output_path) - if not input_audio: - # ffmpeg concat subprocess - self.log.debug( - "Executing concat: {}".format(" ".join(concat_args)) - ) - openpype.api.run_subprocess( - concat_args, logger=self.log - ) - else: - self.log.warning( - "Audio found. Creating slate with audio" - " is not supported at this time. Outputing slate-less" - ":\n{}".format(input_file)) - # skip concatenating slate, use slate-less file instead - shutil.copyfile(input_path, output_path) + # ffmpeg concat subprocess + self.log.debug( + "Executing concat: {}".format(" ".join(concat_args)) + ) + openpype.api.run_subprocess( + concat_args, logger=self.log + ) self.log.debug("__ repre[tags]: {}".format(repre["tags"])) repre_update = { @@ -438,7 +459,6 @@ class ExtractReviewSlate(openpype.api.Extractor): return vf_back - def _get_format_codec_args(self, repre): """Detect possible codec arguments from representation.""" codec_args = [] From b0c9e8a29d4c16d3276989fee37c8d8762d67809 Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Tue, 10 May 2022 20:35:04 +0200 Subject: [PATCH 096/350] hound --- openpype/plugins/publish/extract_review_slate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 2ef5308225..d3f8934620 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -334,8 +334,8 @@ class ExtractReviewSlate(openpype.api.Extractor): slate_silent_subprocess_cmd = " ".join(slate_silent_args) # run slate generation subprocess self.log.debug( - "Silent Slate Executing: {}".format(slate_silent_subprocess_cmd) - ) + "Silent Slate Executing: {}".format( + slate_silent_subprocess_cmd)) openpype.api.run_subprocess( slate_silent_subprocess_cmd, shell=True, logger=self.log ) From ff37e6135b6a2e22fede236268683ae3e5e1936c Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 10 May 2022 20:51:28 +0200 Subject: [PATCH 097/350] global: removing `clip` family from excluded - obsolete --- openpype/plugins/publish/integrate_new.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/integrate_new.py b/openpype/plugins/publish/integrate_new.py index bf13a4050e..353314fff2 100644 --- a/openpype/plugins/publish/integrate_new.py +++ b/openpype/plugins/publish/integrate_new.py @@ -113,7 +113,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): "usdOverride", "simpleUnrealTexture" ] - exclude_families = ["clip", "render.farm"] + exclude_families = ["render.farm"] db_representation_context_keys = [ "project", "asset", "task", "subset", "version", "representation", "family", "hierarchy", "task", "username" From ba1587efb6faf0e8cf21bf949fa36dbc5061d780 Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Wed, 11 May 2022 12:22:34 +0200 Subject: [PATCH 098/350] safer code --- .../plugins/publish/extract_review_slate.py | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index d3f8934620..b84dbbc2ac 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -79,7 +79,7 @@ class ExtractReviewSlate(openpype.api.Extractor): ) # Get video metadata for stream in streams: - input_timecode = None + input_timecode = "" input_width = None input_height = None input_frame_rate = None @@ -89,18 +89,20 @@ class ExtractReviewSlate(openpype.api.Extractor): tags = stream.get("tags") or {} input_timecode = tags.get("timecode") or "" if "width" in stream and "height" in stream: - input_width = int(stream.get("width")) - input_height = int(stream.get("height")) + input_width = stream.get("width") + input_height = stream.get("height") if "r_frame_rate" in stream: # get frame rate in a form of # x/y, like 24000/1001 for 23.976 - input_frame_rate = str(stream.get("r_frame_rate")) + input_frame_rate = stream.get("r_frame_rate") if ( - input_timecode - and input_width + input_width and input_height and input_frame_rate ): + input_width = int(input_width) + input_height = int(input_height) + input_frame_rate = str(input_frame_rate) break # Raise exception of any stream didn't define input resolution if input_width is None: @@ -131,7 +133,10 @@ class ExtractReviewSlate(openpype.api.Extractor): and audio_channel_layout and audio_codec ): - input_audio = True + input_audio = str(input_audio) + audio_sample_rate = str(audio_sample_rate) + audio_channel_layout = str(audio_channel_layout) + audio_codec = str(audio_codec) break # Get duration of one frame in micro seconds one_frame_duration = "40000us" @@ -207,7 +212,7 @@ class ExtractReviewSlate(openpype.api.Extractor): input_args.extend(["-r {}".format(input_frame_rate)]) input_args.extend(["-frames:v 1"]) # add timecode from source to the slate, substract one frame - offset_timecode = "00:00:00:00" + offset_timecode = "" if input_timecode: offset_timecode = str(input_timecode) offset_timecode = self._tc_offset( @@ -311,7 +316,8 @@ class ExtractReviewSlate(openpype.api.Extractor): # Create slate with silent audio track if input_audio: # silent slate output path - slate_silent_path = slate_path.replace(".png", "Silent" + ext) + slate_silent_path = "_silent".join( + os.path.splitext(slate_v_path)) _remove_at_end.append(slate_silent_path) slate_silent_args = [ @@ -331,13 +337,12 @@ class ExtractReviewSlate(openpype.api.Extractor): "-y", slate_silent_path ] - slate_silent_subprocess_cmd = " ".join(slate_silent_args) # run slate generation subprocess self.log.debug( "Silent Slate Executing: {}".format( - slate_silent_subprocess_cmd)) + " ".join(slate_silent_args))) openpype.api.run_subprocess( - slate_silent_subprocess_cmd, shell=True, logger=self.log + slate_silent_args, logger=self.log ) # replace slate with silent slate for concat @@ -367,8 +372,9 @@ class ExtractReviewSlate(openpype.api.Extractor): "-safe", "0", "-i", conc_text_path, "-c", "copy", - "-timecode", offset_timecode, ] + if offset_timecode: + concat_args.extend(["-timecode", offset_timecode]) # NOTE: Added because of OP Atom demuxers # Add format arguments if there are any # - keep format of output From 26fcd19a5d8bed9849c924c62a949b25e62c6189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 11 May 2022 12:29:30 +0200 Subject: [PATCH 099/350] use dbcon.Session instead of collection --- openpype/modules/kitsu/utils/sync_service.py | 83 +++++++++---------- .../modules/kitsu/utils/update_op_with_zou.py | 42 +++++----- .../modules/kitsu/utils/update_zou_with_op.py | 6 +- 3 files changed, 63 insertions(+), 68 deletions(-) diff --git a/openpype/modules/kitsu/utils/sync_service.py b/openpype/modules/kitsu/utils/sync_service.py index 01596e2667..ad18e1f391 100644 --- a/openpype/modules/kitsu/utils/sync_service.py +++ b/openpype/modules/kitsu/utils/sync_service.py @@ -119,8 +119,8 @@ class Listener: # Write into DB if update_project: - project_col = self.dbcon.database[project_name] - project_col.bulk_write([update_project]) + self.dbcon = self.dbcon.database[project_name] + self.dbcon.bulk_write([update_project]) def _delete_project(self, data): """Delete project.""" @@ -129,28 +129,27 @@ class Listener: project = gazu.project.get_project(data["project_id"]) # Delete project collection - project_col = self.dbcon.database[project["name"]] - project_col.drop() + # self.dbcon = self.dbcon.database[project["name"]] # == Asset == def _new_asset(self, data): """Create new asset into OP DB.""" # Get project entity - project_col = set_op_project(self.dbcon, data["project_id"]) + set_op_project(self.dbcon, data["project_id"]) # Get gazu entity asset = gazu.asset.get_asset(data["asset_id"]) # Insert doc in DB - project_col.insert_one(create_op_asset(asset)) + self.dbcon.insert_one(create_op_asset(asset)) # Update self._update_asset(data) def _update_asset(self, data): """Update asset into OP DB.""" - project_col = set_op_project(self.dbcon, data["project_id"]) + set_op_project(self.dbcon, data["project_id"]) project_doc = self.dbcon.find_one({"type": "project"}) # Get gazu entity @@ -160,23 +159,23 @@ class Listener: # Query all assets of the local project zou_ids_and_asset_docs = { asset_doc["data"]["zou"]["id"]: asset_doc - for asset_doc in project_col.find({"type": "asset"}) + for asset_doc in self.dbcon.find({"type": "asset"}) if asset_doc["data"].get("zou", {}).get("id") } zou_ids_and_asset_docs[asset["project_id"]] = project_doc # Update asset_doc_id, asset_update = update_op_assets( - project_col[asset], zou_ids_and_asset_docs + self.dbcon[asset], zou_ids_and_asset_docs )[0] - project_col.update_one({"_id": asset_doc_id}, asset_update) + self.dbcon.update_one({"_id": asset_doc_id}, asset_update) def _delete_asset(self, data): """Delete asset of OP DB.""" - project_col = set_op_project(self.dbcon, data["project_id"]) + set_op_project(self.dbcon, data["project_id"]) # Delete - project_col.delete_one( + self.dbcon.delete_one( {"type": "asset", "data.zou.id": data["asset_id"]} ) @@ -184,20 +183,20 @@ class Listener: def _new_episode(self, data): """Create new episode into OP DB.""" # Get project entity - project_col = set_op_project(self.dbcon, data["project_id"]) + set_op_project(self.dbcon, data["project_id"]) # Get gazu entity episode = gazu.shot.get_episode(data["episode_id"]) # Insert doc in DB - project_col.insert_one(create_op_asset(episode)) + self.dbcon.insert_one(create_op_asset(episode)) # Update self._update_episode(data) def _update_episode(self, data): """Update episode into OP DB.""" - project_col = set_op_project(self.dbcon, data["project_id"]) + set_op_project(self.dbcon, data["project_id"]) project_doc = self.dbcon.find_one({"type": "project"}) # Get gazu entity @@ -207,24 +206,24 @@ class Listener: # Query all assets of the local project zou_ids_and_asset_docs = { asset_doc["data"]["zou"]["id"]: asset_doc - for asset_doc in project_col.find({"type": "asset"}) + for asset_doc in self.dbcon.find({"type": "asset"}) if asset_doc["data"].get("zou", {}).get("id") } zou_ids_and_asset_docs[episode["project_id"]] = project_doc # Update asset_doc_id, asset_update = update_op_assets( - project_col, [episode], zou_ids_and_asset_docs + self.dbcon, [episode], zou_ids_and_asset_docs )[0] - project_col.update_one({"_id": asset_doc_id}, asset_update) + self.dbcon.update_one({"_id": asset_doc_id}, asset_update) def _delete_episode(self, data): """Delete shot of OP DB.""" - project_col = set_op_project(self.dbcon, data["project_id"]) + set_op_project(self.dbcon, data["project_id"]) print("delete episode") # TODO check bugfix # Delete - project_col.delete_one( + self.dbcon.delete_one( {"type": "asset", "data.zou.id": data["episode_id"]} ) @@ -232,20 +231,20 @@ class Listener: def _new_sequence(self, data): """Create new sequnce into OP DB.""" # Get project entity - project_col = set_op_project(self.dbcon, data["project_id"]) + set_op_project(self.dbcon, data["project_id"]) # Get gazu entity sequence = gazu.shot.get_sequence(data["sequence_id"]) # Insert doc in DB - project_col.insert_one(create_op_asset(sequence)) + self.dbcon.insert_one(create_op_asset(sequence)) # Update self._update_sequence(data) def _update_sequence(self, data): """Update sequence into OP DB.""" - project_col = set_op_project(self.dbcon, data["project_id"]) + set_op_project(self.dbcon, data["project_id"]) project_doc = self.dbcon.find_one({"type": "project"}) # Get gazu entity @@ -255,24 +254,24 @@ class Listener: # Query all assets of the local project zou_ids_and_asset_docs = { asset_doc["data"]["zou"]["id"]: asset_doc - for asset_doc in project_col.find({"type": "asset"}) + for asset_doc in self.dbcon.find({"type": "asset"}) if asset_doc["data"].get("zou", {}).get("id") } zou_ids_and_asset_docs[sequence["project_id"]] = project_doc # Update asset_doc_id, asset_update = update_op_assets( - project_col, [sequence], zou_ids_and_asset_docs + self.dbcon, [sequence], zou_ids_and_asset_docs )[0] - project_col.update_one({"_id": asset_doc_id}, asset_update) + self.dbcon.update_one({"_id": asset_doc_id}, asset_update) def _delete_sequence(self, data): """Delete sequence of OP DB.""" - project_col = set_op_project(self.dbcon, data["project_id"]) + set_op_project(self.dbcon, data["project_id"]) print("delete sequence") # TODO check bugfix # Delete - project_col.delete_one( + self.dbcon.delete_one( {"type": "asset", "data.zou.id": data["sequence_id"]} ) @@ -280,20 +279,20 @@ class Listener: def _new_shot(self, data): """Create new shot into OP DB.""" # Get project entity - project_col = set_op_project(self.dbcon, data["project_id"]) + set_op_project(self.dbcon, data["project_id"]) # Get gazu entity shot = gazu.shot.get_shot(data["shot_id"]) # Insert doc in DB - project_col.insert_one(create_op_asset(shot)) + self.dbcon.insert_one(create_op_asset(shot)) # Update self._update_shot(data) def _update_shot(self, data): """Update shot into OP DB.""" - project_col = set_op_project(self.dbcon, data["project_id"]) + set_op_project(self.dbcon, data["project_id"]) project_doc = self.dbcon.find_one({"type": "project"}) # Get gazu entity @@ -303,23 +302,23 @@ class Listener: # Query all assets of the local project zou_ids_and_asset_docs = { asset_doc["data"]["zou"]["id"]: asset_doc - for asset_doc in project_col.find({"type": "asset"}) + for asset_doc in self.dbcon.find({"type": "asset"}) if asset_doc["data"].get("zou", {}).get("id") } zou_ids_and_asset_docs[shot["project_id"]] = project_doc # Update asset_doc_id, asset_update = update_op_assets( - project_col, [shot], zou_ids_and_asset_docs + self.dbcon, [shot], zou_ids_and_asset_docs )[0] - project_col.update_one({"_id": asset_doc_id}, asset_update) + self.dbcon.update_one({"_id": asset_doc_id}, asset_update) def _delete_shot(self, data): """Delete shot of OP DB.""" - project_col = set_op_project(self.dbcon, data["project_id"]) + set_op_project(self.dbcon, data["project_id"]) # Delete - project_col.delete_one( + self.dbcon.delete_one( {"type": "asset", "data.zou.id": data["shot_id"]} ) @@ -327,13 +326,13 @@ class Listener: def _new_task(self, data): """Create new task into OP DB.""" # Get project entity - project_col = set_op_project(self.dbcon, data["project_id"]) + set_op_project(self.dbcon, data["project_id"]) # Get gazu entity task = gazu.task.get_task(data["task_id"]) # Find asset doc - asset_doc = project_col.find_one( + asset_doc = self.dbcon.find_one( {"type": "asset", "data.zou.id": task["entity"]["id"]} ) @@ -341,7 +340,7 @@ class Listener: asset_tasks = asset_doc["data"].get("tasks") task_type_name = task["task_type"]["name"] asset_tasks[task_type_name] = {"type": task_type_name, "zou": task} - project_col.update_one( + self.dbcon.update_one( {"_id": asset_doc["_id"]}, {"$set": {"data.tasks": asset_tasks}} ) @@ -352,10 +351,10 @@ class Listener: def _delete_task(self, data): """Delete task of OP DB.""" - project_col = set_op_project(self.dbcon, data["project_id"]) + set_op_project(self.dbcon, data["project_id"]) # Find asset doc - asset_docs = [doc for doc in project_col.find({"type": "asset"})] + asset_docs = [doc for doc in self.dbcon.find({"type": "asset"})] for doc in asset_docs: # Match task for name, task in doc["data"]["tasks"].items(): @@ -365,7 +364,7 @@ class Listener: asset_tasks.pop(name) # Delete task in DB - project_col.update_one( + self.dbcon.update_one( {"_id": doc["_id"]}, {"$set": {"data.tasks": asset_tasks}}, ) diff --git a/openpype/modules/kitsu/utils/update_op_with_zou.py b/openpype/modules/kitsu/utils/update_op_with_zou.py index 25c89800d4..6e82ffbd05 100644 --- a/openpype/modules/kitsu/utils/update_op_with_zou.py +++ b/openpype/modules/kitsu/utils/update_op_with_zou.py @@ -29,18 +29,17 @@ def create_op_asset(gazu_entity: dict) -> dict: } -def set_op_project(dbcon, project_id) -> Collection: +def set_op_project(dbcon: AvalonMongoDB, project_id: str): """Set project context. - :param dbcon: Connection to DB. - :param project_id: Project zou ID + Args: + dbcon (AvalonMongoDB): Connection to DB. + project_id (str): Project zou ID """ project = gazu.project.get_project(project_id) project_name = project["name"] dbcon.Session["AVALON_PROJECT"] = project_name - return dbcon.database[project_name] - def update_op_assets( project_col: Collection, @@ -258,28 +257,25 @@ def sync_all_project(login: str, password: str): dbcon.install() all_projects = gazu.project.all_open_projects() for project in all_projects: - sync_project_from_kitsu(project["name"], dbcon, project) + sync_project_from_kitsu(dbcon, project) def sync_project_from_kitsu( - project_name: str, dbcon: AvalonMongoDB, project: dict = None + dbcon: AvalonMongoDB, project: dict ): """Update OP project in DB with Zou data. Args: - project_name (str): Name of project to sync dbcon (AvalonMongoDB): MongoDB connection - project (dict, optional): Project dict got using gazu. - Defaults to None. + project (dict): Project dict got using gazu. """ bulk_writes = [] # Get project from zou if not project: - project = gazu.project.get_project_by_name(project_name) - project_code = project_name + project = gazu.project.get_project_by_name(project["name"]) - print(f"Synchronizing {project_name}...") + print(f"Synchronizing {project['name']}...") # Get all assets from zou all_assets = gazu.asset.all_assets_for_project(project) @@ -292,28 +288,28 @@ def sync_project_from_kitsu( bulk_writes.append(write_project_to_op(project, dbcon)) # Try to find project document - project_col = dbcon.database[project_code] - project_doc = project_col.find_one({"type": "project"}) + dbcon.Session["AVALON_PROJECT"] = project["name"] + project_doc = dbcon.find_one({"type": "project"}) # Query all assets of the local project zou_ids_and_asset_docs = { asset_doc["data"]["zou"]["id"]: asset_doc - for asset_doc in project_col.find({"type": "asset"}) + for asset_doc in dbcon.find({"type": "asset"}) if asset_doc["data"].get("zou", {}).get("id") } zou_ids_and_asset_docs[project["id"]] = project_doc # Create entities root folders - project_module_settings = get_project_settings(project_name)["kitsu"] + project_module_settings = get_project_settings(project["name"])["kitsu"] for entity_type, root in project_module_settings["entities_root"].items(): parent_folders = root.split("/") direct_parent_doc = None for i, folder in enumerate(parent_folders, 1): - parent_doc = project_col.find_one( + parent_doc = dbcon.find_one( {"type": "asset", "name": folder, "data.root_of": entity_type} ) if not parent_doc: - direct_parent_doc = project_col.insert_one( + direct_parent_doc = dbcon.insert_one( { "name": folder, "type": "asset", @@ -338,13 +334,13 @@ def sync_project_from_kitsu( ) if to_insert: # Insert doc in DB - project_col.insert_many(to_insert) + dbcon.insert_many(to_insert) # Update existing docs zou_ids_and_asset_docs.update( { asset_doc["data"]["zou"]["id"]: asset_doc - for asset_doc in project_col.find({"type": "asset"}) + for asset_doc in dbcon.find({"type": "asset"}) if asset_doc["data"].get("zou") } ) @@ -354,7 +350,7 @@ def sync_project_from_kitsu( [ UpdateOne({"_id": id}, update) for id, update in update_op_assets( - project_col, all_entities, zou_ids_and_asset_docs + dbcon, all_entities, zou_ids_and_asset_docs ) ] ) @@ -373,4 +369,4 @@ def sync_project_from_kitsu( # Write into DB if bulk_writes: - project_col.bulk_write(bulk_writes) + dbcon.bulk_write(bulk_writes) diff --git a/openpype/modules/kitsu/utils/update_zou_with_op.py b/openpype/modules/kitsu/utils/update_zou_with_op.py index 526159d101..81d421206f 100644 --- a/openpype/modules/kitsu/utils/update_zou_with_op.py +++ b/openpype/modules/kitsu/utils/update_zou_with_op.py @@ -93,10 +93,10 @@ def sync_zou_from_op_project( # Query all assets of the local project project_module_settings = get_project_settings(project_name)["kitsu"] - project_col = dbcon.database[project_name] + dbcon.Session["AVALON_PROJECT"] = project_name asset_docs = { asset_doc["_id"]: asset_doc - for asset_doc in project_col.find({"type": "asset"}) + for asset_doc in dbcon.find({"type": "asset"}) } # Create new assets @@ -259,4 +259,4 @@ def sync_zou_from_op_project( # Write into DB if bulk_writes: - project_col.bulk_write(bulk_writes) + dbcon.bulk_write(bulk_writes) From 765546e6f96cf8ba480c20e65ad3f19cc8a24267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 11 May 2022 12:31:08 +0200 Subject: [PATCH 100/350] fix unused var --- openpype/modules/kitsu/utils/sync_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/kitsu/utils/sync_service.py b/openpype/modules/kitsu/utils/sync_service.py index ad18e1f391..8c7ce730a7 100644 --- a/openpype/modules/kitsu/utils/sync_service.py +++ b/openpype/modules/kitsu/utils/sync_service.py @@ -126,7 +126,7 @@ class Listener: """Delete project.""" # Get project entity print(data) # TODO check bugfix - project = gazu.project.get_project(data["project_id"]) + # project = gazu.project.get_project(data["project_id"]) # Delete project collection # self.dbcon = self.dbcon.database[project["name"]] From 43baf02d98e2fa899ec84ab163cb97d8453167d8 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 11 May 2022 13:22:42 +0200 Subject: [PATCH 101/350] flame: refactory MediaInfo class - to be able match collection if sequence with holes - also make code more explicit about input arguments --- openpype/hosts/flame/api/lib.py | 119 ++++++++++++++++++++++++++++---- 1 file changed, 105 insertions(+), 14 deletions(-) diff --git a/openpype/hosts/flame/api/lib.py b/openpype/hosts/flame/api/lib.py index 2e9b535764..15e6f8ae80 100644 --- a/openpype/hosts/flame/api/lib.py +++ b/openpype/hosts/flame/api/lib.py @@ -3,6 +3,7 @@ import os import re import json import pickle +import clique import tempfile import itertools import contextlib @@ -773,17 +774,24 @@ class MediaInfoFile(object): self._validate_media_script_path() # derivate other feed variables - self.feed_basename = os.path.basename(path) - self.feed_dir = os.path.dirname(path) - self.feed_ext = os.path.splitext(self.feed_basename)[1][1:].lower() + feed_basename = os.path.basename(path) + feed_dir = os.path.dirname(path) + feed_ext = os.path.splitext(feed_basename)[1][1:].lower() with maintained_temp_file_path(".clip") as tmp_path: self.log.info("Temp File: {}".format(tmp_path)) - self._generate_media_info_file(tmp_path) + self._generate_media_info_file(tmp_path, feed_ext, feed_dir) + + if os.path.exists(os.path.join(feed_dir, feed_basename)): + test_fname = feed_basename + else: + # get collection containing feed_basename from path + test_fname = self._get_collection(feed_basename, feed_dir, feed_ext) # get clip data and make them single if there is multiple # clips data - xml_data = self._make_single_clip_media_info(tmp_path) + xml_data = self._make_single_clip_media_info( + tmp_path, feed_basename, test_fname) self.log.debug("xml_data: {}".format(xml_data)) self.log.debug("type: {}".format(type(xml_data))) @@ -794,6 +802,73 @@ class MediaInfoFile(object): self.log.debug("drop frame: {}".format(self.drop_mode)) self.clip_data = xml_data + def _get_collection(self, feed_basename, feed_dir, feed_ext): + partialname = self._separate_file_head(feed_basename, feed_ext) + log.debug("__ partialname: {}".format(partialname)) + + # make sure partial input basename is having correct extensoon + if not partialname: + raise IOError("File doesnt exists. Basename - {}, Ext - {}".format( + feed_basename, feed_ext + )) + + # get all related files + files = [ + f for f in os.listdir(feed_dir) + if partialname == self._separate_file_head(f, feed_ext) + ] + + # ignore reminders as we dont need them + collections = clique.assemble(files)[0] + + # if no collection rise + if not collections: + raise IOError("_get_collection is failing on: {} {} {}".format( + feed_basename, feed_dir, feed_ext + )) + else: + # we expect only one collection + collection = collections[0] + + if collection.is_contiguous(): + # if no holes then return collection + return collection.format("{head}[{range}]{tail}") + + # add `[` in front to make sure it want capture + # shot name with the same number + number_from_path = "[" + self._separate_number(feed_basename, feed_ext) + # convert to multiple collections + _continues_colls = collection.separate() + for _coll in _continues_colls: + coll_to_text = _coll.format("{head}[{range}]{tail}") + log.debug("__ coll_to_text: {}".format(coll_to_text)) + if number_from_path in coll_to_text: + return coll_to_text + + def _separate_file_head(self, basename, extension): + # in case sequence file + found = re.findall( + r"(.*)[._][\d]*(?=.{})".format(extension), + basename, + ) + if found: + return found.pop() + + # in case single file + name, ext = os.path.splitext(basename) + + if extension == ext[1:]: + return name + + def _separate_number(self, basename, extension): + # in case sequence file + found = re.findall( + r"[._]([\d]*)(?=.{})".format(extension), + basename, + ) + if found: + return found.pop() + @property def clip_data(self): """Clip's xml clip data @@ -851,13 +926,13 @@ class MediaInfoFile(object): raise IOError("Media Scirpt does not exist: `{}`".format( self.MEDIA_SCRIPT_PATH)) - def _generate_media_info_file(self, fpath): + def _generate_media_info_file(self, fpath, feed_ext, feed_dir): # Create cmd arguments for gettig xml file info file cmd_args = [ self.MEDIA_SCRIPT_PATH, - "-e", self.feed_ext, + "-e", feed_ext, "-o", fpath, - self.feed_dir + feed_dir ] try: @@ -867,7 +942,7 @@ class MediaInfoFile(object): raise TypeError( "Error creating `{}` due: {}".format(fpath, error)) - def _make_single_clip_media_info(self, fpath): + def _make_single_clip_media_info(self, fpath, feed_basename, path_pattern): with open(fpath) as f: lines = f.readlines() _added_root = itertools.chain( @@ -878,14 +953,32 @@ class MediaInfoFile(object): xml_clips = new_root.findall("clip") matching_clip = None for xml_clip in xml_clips: - if xml_clip.find("name").text in self.feed_basename: - matching_clip = xml_clip + clip_name = xml_clip.find("name").text + log.debug("__ clip_name: `{}`".format(clip_name)) + if clip_name not in feed_basename: + continue + + # test path pattern + for out_track in xml_clip.iter("track"): + for out_feed in out_track.iter("feed"): + for span in out_feed.iter("span"): + # start frame + span_path = span.find("path") + if not span_path: + continue + log.debug( + "__ span_path.text: {}, path_pattern: {}".format( + span_path.text, path_pattern + ) + ) + if path_pattern in span_path.text: + matching_clip = xml_clip if matching_clip is None: # return warning there is missing clip raise ET.ParseError( "Missing clip in `{}`. Available clips {}".format( - self.feed_basename, [ + feed_basename, [ xml_clip.find("name").text for xml_clip in xml_clips ] @@ -912,8 +1005,6 @@ class MediaInfoFile(object): 'startTimecode/dropMode') self.drop_mode = out_feed_drop_mode_obj.text break - else: - continue except Exception as msg: self.log.warning(msg) From c34ecfd9127004e0c739be7bb0efdb11d162c447 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 11 May 2022 13:35:35 +0200 Subject: [PATCH 102/350] flame: fixing logger --- openpype/hosts/flame/api/lib.py | 8 ++++---- openpype/hosts/flame/otio/flame_export.py | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/flame/api/lib.py b/openpype/hosts/flame/api/lib.py index 15e6f8ae80..6fff3edc30 100644 --- a/openpype/hosts/flame/api/lib.py +++ b/openpype/hosts/flame/api/lib.py @@ -804,7 +804,7 @@ class MediaInfoFile(object): def _get_collection(self, feed_basename, feed_dir, feed_ext): partialname = self._separate_file_head(feed_basename, feed_ext) - log.debug("__ partialname: {}".format(partialname)) + self.log.debug("__ partialname: {}".format(partialname)) # make sure partial input basename is having correct extensoon if not partialname: @@ -841,7 +841,7 @@ class MediaInfoFile(object): _continues_colls = collection.separate() for _coll in _continues_colls: coll_to_text = _coll.format("{head}[{range}]{tail}") - log.debug("__ coll_to_text: {}".format(coll_to_text)) + self.log.debug("__ coll_to_text: {}".format(coll_to_text)) if number_from_path in coll_to_text: return coll_to_text @@ -954,7 +954,7 @@ class MediaInfoFile(object): matching_clip = None for xml_clip in xml_clips: clip_name = xml_clip.find("name").text - log.debug("__ clip_name: `{}`".format(clip_name)) + self.log.debug("__ clip_name: `{}`".format(clip_name)) if clip_name not in feed_basename: continue @@ -966,7 +966,7 @@ class MediaInfoFile(object): span_path = span.find("path") if not span_path: continue - log.debug( + self.log.debug( "__ span_path.text: {}, path_pattern: {}".format( span_path.text, path_pattern ) diff --git a/openpype/hosts/flame/otio/flame_export.py b/openpype/hosts/flame/otio/flame_export.py index fc960b670c..c54ebb43d3 100644 --- a/openpype/hosts/flame/otio/flame_export.py +++ b/openpype/hosts/flame/otio/flame_export.py @@ -280,7 +280,9 @@ def create_otio_clip(clip_data): segment = clip_data["PySegment"] # calculate source in - media_info = MediaInfoFile(clip_data["fpath"]) + media_info = MediaInfoFile(clip_data["fpath"], **{ + "logger": log + }) media_timecode_start = media_info.start_frame media_fps = media_info.fps From 27d9e9bd3e9a9ef03489290101535aeb79617e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 11 May 2022 14:08:05 +0200 Subject: [PATCH 103/350] Fix delete project --- openpype/modules/kitsu/utils/sync_service.py | 9 +++++---- openpype/modules/kitsu/utils/update_op_with_zou.py | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/openpype/modules/kitsu/utils/sync_service.py b/openpype/modules/kitsu/utils/sync_service.py index 8c7ce730a7..8d1ffb199d 100644 --- a/openpype/modules/kitsu/utils/sync_service.py +++ b/openpype/modules/kitsu/utils/sync_service.py @@ -124,12 +124,13 @@ class Listener: def _delete_project(self, data): """Delete project.""" - # Get project entity - print(data) # TODO check bugfix - # project = gazu.project.get_project(data["project_id"]) + project_doc = self.dbcon.find_one( + {"type": "project", "data.zou_id": data["project_id"]} + ) # Delete project collection - # self.dbcon = self.dbcon.database[project["name"]] + self.dbcon.database[project_doc["name"]].drop() + # == Asset == diff --git a/openpype/modules/kitsu/utils/update_op_with_zou.py b/openpype/modules/kitsu/utils/update_op_with_zou.py index 6e82ffbd05..03a10e76a6 100644 --- a/openpype/modules/kitsu/utils/update_op_with_zou.py +++ b/openpype/modules/kitsu/utils/update_op_with_zou.py @@ -218,6 +218,7 @@ def write_project_to_op(project: dict, dbcon: AvalonMongoDB) -> UpdateOne: "fps": project["fps"], "resolutionWidth": project["resolution"].split("x")[0], "resolutionHeight": project["resolution"].split("x")[1], + "zou_id": project["id"], } ) From aac7797f06934dfc123c8a97e53106b6c442c54b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 11 May 2022 14:26:36 +0200 Subject: [PATCH 104/350] flame: check collection first --- openpype/hosts/flame/api/lib.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/flame/api/lib.py b/openpype/hosts/flame/api/lib.py index 6fff3edc30..8e2ef2d624 100644 --- a/openpype/hosts/flame/api/lib.py +++ b/openpype/hosts/flame/api/lib.py @@ -782,11 +782,15 @@ class MediaInfoFile(object): self.log.info("Temp File: {}".format(tmp_path)) self._generate_media_info_file(tmp_path, feed_ext, feed_dir) - if os.path.exists(os.path.join(feed_dir, feed_basename)): + # get collection containing feed_basename from path + test_fname = self._get_collection( + feed_basename, feed_dir, feed_ext) + + if ( + not test_fname + and os.path.exists(os.path.join(feed_dir, feed_basename)) + ): test_fname = feed_basename - else: - # get collection containing feed_basename from path - test_fname = self._get_collection(feed_basename, feed_dir, feed_ext) # get clip data and make them single if there is multiple # clips data From 82e62230fa78520d6cf167b0eaaec8095e5d18a6 Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Wed, 11 May 2022 14:35:38 +0200 Subject: [PATCH 105/350] int back --- openpype/plugins/publish/extract_review_slate.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index b84dbbc2ac..7b2df4dc5f 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -89,8 +89,8 @@ class ExtractReviewSlate(openpype.api.Extractor): tags = stream.get("tags") or {} input_timecode = tags.get("timecode") or "" if "width" in stream and "height" in stream: - input_width = stream.get("width") - input_height = stream.get("height") + input_width = int(stream.get("width")) + input_height = int(stream.get("height")) if "r_frame_rate" in stream: # get frame rate in a form of # x/y, like 24000/1001 for 23.976 @@ -100,8 +100,6 @@ class ExtractReviewSlate(openpype.api.Extractor): and input_height and input_frame_rate ): - input_width = int(input_width) - input_height = int(input_height) input_frame_rate = str(input_frame_rate) break # Raise exception of any stream didn't define input resolution From b7f7af46fbd00e8b62822efd8b999f28fdb5bf6b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 11 May 2022 14:47:34 +0200 Subject: [PATCH 106/350] flame: redundant condition --- openpype/hosts/flame/api/lib.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/hosts/flame/api/lib.py b/openpype/hosts/flame/api/lib.py index 8e2ef2d624..660466b0aa 100644 --- a/openpype/hosts/flame/api/lib.py +++ b/openpype/hosts/flame/api/lib.py @@ -968,8 +968,6 @@ class MediaInfoFile(object): for span in out_feed.iter("span"): # start frame span_path = span.find("path") - if not span_path: - continue self.log.debug( "__ span_path.text: {}, path_pattern: {}".format( span_path.text, path_pattern From 7f1b8f7f038d63cd53ee36e6d419aff62271adb3 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 11 May 2022 16:00:30 +0200 Subject: [PATCH 107/350] flame: adding docstrings --- openpype/hosts/flame/api/lib.py | 39 ++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/flame/api/lib.py b/openpype/hosts/flame/api/lib.py index 660466b0aa..7125a540a0 100644 --- a/openpype/hosts/flame/api/lib.py +++ b/openpype/hosts/flame/api/lib.py @@ -807,12 +807,26 @@ class MediaInfoFile(object): self.clip_data = xml_data def _get_collection(self, feed_basename, feed_dir, feed_ext): + """ Get collection string + + Args: + feed_basename (str): file base name + feed_dir (str): file's directory + feed_ext (str): file extension + + Raises: + AttributeError: feed_ext is not matching feed_basename + IOError: Failing on not correct input data + + Returns: + str: collection basename with range of sequence + """ partialname = self._separate_file_head(feed_basename, feed_ext) self.log.debug("__ partialname: {}".format(partialname)) # make sure partial input basename is having correct extensoon if not partialname: - raise IOError("File doesnt exists. Basename - {}, Ext - {}".format( + raise AttributeError("Wrong input attributes. Basename - {}, Ext - {}".format( feed_basename, feed_ext )) @@ -850,6 +864,15 @@ class MediaInfoFile(object): return coll_to_text def _separate_file_head(self, basename, extension): + """ Get only head with out sequence and extension + + Args: + basename (str): file base name + extension (str): file extension + + Returns: + str: file head + """ # in case sequence file found = re.findall( r"(.*)[._][\d]*(?=.{})".format(extension), @@ -865,6 +888,15 @@ class MediaInfoFile(object): return name def _separate_number(self, basename, extension): + """ Get only sequence number as string + + Args: + basename (str): file base name + extension (str): file extension + + Returns: + str: number with padding + """ # in case sequence file found = re.findall( r"[._]([\d]*)(?=.{})".format(extension), @@ -989,6 +1021,11 @@ class MediaInfoFile(object): return matching_clip def _get_time_info_from_origin(self, xml_data): + """Set time info to class attributes + + Args: + xml_data (ET.Element): clip data + """ try: for out_track in xml_data.iter('track'): for out_feed in out_track.iter('feed'): From ac16e1f8bb6f79a3dca750848b5d7450571ff6b3 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 11 May 2022 16:05:22 +0200 Subject: [PATCH 108/350] flame: adding more docstring --- openpype/hosts/flame/api/lib.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/openpype/hosts/flame/api/lib.py b/openpype/hosts/flame/api/lib.py index 7125a540a0..03e3d117a3 100644 --- a/openpype/hosts/flame/api/lib.py +++ b/openpype/hosts/flame/api/lib.py @@ -963,6 +963,16 @@ class MediaInfoFile(object): self.MEDIA_SCRIPT_PATH)) def _generate_media_info_file(self, fpath, feed_ext, feed_dir): + """ Generate media info xml .clip file + + Args: + fpath (str): .clip file path + feed_ext (str): file extension to be filtered + feed_dir (str): look up directory + + Raises: + TypeError: Type error if it fails + """ # Create cmd arguments for gettig xml file info file cmd_args = [ self.MEDIA_SCRIPT_PATH, @@ -979,6 +989,19 @@ class MediaInfoFile(object): "Error creating `{}` due: {}".format(fpath, error)) def _make_single_clip_media_info(self, fpath, feed_basename, path_pattern): + """ Separate only relative clip object form .clip file + + Args: + fpath (str): clip file path + feed_basename (str): search basename + path_pattern (str): search file pattern (file.[1-2].exr) + + Raises: + ET.ParseError: if nothing found + + Returns: + ET.Element: xml element data of matching clip + """ with open(fpath) as f: lines = f.readlines() _added_root = itertools.chain( From af77d5a888f371c3bab4c2e38483ecaa7e7c6023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 11 May 2022 16:37:17 +0200 Subject: [PATCH 109/350] fix wrong name entities makes crash: they are skipped --- openpype/modules/kitsu/utils/sync_service.py | 2 +- .../modules/kitsu/utils/update_op_with_zou.py | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/openpype/modules/kitsu/utils/sync_service.py b/openpype/modules/kitsu/utils/sync_service.py index 8d1ffb199d..46d3422727 100644 --- a/openpype/modules/kitsu/utils/sync_service.py +++ b/openpype/modules/kitsu/utils/sync_service.py @@ -131,7 +131,6 @@ class Listener: # Delete project collection self.dbcon.database[project_doc["name"]].drop() - # == Asset == def _new_asset(self, data): @@ -150,6 +149,7 @@ class Listener: def _update_asset(self, data): """Update asset into OP DB.""" + # TODO check if asset doesn't exist, create it (case where name wasn't valid) set_op_project(self.dbcon, data["project_id"]) project_doc = self.dbcon.find_one({"type": "project"}) diff --git a/openpype/modules/kitsu/utils/update_op_with_zou.py b/openpype/modules/kitsu/utils/update_op_with_zou.py index 03a10e76a6..fbc23cf52e 100644 --- a/openpype/modules/kitsu/utils/update_op_with_zou.py +++ b/openpype/modules/kitsu/utils/update_op_with_zou.py @@ -1,5 +1,6 @@ """Functions to update OpenPype data using Kitsu DB (a.k.a Zou).""" from copy import deepcopy +import re from typing import Dict, List from pymongo import DeleteOne, UpdateOne @@ -16,6 +17,10 @@ from openpype.lib import create_project from openpype.modules.kitsu.utils.credentials import validate_credentials +# Accepted namin pattern for OP +naming_pattern = re.compile("^[a-zA-Z0-9_.]*$") + + def create_op_asset(gazu_entity: dict) -> dict: """Create OP asset dict from gazu entity. @@ -261,9 +266,7 @@ def sync_all_project(login: str, password: str): sync_project_from_kitsu(dbcon, project) -def sync_project_from_kitsu( - dbcon: AvalonMongoDB, project: dict -): +def sync_project_from_kitsu(dbcon: AvalonMongoDB, project: dict): """Update OP project in DB with Zou data. Args: @@ -283,7 +286,11 @@ def sync_project_from_kitsu( all_episodes = gazu.shot.all_episodes_for_project(project) all_seqs = gazu.shot.all_sequences_for_project(project) all_shots = gazu.shot.all_shots_for_project(project) - all_entities = all_assets + all_episodes + all_seqs + all_shots + all_entities = [ + item + for item in all_assets + all_episodes + all_seqs + all_shots + if naming_pattern.match(item["name"]) + ] # Sync project. Create if doesn't exist bulk_writes.append(write_project_to_op(project, dbcon)) From ea54b0dc2512eeb428b1f3ea702a10a55ac6ccf3 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Mon, 9 May 2022 10:28:09 +0200 Subject: [PATCH 110/350] refactor --- openpype/hosts/nuke/startup/menu.py | 31 +++++++++++++++++++ .../defaults/project_settings/nuke.json | 4 +++ .../projects_schema/schema_project_maya.json | 2 +- .../projects_schema/schema_project_nuke.json | 4 +++ ...riptsmenu.json => schema_scriptsmenu.json} | 0 5 files changed, 40 insertions(+), 1 deletion(-) rename openpype/settings/entities/schemas/projects_schema/schemas/{schema_maya_scriptsmenu.json => schema_scriptsmenu.json} (100%) diff --git a/openpype/hosts/nuke/startup/menu.py b/openpype/hosts/nuke/startup/menu.py index 9ed43b2110..dee1d9d868 100644 --- a/openpype/hosts/nuke/startup/menu.py +++ b/openpype/hosts/nuke/startup/menu.py @@ -1,5 +1,7 @@ import nuke +import os +import avalon.api from openpype.api import Logger from openpype.pipeline import install_host from openpype.hosts.nuke import api @@ -9,6 +11,7 @@ from openpype.hosts.nuke.api.lib import ( WorkfileSettings, dirmap_file_name_filter ) +from openpype.settings import get_project_settings log = Logger.get_logger(__name__) @@ -28,3 +31,31 @@ nuke.addOnScriptLoad(WorkfileSettings().set_context_settings) nuke.addFilenameFilter(dirmap_file_name_filter) log.info('Automatic syncing of write file knob to script version') + + +def add_scripts_menu(): + try: + from scriptsmenu import launchfornuke + except ImportError: + log.warning( + "Skipping studio.menu install, because " + "'scriptsmenu' module seems unavailable." + ) + return + + # load configuration of custom menu + project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) + config = project_settings["nuke"]["scriptsmenu"]["definition"] + _menu = project_settings["nuke"]["scriptsmenu"]["name"] + + if not config: + log.warning("Skipping studio menu, no definition found.") + return + + # run the launcher for Maya menu + studio_menu = launchfornuke.main(title=_menu.title()) + + # apply configuration + studio_menu.build_from_configuration(studio_menu, config) + +add_scripts_menu() diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 128d440732..a9d284873c 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -15,6 +15,10 @@ "destination-path": [] } }, + "scriptsmenu": { + "name": "OpenPype Tools", + "definition": [] + }, "create": { "CreateWriteRender": { "fpath_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}", diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json index cc70516c72..0c7943447b 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json @@ -49,7 +49,7 @@ }, { "type": "schema", - "name": "schema_maya_scriptsmenu" + "name": "schema_scriptsmenu" }, { "type": "schema", diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json index bc572cbdc8..1ae4efd8ea 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json @@ -79,6 +79,10 @@ } ] }, + { + "type": "schema", + "name": "schema_scriptsmenu" + }, { "type": "dict", "collapsible": true, diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_scriptsmenu.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_scriptsmenu.json similarity index 100% rename from openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_scriptsmenu.json rename to openpype/settings/entities/schemas/projects_schema/schemas/schema_scriptsmenu.json From 8a1f7c10061387b03674eb0e21faf05f0bf8fbd5 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 11 May 2022 17:12:54 +0200 Subject: [PATCH 111/350] flame: fix for single file use --- openpype/hosts/flame/api/lib.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/flame/api/lib.py b/openpype/hosts/flame/api/lib.py index 03e3d117a3..933cfbe267 100644 --- a/openpype/hosts/flame/api/lib.py +++ b/openpype/hosts/flame/api/lib.py @@ -839,14 +839,13 @@ class MediaInfoFile(object): # ignore reminders as we dont need them collections = clique.assemble(files)[0] - # if no collection rise + # in case no collection found return None + # it is probably just single file if not collections: - raise IOError("_get_collection is failing on: {} {} {}".format( - feed_basename, feed_dir, feed_ext - )) - else: - # we expect only one collection - collection = collections[0] + return + + # we expect only one collection + collection = collections[0] if collection.is_contiguous(): # if no holes then return collection From f7d4cbecfe36826865cb3aba3e33da10fd0aeb71 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Mon, 2 May 2022 17:17:29 +0200 Subject: [PATCH 112/350] add the scriptsmenu schema to nuke --- .../projects_schema/schema_project_nuke.json | 4 ++++ .../schemas/schema_nuke_scriptsmenu.json | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsmenu.json diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json index 1ae4efd8ea..1fc925557b 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json @@ -290,6 +290,10 @@ } ] }, + { + "type": "schema", + "name": "schema_nuke_scriptsmenu" + }, { "type": "schema", "name": "schema_nuke_publish", diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsmenu.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsmenu.json new file mode 100644 index 0000000000..e841d6ba77 --- /dev/null +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsmenu.json @@ -0,0 +1,22 @@ +{ + "type": "dict", + "collapsible": true, + "key": "scriptsmenu", + "label": "Scripts Menu Definition", + "children": [ + { + "type": "text", + "key": "name", + "label": "Menu Name" + }, + { + "type": "splitter" + }, + { + "type": "raw-json", + "key": "definition", + "label": "Menu definition", + "is_list": true + } + ] +} \ No newline at end of file From eb5605a3ade0e4f59b8ffb21a7914c446b75372d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 11 May 2022 17:24:11 +0200 Subject: [PATCH 113/350] fix updated asset skipped because of wrong name --- openpype/modules/kitsu/utils/sync_service.py | 9 ++++--- .../modules/kitsu/utils/update_op_with_zou.py | 24 ++++++++++++------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/openpype/modules/kitsu/utils/sync_service.py b/openpype/modules/kitsu/utils/sync_service.py index 46d3422727..6c003942f8 100644 --- a/openpype/modules/kitsu/utils/sync_service.py +++ b/openpype/modules/kitsu/utils/sync_service.py @@ -149,7 +149,6 @@ class Listener: def _update_asset(self, data): """Update asset into OP DB.""" - # TODO check if asset doesn't exist, create it (case where name wasn't valid) set_op_project(self.dbcon, data["project_id"]) project_doc = self.dbcon.find_one({"type": "project"}) @@ -167,7 +166,7 @@ class Listener: # Update asset_doc_id, asset_update = update_op_assets( - self.dbcon[asset], zou_ids_and_asset_docs + self.dbcon, project_doc, [asset], zou_ids_and_asset_docs )[0] self.dbcon.update_one({"_id": asset_doc_id}, asset_update) @@ -214,7 +213,7 @@ class Listener: # Update asset_doc_id, asset_update = update_op_assets( - self.dbcon, [episode], zou_ids_and_asset_docs + self.dbcon, project_doc, [episode], zou_ids_and_asset_docs )[0] self.dbcon.update_one({"_id": asset_doc_id}, asset_update) @@ -262,7 +261,7 @@ class Listener: # Update asset_doc_id, asset_update = update_op_assets( - self.dbcon, [sequence], zou_ids_and_asset_docs + self.dbcon, project_doc, [sequence], zou_ids_and_asset_docs )[0] self.dbcon.update_one({"_id": asset_doc_id}, asset_update) @@ -310,7 +309,7 @@ class Listener: # Update asset_doc_id, asset_update = update_op_assets( - self.dbcon, [shot], zou_ids_and_asset_docs + self.dbcon, project_doc, [shot], zou_ids_and_asset_docs )[0] self.dbcon.update_one({"_id": asset_doc_id}, asset_update) diff --git a/openpype/modules/kitsu/utils/update_op_with_zou.py b/openpype/modules/kitsu/utils/update_op_with_zou.py index fbc23cf52e..fa0bee8365 100644 --- a/openpype/modules/kitsu/utils/update_op_with_zou.py +++ b/openpype/modules/kitsu/utils/update_op_with_zou.py @@ -38,7 +38,7 @@ def set_op_project(dbcon: AvalonMongoDB, project_id: str): """Set project context. Args: - dbcon (AvalonMongoDB): Connection to DB. + dbcon (AvalonMongoDB): Connection to DB project_id (str): Project zou ID """ project = gazu.project.get_project(project_id) @@ -47,7 +47,8 @@ def set_op_project(dbcon: AvalonMongoDB, project_id: str): def update_op_assets( - project_col: Collection, + dbcon: AvalonMongoDB, + project_doc: dict, entities_list: List[dict], asset_doc_ids: Dict[str, dict], ) -> List[Dict[str, dict]]: @@ -55,19 +56,27 @@ def update_op_assets( Set 'data' and 'parent' fields. Args: - project_col (Collection): Mongo project collection to sync + dbcon (AvalonMongoDB): Connection to DB entities_list (List[dict]): List of zou entities to update asset_doc_ids (Dict[str, dict]): Dicts of [{zou_id: asset_doc}, ...] Returns: List[Dict[str, dict]]: List of (doc_id, update_dict) tuples """ - project_name = project_col.name + project_name = project_doc["name"] assets_with_update = [] for item in entities_list: + # Check asset exists + item_doc = asset_doc_ids.get(item["id"]) + if not item_doc: # Create asset + op_asset = create_op_asset(item) + insert_result = dbcon.insert_one(op_asset) + item_doc = dbcon.find_one( + {"type": "asset", "_id": insert_result.inserted_id} + ) + # Update asset - item_doc = asset_doc_ids[item["id"]] item_data = deepcopy(item_doc["data"]) item_data.update(item.get("data") or {}) item_data["zou"] = item @@ -86,7 +95,6 @@ def update_op_assets( item_data["frameEnd"] = int(frame_out) # Fps, fallback to project's value when entity fps is deleted if not item_data.get("fps") and item_doc["data"].get("fps"): - project_doc = project_col.find_one({"type": "project"}) item_data["fps"] = project_doc["data"]["fps"] # Tasks @@ -139,7 +147,7 @@ def update_op_assets( ) if visual_parent_doc_id is None: # Find root folder doc - root_folder_doc = project_col.find_one( + root_folder_doc = dbcon.find_one( { "type": "asset", "name": entity_parent_folders[-1], @@ -358,7 +366,7 @@ def sync_project_from_kitsu(dbcon: AvalonMongoDB, project: dict): [ UpdateOne({"_id": id}, update) for id, update in update_op_assets( - dbcon, all_entities, zou_ids_and_asset_docs + dbcon, project_doc, all_entities, zou_ids_and_asset_docs ) ] ) From c90a949076a1c8d2237fcc6ec118549344a50343 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Tue, 3 May 2022 12:41:37 +0200 Subject: [PATCH 114/350] call the launchfornuke module from the nuke menu.py to generate custom menu --- openpype/hosts/nuke/startup/menu.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/nuke/startup/menu.py b/openpype/hosts/nuke/startup/menu.py index dee1d9d868..3a0bfdb28f 100644 --- a/openpype/hosts/nuke/startup/menu.py +++ b/openpype/hosts/nuke/startup/menu.py @@ -58,4 +58,5 @@ def add_scripts_menu(): # apply configuration studio_menu.build_from_configuration(studio_menu, config) + add_scripts_menu() From a18c4d3d16e5454f86cd1b4f539c6e3031bd7c9c Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Tue, 3 May 2022 17:27:32 +0200 Subject: [PATCH 115/350] add a function in the nuke menu.py module to also add gizmos --- openpype/hosts/nuke/startup/menu.py | 58 +++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/openpype/hosts/nuke/startup/menu.py b/openpype/hosts/nuke/startup/menu.py index 3a0bfdb28f..bb81ee7fac 100644 --- a/openpype/hosts/nuke/startup/menu.py +++ b/openpype/hosts/nuke/startup/menu.py @@ -1,5 +1,6 @@ import nuke import os +import json import avalon.api from openpype.api import Logger @@ -59,4 +60,61 @@ def add_scripts_menu(): studio_menu.build_from_configuration(studio_menu, config) +def add_gizmos(): + """ Build a custom gizmo menu from a yaml description file. + """ + quad_plugin_path = os.environ.get("QUAD_PLUGIN_PATH") + gizmos_folder = os.path.join(quad_plugin_path, 'nuke/gizmos') + icons_folder = os.path.join(quad_plugin_path, 'nuke/icons') + json_file = os.path.join(quad_plugin_path, 'nuke/toolbar.json') + + if os.path.isdir(gizmos_folder): + for p in os.listdir(gizmos_folder): + if os.path.isdir(os.path.join(gizmos_folder, p)): + nuke.pluginAddPath(os.path.join(gizmos_folder, p)) + nuke.pluginAddPath(gizmos_folder) + + with open(json_file, 'rb') as fd: + try: + data = json.loads(fd.read()) + except Exception as e: + print(f"Problem occurs when reading toolbar file: {e}") + return + + if data is None or not isinstance(data, list): + # return early if the json file is empty or not well structured + return + + bar = nuke.menu("Nodes") + menu = bar.addMenu( + "FixStudio", + icon=os.path.join(icons_folder, 'fixstudio.png') + ) + + # populate the menu + for entry in data: + # make fail if the name or command key doesn't exists + name = entry['name'] + + command = entry.get('command', "") + + if command.find('{pipe_path}') > -1: + command = command.format(pipe_path=os.environ['QUAD_PLUGIN_PATH']) + + hotkey = entry.get('hotkey', "") + icon = entry.get('icon', "") + + parent_name = os.path.dirname(name) + + if 'separator' in name: + current = menu.findItem(parent_name) + if current: + current.addSeparator() + else: + menu.addCommand( + name, command=command, shortcut=hotkey, icon=icon, + ) + + +add_gizmos() add_scripts_menu() From f479dd8635b95c1463bab44d79c85d19fc72095e Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Tue, 3 May 2022 17:54:30 +0200 Subject: [PATCH 116/350] Revert "add a function in the nuke menu.py module to also add gizmos" This reverts commit 2f3bafb2fb8cbf247c354a8904acbc78ae081731. --- openpype/hosts/nuke/startup/menu.py | 58 ----------------------------- 1 file changed, 58 deletions(-) diff --git a/openpype/hosts/nuke/startup/menu.py b/openpype/hosts/nuke/startup/menu.py index bb81ee7fac..3a0bfdb28f 100644 --- a/openpype/hosts/nuke/startup/menu.py +++ b/openpype/hosts/nuke/startup/menu.py @@ -1,6 +1,5 @@ import nuke import os -import json import avalon.api from openpype.api import Logger @@ -60,61 +59,4 @@ def add_scripts_menu(): studio_menu.build_from_configuration(studio_menu, config) -def add_gizmos(): - """ Build a custom gizmo menu from a yaml description file. - """ - quad_plugin_path = os.environ.get("QUAD_PLUGIN_PATH") - gizmos_folder = os.path.join(quad_plugin_path, 'nuke/gizmos') - icons_folder = os.path.join(quad_plugin_path, 'nuke/icons') - json_file = os.path.join(quad_plugin_path, 'nuke/toolbar.json') - - if os.path.isdir(gizmos_folder): - for p in os.listdir(gizmos_folder): - if os.path.isdir(os.path.join(gizmos_folder, p)): - nuke.pluginAddPath(os.path.join(gizmos_folder, p)) - nuke.pluginAddPath(gizmos_folder) - - with open(json_file, 'rb') as fd: - try: - data = json.loads(fd.read()) - except Exception as e: - print(f"Problem occurs when reading toolbar file: {e}") - return - - if data is None or not isinstance(data, list): - # return early if the json file is empty or not well structured - return - - bar = nuke.menu("Nodes") - menu = bar.addMenu( - "FixStudio", - icon=os.path.join(icons_folder, 'fixstudio.png') - ) - - # populate the menu - for entry in data: - # make fail if the name or command key doesn't exists - name = entry['name'] - - command = entry.get('command', "") - - if command.find('{pipe_path}') > -1: - command = command.format(pipe_path=os.environ['QUAD_PLUGIN_PATH']) - - hotkey = entry.get('hotkey', "") - icon = entry.get('icon', "") - - parent_name = os.path.dirname(name) - - if 'separator' in name: - current = menu.findItem(parent_name) - if current: - current.addSeparator() - else: - menu.addCommand( - name, command=command, shortcut=hotkey, icon=icon, - ) - - -add_gizmos() add_scripts_menu() From 4e694a3f36f740fe9b5488cf75ba421e4b520d97 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Mon, 9 May 2022 11:27:51 +0200 Subject: [PATCH 117/350] changes from comments --- .../entities/schemas/projects_schema/schema_project_nuke.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json index 1fc925557b..1ae4efd8ea 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json @@ -290,10 +290,6 @@ } ] }, - { - "type": "schema", - "name": "schema_nuke_scriptsmenu" - }, { "type": "schema", "name": "schema_nuke_publish", From 2eea2522be0ecce65c8fc5876a628b15169f3189 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Mon, 9 May 2022 11:31:05 +0200 Subject: [PATCH 118/350] delete schema_nuke_scriptsmenu.json since we use a schema_scriptsmenu.json for both maya and nuke --- .../schemas/schema_nuke_scriptsmenu.json | 22 ------------------- 1 file changed, 22 deletions(-) delete mode 100644 openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsmenu.json diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsmenu.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsmenu.json deleted file mode 100644 index e841d6ba77..0000000000 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsmenu.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "type": "dict", - "collapsible": true, - "key": "scriptsmenu", - "label": "Scripts Menu Definition", - "children": [ - { - "type": "text", - "key": "name", - "label": "Menu Name" - }, - { - "type": "splitter" - }, - { - "type": "raw-json", - "key": "definition", - "label": "Menu definition", - "is_list": true - } - ] -} \ No newline at end of file From f081fe3521158cba9425f86a866fd50fc8106f6f Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Mon, 9 May 2022 11:58:28 +0200 Subject: [PATCH 119/350] add nuke doc for custom menu --- website/docs/admin_hosts_nuke.md | 14 ++++++++++++++ website/docs/assets/nuke-admin_scriptsmenu.png | Bin 0 -> 21712 bytes website/sidebars.js | 1 + 3 files changed, 15 insertions(+) create mode 100644 website/docs/admin_hosts_nuke.md create mode 100644 website/docs/assets/nuke-admin_scriptsmenu.png diff --git a/website/docs/admin_hosts_nuke.md b/website/docs/admin_hosts_nuke.md new file mode 100644 index 0000000000..46f596a2dc --- /dev/null +++ b/website/docs/admin_hosts_nuke.md @@ -0,0 +1,14 @@ +--- +id: admin_hosts_nuke +title: Nuke +sidebar_label: Nuke +--- + +## Custom Menu +You can add your custom tools menu into Nuke by extending definitions in **Nuke -> Scripts Menu Definition**. +![Custom menu definition](assets/nuke-admin_scriptsmenu.png) + +:::note Work in progress +This is still work in progress. Menu definition will be handled more friendly with widgets and not +raw json. +::: diff --git a/website/docs/assets/nuke-admin_scriptsmenu.png b/website/docs/assets/nuke-admin_scriptsmenu.png new file mode 100644 index 0000000000000000000000000000000000000000..cad2a4411d058a35995863a57bdbcc4cd2793457 GIT binary patch literal 21712 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 literal 0 HcmV?d00001 diff --git a/website/sidebars.js b/website/sidebars.js index 105afc30eb..0e33bed949 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -88,6 +88,7 @@ module.exports = { items: [ "admin_hosts_blender", "admin_hosts_maya", + "admin_hosts_nuke", "admin_hosts_resolve", "admin_hosts_harmony", "admin_hosts_aftereffects", From 70bb0fd7bc5c37447e6f7d7d9dcdce5f940de919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Wed, 11 May 2022 17:38:46 +0200 Subject: [PATCH 120/350] fix flake --- openpype/modules/kitsu/utils/update_op_with_zou.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/modules/kitsu/utils/update_op_with_zou.py b/openpype/modules/kitsu/utils/update_op_with_zou.py index fa0bee8365..10349a999c 100644 --- a/openpype/modules/kitsu/utils/update_op_with_zou.py +++ b/openpype/modules/kitsu/utils/update_op_with_zou.py @@ -4,7 +4,6 @@ import re from typing import Dict, List from pymongo import DeleteOne, UpdateOne -from pymongo.collection import Collection import gazu from gazu.task import ( all_tasks_for_asset, From d5fa437912b8f03dfa705967c60fe2212065996a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 11 May 2022 17:51:11 +0200 Subject: [PATCH 121/350] flame: thumbnail frame number if not `Sequence Publish` --- .../flame/plugins/publish/extract_subset_resources.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index fd0ece2590..7dcaec7eee 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -236,6 +236,17 @@ class ExtractSubsetResources(openpype.api.Extractor): # define kwargs based on preset type if "thumbnail" in unique_name: + if export_type != "Sequence Publish": + # if not sequence preset + in_mark = int(source_start_handles - source_first_frame) + + self.log.debug("__ in_mark: {}".format(in_mark)) + self.log.debug("__ source_duration_handles: {}".format( + source_duration_handles)) + self.log.debug("__ thumb_frame_number: {}".format( + int(in_mark + (source_duration_handles / 2)) + )) + export_kwargs["thumb_frame_number"] = int(in_mark + ( source_duration_handles / 2)) else: From 8f24a764fd3f5061573931757e0eb6817949e77f Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 11 May 2022 18:02:22 +0200 Subject: [PATCH 122/350] remove avalon.api import --- openpype/hosts/nuke/startup/menu.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/nuke/startup/menu.py b/openpype/hosts/nuke/startup/menu.py index 3a0bfdb28f..49edb22a89 100644 --- a/openpype/hosts/nuke/startup/menu.py +++ b/openpype/hosts/nuke/startup/menu.py @@ -1,7 +1,6 @@ import nuke import os -import avalon.api from openpype.api import Logger from openpype.pipeline import install_host from openpype.hosts.nuke import api From 8892422b0edb6182a119dc848bdfa534e344744b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 11 May 2022 21:22:01 +0200 Subject: [PATCH 123/350] flame: attempt to solve issue with single frame imported clip --- openpype/hosts/flame/api/lib.py | 24 ++++++++++++++---- .../publish/extract_subset_resources.py | 25 ++++++++++++++----- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/openpype/hosts/flame/api/lib.py b/openpype/hosts/flame/api/lib.py index 933cfbe267..80818fbbfd 100644 --- a/openpype/hosts/flame/api/lib.py +++ b/openpype/hosts/flame/api/lib.py @@ -763,6 +763,7 @@ class MediaInfoFile(object): _start_frame = None _fps = None _drop_mode = None + _file_pattern = None def __init__(self, path, **kwargs): @@ -778,24 +779,25 @@ class MediaInfoFile(object): feed_dir = os.path.dirname(path) feed_ext = os.path.splitext(feed_basename)[1][1:].lower() + with maintained_temp_file_path(".clip") as tmp_path: self.log.info("Temp File: {}".format(tmp_path)) self._generate_media_info_file(tmp_path, feed_ext, feed_dir) # get collection containing feed_basename from path - test_fname = self._get_collection( + self.file_pattern = self._get_collection( feed_basename, feed_dir, feed_ext) if ( - not test_fname + not self.file_pattern and os.path.exists(os.path.join(feed_dir, feed_basename)) ): - test_fname = feed_basename + self.file_pattern = feed_basename # get clip data and make them single if there is multiple # clips data xml_data = self._make_single_clip_media_info( - tmp_path, feed_basename, test_fname) + tmp_path, feed_basename, self.file_pattern) self.log.debug("xml_data: {}".format(xml_data)) self.log.debug("type: {}".format(type(xml_data))) @@ -816,7 +818,6 @@ class MediaInfoFile(object): Raises: AttributeError: feed_ext is not matching feed_basename - IOError: Failing on not correct input data Returns: str: collection basename with range of sequence @@ -956,6 +957,19 @@ class MediaInfoFile(object): def drop_mode(self, text): self._drop_mode = str(text) + @property + def file_pattern(self): + """Clips file patter + + Returns: + str: file pattern. ex. file.[1-2].exr + """ + return self._file_pattern + + @file_pattern.setter + def file_pattern(self, fpattern): + self._file_pattern = fpattern + def _validate_media_script_path(self): if not os.path.isfile(self.MEDIA_SCRIPT_PATH): raise IOError("Media Scirpt does not exist: `{}`".format( diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index 7dcaec7eee..d8cc14a506 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -6,6 +6,7 @@ from copy import deepcopy import pyblish.api import openpype.api from openpype.hosts.flame import api as opfapi +from openpype.hosts.flame.api import MediaInfoFile import flame @@ -67,6 +68,7 @@ class ExtractSubsetResources(openpype.api.Extractor): instance.data["representations"] = [] # flame objects + self.project = instance.context.data["flameProject"] segment = instance.data["item"] asset_name = instance.data["asset"] segment_name = segment.name.get_value() @@ -239,16 +241,18 @@ class ExtractSubsetResources(openpype.api.Extractor): if export_type != "Sequence Publish": # if not sequence preset in_mark = int(source_start_handles - source_first_frame) + thumb_frame_number = int(in_mark + ( + source_duration_handles / 2)) + else: + thumb_frame_number = int(in_mark + ( + (clip_out - clip_in) / 2)) self.log.debug("__ in_mark: {}".format(in_mark)) - self.log.debug("__ source_duration_handles: {}".format( - source_duration_handles)) self.log.debug("__ thumb_frame_number: {}".format( - int(in_mark + (source_duration_handles / 2)) + thumb_frame_number )) - export_kwargs["thumb_frame_number"] = int(in_mark + ( - source_duration_handles / 2)) + export_kwargs["thumb_frame_number"] = thumb_frame_number else: export_kwargs.update({ "in_mark": in_mark, @@ -419,7 +423,16 @@ class ExtractSubsetResources(openpype.api.Extractor): """ Import clip from path """ - clips = flame.import_clips(path) + media_info = MediaInfoFile(path, **{ + "logger": self.log + }) + file_pattern = media_info.file_pattern + self.log.debug("__ file_pattern: {}".format(file_pattern)) + + project_desktop = self.project.current_workspace.desktop + reel = project_desktop.reel_groups[0].reels[0] + + clips = flame.import_clips(file_pattern, reel) self.log.info("Clips [{}] imported from `{}`".format(clips, path)) if not clips: self.log.warning("Path `{}` is not having any clips".format(path)) From 12abc9e2bec0715836bd7d0ad3fe740b92e6eab4 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 11 May 2022 21:31:12 +0200 Subject: [PATCH 124/350] flame: thumbnails and mov presets are created correctly now --- .../flame/plugins/publish/extract_subset_resources.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index d8cc14a506..6098f2e1e9 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -423,17 +423,19 @@ class ExtractSubsetResources(openpype.api.Extractor): """ Import clip from path """ + dir_path = os.path.dirname(path) media_info = MediaInfoFile(path, **{ "logger": self.log }) file_pattern = media_info.file_pattern self.log.debug("__ file_pattern: {}".format(file_pattern)) - project_desktop = self.project.current_workspace.desktop - reel = project_desktop.reel_groups[0].reels[0] + # rejoin the pattern to dir path + new_path = os.path.join(dir_path, file_pattern) - clips = flame.import_clips(file_pattern, reel) + clips = flame.import_clips(new_path) self.log.info("Clips [{}] imported from `{}`".format(clips, path)) + if not clips: self.log.warning("Path `{}` is not having any clips".format(path)) return None From df1b5c6e66cdf48f5f26fca6812d208ad24dd5b3 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 12 May 2022 08:57:04 +0200 Subject: [PATCH 125/350] flame: reducing code redundancy --- .../publish/extract_subset_resources.py | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index 6098f2e1e9..176629fbfc 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -68,7 +68,6 @@ class ExtractSubsetResources(openpype.api.Extractor): instance.data["representations"] = [] # flame objects - self.project = instance.context.data["flameProject"] segment = instance.data["item"] asset_name = instance.data["asset"] segment_name = segment.name.get_value() @@ -182,15 +181,15 @@ class ExtractSubsetResources(openpype.api.Extractor): name_patern_xml = ( "__{}.").format( unique_name) + + # change in/out marks to timeline in/out + in_mark = clip_in + out_mark = clip_out else: exporting_clip = self.import_clip(clip_path) exporting_clip.name.set_value("{}_{}".format( asset_name, segment_name)) - # change in/out marks to timeline in/out - in_mark = clip_in - out_mark = clip_out - # add xml tags modifications modify_xml_data.update({ "exportHandles": True, @@ -238,14 +237,8 @@ class ExtractSubsetResources(openpype.api.Extractor): # define kwargs based on preset type if "thumbnail" in unique_name: - if export_type != "Sequence Publish": - # if not sequence preset - in_mark = int(source_start_handles - source_first_frame) - thumb_frame_number = int(in_mark + ( - source_duration_handles / 2)) - else: - thumb_frame_number = int(in_mark + ( - (clip_out - clip_in) / 2)) + thumb_frame_number = int(in_mark + ( + source_duration_handles / 2)) self.log.debug("__ in_mark: {}".format(in_mark)) self.log.debug("__ thumb_frame_number: {}".format( From 987b5df1ddf44a0feabe27feca8930782a05d18b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Thu, 12 May 2022 09:16:49 +0200 Subject: [PATCH 126/350] optim get_project_settings --- openpype/modules/kitsu/utils/update_op_with_zou.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/kitsu/utils/update_op_with_zou.py b/openpype/modules/kitsu/utils/update_op_with_zou.py index 10349a999c..0c72537c94 100644 --- a/openpype/modules/kitsu/utils/update_op_with_zou.py +++ b/openpype/modules/kitsu/utils/update_op_with_zou.py @@ -63,6 +63,7 @@ def update_op_assets( List[Dict[str, dict]]: List of (doc_id, update_dict) tuples """ project_name = project_doc["name"] + project_module_settings = get_project_settings(project_name)["kitsu"] assets_with_update = [] for item in entities_list: @@ -126,7 +127,6 @@ def update_op_assets( ) # TODO check consistency # Substitute Episode and Sequence by Shot - project_module_settings = get_project_settings(project_name)["kitsu"] substitute_item_type = ( "shots" if item_type in ["Episode", "Sequence"] From e0bd8777d1b9563d292a72ff592e461eb47e50f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Thu, 12 May 2022 09:42:51 +0200 Subject: [PATCH 127/350] pop useless item_data --- openpype/modules/kitsu/utils/update_op_with_zou.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/modules/kitsu/utils/update_op_with_zou.py b/openpype/modules/kitsu/utils/update_op_with_zou.py index 0c72537c94..673a195747 100644 --- a/openpype/modules/kitsu/utils/update_op_with_zou.py +++ b/openpype/modules/kitsu/utils/update_op_with_zou.py @@ -85,6 +85,7 @@ def update_op_assets( # Frame in, fallback on 0 frame_in = int(item_data.get("frame_in") or 0) item_data["frameStart"] = frame_in + item_data.pop("frame_in") # Frame out, fallback on frame_in + duration frames_duration = int(item.get("nb_frames") or 1) frame_out = ( @@ -93,6 +94,7 @@ def update_op_assets( else frame_in + frames_duration ) item_data["frameEnd"] = int(frame_out) + item_data.pop("frame_out") # Fps, fallback to project's value when entity fps is deleted if not item_data.get("fps") and item_doc["data"].get("fps"): item_data["fps"] = project_doc["data"]["fps"] From ae69db29cac488410fa00c547042126831d3be0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Thu, 12 May 2022 09:59:02 +0200 Subject: [PATCH 128/350] black pyblish --- .../plugins/publish/collect_kitsu_credential.py | 4 ++-- .../plugins/publish/collect_kitsu_entities.py | 16 ++++------------ .../plugins/publish/integrate_kitsu_note.py | 6 ++---- .../plugins/publish/integrate_kitsu_review.py | 9 ++------- .../plugins/publish/validate_kitsu_intent.py | 6 ++---- 5 files changed, 12 insertions(+), 29 deletions(-) diff --git a/openpype/modules/kitsu/plugins/publish/collect_kitsu_credential.py b/openpype/modules/kitsu/plugins/publish/collect_kitsu_credential.py index 4a27117e03..b7f6f67a40 100644 --- a/openpype/modules/kitsu/plugins/publish/collect_kitsu_credential.py +++ b/openpype/modules/kitsu/plugins/publish/collect_kitsu_credential.py @@ -5,7 +5,7 @@ import gazu import pyblish.api -class CollectKitsuSession(pyblish.api.ContextPlugin): #rename log in +class CollectKitsuSession(pyblish.api.ContextPlugin): # rename log in """Collect Kitsu session using user credentials""" order = pyblish.api.CollectorOrder @@ -15,4 +15,4 @@ class CollectKitsuSession(pyblish.api.ContextPlugin): #rename log in def process(self, context): gazu.client.set_host(os.environ["KITSU_SERVER"]) - gazu.log_in(os.environ["KITSU_LOGIN"], os.environ["KITSU_PWD"]) \ No newline at end of file + gazu.log_in(os.environ["KITSU_LOGIN"], os.environ["KITSU_PWD"]) diff --git a/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py index 935b020641..66c35e54c4 100644 --- a/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py +++ b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py @@ -19,8 +19,7 @@ class CollectKitsuEntities(pyblish.api.ContextPlugin): raise AssertionError("Zou asset data not found in OpenPype!") self.log.debug("Collected zou asset data: {}".format(zou_asset_data)) - zou_task_data = asset_data["tasks"][ - os.environ["AVALON_TASK"]].get("zou") + zou_task_data = asset_data["tasks"][os.environ["AVALON_TASK"]].get("zou") if not zou_task_data: self.log.warning("Zou task data not found in OpenPype!") self.log.debug("Collected zou task data: {}".format(zou_task_data)) @@ -45,20 +44,13 @@ class CollectKitsuEntities(pyblish.api.ContextPlugin): self.log.debug("Collect kitsu task: {}".format(kitsu_task)) else: - kitsu_task_type = gazu.task.get_task_type_by_name( - os.environ["AVALON_TASK"] - ) + kitsu_task_type = gazu.task.get_task_type_by_name(os.environ["AVALON_TASK"]) if not kitsu_task_type: raise AssertionError( - "Task type {} not found in Kitsu!".format( - os.environ["AVALON_TASK"] - ) + "Task type {} not found in Kitsu!".format(os.environ["AVALON_TASK"]) ) - kitsu_task = gazu.task.get_task_by_name( - kitsu_asset, - kitsu_task_type - ) + kitsu_task = gazu.task.get_task_by_name(kitsu_asset, kitsu_task_type) if not kitsu_task: raise AssertionError("Task not found in kitsu!") context.data["kitsu_task"] = kitsu_task diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py index 61e4d2454c..99d891d514 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py @@ -30,9 +30,7 @@ class IntegrateKitsuNote(pyblish.api.ContextPlugin): self.log.debug("Kitsu status: {}".format(kitsu_status)) kitsu_comment = gazu.task.add_comment( - context.data["kitsu_task"], - kitsu_status, - comment = publish_comment + context.data["kitsu_task"], kitsu_status, comment=publish_comment ) - context.data["kitsu_comment"] = kitsu_comment \ No newline at end of file + context.data["kitsu_comment"] = kitsu_comment diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py index c38f14e8a4..65179bc0bf 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py @@ -21,15 +21,10 @@ class IntegrateKitsuReview(pyblish.api.InstancePlugin): review_path = representation.get("published_path") - if 'review' not in representation.get("tags", []): + if "review" not in representation.get("tags", []): continue self.log.debug("Found review at: {}".format(review_path)) - gazu.task.add_preview( - task, - comment, - review_path, - normalize_movie=True - ) + gazu.task.add_preview(task, comment, review_path, normalize_movie=True) self.log.info("Review upload on comment") diff --git a/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py b/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py index c82130b33b..e0fad3b79f 100644 --- a/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py +++ b/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py @@ -19,9 +19,7 @@ class ValidateKitsuIntent(pyblish.api.ContextPlugin): kitsu_status = gazu.task.get_task_status_by_short_name(publish_status) if not kitsu_status: - raise AssertionError( - "Status `{}` not found in kitsu!".format(kitsu_status) - ) + raise AssertionError("Status `{}` not found in kitsu!".format(kitsu_status)) self.log.debug("Collect kitsu status: {}".format(kitsu_status)) - context.data["kitsu_status"] = kitsu_status \ No newline at end of file + context.data["kitsu_status"] = kitsu_status From 3583d85cd2a7d25abf184411c23a273b0f8671c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Thu, 12 May 2022 09:59:35 +0200 Subject: [PATCH 129/350] black pyblish --- .../plugins/publish/collect_kitsu_entities.py | 16 ++++++++++++---- .../plugins/publish/integrate_kitsu_review.py | 4 +++- .../plugins/publish/validate_kitsu_intent.py | 4 +++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py index 66c35e54c4..84c400bde9 100644 --- a/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py +++ b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py @@ -19,7 +19,9 @@ class CollectKitsuEntities(pyblish.api.ContextPlugin): raise AssertionError("Zou asset data not found in OpenPype!") self.log.debug("Collected zou asset data: {}".format(zou_asset_data)) - zou_task_data = asset_data["tasks"][os.environ["AVALON_TASK"]].get("zou") + zou_task_data = asset_data["tasks"][os.environ["AVALON_TASK"]].get( + "zou" + ) if not zou_task_data: self.log.warning("Zou task data not found in OpenPype!") self.log.debug("Collected zou task data: {}".format(zou_task_data)) @@ -44,13 +46,19 @@ class CollectKitsuEntities(pyblish.api.ContextPlugin): self.log.debug("Collect kitsu task: {}".format(kitsu_task)) else: - kitsu_task_type = gazu.task.get_task_type_by_name(os.environ["AVALON_TASK"]) + kitsu_task_type = gazu.task.get_task_type_by_name( + os.environ["AVALON_TASK"] + ) if not kitsu_task_type: raise AssertionError( - "Task type {} not found in Kitsu!".format(os.environ["AVALON_TASK"]) + "Task type {} not found in Kitsu!".format( + os.environ["AVALON_TASK"] + ) ) - kitsu_task = gazu.task.get_task_by_name(kitsu_asset, kitsu_task_type) + kitsu_task = gazu.task.get_task_by_name( + kitsu_asset, kitsu_task_type + ) if not kitsu_task: raise AssertionError("Task not found in kitsu!") context.data["kitsu_task"] = kitsu_task diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py index 65179bc0bf..08fa4ee010 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py @@ -26,5 +26,7 @@ class IntegrateKitsuReview(pyblish.api.InstancePlugin): self.log.debug("Found review at: {}".format(review_path)) - gazu.task.add_preview(task, comment, review_path, normalize_movie=True) + gazu.task.add_preview( + task, comment, review_path, normalize_movie=True + ) self.log.info("Review upload on comment") diff --git a/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py b/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py index e0fad3b79f..6b2635bf05 100644 --- a/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py +++ b/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py @@ -19,7 +19,9 @@ class ValidateKitsuIntent(pyblish.api.ContextPlugin): kitsu_status = gazu.task.get_task_status_by_short_name(publish_status) if not kitsu_status: - raise AssertionError("Status `{}` not found in kitsu!".format(kitsu_status)) + raise AssertionError( + "Status `{}` not found in kitsu!".format(kitsu_status) + ) self.log.debug("Collect kitsu status: {}".format(kitsu_status)) context.data["kitsu_status"] = kitsu_status From 2a94ac1248446d8735bf34ebda62356af5658358 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Thu, 12 May 2022 10:10:57 +0200 Subject: [PATCH 130/350] Add doc to default value --- openpype/settings/defaults/project_settings/nuke.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index a9d284873c..7f916424ed 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -17,7 +17,15 @@ }, "scriptsmenu": { "name": "OpenPype Tools", - "definition": [] + "definition": [ + { + "type": "action", + "sourcetype": "python", + "title": "OpenPype Docs", + "command": "import webbrowser;webbrowser.open(url='https://openpype.io/docs/artist_hosts_nuke_tut')", + "tooltip": "Open the OpenPype Nuke user doc page" + } + ] }, "create": { "CreateWriteRender": { From 687f7260ceef7c0c3b2966f387e0f678a0fa0f8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Thu, 12 May 2022 10:57:18 +0200 Subject: [PATCH 131/350] optim publish status intent --- .../modules/kitsu/plugins/publish/validate_kitsu_intent.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py b/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py index 6b2635bf05..e2023b171e 100644 --- a/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py +++ b/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py @@ -12,10 +12,11 @@ class ValidateKitsuIntent(pyblish.api.ContextPlugin): optional = True def process(self, context): - + # Check publish status exists publish_status = context.data.get("intent", {}).get("value") if not publish_status: self.log.info("Status is not set.") + return kitsu_status = gazu.task.get_task_status_by_short_name(publish_status) if not kitsu_status: From 20f819c1dd2eab2e6401a80c3996c3a93ca0a089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Thu, 12 May 2022 12:36:47 +0200 Subject: [PATCH 132/350] change intent wrongly used as status choice --- .../plugins/publish/collect_kitsu_entities.py | 16 +++-------- .../plugins/publish/integrate_kitsu_note.py | 20 ++++++++----- .../plugins/publish/integrate_kitsu_review.py | 21 ++++++++------ .../plugins/publish/validate_kitsu_intent.py | 28 ------------------- 4 files changed, 30 insertions(+), 55 deletions(-) delete mode 100644 openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py diff --git a/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py index 84c400bde9..66c35e54c4 100644 --- a/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py +++ b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py @@ -19,9 +19,7 @@ class CollectKitsuEntities(pyblish.api.ContextPlugin): raise AssertionError("Zou asset data not found in OpenPype!") self.log.debug("Collected zou asset data: {}".format(zou_asset_data)) - zou_task_data = asset_data["tasks"][os.environ["AVALON_TASK"]].get( - "zou" - ) + zou_task_data = asset_data["tasks"][os.environ["AVALON_TASK"]].get("zou") if not zou_task_data: self.log.warning("Zou task data not found in OpenPype!") self.log.debug("Collected zou task data: {}".format(zou_task_data)) @@ -46,19 +44,13 @@ class CollectKitsuEntities(pyblish.api.ContextPlugin): self.log.debug("Collect kitsu task: {}".format(kitsu_task)) else: - kitsu_task_type = gazu.task.get_task_type_by_name( - os.environ["AVALON_TASK"] - ) + kitsu_task_type = gazu.task.get_task_type_by_name(os.environ["AVALON_TASK"]) if not kitsu_task_type: raise AssertionError( - "Task type {} not found in Kitsu!".format( - os.environ["AVALON_TASK"] - ) + "Task type {} not found in Kitsu!".format(os.environ["AVALON_TASK"]) ) - kitsu_task = gazu.task.get_task_by_name( - kitsu_asset, kitsu_task_type - ) + kitsu_task = gazu.task.get_task_by_name(kitsu_asset, kitsu_task_type) if not kitsu_task: raise AssertionError("Task not found in kitsu!") context.data["kitsu_task"] = kitsu_task diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py index 99d891d514..980589365d 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py @@ -11,24 +11,30 @@ class IntegrateKitsuNote(pyblish.api.ContextPlugin): # families = ["kitsu"] def process(self, context): + # Check if work version for user + is_work_version = bool(context.data.get("intent", {}).get("value")) + if is_work_version: + self.log.info("Work version, nothing pushed to Kitsu.") + return + # Get comment text body publish_comment = context.data.get("comment") if not publish_comment: self.log.info("Comment is not set.") - publish_status = context.data.get("intent", {}).get("value") - if not publish_status: - self.log.info("Status is not set.") - self.log.debug("Comment is `{}`".format(publish_comment)) - self.log.debug("Status is `{}`".format(publish_status)) - kitsu_status = context.data.get("kitsu_status") + # Get Waiting for Approval status + kitsu_status = gazu.task.get_task_status_by_short_name("wfa") if not kitsu_status: - self.log.info("The status will not be changed") + self.log.info( + "Cannot find 'Waiting For Approval' status." + "The status will not be changed" + ) kitsu_status = context.data["kitsu_task"].get("task_status") self.log.debug("Kitsu status: {}".format(kitsu_status)) + # Add comment to kitsu task kitsu_comment = gazu.task.add_comment( context.data["kitsu_task"], kitsu_status, comment=publish_comment ) diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py index 08fa4ee010..76cfe62988 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py @@ -15,18 +15,23 @@ class IntegrateKitsuReview(pyblish.api.InstancePlugin): context = instance.context task = context.data["kitsu_task"] - comment = context.data["kitsu_comment"] + comment = context.data.get("kitsu_comment") - for representation in instance.data.get("representations", []): + # Check comment has been created + if not comment: + self.log.debug("Comment not created, review not pushed to preview.") + return + + # Add review representations as preview of comment + for representation in [ + r + for r in instance.data.get("representations", []) + if "review" in representation.get("tags", []) + ]: review_path = representation.get("published_path") - if "review" not in representation.get("tags", []): - continue - self.log.debug("Found review at: {}".format(review_path)) - gazu.task.add_preview( - task, comment, review_path, normalize_movie=True - ) + gazu.task.add_preview(task, comment, review_path, normalize_movie=True) self.log.info("Review upload on comment") diff --git a/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py b/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py deleted file mode 100644 index e2023b171e..0000000000 --- a/openpype/modules/kitsu/plugins/publish/validate_kitsu_intent.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- -import pyblish.api -import gazu - - -class ValidateKitsuIntent(pyblish.api.ContextPlugin): - """Validate Kitsu Status""" - - order = pyblish.api.ValidatorOrder - label = "Kitsu Intent/Status" - # families = ["kitsu"] - optional = True - - def process(self, context): - # Check publish status exists - publish_status = context.data.get("intent", {}).get("value") - if not publish_status: - self.log.info("Status is not set.") - return - - kitsu_status = gazu.task.get_task_status_by_short_name(publish_status) - if not kitsu_status: - raise AssertionError( - "Status `{}` not found in kitsu!".format(kitsu_status) - ) - self.log.debug("Collect kitsu status: {}".format(kitsu_status)) - - context.data["kitsu_status"] = kitsu_status From 330d4340cc082307bd2a5bda951d7f2e491279f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Thu, 12 May 2022 12:39:03 +0200 Subject: [PATCH 133/350] black --- .../plugins/publish/collect_kitsu_entities.py | 16 ++++++++++++---- .../plugins/publish/integrate_kitsu_review.py | 10 +++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py index 66c35e54c4..84c400bde9 100644 --- a/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py +++ b/openpype/modules/kitsu/plugins/publish/collect_kitsu_entities.py @@ -19,7 +19,9 @@ class CollectKitsuEntities(pyblish.api.ContextPlugin): raise AssertionError("Zou asset data not found in OpenPype!") self.log.debug("Collected zou asset data: {}".format(zou_asset_data)) - zou_task_data = asset_data["tasks"][os.environ["AVALON_TASK"]].get("zou") + zou_task_data = asset_data["tasks"][os.environ["AVALON_TASK"]].get( + "zou" + ) if not zou_task_data: self.log.warning("Zou task data not found in OpenPype!") self.log.debug("Collected zou task data: {}".format(zou_task_data)) @@ -44,13 +46,19 @@ class CollectKitsuEntities(pyblish.api.ContextPlugin): self.log.debug("Collect kitsu task: {}".format(kitsu_task)) else: - kitsu_task_type = gazu.task.get_task_type_by_name(os.environ["AVALON_TASK"]) + kitsu_task_type = gazu.task.get_task_type_by_name( + os.environ["AVALON_TASK"] + ) if not kitsu_task_type: raise AssertionError( - "Task type {} not found in Kitsu!".format(os.environ["AVALON_TASK"]) + "Task type {} not found in Kitsu!".format( + os.environ["AVALON_TASK"] + ) ) - kitsu_task = gazu.task.get_task_by_name(kitsu_asset, kitsu_task_type) + kitsu_task = gazu.task.get_task_by_name( + kitsu_asset, kitsu_task_type + ) if not kitsu_task: raise AssertionError("Task not found in kitsu!") context.data["kitsu_task"] = kitsu_task diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py index 76cfe62988..57e0286b00 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py @@ -19,19 +19,23 @@ class IntegrateKitsuReview(pyblish.api.InstancePlugin): # Check comment has been created if not comment: - self.log.debug("Comment not created, review not pushed to preview.") + self.log.debug( + "Comment not created, review not pushed to preview." + ) return # Add review representations as preview of comment for representation in [ r for r in instance.data.get("representations", []) - if "review" in representation.get("tags", []) + if "review" in r.get("tags", []) ]: review_path = representation.get("published_path") self.log.debug("Found review at: {}".format(review_path)) - gazu.task.add_preview(task, comment, review_path, normalize_movie=True) + gazu.task.add_preview( + task, comment, review_path, normalize_movie=True + ) self.log.info("Review upload on comment") From dd77f7cd9bff9bfa5405ba13aa5760675b1b2a89 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 12 May 2022 13:37:34 +0200 Subject: [PATCH 134/350] flame: fixing padding in collection ranges --- openpype/hosts/flame/api/lib.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/flame/api/lib.py b/openpype/hosts/flame/api/lib.py index 80818fbbfd..f2f5db184b 100644 --- a/openpype/hosts/flame/api/lib.py +++ b/openpype/hosts/flame/api/lib.py @@ -848,9 +848,10 @@ class MediaInfoFile(object): # we expect only one collection collection = collections[0] + self.log.debug("__ collection: {}".format(collection)) + if collection.is_contiguous(): - # if no holes then return collection - return collection.format("{head}[{range}]{tail}") + return self._format_collection(collection) # add `[` in front to make sure it want capture # shot name with the same number @@ -858,11 +859,25 @@ class MediaInfoFile(object): # convert to multiple collections _continues_colls = collection.separate() for _coll in _continues_colls: - coll_to_text = _coll.format("{head}[{range}]{tail}") + coll_to_text = self._format_collection(_coll) self.log.debug("__ coll_to_text: {}".format(coll_to_text)) if number_from_path in coll_to_text: return coll_to_text + @staticmethod + def _format_collection(collection): + # if no holes then return collection + head = collection.format("{head}") + tail = collection.format("{tail}") + range_template = "[{{:0{0}d}}-{{:0{0}d}}]".format( + len(str(max(collection.indexes)))) + ranges = range_template.format( + min(collection.indexes), + max(collection.indexes) + ) + # if no holes then return collection + return "{}{}{}".format(head, ranges, tail) + def _separate_file_head(self, basename, extension): """ Get only head with out sequence and extension From aeff57dab75cb1a37d0f971b96d36b3cebd0ef0e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 12 May 2022 15:08:38 +0200 Subject: [PATCH 135/350] flame: expanding retiming features --- openpype/hosts/flame/otio/flame_export.py | 74 ++++++++++++++--------- 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/openpype/hosts/flame/otio/flame_export.py b/openpype/hosts/flame/otio/flame_export.py index c54ebb43d3..e3801a0a4f 100644 --- a/openpype/hosts/flame/otio/flame_export.py +++ b/openpype/hosts/flame/otio/flame_export.py @@ -98,26 +98,26 @@ def _get_metadata(item): return {} -# def create_time_effects(otio_clip, clip_data): -# otio_effect = None +def create_time_effects(otio_clip, speed): + otio_effect = None -# # retime on track item -# if speed != 1.: -# # make effect -# otio_effect = otio.schema.LinearTimeWarp() -# otio_effect.name = "Speed" -# otio_effect.time_scalar = speed -# otio_effect.metadata = {} + # retime on track item + if speed != 1.: + # make effect + otio_effect = otio.schema.LinearTimeWarp() + otio_effect.name = "Speed" + otio_effect.time_scalar = speed + otio_effect.metadata = {} -# # freeze frame effect -# if speed == 0.: -# otio_effect = otio.schema.FreezeFrame() -# otio_effect.name = "FreezeFrame" -# otio_effect.metadata = {} + # freeze frame effect + if speed == 0.: + otio_effect = otio.schema.FreezeFrame() + otio_effect.name = "FreezeFrame" + otio_effect.metadata = {} -# if otio_effect: -# # add otio effect to clip effects -# otio_clip.effects.append(otio_effect) + if otio_effect: + # add otio effect to clip effects + otio_clip.effects.append(otio_effect) def _get_marker_color(flame_colour): @@ -205,7 +205,7 @@ def create_otio_markers(otio_item, item): otio_item.markers.append(otio_marker) -def create_otio_reference(clip_data, fps=None): +def create_otio_reference(clip_data, duration, fps=None): metadata = _get_metadata(clip_data) # get file info for path and start frame @@ -220,7 +220,6 @@ def create_otio_reference(clip_data, fps=None): # get padding and other file infos log.debug("_ path: {}".format(path)) - frame_duration = clip_data["source_duration"] otio_ex_ref_item = None is_sequence = frame_number = utils.get_frame_from_filename(file_name) @@ -247,7 +246,7 @@ def create_otio_reference(clip_data, fps=None): rate=fps, available_range=create_otio_time_range( frame_start, - frame_duration, + duration, fps ) ) @@ -263,7 +262,7 @@ def create_otio_reference(clip_data, fps=None): target_url=reformated_path, available_range=create_otio_time_range( frame_start, - frame_duration, + duration, fps ) ) @@ -286,19 +285,39 @@ def create_otio_clip(clip_data): media_timecode_start = media_info.start_frame media_fps = media_info.fps - # create media reference - media_reference = create_otio_reference(clip_data, media_fps) - # define first frame first_frame = media_timecode_start or utils.get_frame_from_filename( clip_data["fpath"]) or 0 - source_in = int(clip_data["source_in"]) - int(first_frame) + _clip_source_in = int(clip_data["source_in"]) + _clip_source_out = int(clip_data["source_out"]) + _clip_record_duration = int(clip_data["record_duration"]) + + # first solve if the reverse timing + speed = 1 + if clip_data["source_in"] > clip_data["source_out"]: + source_in = _clip_source_out - int(first_frame) + source_out = _clip_source_in - int(first_frame) + speed = -1 + else: + source_in = _clip_source_in - int(first_frame) + source_out = _clip_source_out - int(first_frame) + + source_duration = (source_out - source_in + 1) + + # secondly check if any change of speed + if source_duration != _clip_record_duration: + retime_speed = source_duration / _clip_record_duration + speed *= retime_speed + + # create media reference + media_reference = create_otio_reference( + clip_data, source_duration, media_fps) # creatae source range source_range = create_otio_time_range( source_in, - clip_data["record_duration"], + _clip_record_duration, CTX.get_fps() ) @@ -312,7 +331,8 @@ def create_otio_clip(clip_data): if MARKERS_INCLUDE: create_otio_markers(otio_clip, segment) - # create_time_effects(otio_clip, clip_data) + if speed != 1: + create_time_effects(otio_clip, speed) return otio_clip From ce250a6749cd0f6d6f220ada9830ed154ef4e481 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 12 May 2022 15:10:17 +0200 Subject: [PATCH 136/350] flame: debug logging --- openpype/hosts/flame/otio/flame_export.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openpype/hosts/flame/otio/flame_export.py b/openpype/hosts/flame/otio/flame_export.py index e3801a0a4f..500b1a3eb1 100644 --- a/openpype/hosts/flame/otio/flame_export.py +++ b/openpype/hosts/flame/otio/flame_export.py @@ -305,6 +305,11 @@ def create_otio_clip(clip_data): source_duration = (source_out - source_in + 1) + log.debug("_ source_in: {}".format(source_in)) + log.debug("_ source_out: {}".format(source_out)) + log.debug("_ speed: {}".format(speed)) + log.debug("_ source_duration: {}".format(source_duration)) + # secondly check if any change of speed if source_duration != _clip_record_duration: retime_speed = source_duration / _clip_record_duration From ee274f81e33fdb8a9741f2c2d397355702de5699 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 12 May 2022 15:12:03 +0200 Subject: [PATCH 137/350] flame: solving issue with frame longer renders --- .../hosts/flame/plugins/publish/extract_subset_resources.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index 176629fbfc..0e04336211 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -160,7 +160,7 @@ class ExtractSubsetResources(openpype.api.Extractor): # get frame range with handles for representation range frame_start_handle = frame_start - handle_start source_duration_handles = ( - source_end_handles - source_start_handles) + 1 + source_end_handles - source_start_handles) # define in/out marks in_mark = (source_start_handles - source_first_frame) + 1 From 3f917055c135be7b6ba984a6c1245384b3389c79 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 12 May 2022 15:21:15 +0200 Subject: [PATCH 138/350] flame: improving logging --- openpype/hosts/flame/otio/flame_export.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/flame/otio/flame_export.py b/openpype/hosts/flame/otio/flame_export.py index 500b1a3eb1..8562a766e9 100644 --- a/openpype/hosts/flame/otio/flame_export.py +++ b/openpype/hosts/flame/otio/flame_export.py @@ -305,15 +305,17 @@ def create_otio_clip(clip_data): source_duration = (source_out - source_in + 1) + # secondly check if any change of speed + if source_duration != _clip_record_duration: + retime_speed = source_duration / _clip_record_duration + log.debug("_ retime_speed: {}".format(retime_speed)) + speed *= retime_speed + log.debug("_ source_in: {}".format(source_in)) log.debug("_ source_out: {}".format(source_out)) log.debug("_ speed: {}".format(speed)) log.debug("_ source_duration: {}".format(source_duration)) - - # secondly check if any change of speed - if source_duration != _clip_record_duration: - retime_speed = source_duration / _clip_record_duration - speed *= retime_speed + log.debug("_ _clip_record_duration: {}".format(_clip_record_duration)) # create media reference media_reference = create_otio_reference( From 71bd7eb337bfc372b66973a10ff00d32c838a628 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 12 May 2022 15:24:38 +0200 Subject: [PATCH 139/350] flame: retime is float value --- openpype/hosts/flame/otio/flame_export.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/flame/otio/flame_export.py b/openpype/hosts/flame/otio/flame_export.py index 8562a766e9..08478d4b98 100644 --- a/openpype/hosts/flame/otio/flame_export.py +++ b/openpype/hosts/flame/otio/flame_export.py @@ -307,7 +307,7 @@ def create_otio_clip(clip_data): # secondly check if any change of speed if source_duration != _clip_record_duration: - retime_speed = source_duration / _clip_record_duration + retime_speed = float(source_duration / _clip_record_duration) log.debug("_ retime_speed: {}".format(retime_speed)) speed *= retime_speed From 334ef56d63bebea8167776c9c6776719f8adc939 Mon Sep 17 00:00:00 2001 From: pberto Date: Fri, 13 May 2022 13:17:09 +0900 Subject: [PATCH 140/350] docs: finished multiverse documentation --- website/docs/artist_hosts_maya.md | 222 ++++++++++-------- ...maya-multiverse_openpype_asset_creator.png | Bin 0 -> 193795 bytes ...ultiverse_openpype_composition_creator.png | Bin 0 -> 114263 bytes .../maya-multiverse_openpype_loader.png | Bin 0 -> 80108 bytes .../maya-multiverse_openpype_look_creator.png | Bin 0 -> 26190 bytes ...a-multiverse_openpype_override_creator.png | Bin 0 -> 125997 bytes .../maya-multiverse_openpype_publishers.png | Bin 0 -> 182542 bytes website/docs/assets/maya-multiverse_setup.png | Bin 0 -> 164855 bytes 8 files changed, 128 insertions(+), 94 deletions(-) create mode 100644 website/docs/assets/maya-multiverse_openpype_asset_creator.png create mode 100644 website/docs/assets/maya-multiverse_openpype_composition_creator.png create mode 100644 website/docs/assets/maya-multiverse_openpype_loader.png create mode 100644 website/docs/assets/maya-multiverse_openpype_look_creator.png create mode 100644 website/docs/assets/maya-multiverse_openpype_override_creator.png create mode 100644 website/docs/assets/maya-multiverse_openpype_publishers.png create mode 100644 website/docs/assets/maya-multiverse_setup.png diff --git a/website/docs/artist_hosts_maya.md b/website/docs/artist_hosts_maya.md index 84285bc6dd..7f7f360b82 100644 --- a/website/docs/artist_hosts_maya.md +++ b/website/docs/artist_hosts_maya.md @@ -602,134 +602,116 @@ be published as separate entity. ## Working with Multiverse in OpenPype OpenPype supports creating, publishing and loading of [Multiverse | USD]( -https://multi-verse.io) data. +https://multi-verse.io) data. The minimum Multiverse version supported is v6.7, +and version 7.0 is recommended. -More specifically it is possible to: +In a nutshell it is possible to: + +- Create USD Assets, USD compositions, USD Overrides. + + This _creates_ OpenPype instances as Maya set nodes that contain information + for published USD data. + +- Create Multiverse Looks. + + This _creates_ OpenPype instances as Maya set nodes that contain information + for published Maya shading networks data. + +- Publish USD Assets, USD compositions and USD Overrides. + + This _writes_ USD files to disk and _publishes_ information to the OpenPype + database. + +- Publish Multiverse Looks. + + This _writes_ Maya files to disk and _publishes_ information to the OpenPype + database. + + +- Load any USD data into Multiverse "Compound" shape nodes. + + This _reads_ USD files (and also Alembic files) into Maya by _streaming_ them + to the viewport. -- Create USD Assets, USD compositions and USD Overrides. This _creates_ OpenPype - instances as Maya set nodes that contain information for published USD data. -- Publish USD Assets, USD compositions and USD Overrides. This _writes_ USD - files to disk and _publishes_ information to the OpenPype database. -- Load any USD data into Multiverse "Compound" shape nodes. This _reads_ USD - files (and also Alembic files) into Maya by streaming them to the viewport. - Rendering USD data procedurally with 3DelightNSI, Arnold, Redshift, - RenderMan and VRay. This reads USD files by streaming them procedurally to the renderer, at render time. + RenderMan and VRay. + + This reads USD files by _streaming_ them procedurally to the renderer, at + render time. USD files written by Multiverse are 100% native USD data, they can be exchanged with any other DCC applications able to interchange USD. Likewise, Multiverse -can read native USD data created by other applications. All the extensions are -supported: `.usd`, `.usdc`, `.usda`, `.usdz`. Sequences of USD files can also be -read, as USD clips. +can read native USD data created by other applications. The USD extensions are +supported: `.usd` (binary), `.usda` (ASCII), `.usdz`. (zipped, optionally with +textures). Sequences of USD files can also be read via "USD clips". It is also possible to load Alembic data (`.abc`) in Multiverse Compounds, further compose it & override it in other USD files, and render it procedurally. Alembic data is always converted on the fly (in memory) to USD data. USD clip from Alembic data are also supported. + ### Configuration -To configure Multiverse in OpenPype, a user with admin privileges needs to setup -a new tool in OpenPype Project Settings, using a similar configuration as -depicted here: +To configure Multiverse in OpenPype, an admin privileges needs to setup a new +OpenPype tool in the OpenPype Project Settings, using a similar configuration as +the one depicted here: ![Maya - Multiverse Setup](assets/maya-multiverse_setup.png) -For more information about setup of Multiverse please refer to: LINK. +For more information about setup of Multiverse please refer to the relative page +on the [Multiverse official documentation](https://multi-verse.io/docs). -### Understanding Assets, Compositions and Overrides +### Understanding Assets, Compounds, Compositions, Overrides and Layering -In Multiverse there are three main concepts for representing USD data. +In Multiverse we use some terminology that relates to USD I/O: terms like +"Assets", "Compounds", "Compositions", "Overrides" and "Layering". - -#### Assets - -In Multiverse, the term "asset" refers to a USD file that contains a hierarchy -of primitives (transforms and shapes). In Maya this is typically a hierarchy of -nodes, as it can be seen in Outliner, that is written out to a USD file. Once -loaded, the same hierarchy will be visible in MEOW (Multiverse Explore and -Override Window). - -![Maya - Outliner vs MEOW](assets/maya-multiverse_asset_outliner_meow.png) - -An asset typically contains static or animated data such as: poly meshes, blend -shapes, reference objects, particles/points, curves, joint, subdivision surfaces -and other attributes such as normals, UVs, color sets, tangents, skin weights, -material assignment and shading networks, cameras, lights etc. It is also -possible to specify Maya data to be part of variants and to be used as proxies -by tagging them with attributes. - -An asset is typically read back into Maya into a Multiverse Compound shape -node and it can be composed and overridden. - -![Maya - Multiverse Compound Shape(assets/maya-multiverse_compound.png) - - -#### Composition - -In Multiverse, the term "composition" refers to a USD file that contains a -hierarchy of Multiverse Compounds shape nodes and Maya transform nodes, as it -can be seen in Outliner. This hierarchy is written out to a USD file that -effectively contains a static or animated composition of other USD files written -as references or payloads (according to the relative setting in the Compound). - -![Maya - Multiverse Composition](assets/maya-multiverse_composition_outliner_meow.png) - -A Composition is is typically read back into Maya into a Multiverse Compound -shape and it can be further composed and overridden. - - -#### Override - -In Multiverse, the term "override" refers to a USD file that contains static or animated overrides for a USD hierarchy. Overrides are set in MEOW, they can be: - -- render visibility overrides -- transform overrides -- attribute overrides -- material assignment overrides -- variant and variant definition overrides -- Instancing state overrides -- activity state overrides - -![Maya - Multiverse Override](assets/maya-multiverse_override_meow.png) - -Overrides are written out to a USD file that effectively contains a static or -animated hierarchy of overrides that can be "layered" on top of Assets, -Compositions and other Overrides. - -![Maya - Multiverse Override](assets/maya-multiverse_override_compound_layer.png) - -An Override is is typically read back into Maya as a layer of a Multiverse -Compound shape and it can be further composed and overridden. +Please hop to the new [Multiverse Introduction]( +https://j-cube.jp/solutions/multiverse/docs/usage/introduction) page on the +official documentation to understand them before reading the next sections. ### Creators -It is possible to create OpenPype "instances" (Maya sets) for publishing -Multiverse USD Asset, Composition and Override. +It is possible to create OpenPype "instances" (resulting in Maya set containers) +for publishing Multiverse USD Assets, Compositions, Overrides and Looks. -![Maya - Multiverse Creators](assets/maya-multiverse_openpype_creator.png) - -When creating OpenPype instances for Multiverse USD asset, compositions and -overrides the creator plug-in will put the relative selected data in a Maya set -node which holds the properties used by the Multiverse data writer for +When creating OpenPype instances for Multiverse USD Asset, Composition, +Override and Look, the creator plug-in will put the relative selected data in a +Maya set node which holds the properties used by the Multiverse data writer for publishing. +You can choose the USD file format in the Creators' set nodes: + +- Assets: `.usd` or `.usda` or `.usdz` +- Compositions: `.usd` or `.usda` +- Overrides: `.usd` or `.usda` +- Looks: `.ma` + +![Maya - Multiverse Asset Creator](assets/maya-multiverse_openpype_asset_creator.png) + +![Maya - Multiverse Asset Creator](assets/maya-multiverse_openpype_composition_creator.png) + +![Maya - Multiverse Asset Creator](assets/maya-multiverse_openpype_override_creator.png) + +![Maya - Multiverse Asset Creator](assets/maya-multiverse_openpype_look_creator.png) ### Publishers -The relative publishers for Asset, Composition and Overrides are available. They -all write USD files to disk and communicate publish info to the OpenPype -database. +The relative publishers for Multiverse USD Asset, Composition, Override and Look +are available. The first three write USD files to disk, while look writes a maya +file. All communicate publish info to the OpenPype database. -![Maya - Multiverse Creators](assets/maya-multiverse_openpype_publisher.png) +![Maya - Multiverse Publisher](assets/maya-multiverse_openpype_publishers.png) ### Loader -The loader creates a Multiverse Compound shape node reading the USD file of -choice. All data is streamed to the viewport and not contained in Maya. Thanks -to the various viewport load options the user can strategically decide how to +The loader creates a Multiverse "Compound" shape node reading the USD file of +choice. All data is _streamed_ to the viewport and not contained in Maya. Thanks +to the various viewport draw options the user can strategically decide how to minimize the cost of viewport draw effectively being able to load any data, this allows to bring into Maya scenes of virtually unlimited complexity. @@ -741,9 +723,44 @@ Maya scene as Maya data. Instead, when desired, Multiverse permits to import specific USD primitives into the Maya scene as Maya data selectively from MEOW, it also tracks what is being imported, so upon modification, it is possible to write (create & publish) the modifies data as a USD file for being layered on -top of its relative Compound. See LINK. +top of its relative Compound. See the [Multiverse Importer]( +https://j-cube.jp/solutions/multiverse/docs/usage/importer)) documentation. ::: +### Look + +In OpenPype a Multiverse Look is a Maya file that contains shading networks that +are assigned to the items of a Multiverse Compound. + +Multiverse Looks are typically Maya-referenced in the lighting and shot scenes. + +Materials are assigned to the USD items in the Compound via the "material +assignment" information that is output in the lookdev stage by a Multiverse +Override. Once published the override can be Layered on the Compound so that +materials will be assigned to items. Finally, an attribute Override on the root +item of the Compound is used to define the `namespace` with which the shading +networks were referenced in Maya. At this point the renderer knows which +material to assign to which item and it is possible to render and edit the +materials as usual. Because the material exists in Maya you can perform IPR and +tune the materials as you please. + +As of Multiverse 7 it is also possible to write shading networks inside the USD +files: that is achieved by using either the Asset writer (if material are +defined in the modeling stage) and the Override writer (if materials are +defined in the lookdev or later stage). Shading networks in USD can then be +rendered in 3Delight NSI or used for interchange with DCC apps. + +Some interesting consequences of USD shading networks in Multiverse: + +1. they can be overridden by a shading network in Maya by assigning in MEOW a + Maya material as an override +2. they are available for assignment in MEOW, so you can assign a USD material + to an item as an override +3. From Hypershade you can use the Multiverse USD shading network write File> + Export option to write USD shading network libraries to then layer on an asset + and perform 2. again. + + ### Rendering Multiverse offers procedural rendering with all the major production renderers: @@ -754,11 +771,28 @@ Multiverse offers procedural rendering with all the major production renderers: - RenderMan - VRay +Procedural rendering effectively means that data is _streamed_ to the renderer +at render-time, without the need to store the data in the Maya scene (this +effectively means small .ma/.mb files that load fast) nor in the renderer native +file format scene description file (this effectively means tiny `.nsi` / `.ass` +/ `.vrscene` / `.rib` files that load fast). + This is completely transparent to the user: Multiverse Compound nodes present in the scene, once a render is launched, will stream data to the renderer in a procedural fashion. -![Maya - Multiverse Rendering](assets/maya-multiverse_rendering.png) + +### Example Multiverse Pipeline and API + +An example diagram of the data flow in a Maya pipeline using Multiverse is +available, see the [Multiverse Pipeline]( +https://j-cube.jp/solutions/multiverse/docs/pipeline) documentation. + + +A very easy to use Python API to automate any task is available, the API is +user friendly and does not require any knowledge of the vast and complex USD +APIs. See the [Multiverse Python API]( +https://j-cube.jp/solutions/multiverse/docs/dev/python-api.html) documentation. ## Working with Yeti in OpenPype diff --git a/website/docs/assets/maya-multiverse_openpype_asset_creator.png b/website/docs/assets/maya-multiverse_openpype_asset_creator.png new file mode 100644 index 0000000000000000000000000000000000000000..0426e9f82302f0306a53005fcba6c22b960f2368 GIT binary patch literal 193795 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 literal 0 HcmV?d00001 diff --git a/website/docs/assets/maya-multiverse_openpype_composition_creator.png b/website/docs/assets/maya-multiverse_openpype_composition_creator.png new file mode 100644 index 0000000000000000000000000000000000000000..eb0e5e33487b804e405d5a27d8048a485693ed6f GIT binary patch literal 114263 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 literal 0 HcmV?d00001 diff --git a/website/docs/assets/maya-multiverse_openpype_look_creator.png b/website/docs/assets/maya-multiverse_openpype_look_creator.png new file mode 100644 index 0000000000000000000000000000000000000000..14541e9e398fc99e3910d50a5286bdd8906b9f1a GIT binary patch literal 26190 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 XNN#wif}p^6lEBGJD?=(?y$$*wxlGVg literal 0 HcmV?d00001 diff --git a/website/docs/assets/maya-multiverse_openpype_override_creator.png b/website/docs/assets/maya-multiverse_openpype_override_creator.png new file mode 100644 index 0000000000000000000000000000000000000000..d7b1299ba652208c3842add85501e590453f4992 GIT binary patch literal 125997 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

$B)J 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 literal 0 HcmV?d00001 diff --git a/website/docs/assets/maya-multiverse_openpype_publishers.png b/website/docs/assets/maya-multiverse_openpype_publishers.png new file mode 100644 index 0000000000000000000000000000000000000000..b83fa5f59cd95ac8f6feab2e043fb9514ab257a7 GIT binary patch literal 182542 zcmY&<2Q*wy__h*lwbhAW5xqw5y$hmuk`N-Ix2Q`5OY|BMM2{Z5FJZArh?Nj^)o5XL ztL=XK`~S~(&i9>j_nf=4ckj$RGxN^-KJPP$PmFab0rvrTczBfhdRk_9ctp{7cm!>v z#JCbabpt3K9)666rsk6XGhGdkzP6^!BY7Da5ed;pczFC7K^ap*TBh`)s*-B?Lvl6?k)v7D#Xgf<}HzL7R^7N@&u;^-J=_f$G5rtq)HMNOxyny_QkDvTS z_t2Q-0t#u`$1H2=4q$2&PtNXJngnt+`Kdz_sGO2`MJ-ge?|Vc{Vs^Kh(vCRek1R)1Z#AbQaamAf{~W%l(V=dzuXJSthtA4?`C@m@H&yl!Fw(z7xu7&tooA^6uEjzXnfCT|yZZ7+p){G7eK zilADOJoql4i2AOG>dpElt}qokkiK&%G9bjW$wKykS{VP3*uS9iRs1vN_@=R4!U)4c zX9B6*bRXx{r>h=MM|i*FJ$o(mk0b*4hTy~RNhK2kNmD<6bXfu^9+oJQydM3JZSQ|nd7)q{6|ET6eZ z4SU?&cLAMI)nsMhsp6|~jF&T$Y6TW>Go3ngvtk_&4upn0E?JoO@J?63D1 z_YFJ?Cp+qRCnY^_wRgLXKB-qddZa~ln5ZiYxe#ag&Kx2jNlxO)Mz5h#+Vj4!3V-g+7IwMpE1YHbG(ruRix}x z;kl!ZF246{C_0C&H%ga&AnS;)m6&^c;*w645aWDyqq6$vos?Y(DKu3u_VL%^Sh%Gw zYpF>mRVS|k2jO=^eyow!q-xrZQc2c!4S!!|5RHCwCf^&RGSD*b4Lm6!+Gn|nhdqI_b6ZMS$=Ub(!b2RD=-zI81 z8)RY>qZI!vQ1ybZ-?6Vm?RuVUHz9cax`*V2Wlg6THyu2LBvde(sr2mG(oI}3jcQA{ zIpP5X`VKoZb9ky&@)-*(Jw-<*0ym0wc}FVd5iTtV2O_U(f1i!p`My zTW*OVaRs$6c$1uLe;;}q==D_74~*6xeN!(w9uSKb%jj3yzEg8&7ziQ0T6}x@0?n4C z0eBjD+o9%&VAfM2ojFHGC{D~foaqw3mtUQ+?-a$gnNlCHI{dIPP*7J`QZ|nO-C=5z z8D3sS6GBrF*xAEfXo_deX($%t;OQIHB3Si-z=lKBdsNv1--IWdW_%0lshf||P1Pj+ z!$CfX)l-6-j0cc4F?2m+Ue0?+DjEus*Az)~J(7(~Ji z=BNd}FVdjUs(Wd8eEEmr3{RzWa!M=L+k$(-*@SmqEOUcPi+L7QSS>J+P}Z3Sny`lc zNxlB`c!{hVfYvy>nVAl~|6(8&jt8w)>!vvN|JjCSi!E;*DwUYIRgR>!uX)bA%)*BZ z*2-N^NGgkkFtirfF3bqpqxVL)lnh8g6V{_T+7SAa5}% z^9cRd)_!=$oBnLR6wTc)#gFh|!=nsDCtwO&Mg;}I{lInoXb!Hd#kjhO2isgxFWK_A z?;1OR`=~Nt*PEaii7>9n*55o1V&AP};kREKOOeiwiCgDM_p#bYi&@rzPa1zi$F61X(udMdrR{9hses(3+oP@)JNKL70tctQVx@7aSDj z?n*%B`kE%y+F0ir2r^jKh#IS+?OA7yK{fB#MYv>mPpi&owOi=RtA*bb3;ippii70~z$yv0zOowK8-scE;1*@4mrV__@cJfI$ z+gb`aVqJBHg|o->ZmVXXUhTbHXQ&RK$@R1+fNAp_I%h(Q`0jY& zpsZCN8k0;XmMtvabDMT<1ah7wlpUnwl2+rHOl+)`eQZcm5%#E1m-x|lxqDYoMjBL5 zQ-hkykhlTN7H^94uvPVA`r*S{md=OdtI~Uagy7)zq#455p9F6}TtCmu;9)tJ56kfb zwu`miB`Q+qjlJ#U^F5Z#h_4Xy72t}tE8Fi&`VOEXJyCtI)yJ)Xy|?c3M76dox?k%> zXIKXalQ=~>&dOL3DbVfBTIz}xsSsdNbiuE4U%t=(Bd?r77~ zShn#Zgf{!lt}*xT($%*lVYM%vG_S?=CEgI797ZMZ^ZM`|x=VxZnm>M-RQ=ZB52gfz zlrzxwXqwX3Z=O^*C!R569=_n%3=hvjhlg_sR!Qg;s9&4R(N4HqBMYLrO9K}-z&Ek! zD7#Csg||}S_qM|-Y^6_>RdssT-MuYPWMr38ih>)&!bOIUa;q69v*>~ogl)VR?iZMLdTD8?A-Z&nQ{mL=eL=^tYf12 z9jt4=Hga~eghUDZ;$r|6esE-#BDPEr>w-q6Wep?Ex7Y6Z68Rb$+-+y5vbZqokoW>t zdEnnOZ#F2FMddi#m{|flRdwp|X2Ip*Bv<{V>t~1QB?M@}Ozck3eUW6MZ ziy-C(k~3aL)bNPSne6s~pC)!5bnpW{!0(_?lLoGBCgw~+wzgiHJCH505FK5pub9;Z zkqbnt(-ZDne)OGrClw50j~3Oum(Mu6O|motuy4%B5_eqln^D89PC_F<@u-h4t~3iU++Wi@sg? zMij>(0S$_HV3419X(xFe``(8Ca~?MnhA7q2m%lvv-`b4O*R(jj>JmGyNiN?gedo@E zz%|lCurB5{CQ$DYkvM$yag}_tUOwNK*7|Ifue&KWITgx1+M6bLa&eoAFl5M^@A%$E ziHp%TC(*r%Oe%S2KEI88<#^XkO5;a=plivo&M~d>&nIfx-X48J12)RJE$S!|$7}9+ z3#I!=U)|YG9*Ay=G}8KsQ24bg4`~?~Zjh2`+cRwHg#ruZWJ!BD$91 z;oKqb4lEcj?4tdY4L8piI*3_N7_xr0?qZv72d;0kn7TzG$#;i#_KTxciJjy5t(Nck z=h_&*OX_uVO>P*y3xLnbz6;dBSCS^h%EskP4$}{SMhw;@1z`DtUL}?aED>E>BQ>&L zzWO$=gBUuf{LH^ZQg(1ME=pSb0X(nhx55*Hte^E2CaGcy**a&yPj9vP=dzdL5El`-(M)MNZSd z@tZofZS5n|+rffRjqVRV8#te+gYR%|6F5f)=5cCgHA^Ds^hy8AO6DPjtwJy^M9XRk z;jL&3w?(D)mn=s_^k z>`JxEvBO|cLU6mgGrtnw|M4IU7nqs7Bs!8tpP2bXL_VXRjpvUD>hH&a0jjldwAmqi zBvQvAVRm6~2tv}j1> zmq5=%*_t1#m$87ZuD6o{(Lxzeb^gXEqZ7A{3jXNuwT^vfAv5sZr(%&zt9=5|#6gvs zL92C>%)RDD^}6t&yGsj?Hosrmrhf)NeYG3b8JEhL5rki4v~nZyLy=n#ao7vix^0H@ zYeG5et#NjQ+Y%kN8Gi4|t+KlFqVuB^1vh>bo>LkrqkBd`fk7GTF*R3`RLIJ2z*D`$ z@17b&;^>zAFv3U51J^!*Xqs3y-Ts@hSKV$>NL z`YvhauBZx99LjNfIU8-mtXO2_H(BNP1rJkWpvnyP{dWzis`+ZS8ScM>dPaHNQCgpY zo1(jom?Fe=vip~>Kl4I9xRYKXkG3tYp%BFUut!B))ONt}jq8ksLvqYPpW!9P|O!Rm=46 z6|HEzkbYMsxV)wQsoer&uHj^a>l!Gs3`=w@zsVA%q-UQ*z#L(FG?OirN@B54kW~Jg zapurz;+StvwS4frNA7|1U*!kc%67xc9C2}gRYiD+BZFXc))}5Y;OT+rSqbRQR?t`| zy1#y~k@93GL`kHCYQ(MdgO8-kVkv+{P66A?!E^W-%yo@rb9LjdE3I6=}zykVbBm`7=Up8P#OZZE(df(FP6D3#16+fnvB@?X$ zu86Z=rmB>*8SlC!!+OeRqy)SG0bYHcG6^HQqNt0xZ7&p7{QVKk} z-b-@HQg3kw?Rth)TmPZj0;zy_V;Q*#wdXKwb?b`_!sW=@&|N9CtD@t41W@x4~<*EPQyC-X z-WpGGXbZRCe8oq0vr)`QRG0VSj8%*Rxp{)sQOx77D{t!r708_{cRg{o+PPn3eEB{ufQx~BYF%;A~(^s7{GRH|tr`MMNDh#dq?hwn*7_@<4ZQ8jmRA@z5i{0LBGx5?a6iR0Ud*0=+2t*4BpnbJ5zzmJthzUDb!b;;Qdl zA_S*9zG4e3d_Sg9|3>uO>AWR8@s_QL=?jviJo`A<7ix7Er2?_n@f$n|WN8p9+rM*2 zS4rr9R$6nZOz9=4dwAxN>I3X4zPUs7uPDrr@Jlh z8Zm8}Zqe+8q112Zj7<8Cqh&pnm9%G)Ggp<> zNIuRx`8#N%#&x{{n8EQBDorjB*&GJBz6%4&Cb$A38?Sw8l#$8P!>_$^#dPM5IAAs9 z1g5z!5?NC&D8h!m{izK8b0^vyxR#|CtHOW`g0(^7^xp&QV|~_WnguyuduiARaYYwm zpI0USBfG_;v0);fb27#xf2eFybC6qQ)xhA@@nI-lD32*6{JN2Zh`E$TWC`59mbyD4 z(HxFoaXY%xqEyeVf7nDW!Cw#~JaPYh=eb;3C*dRZCeRACt?{i4B43fo6sA~PKm#eo zFvAQC`qSpogH|mPJWJxqhZBwvjg|)>5rQ>&cQid(_-$2hd;#5;%#;5`c}y6EyauQ#w|@ zv1jg4*=AKw+U1j2uG&UPeFgl$AzWN7Y&{j5`9@1~7!rxK0j}uSp$!j>9D+?VzoyaD$$Z?#niw2-edHK zpY8tXos`J|j~{iJRv0e$R*{^f>=o)25@`9HS$r4E8j8SU)w$HX!NWMy&&K{KMvK5y zklq$oe`_MV@%%}nZloC5to?4`n7N|9e`x z)x=U34;=&O5qcEjvE$xHgSAx@weZlGn0a`;e)Dyi8zAxn+VwI+05Is-)QKE zOTJ=37+>SXXs99moTWkE)rwMq1y4PCHYTU z&BboxsDfR*JWGIFlzmf{fvNyR=r1AKP*6B~SYIVtA6|9&Y?{^26I(y=TY83H24h@G z0$uXUomtSu8kRRA1ax+gm+2treWdlBv*nWRv4}Gpx8=3ldg9`LV8b`tSKK*`s_S=C zkf`vS2-!5{GT*$v2RL@UX!o*yS!GwbV6cxZ69*Sx7xWkM$wzA$c|c!r9G-)bhxrRBoqY~q zLF^jXDM%Vs-0+-G{?o+-^r=j~?mY=G*XDx?+w2lw#qRb(snRH1Yan zlnrqER)2pinGzxaJ9c5PHmQ5FTzreaIxkqiZ&)cH(s~jkvc8aqrT z@0kwG3!cuTb#I!QqvBni&Cuf5%l0~J=7J9g*Eo@PDP=79Rtld!z?VGd%I@Ni%sW=rOOnU;+3 zF(5k1SD)_yZJchTlld=m_`U;k&y*_Uao(+S(@d=TBId=DgEPzV*o~m#N{@%D1fm;B zPkQ4hDrJe+aMAgyY-=0jCK1ayzAJ@`t$O0RH}=&(qV64^0*iI>wB~Hzqc(d#5TL=3 z<||%THLP+3IkU22h^_B|b(sQ|$~LK$3jJ(QTH|7fX;0qubI(IkPo4Yr3GMN(G*_k# z(Tu~WRqF0mf=(jvQFYobny~KS_%Xwg2cwB1@e8p0HJDMN=LQUsC{wSv5=WT&qRtFp zL@=?p+v~Zgv&8WkwnmZ+9!W6Ip~Xwja%ZBcbro0rmUe&?h07wB5q<=5lwvCtI1!vl zz3YLcnS|J~F9Ux}X-Ovf^yoJLU;=&)nAKK5>Z*EoQfMQa!Bo}R;y$Jy{uhW5r& zOdJ1`rf@~0#^&lUJo8Q7s7TvEqL_6H#2>8-e|px$|M*f7fz}y}6y+R3ge; zFxs(y?NJ0#YkQ#J5Q<4!cdL&vyNqGs2VBkX{>j1Z1LyfL(`->A4;tgl-k96F?=a^_ zx!g{a!C^oQFG9?waq#b|(DTRmubJ&tJpfPdWcN1Pc=hoqu98Nd5XX7heI)3lj_RpS z`&x)Npn`-C9d(!Fp!7EIO&jpyr)6;kecTvC5dHIyAkUW~Iy!_IdJJw!_pECVOzziFF=@sKYOG6$s8b^fa8BuN> z3BzTX6=0Ws0-_>kC%+#YpDa9V^}jge3hLzPjZAngiWFdQQgP3d9}GQxLA@p(*ppRz(Anq)1F zIzSJ+*7&UrXNA?XTUpd^crFowo;C2rvdR#HGZqT|? z!T4JT`q!w?Lm{>-<^*PoxEHP&408Il-cfI{-si{nuX4*h0IS5Vb!ZY->Vnk6*dU2! z4+n%a<67f_{(7u>QR~=W&2+M<@_k{oWcbq=!D#g&cm7jn-D?69t!@2q;m4egp|=X{ z@;8jbGBNw?O36}3U7%Zu_0)gdXx6OW$Gyo;s3>_7k3eW*V7h0z>aTuIL!B^g@L6Mx zQW|%m`%y>%Mr6I?oW6XzF>O4I-ZrTN#7Pa0zBPeOTseb6&9ji)gzMZH@xBp(DGURe z@Vc4}4@(_H!-}fry&bJh+jcHW)c!yPx<_pr$a8^BcbAs$?#JaRF|j^D77(H6aGDnv zMet}JLJ3KEwot3J)FQAB{WXXBJj_^E7t)97SrrmuI58yt&wPo=Ckv`AA0J!BJA&5Ph(?#Pv1>yxi&PoXl7qz z=`HqfNT36~P+sW6_lTF8xf{+gkAEK0I)e4H!NgoM)+AR@;POq0UVph5*Qj&S$sH^B zd9QRQID}g43%AF{AG0@jyK|os;c^`lXhALLN<#nfQ}SlN{d34*s8SR4H$LEebw6k6 zt??Rg{LMC&<3v`|Q7rZh*dKkT2=0&JPn*&#x+#Jq$7)TleFKIA zG8i8BfRHmirYvHh+RCN)s2^yQjt?+^p!A*`{jOr2#tQ0fwvv3gNs!P{D2`y$$R?W7 zp8E~n2i?if<=N7}>dofJ`qhWTWjGpXO`?8RAGv8^x_&D^>)FcvnQ(>UXlX)p7TT=J zy=>pL#va;vFLeUJCq`+tKANtmhp;=?_?NnCkV)s&CbxQo+}{ADG{!{(@Ki4vDUts-z3vj{% z^Z)jk|F3M?sL5!RV&m@H6BvymWC%S>gis)+Lm437y^g|bWMS86g6dvUMb2#*i<{;TUa zYExm|$htq_wUTu*7{vOC&>{JCu)@9h>{g~DCWP#j;l>`n7(D(>#Tm_iy^H0b^FjN2 zCWcO0hq5OQO2DZqr8Bc^}+Oa`<$6d+w%6PlEKQZOf1kG@x}}n1c|-pu=>6=- z|NJ4^nY%VJmr&Mgt@}T4M{WvhV>)6~2JZe-d*FY-`J>4fr$2UfguNV}{Ld?yn|oWi z4IgVhmSM%A<4*FFdQ}^S=1EkCC%u30RSK}k{)gPQTb2Be&FXy?SDr23r@Uj{(ZpOT zPwf-y^*b~j@GbGgYCRRN@gvKS6B#m*!1eq5B#%jEb&t1TH+^_@>KBpIXS^3)hHOk+oWb|dysHlvN?&R0G`^M^{~&+RMLj7EOM)a47rz_Mt6GryqP=G z&29lrZ7#pt?+&lV=OysLGlWEb{LL#l*s=h z3;r0{1#c0K!_h*0N;PxF1I{s3F*oV%%-yf#t$$y_Kn;yaGm|@Q)T{e6)>KRcmpYeM zSV-Y_#mor2OVaTW)(QETK&q3&D#8%_egYM>TPj?*&srLGOOJLAyp7-Vq0{Ot#=oU| zBN%2}#a(#+2WL&xU72TbV#KJVJ~$6I>;+ko>A@Fn<##tMM>LrvWc`{8t=RXI)S3%F zw=-n!cCtNPOIwk;btZ?}3pcT}2n<*E$o%wGLPpAyNg|A^C(pvX2SBnU7dF5wusTl3Uee#8#%5rXn zZg=BWTyS51HE(l*y>L66>;>k@Fb8v-2gg90UjP2-K!40=#wEK-l@!MSau_us*RFXj z046BXzJ7}nz$jhT;~uQdz`*DAR5$ba??&kk$+YBs3Ap+>bfNi;T;8QpvF3+ZJ1rS7 zS4G5-c=8W*B8eh<2y$eSbN*mmP4NhBV}ySlL7 zTS^8>#K8}*@Gyyh9v;91ZeucsNI2&8Fz?pN;YM|chNX69uG-ThSaalX-(uk$-m}Q5 zcf)(UqQo#QIYu0W(XW2D*$&EzZ}-kuaLTJqR&WY_cq zE}4C=LBDhI)oql;M*=hp!{4H@F*G3YNKVzDiecbAJg?xelN4;$CtC_MF<68&-ZEFL zi)t77S;a-ltmU)dC=04_nyqIgP2WRemF)08NfnK8Zpr;x5M6Vz-Li>sn$l3v8&;3UjeLiH zWPw6>qr47fR3BngfpC0|l#??9xOtk*ec76?#LwS<$`^DX*FK8d1q0vLe!Z=LnAuM? zs~9RB?Xv!!AO4{${MOt2S#3Jcqc~hf)!~f7jg}g=d`y&6)dF}L^8Fi=@LG$YC4O%> zFqr(g2uA#5S*d#bmi_Adi+1kUov&AdQ!j5PM<1_l54Z^av)r`5=ZxPgw-%Oz+pb>A zxB5>9?G42&*Q33=U&W$>^cJrh0G>k~-M1x4o*H$582ap>N&}AZLN}O1)g#h5|MhB+ zH@5^lT#+<{alGH+SxfBpi64%kf%f|OW5{mD5a;NuXj}@~Go3*-uU5$x_Phw}Tnd}#(LQA|J7x}Ls(gLF;?8`I)oBjm%m@&e zTW|C0#Dll_ekl{et>>sCaWP!kEvR{mUQ5SgVwo5>OF&a}rbSstFD8=tr=HyUVQ6Zg zBsE7VrV9ygPa1V7yrJ(@6K@nPQ)L9hDW>JmhOJfl^`5m7{29AEjVXi6+ARu=ODd3} zAOxM1w)&B@C&EFYe6>myg3;%vH>uvfn>BFp+C2Ah zt#gX4`)t%bCwttOp=tF3sj+1J2xm~9a$#^p^MVLr)aOA~2njV#1!T9LU#}V4S#63= zu&_~nPPzUw*2F!ZUNE|t=c2ELTtY9%PZct#Nputdn>AI`y;l$jL(#Px>DZdklNg+Tky0DBak`2oL-E1y~d{Ji#lbjiaX8 z`>FL$w#I_!C~+@>sEKPfr*S#{9bna&8|lm(bB0M=l3cpf+-Wo~~ye*y%nD%his;g4VP7Gt&O)EQk zLcEtFXKvAHwZuy!7~R%(MkJ_Y_|NK#5d8oaa@a$QwgO&e@SEUP?}~c&orPmf>?uw% zK;Z}W=EB_TvsZ|C2k?A&s2DA_Us!SZW%a&1tb6BZr)V$+C!8JmtHGM{&PAwR?j`{+ z2UzVw3x%{k4h;bU0`2l1wydP?scBp%f2O z2ABd72Z zL?UCQIuD^7=6)WRg)l-`>a6{7$T53Dqs;*YIfQ8TRm8X1_pbfPac?Z|*puYeRN1Og zuVAX?w3Lu&Z%t?mnBJpvZvVS&XwV_AF>Aa!RM}V@YIlDB(Kcbcw9p zMEXj?9_ge;827q~e_@g*>Yf|j$)^X@Ai8~Nc)$l!5Go|`=84$4y(iz;Uy}5gw(!~O z<(-P^kIr0-E@@nMkaEg&Tzn!Uy@hVx$OmDZ&J~S1u?7w*ix;(~Tik!}6nAdX< zqa9=G#@F}!HMqsz_ywsSi!j^&9nGJ|R-BBPYpI{3qvmBZf+>D{t5nNGJ3dGGPab_) zA4$#N`CU37_H;Y;l!l&f>8Rn?erwI?1)!x1UU@HdIfF;=6v)Kwf%3!0tOhe2Q+0sG z-&0^(p!8Tc z;eRzGUXvd4N{4;kbv@Nh6fxdj69O6vs8*XaD`J$z9v11b>0@}kJ-&}3ry~R~@7`2P zw0wy09=86|zHUz&;`(`4*iW5z2Tbd@VRoAcNuPTgaEDojy~T`FuB-0r;^vy_&ULo$ zf6nQcC|by7=y>k=d3YMA-o?Y0ef%d|`k15$iArppU0{M0l~1v6%GdAR@1%zJ+9+69 zcf(?mb3P^4tIN<9KK?iED-GpRs*i9Sr9fc+@R2IgVWA;r$NHCrIwhV7tc4XBt-Idv zlhugIYsbAHsXR`)USpX&?(0NbI9k5m*zoOX2pwX_T^Wd#FOGZta7Qm}R_x(BmgVH6 zb^T;7`o8Jkie$$rdm(l%i;SN^gPgxHF8vvqV`qi<=c9)XK_>G<3!l7ftZ1_Lz9wkaPYah(1ZfCtN z`3K)WanOj{{o9FpIJn>K*>h?BN`81VfH-5y&T0=oO4kbCF+pkH87TBRoJ%w>RmUM# znEb?*CXf4>jh_3B`r6ak|JFZH5TQZT=-pFrY#pyKNY?f<=bIw>ki;Lp2lIWssprp4 z-~PJ-I4eZ=>&Gr>GbCrHvGg=;qj9{G5jiN2!#tRk3*1`g%^Td44x12I)2H~Bm!W^j zKx_Ook85;f-G1>^T+o+yqHzznVzG&x6Ss0rrhj)KG>f4)ZG|mQS@AioR*8dwoi3uo zD^T*k#S%&=Cwi@{z!{Z&eP?CBqPS{*-(#Py;~!YzSR$t%)RWbb@ROi}e#vZ7JjwxJeAfCy|?fE5P3~@LgXW0HAt5j zDMauuUX`1f>ejG?($>zO=SUv5-EcFa64#kenrGo9T(T6T=RP13dH1k++KE=bkjxx& zKfX!&IR0807j#?9*G)GMwju4Hefs}oWfC85IqA9vaI#!bty?p@0z(7aR?i5ryv$p)70a5!`H7Tu8uW?A(>+WWgL&m&s17}E zj!~j*1rw1{Qb!iYT4E1mG4Y|duCgM+EmhmftMkzuzboy}lC3!@7}k%6OR>Om$x>j8 zsT%)5Q`OqV$UX@ZywuC>yrIA4Js5>D{{h?`MCCs~N(Wo?41dz1c+ zwMaJG)}Qu;D~$nG%~txIl%;V>RHx-ch5O6E0Q~95>521HSO{J}2h_~QN4#=c(cU|u zpEE@W>%kB#$R)Kvn`%a4SMhn@G6f}jl!J>l_b$8kE~OBxW{wz9bkt?$;SI&}?eoGe z6!)=vep}ngK5Wo_>J>YE_VGMzgCvkfhU(y7B=@dCf>dkHY?$k5bl(w4?SWq$4Xw(4 z>-JI(@&nGcRjN@l5_7RuD_qn1JRpdB(c&2*2`gyU5H34geP!(`;BL1#Z<*A&aa3>7 zMnV3fWkqj03zn5my&=}|`{letBHDyvVlK8gHvOBAJ1QK6sgzFOV*M09H`^Ra0d2di z(hDgpnRmWhp>+0GT8VLsM=OqTvQ9lnvSE|&HjpWPYjf?rhbhKUTGm;FnA%CO{y&Z& z-07C-lE^=vR9YiXw;~*`8s`zSzU?7K~Obud<;|zp)&P5T$nhD z1Qo}0LTm7#si0DvCEqb@z zWHHRa7Pnit*fM=*tX*_48qKk0|GTgP!L+c6V+vgieWm?a+aAnQoW9pn+#9ssu+P}L zkV=53ie-vvp2dqyeK{J2JopgZI$E5166IV`+=%e3kkAYNx87QMTD^Lm2J**>sduug zDY8=_HcP|gCCH9(Oi!c_FsgI>G#3CS&rsaRP+w$$#|Jy>e@XlM>GN$z#`dMxrfv6; zEY7!)Rxe^I^^a1=+$bvJI0N7cgyJ(e8X4m85W{{!aUwU|9EIHGGT7@#kJ-`%hW2r+ z?@w3UJj)Jg2FzGFQ{DZ*$N*UH|MDY#PSmS-q5@5hn9z0vf!{ddyIvOEl-BoqZU>4frcOwxRLEm~1WxrCn?? zTAU13gfzZS{rU-9t;G7a^Yvg*?pjZ}P38KME5^j)kBI3X^69JB-vWeN;|p;Lsxusp7mSo;tp{JaUgJKbJD4^kkN6JpNp;#xC}77 zIk7yVBxe_c9u(e{6E;|60IW(2%%N?^13H!TLY#q(3(Q2rS8hERW2>IHxF z%%LY0=HGHK1OXB_=z&*i94hJKf65J^#JH*9!bDZeO_pBcf8LecfT!vBU_|&dYV;WZ zw;tNv;%RUAOcWM?+7&uNz!}$JX|xr$X8IUXM>>OI@%!q^h)g?0 zchFv&ezX#J`OJll_q;WP)w9rw5+4E{3q83|glPYI0h^FTstK294j;$DPnJ12FYEK( zHR#^6&5S*lib^5vkfg!yrD+nzC~%cOn8>&cC5MJ5*}@}@IotR2*L_#DT+Mr9^kP+& z$LS75odM+O6*A#OYm{)a(o;R;=4T5`Jn4BO!OgnQ¼zTC%cnFn=R3lm5XW25oz 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

+jTLKMEVQn~<}sDNh&32k4p!94^-h8nk-?qrSH7 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

V^Fk7mW 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 literal 0 HcmV?d00001 diff --git a/website/docs/assets/maya-multiverse_setup.png b/website/docs/assets/maya-multiverse_setup.png new file mode 100644 index 0000000000000000000000000000000000000000..8aa89ef7e504272e7b5f9abbfea0ec0ca3d1d783 GIT binary patch literal 164855 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

?;P|97R-)#?HUS+R~+heNwi? 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 diff --git a/openpype/resources/app_icons/nuke.png b/openpype/resources/app_icons/nuke.png index 423445409618d59ff822dc09e1dac2e4d3e241aa..e734b4984e1c5ce86e957274b455fd039c5cd150 100644 GIT binary patch literal 86832 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 V+x*Ep#xxg4tS#)!Yt6hK{RcYQ(zyTt literal 49012 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 NBt&F|s|EG_{|{S*X`BE6 From 8f26e683576ffc9d7be2abb9c3eb40ef01db1e09 Mon Sep 17 00:00:00 2001 From: pberto Date: Tue, 31 May 2022 14:30:38 +0900 Subject: [PATCH 286/350] multiverse documentation: see commit body - better docstrings for pyblish UI - updated images - re-organized Maya content in website by splitting plugin docs and sidebar menu (existing links are not broken since the same entry point doc exists) --- .../publish/extract_multiverse_look.py | 27 +- .../plugins/publish/extract_multiverse_usd.py | 16 +- .../publish/extract_multiverse_usd_comp.py | 16 +- .../publish/extract_multiverse_usd_over.py | 14 +- website/docs/artist_hosts_maya.md | 387 ------------------ website/docs/artist_hosts_maya_multiverse.md | 237 +++++++++++ website/docs/artist_hosts_maya_redshift.md | 31 ++ website/docs/artist_hosts_maya_vray.md | 44 ++ website/docs/artist_hosts_maya_xgen.md | 29 ++ website/docs/artist_hosts_maya_yeti.md | 108 +++++ .../maya-multiverse_openpype_look_creator.png | Bin 26190 -> 125727 bytes .../maya-multiverse_openpype_publishers.png | Bin 182542 -> 309158 bytes website/sidebars.js | 13 +- 13 files changed, 530 insertions(+), 392 deletions(-) create mode 100644 website/docs/artist_hosts_maya_multiverse.md create mode 100644 website/docs/artist_hosts_maya_redshift.md create mode 100644 website/docs/artist_hosts_maya_vray.md create mode 100644 website/docs/artist_hosts_maya_xgen.md create mode 100644 website/docs/artist_hosts_maya_yeti.md diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_look.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_look.py index 5ba840f2b7..d59d03ee58 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_look.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_look.py @@ -7,7 +7,32 @@ from openpype.hosts.maya.api.lib import maintained_selection class ExtractMultiverseLook(openpype.api.Extractor): - """Extractor for Multiverse USD look data into a Maya Scene.""" + """Extractor for Multiverse USD look data. + + This will extract: + + - the shading networks that are assigned in MEOW as Maya material overrides + to a Multiverse Compound + - settings for a Multiverse Write Override operation. + + Relevant settings are visible in the Maya set node created by a Multiverse + USD Look instance creator. + + The input data contained in the set is: + + - a single Multiverse Compound node with any number of Maya material + overrides (typically set in MEOW) + + Upon publish two files will be written: + + - a .usda override file containing material assignment information + - a .ma file containing shading networks + + Note: when layering the material assignment override on a loaded Compound, + remember to set a matching attribute override with the namespace of + the loaded compound in order for the material assignment to resolve. + + """ label = "Extract Multiverse USD Look" hosts = ["maya"] diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py index fe071b08a5..0671813c32 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py @@ -8,7 +8,21 @@ from openpype.hosts.maya.api.lib import maintained_selection class ExtractMultiverseUsd(openpype.api.Extractor): - """Extractor for Multiverse USD asset data.""" + """Extractor for Multiverse USD Asset data. + + This will extract settings for a Multiverse Write Asset operation: + they are visible in the Maya set node created by a Multiverse USD + Asset instance creator. + + The input data contained in the set is: + + - a single hierarchy of Maya nodes. Multiverse supports a variety of Maya + nodes such as transforms, mesh, curves, particles, instances, particle + instancers, pfx, MASH, lights, cameras, joints, connected materials, + shading networks etc. including many of their attributes. + + Upon publish a .usd (or .usdz) asset file will be typically written. + """ label = "Extract Multiverse USD Asset" hosts = ["maya"] diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py index 7be6b101d9..45d0cad368 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py @@ -7,7 +7,21 @@ from openpype.hosts.maya.api.lib import maintained_selection class ExtractMultiverseUsdComposition(openpype.api.Extractor): - """Extractor of Multiverse USD Composition.""" + """Extractor of Multiverse USD Composition data. + + This will extract settings for a Multiverse Write Composition operation: + they are visible in the Maya set node created by a Multiverse USD + Composition instance creator. + + The input data contained in the set is either: + + - a single hierarchy consisting of several Multiverse Compound nodes, with + any number of layers, and Maya transform nodes + - a single Compound node with more than one layer (in this case the "Write + as Compound Layers" option should be set). + + Upon publish a .usda composition file will be written. + """ label = "Extract Multiverse USD Composition" hosts = ["maya"] diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py index 091750c32b..8b14ac3388 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py @@ -7,7 +7,19 @@ from maya import cmds class ExtractMultiverseUsdOverride(openpype.api.Extractor): - """Extractor for Multiverse USD Override.""" + """Extractor for Multiverse USD Override data. + + This will extract settings for a Multiverse Write Override operation: + they are visible in the Maya set node created by a Multiverse USD + Override instance creator. + + The input data contained in the set is: + + - a single Multiverse Compound node with any number of overrides (typically + set in MEOW) + + Upon publish a .usda override file will be written. + """ label = "Extract Multiverse USD Override" hosts = ["maya"] diff --git a/website/docs/artist_hosts_maya.md b/website/docs/artist_hosts_maya.md index 7f7f360b82..79031ccaed 100644 --- a/website/docs/artist_hosts_maya.md +++ b/website/docs/artist_hosts_maya.md @@ -597,390 +597,3 @@ about customizing review process refer to [admin section](project_settings/setti If you don't move `modelMain` into `reviewMain`, review will be generated but it will be published as separate entity. - - -## Working with Multiverse in OpenPype - -OpenPype supports creating, publishing and loading of [Multiverse | USD]( -https://multi-verse.io) data. The minimum Multiverse version supported is v6.7, -and version 7.0 is recommended. - -In a nutshell it is possible to: - -- Create USD Assets, USD compositions, USD Overrides. - - This _creates_ OpenPype instances as Maya set nodes that contain information - for published USD data. - -- Create Multiverse Looks. - - This _creates_ OpenPype instances as Maya set nodes that contain information - for published Maya shading networks data. - -- Publish USD Assets, USD compositions and USD Overrides. - - This _writes_ USD files to disk and _publishes_ information to the OpenPype - database. - -- Publish Multiverse Looks. - - This _writes_ Maya files to disk and _publishes_ information to the OpenPype - database. - - -- Load any USD data into Multiverse "Compound" shape nodes. - - This _reads_ USD files (and also Alembic files) into Maya by _streaming_ them - to the viewport. - -- Rendering USD data procedurally with 3DelightNSI, Arnold, Redshift, - RenderMan and VRay. - - This reads USD files by _streaming_ them procedurally to the renderer, at - render time. - -USD files written by Multiverse are 100% native USD data, they can be exchanged -with any other DCC applications able to interchange USD. Likewise, Multiverse -can read native USD data created by other applications. The USD extensions are -supported: `.usd` (binary), `.usda` (ASCII), `.usdz`. (zipped, optionally with -textures). Sequences of USD files can also be read via "USD clips". - -It is also possible to load Alembic data (`.abc`) in Multiverse Compounds, -further compose it & override it in other USD files, and render it procedurally. -Alembic data is always converted on the fly (in memory) to USD data. USD clip -from Alembic data are also supported. - - -### Configuration - -To configure Multiverse in OpenPype, an admin privileges needs to setup a new -OpenPype tool in the OpenPype Project Settings, using a similar configuration as -the one depicted here: - -![Maya - Multiverse Setup](assets/maya-multiverse_setup.png) - -For more information about setup of Multiverse please refer to the relative page -on the [Multiverse official documentation](https://multi-verse.io/docs). - - -### Understanding Assets, Compounds, Compositions, Overrides and Layering - -In Multiverse we use some terminology that relates to USD I/O: terms like -"Assets", "Compounds", "Compositions", "Overrides" and "Layering". - -Please hop to the new [Multiverse Introduction]( -https://j-cube.jp/solutions/multiverse/docs/usage/introduction) page on the -official documentation to understand them before reading the next sections. - - -### Creators - -It is possible to create OpenPype "instances" (resulting in Maya set containers) -for publishing Multiverse USD Assets, Compositions, Overrides and Looks. - -When creating OpenPype instances for Multiverse USD Asset, Composition, -Override and Look, the creator plug-in will put the relative selected data in a -Maya set node which holds the properties used by the Multiverse data writer for -publishing. - -You can choose the USD file format in the Creators' set nodes: - -- Assets: `.usd` or `.usda` or `.usdz` -- Compositions: `.usd` or `.usda` -- Overrides: `.usd` or `.usda` -- Looks: `.ma` - -![Maya - Multiverse Asset Creator](assets/maya-multiverse_openpype_asset_creator.png) - -![Maya - Multiverse Asset Creator](assets/maya-multiverse_openpype_composition_creator.png) - -![Maya - Multiverse Asset Creator](assets/maya-multiverse_openpype_override_creator.png) - -![Maya - Multiverse Asset Creator](assets/maya-multiverse_openpype_look_creator.png) - -### Publishers - -The relative publishers for Multiverse USD Asset, Composition, Override and Look -are available. The first three write USD files to disk, while look writes a maya -file. All communicate publish info to the OpenPype database. - -![Maya - Multiverse Publisher](assets/maya-multiverse_openpype_publishers.png) - - -### Loader - -The loader creates a Multiverse "Compound" shape node reading the USD file of -choice. All data is _streamed_ to the viewport and not contained in Maya. Thanks -to the various viewport draw options the user can strategically decide how to -minimize the cost of viewport draw effectively being able to load any data, this -allows to bring into Maya scenes of virtually unlimited complexity. - -![Maya - Multiverse Loader](assets/maya-multiverse_openpype_loader.png) - -:::tip Note -When using the Loader, Multiverse, by design, never "imports" USD data into the -Maya scene as Maya data. Instead, when desired, Multiverse permits to import -specific USD primitives into the Maya scene as Maya data selectively from MEOW, -it also tracks what is being imported, so upon modification, it is possible to -write (create & publish) the modifies data as a USD file for being layered on -top of its relative Compound. See the [Multiverse Importer]( -https://j-cube.jp/solutions/multiverse/docs/usage/importer)) documentation. -::: - -### Look - -In OpenPype a Multiverse Look is a Maya file that contains shading networks that -are assigned to the items of a Multiverse Compound. - -Multiverse Looks are typically Maya-referenced in the lighting and shot scenes. - -Materials are assigned to the USD items in the Compound via the "material -assignment" information that is output in the lookdev stage by a Multiverse -Override. Once published the override can be Layered on the Compound so that -materials will be assigned to items. Finally, an attribute Override on the root -item of the Compound is used to define the `namespace` with which the shading -networks were referenced in Maya. At this point the renderer knows which -material to assign to which item and it is possible to render and edit the -materials as usual. Because the material exists in Maya you can perform IPR and -tune the materials as you please. - -As of Multiverse 7 it is also possible to write shading networks inside the USD -files: that is achieved by using either the Asset writer (if material are -defined in the modeling stage) and the Override writer (if materials are -defined in the lookdev or later stage). Shading networks in USD can then be -rendered in 3Delight NSI or used for interchange with DCC apps. - -Some interesting consequences of USD shading networks in Multiverse: - -1. they can be overridden by a shading network in Maya by assigning in MEOW a - Maya material as an override -2. they are available for assignment in MEOW, so you can assign a USD material - to an item as an override -3. From Hypershade you can use the Multiverse USD shading network write File> - Export option to write USD shading network libraries to then layer on an asset - and perform 2. again. - - -### Rendering - -Multiverse offers procedural rendering with all the major production renderers: - -- 3DelightNSI -- Arnold -- Redshift -- RenderMan -- VRay - -Procedural rendering effectively means that data is _streamed_ to the renderer -at render-time, without the need to store the data in the Maya scene (this -effectively means small .ma/.mb files that load fast) nor in the renderer native -file format scene description file (this effectively means tiny `.nsi` / `.ass` -/ `.vrscene` / `.rib` files that load fast). - -This is completely transparent to the user: Multiverse Compound nodes present in -the scene, once a render is launched, will stream data to the renderer in a -procedural fashion. - - -### Example Multiverse Pipeline and API - -An example diagram of the data flow in a Maya pipeline using Multiverse is -available, see the [Multiverse Pipeline]( -https://j-cube.jp/solutions/multiverse/docs/pipeline) documentation. - - -A very easy to use Python API to automate any task is available, the API is -user friendly and does not require any knowledge of the vast and complex USD -APIs. See the [Multiverse Python API]( -https://j-cube.jp/solutions/multiverse/docs/dev/python-api.html) documentation. - - -## Working with Yeti in OpenPype - -OpenPype can work with [Yeti](https://peregrinelabs.com/yeti/) in two data modes. -It can handle Yeti caches and Yeti rigs. - -### Creating and publishing Yeti caches - -Let start by creating simple Yeti setup, just one object and Yeti node. Open new -empty scene in Maya and create sphere. Then select sphere and go **Yeti → Create Yeti Node on Mesh** -Open Yeti node graph **Yeti → Open Graph Editor** and create setup like this: - -![Maya - Yeti Basic Graph](assets/maya-yeti_basic_setup.jpg) - -It doesn't matter what setting you use now, just select proper shape in first -*Import* node. Select your Yeti node and create *Yeti Cache instance* - **OpenPype → Create...** -and select **Yeti Cache**. Leave `Use selection` checked. You should end up with this setup: - -![Maya - Yeti Basic Setup](assets/maya-yeti_basic_setup_outline.jpg) - -You can see there is `yeticacheDefault` set. Instead of *Default* it could be named with -whatever name you've entered in `subset` field during instance creation. - -We are almost ready for publishing cache. You can check basic settings by selecting -Yeti cache set and opening *Extra attributes* in Maya **Attribute Editor**. - -![Maya - Yeti Basic Setup](assets/maya-yeti_cache_attributes.jpg) - -Those attributes there are self-explanatory, but: - -- `Preroll` is number of frames simulation will run before cache frames are stored. -This is useful to "steady" simulation for example. -- `Frame Start` from what frame we start to store cache files -- `Frame End` to what frame we are storing cache files -- `Fps` of cache -- `Samples` how many time samples we take during caching - -You can now publish Yeti cache as any other types. **OpenPype → Publish**. It will -create sequence of `.fur` files and `.fursettings` metadata file with Yeti node -setting. - -### Loading Yeti caches - -You can load Yeti cache by **OpenPype → Load ...**. Select your cache, right+click on -it and select **Load Yeti cache**. This will create Yeti node in scene and set its -cache path to point to your published cache files. Note that this Yeti node will -be named with same name as the one you've used to publish cache. Also notice that -when you open graph on this Yeti node, all nodes are as they were in publishing node. - -### Creating and publishing Yeti Rig - -Yeti Rigs are working in similar way as caches, but are more complex and they deal with -other data used by Yeti, like geometry and textures. - -Let's start by [loading](artist_hosts_maya.md#loading-model) into new scene some model. -I've loaded my Buddha model. - -Create select model mesh, create Yeti node - **Yeti → Create Yeti Node on Mesh** and -setup similar Yeti graph as in cache example above. - -Then select this Yeti node (mine is called with default name `pgYetiMaya1`) and -create *Yeti Rig instance* - **OpenPype → Create...** and select **Yeti Cache**. -Leave `Use selection` checked. - -Last step is to add our model geometry to rig instance, so middle+drag its -geometry to `input_SET` under `yetiRigDefault` set representing rig instance. -Note that its name can differ and is based on your subset name. - -![Maya - Yeti Rig Setup](assets/maya-yeti_rig.jpg) - -Save your scene and ready for publishing our new simple Yeti Rig! - -Go to publish **OpenPype → Publish** and run. This will publish rig with its geometry -as `.ma` scene, save Yeti node settings and export one frame of Yeti cache from -the beginning of your timeline. It will also collect all textures used in Yeti -node, copy them to publish folder `resource` directory and set *Image search path* -of published node to this location. - -:::note Collect Yeti Cache failure -If you encounter **Collect Yeti Cache** failure during collecting phase, and the error is like -```fix -No object matches name: pgYetiMaya1Shape.cbId -``` -then it is probably caused by scene not being saved before publishing. -::: - -### Loading Yeti Rig - -You can load published Yeti Rigs as any other thing in OpenPype - **OpenPype → Load ...**, -select you Yeti rig and right+click on it. In context menu you should see -**Load Yeti Cache** and **Load Yeti Rig** items (among others). First one will -load that one frame cache. The other one will load whole rig. - -Notice that although we put only geometry into `input_SET`, whole hierarchy was -pulled inside also. This allows you to store complex scene element along Yeti -node. - -:::tip auto-connecting rig mesh to existing one -If you select some objects before loading rig it will try to find shapes -under selected hierarchies and match them with shapes loaded with rig (published -under `input_SET`). This mechanism uses *cbId* attribute on those shapes. -If match is found shapes are connected using their `outMesh` and `outMesh`. Thus you can easily connect existing animation to loaded rig. -::: - -## Working with Xgen in OpenPype - -OpenPype support publishing and loading of Xgen interactive grooms. You can publish -them as mayaAscii files with scalps that can be loaded into another maya scene, or as -alembic caches. - -### Publishing Xgen Grooms - -To prepare xgen for publishing just select all the descriptions that should be published together and the create Xgen Subset in the scene using - **OpenPype menu** → **Create**... and select **Xgen Interactive**. Leave Use selection checked. - -For actual publishing of your groom to go **OpenPype → Publish** and then press ▶ to publish. This will export `.ma` file containing your grooms with any geometries they are attached to and also a baked cache in `.abc` format - - -:::tip adding more descriptions -You can add multiple xgen description into the subset you are about to publish, simply by -adding them to the maya set that was created for you. Please make sure that only xgen description nodes are present inside of the set and not the scalp geometry. -::: - -### Loading Xgen - -You can use published xgens by loading them using OpenPype Publisher. You can choose to reference or import xgen. We don't have any automatic mesh linking at the moment and it is expected, that groom is published with a scalp, that can then be manually attached to your animated mesh for example. - -The alembic representation can be loaded too and it contains the groom converted to curves. Keep in mind that the density of the alembic directly depends on your viewport xgen density at the point of export. - - - -## Using Redshift Proxies - -OpenPype supports working with Redshift Proxy files. You can create Redshift Proxy from almost -any hierarchy in Maya and it will be included there. Redshift can export animation -proxy file per frame. - -### Creating Redshift Proxy - -To mark data to publish as Redshift Proxy, select them in Maya and - **OpenPype → Create ...** and -then select **Redshift Proxy**. You can name your subset and hit **Create** button. - -You can enable animation in Attribute Editor: - -![Maya - Yeti Rig Setup](assets/maya-create_rs_proxy.jpg) - -### Publishing Redshift Proxies - -Once data are marked as Redshift Proxy instance, they can be published - **OpenPype → Publish ...** - -### Using Redshift Proxies - -Published proxy files can be loaded with OpenPype Loader. It will create mesh and attach Redshift Proxy -parameters to it - Redshift will then represent proxy with bounding box. - -## Using VRay Proxies - -OpenPype support publishing, loading and using of VRay Proxy in look management. Their underlying format -can be either vrmesh or alembic. - -:::warning vrmesh or alembic and look management -Be aware that **vrmesh** cannot be used with looks as it doesn't retain IDs necessary to map shaders to geometry. -::: - -### Creating VRay Proxy - -To create VRay Proxy, select geometry you want and - **OpenPype → Create ...** select **VRay Proxy**. Name your -subset as you want and press **Create** button. - -This will create `vrayproxy` set for your subset. You can set some options in Attribute editor, mainly if you want -export animation instead of single frame. - -![Maya - VRay Proxy Creation](assets/maya-vray_proxy.jpg) - -### Publishing VRay Proxies - -VRay Proxy can be published - **OpenPype → Publish ...**. It will publish data as VRays `vrmesh` format and as -Alembic file. - -## Using VRay Proxies - -You can load VRay Proxy using loader - **OpenPype → Loader ...** - -![Maya - VRay Proxy Creation](assets/maya-vray_proxy-loader.jpg) - -Select your subset and right-click. Select **Import VRay Proxy (vrmesh)** to import it. - -:::note -Note that even if it states `vrmesh` in descriptions, if loader finds Alembic published along (default behavior) it will -use abc file instead of vrmesh as it is more flexible and without it looks doesn't work. -::: diff --git a/website/docs/artist_hosts_maya_multiverse.md b/website/docs/artist_hosts_maya_multiverse.md new file mode 100644 index 0000000000..e6520bafa0 --- /dev/null +++ b/website/docs/artist_hosts_maya_multiverse.md @@ -0,0 +1,237 @@ +--- +id: artist_hosts_maya_multiverse +title: Multiverse for Maya +sidebar_label: Multiverse USD +--- + +## Working with Multiverse in OpenPype + +OpenPype supports creating, publishing and loading of [Multiverse | USD]( +https://multi-verse.io) data. The minimum Multiverse version supported is v6.7, +and version 7.0 is recommended. + +In a nutshell it is possible to: + +- Create USD Assets, USD compositions, USD Overrides. + + This _creates_ OpenPype instances as Maya set nodes that contain information + for published USD data. + +- Create Multiverse Looks. + + This _creates_ OpenPype instances as Maya set nodes that contain information + for published Maya shading networks data and USD material assignment data. + +- Publish USD Assets, USD compositions and USD Overrides. + + This _writes_ USD files to disk and _publishes_ information to the OpenPype + database. + +- Publish Multiverse Looks. + + This _writes_ a Maya file containing shading networks (to import in Maya), a + USD override file containing material assignment information (to layer in a + Multiverse Compound), it copies original & mip-mapped textures to disk and + _publishes_ information to the OpenPype database. + +- Load any USD data into Multiverse "Compound" shape nodes. + + This _reads_ USD files (and also Alembic files) into Maya by _streaming_ them + to the viewport. + +- Rendering USD data procedurally with 3DelightNSI, Arnold, Redshift, + RenderMan and VRay. + + This reads USD files by _streaming_ them procedurally to the renderer, at + render time. + +USD files written by Multiverse are 100% native USD data, they can be exchanged +with any other DCC applications able to interchange USD. Likewise, Multiverse +can read native USD data created by other applications. The USD extensions are +supported: `.usd` (binary), `.usda` (ASCII), `.usdz`. (zipped, optionally with +textures). Sequences of USD files can also be read via "USD clips". + +It is also possible to load Alembic data (`.abc`) in Multiverse Compounds, +further compose it & override it in other USD files, and render it procedurally. +Alembic data is always converted on the fly (in memory) to USD data. USD clip +from Alembic data are also supported. + + +### Configuration + +To configure Multiverse in OpenPype, an admin privileges needs to setup a new +OpenPype tool in the OpenPype Project Settings, using a similar configuration as +the one depicted here: + +![Maya - Multiverse Setup](assets/maya-multiverse_setup.png) + +For more information about setup of Multiverse please refer to the relative page +on the [Multiverse official documentation](https://multi-verse.io/docs). + + +### Understanding Assets, Compounds, Compositions, Overrides and Layering + +In Multiverse we use some terminology that relates to USD I/O: terms like +"Assets", "Compounds", "Compositions", "Overrides" and "Layering". + +Please hop to the new [Multiverse Introduction]( +https://j-cube.jp/solutions/multiverse/docs/usage/introduction) page on the +official documentation to understand them before reading the next sections. + + +### Creators + +It is possible to create OpenPype "instances" (resulting in Maya set containers) +for publishing Multiverse USD Assets, Compositions, Overrides and Looks. + +When creating OpenPype instances for Multiverse USD Asset, Composition, +Override and Look, the creator plug-in will put the relative selected data in a +Maya set node which holds the properties used by the Multiverse data writer for +publishing. + +You can choose the USD file format in the Creators' set nodes: + +- Assets: `.usd` (default) or `.usda` or `.usdz` +- Compositions: `.usda` (default) or `.usd` +- Overrides: `.usda` (default) or `.usd` +- Looks: `.ma` + +![Maya - Multiverse Asset Creator](assets/maya-multiverse_openpype_asset_creator.png) + +![Maya - Multiverse Asset Creator](assets/maya-multiverse_openpype_composition_creator.png) + +![Maya - Multiverse Asset Creator](assets/maya-multiverse_openpype_override_creator.png) + +![Maya - Multiverse Asset Creator](assets/maya-multiverse_openpype_look_creator.png) + +### Publishers + +The relative publishers for Multiverse USD Asset, Composition, Override and Look +are available. The first three write USD files to disk, while look writes a Maya +file along with the mip-mapped textures. All communicate publish info to the +OpenPype database. + +![Maya - Multiverse Publisher](assets/maya-multiverse_openpype_publishers.png) + + +### Loader + +The loader creates a Multiverse "Compound" shape node reading the USD file of +choice. All data is _streamed_ to the viewport and not contained in Maya. Thanks +to the various viewport draw options the user can strategically decide how to +minimize the cost of viewport draw effectively being able to load any data, this +allows to bring into Maya scenes of virtually unlimited complexity. + +![Maya - Multiverse Loader](assets/maya-multiverse_openpype_loader.png) + +:::tip Note +When using the Loader, Multiverse, by design, never "imports" USD data into the +Maya scene as Maya data. Instead, when desired, Multiverse permits to import +specific USD primitives, or entire hierarchies, into the Maya scene as Maya data +selectively from MEOW, it also tracks what is being imported with a "live +connection" , so upon modification, it is possible to write (create & publish) +the modifies data as a USD file for being layered on top of its relative +Compound. See the [Multiverse Importer]( +https://j-cube.jp/solutions/multiverse/docs/usage/importer)) documentation. +::: + +### Look + +In OpenPype a Multiverse Look is the combination of: + +- a Maya file that contains the shading networks that were assigned to the items + of a Multiverse Compound. +- a Multiverse USD Override file that contains the material assignment + information (which Maya material was assigned to which USD item) +- mip-mapped textures + +Multiverse Look shading networks are typically Maya-referenced in the lighting +and shot scenes. + +Materials are assigned to the USD items in the Compound via the "material +assignment" information that is output in the lookdev stage by a Multiverse +Override. Once published the override can be Layered on the Compound so that +materials will be assigned to items. Finally, an attribute Override on the root +item of the Compound is used to define the `namespace` with which the shading +networks were referenced in Maya. At this point the renderer knows which +material to assign to which item and it is possible to render and edit the +materials as usual. Because the material exists in Maya you can perform IPR and +tune the materials as you please. + +The Multiverse Look will also publish textures in optimized mip-map format, +currently supporting the `.tdl` (Texture Delight) mip map format of the 3Delight +NSI renderer. MipMaps are required when the relative option is checked and you +are publishing Multiverse Looks with the `final` or `-` subset, while they are +not required with the `WIP` or `test` subsets. MipMaps are found automatically +as long as they exist alongside the original textures. Their generation can be +automatic when using 3Delight for Maya or can be manual by using the `tdlmake` +binary utility. + + +### About embedding shading networks in USD + +Alternatively, but also complementary to the Multiverse Look, as of Multiverse +7 it is also possible to write shading networks _inside_ USD files: that is +achieved by using either the Asset writer (if material are defined in the +modeling stage) and the Override writer (if materials are defined in the lookdev +or later stage). + +Some interesting consequences of USD shading networks in Multiverse: + +1. they can be overridden by a shading network in Maya by assigning in MEOW a + Maya material as an override +2. they are available for assignment in MEOW, so you can assign a USD material + to an item as an override +3. From Hypershade you can use the Multiverse USD shading network write File> + Export option to write USD shading network libraries to then layer on an asset + and perform 2. again. + +Note that: + +- Shading networks in USD can then be currently rendered with + 3DelightNSI +- Shading networks in USD can be used for interchange with DCC apps. Multiverse + shading networks are written natively with the USD Shade schema. +- usdPreviewSurface shading networks are too considered embedded shading + networks, though they are classified separately from non-preview / final + quality shading networks +- USDZ files use usdPreviewSurface shading networks, and therefore can be, too, + rendered (with 3DelightNSI) +- in case both usdPreviewSurface and final quality shading networks, the latter + will be used for rendering (while the former can be previewed in the viewport) +- it is possible to disable rendering of any embedded shading network via the + relative option in the Compound Attribute Editor. + + +### Rendering + +Multiverse offers procedural rendering with all the major production renderers: + +- 3DelightNSI +- Arnold +- Redshift +- RenderMan +- VRay + +Procedural rendering effectively means that data is _streamed_ to the renderer +at render-time, without the need to store the data in the Maya scene (this +effectively means small .ma/.mb files that load fast) nor in the renderer native +file format scene description file (this effectively means tiny `.nsi` / `.ass` +/ `.vrscene` / `.rib` files that load fast). + +This is completely transparent to the user: Multiverse Compound nodes present in +the scene, once a render is launched, will stream data to the renderer in a +procedural fashion. + + +### Example Multiverse Pipeline and API + +An example diagram of the data flow in a Maya pipeline using Multiverse is +available, see the [Multiverse Pipeline]( +https://j-cube.jp/solutions/multiverse/docs/pipeline) documentation. + + +A very easy to use Python API to automate any task is available, the API is +user friendly and does not require any knowledge of the vast and complex USD +APIs. See the [Multiverse Python API]( +https://j-cube.jp/solutions/multiverse/docs/dev/python-api.html) documentation. diff --git a/website/docs/artist_hosts_maya_redshift.md b/website/docs/artist_hosts_maya_redshift.md new file mode 100644 index 0000000000..268c49d75c --- /dev/null +++ b/website/docs/artist_hosts_maya_redshift.md @@ -0,0 +1,31 @@ +--- +id: artist_hosts_maya_redshift +title: Redshift for Maya +sidebar_label: Redshift +--- + +## Working with Redshift in OpenPype + +### Using Redshift Proxies + +OpenPype supports working with Redshift Proxy files. You can create Redshift Proxy from almost +any hierarchy in Maya and it will be included there. Redshift can export animation +proxy file per frame. + +### Creating Redshift Proxy + +To mark data to publish as Redshift Proxy, select them in Maya and - **OpenPype → Create ...** and +then select **Redshift Proxy**. You can name your subset and hit **Create** button. + +You can enable animation in Attribute Editor: + +![Maya - Yeti Rig Setup](assets/maya-create_rs_proxy.jpg) + +### Publishing Redshift Proxies + +Once data are marked as Redshift Proxy instance, they can be published - **OpenPype → Publish ...** + +### Using Redshift Proxies + +Published proxy files can be loaded with OpenPype Loader. It will create mesh and attach Redshift Proxy +parameters to it - Redshift will then represent proxy with bounding box. diff --git a/website/docs/artist_hosts_maya_vray.md b/website/docs/artist_hosts_maya_vray.md new file mode 100644 index 0000000000..a19fce9735 --- /dev/null +++ b/website/docs/artist_hosts_maya_vray.md @@ -0,0 +1,44 @@ +--- +id: artist_hosts_maya_vray +title: VRay for Maya +sidebar_label: VRay +--- + +## Working with VRay in OpenPype + +### #Using VRay Proxies + +OpenPype support publishing, loading and using of VRay Proxy in look management. Their underlying format +can be either vrmesh or alembic. + +:::warning vrmesh or alembic and look management +Be aware that **vrmesh** cannot be used with looks as it doesn't retain IDs necessary to map shaders to geometry. +::: + +### Creating VRay Proxy + +To create VRay Proxy, select geometry you want and - **OpenPype → Create ...** select **VRay Proxy**. Name your +subset as you want and press **Create** button. + +This will create `vrayproxy` set for your subset. You can set some options in Attribute editor, mainly if you want +export animation instead of single frame. + +![Maya - VRay Proxy Creation](assets/maya-vray_proxy.jpg) + +### Publishing VRay Proxies + +VRay Proxy can be published - **OpenPype → Publish ...**. It will publish data as VRays `vrmesh` format and as +Alembic file. + +## Using VRay Proxies + +You can load VRay Proxy using loader - **OpenPype → Loader ...** + +![Maya - VRay Proxy Creation](assets/maya-vray_proxy-loader.jpg) + +Select your subset and right-click. Select **Import VRay Proxy (vrmesh)** to import it. + +:::note +Note that even if it states `vrmesh` in descriptions, if loader finds Alembic published along (default behavior) it will +use abc file instead of vrmesh as it is more flexible and without it looks doesn't work. +::: diff --git a/website/docs/artist_hosts_maya_xgen.md b/website/docs/artist_hosts_maya_xgen.md new file mode 100644 index 0000000000..8b0174a29f --- /dev/null +++ b/website/docs/artist_hosts_maya_xgen.md @@ -0,0 +1,29 @@ +--- +id: artist_hosts_maya_xgen +title: Xgen for Maya +sidebar_label: Xgen +--- + +## Working with Xgen in OpenPype + +OpenPype support publishing and loading of Xgen interactive grooms. You can publish +them as mayaAscii files with scalps that can be loaded into another maya scene, or as +alembic caches. + +### Publishing Xgen Grooms + +To prepare xgen for publishing just select all the descriptions that should be published together and the create Xgen Subset in the scene using - **OpenPype menu** → **Create**... and select **Xgen Interactive**. Leave Use selection checked. + +For actual publishing of your groom to go **OpenPype → Publish** and then press ▶ to publish. This will export `.ma` file containing your grooms with any geometries they are attached to and also a baked cache in `.abc` format + + +:::tip adding more descriptions +You can add multiple xgen description into the subset you are about to publish, simply by +adding them to the maya set that was created for you. Please make sure that only xgen description nodes are present inside of the set and not the scalp geometry. +::: + +### Loading Xgen + +You can use published xgens by loading them using OpenPype Publisher. You can choose to reference or import xgen. We don't have any automatic mesh linking at the moment and it is expected, that groom is published with a scalp, that can then be manually attached to your animated mesh for example. + +The alembic representation can be loaded too and it contains the groom converted to curves. Keep in mind that the density of the alembic directly depends on your viewport xgen density at the point of export. diff --git a/website/docs/artist_hosts_maya_yeti.md b/website/docs/artist_hosts_maya_yeti.md new file mode 100644 index 0000000000..f5a6a4d2c9 --- /dev/null +++ b/website/docs/artist_hosts_maya_yeti.md @@ -0,0 +1,108 @@ +--- +id: artist_hosts_maya_yeti +title: Yeti for Maya +sidebar_label: Yeti +--- + +## Working with Yeti in OpenPype + +OpenPype can work with [Yeti](https://peregrinelabs.com/yeti/) in two data modes. +It can handle Yeti caches and Yeti rigs. + +### Creating and publishing Yeti caches + +Let start by creating simple Yeti setup, just one object and Yeti node. Open new +empty scene in Maya and create sphere. Then select sphere and go **Yeti → Create Yeti Node on Mesh** +Open Yeti node graph **Yeti → Open Graph Editor** and create setup like this: + +![Maya - Yeti Basic Graph](assets/maya-yeti_basic_setup.jpg) + +It doesn't matter what setting you use now, just select proper shape in first +*Import* node. Select your Yeti node and create *Yeti Cache instance* - **OpenPype → Create...** +and select **Yeti Cache**. Leave `Use selection` checked. You should end up with this setup: + +![Maya - Yeti Basic Setup](assets/maya-yeti_basic_setup_outline.jpg) + +You can see there is `yeticacheDefault` set. Instead of *Default* it could be named with +whatever name you've entered in `subset` field during instance creation. + +We are almost ready for publishing cache. You can check basic settings by selecting +Yeti cache set and opening *Extra attributes* in Maya **Attribute Editor**. + +![Maya - Yeti Basic Setup](assets/maya-yeti_cache_attributes.jpg) + +Those attributes there are self-explanatory, but: + +- `Preroll` is number of frames simulation will run before cache frames are stored. +This is useful to "steady" simulation for example. +- `Frame Start` from what frame we start to store cache files +- `Frame End` to what frame we are storing cache files +- `Fps` of cache +- `Samples` how many time samples we take during caching + +You can now publish Yeti cache as any other types. **OpenPype → Publish**. It will +create sequence of `.fur` files and `.fursettings` metadata file with Yeti node +setting. + +### Loading Yeti caches + +You can load Yeti cache by **OpenPype → Load ...**. Select your cache, right+click on +it and select **Load Yeti cache**. This will create Yeti node in scene and set its +cache path to point to your published cache files. Note that this Yeti node will +be named with same name as the one you've used to publish cache. Also notice that +when you open graph on this Yeti node, all nodes are as they were in publishing node. + +### Creating and publishing Yeti Rig + +Yeti Rigs are working in similar way as caches, but are more complex and they deal with +other data used by Yeti, like geometry and textures. + +Let's start by [loading](artist_hosts_maya.md#loading-model) into new scene some model. +I've loaded my Buddha model. + +Create select model mesh, create Yeti node - **Yeti → Create Yeti Node on Mesh** and +setup similar Yeti graph as in cache example above. + +Then select this Yeti node (mine is called with default name `pgYetiMaya1`) and +create *Yeti Rig instance* - **OpenPype → Create...** and select **Yeti Cache**. +Leave `Use selection` checked. + +Last step is to add our model geometry to rig instance, so middle+drag its +geometry to `input_SET` under `yetiRigDefault` set representing rig instance. +Note that its name can differ and is based on your subset name. + +![Maya - Yeti Rig Setup](assets/maya-yeti_rig.jpg) + +Save your scene and ready for publishing our new simple Yeti Rig! + +Go to publish **OpenPype → Publish** and run. This will publish rig with its geometry +as `.ma` scene, save Yeti node settings and export one frame of Yeti cache from +the beginning of your timeline. It will also collect all textures used in Yeti +node, copy them to publish folder `resource` directory and set *Image search path* +of published node to this location. + +:::note Collect Yeti Cache failure +If you encounter **Collect Yeti Cache** failure during collecting phase, and the error is like +```fix +No object matches name: pgYetiMaya1Shape.cbId +``` +then it is probably caused by scene not being saved before publishing. +::: + +### Loading Yeti Rig + +You can load published Yeti Rigs as any other thing in OpenPype - **OpenPype → Load ...**, +select you Yeti rig and right+click on it. In context menu you should see +**Load Yeti Cache** and **Load Yeti Rig** items (among others). First one will +load that one frame cache. The other one will load whole rig. + +Notice that although we put only geometry into `input_SET`, whole hierarchy was +pulled inside also. This allows you to store complex scene element along Yeti +node. + +:::tip auto-connecting rig mesh to existing one +If you select some objects before loading rig it will try to find shapes +under selected hierarchies and match them with shapes loaded with rig (published +under `input_SET`). This mechanism uses *cbId* attribute on those shapes. +If match is found shapes are connected using their `outMesh` and `outMesh`. Thus you can easily connect existing animation to loaded rig. +::: diff --git a/website/docs/assets/maya-multiverse_openpype_look_creator.png b/website/docs/assets/maya-multiverse_openpype_look_creator.png index 14541e9e398fc99e3910d50a5286bdd8906b9f1a..fd27d5fd1af7d8ac4d9bc83799c52972615f251e 100644 GIT binary patch literal 125727 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 Pp4Go+auDm7PT|Bi* literal 26190 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 XNN#wif}p^6lEBGJD?=(?y$$*wxlGVg diff --git a/website/docs/assets/maya-multiverse_openpype_publishers.png b/website/docs/assets/maya-multiverse_openpype_publishers.png index b83fa5f59cd95ac8f6feab2e043fb9514ab257a7..bee6c79fe9802337520574fc619da0b63b62918b 100644 GIT binary patch literal 309158 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%0Dj1JpW~1Q|YqP!3 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�kJI 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

Nf;6b8`XXkU*mAAa2w5Kiw5OZ<+ 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%0A{^xbkk2>37iiz1t7NI7 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 literal 182542 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¼zTC%cnFn=R3lm5XW25oz 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

+jTLKMEVQn~<}sDNh&32k4p!94^-h8nk-?qrSH7 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

V^Fk7mW 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 diff --git a/website/sidebars.js b/website/sidebars.js index 105afc30eb..b105e6ea93 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -19,7 +19,18 @@ module.exports = { items: [ "artist_hosts_hiero", "artist_hosts_nuke_tut", - "artist_hosts_maya", + { + type: "category", + label: "Maya", + items: [ + "artist_hosts_maya", + "artist_hosts_maya_multiverse", + "artist_hosts_maya_yeti", + "artist_hosts_maya_xgen", + "artist_hosts_maya_vray", + "artist_hosts_maya_redshift", + ], + }, "artist_hosts_blender", "artist_hosts_harmony", "artist_hosts_houdini", From 5c8e7fd3305dc67d339e49837d0a224961e274e3 Mon Sep 17 00:00:00 2001 From: pberto Date: Tue, 31 May 2022 14:36:06 +0900 Subject: [PATCH 287/350] docstring: addressing trailing whitespaces to placate the hound --- openpype/hosts/maya/plugins/publish/extract_multiverse_look.py | 1 - openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py | 2 +- .../hosts/maya/plugins/publish/extract_multiverse_usd_comp.py | 2 +- .../hosts/maya/plugins/publish/extract_multiverse_usd_over.py | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_look.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_look.py index d59d03ee58..82e2b41929 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_look.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_look.py @@ -31,7 +31,6 @@ class ExtractMultiverseLook(openpype.api.Extractor): Note: when layering the material assignment override on a loaded Compound, remember to set a matching attribute override with the namespace of the loaded compound in order for the material assignment to resolve. - """ label = "Extract Multiverse USD Look" diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py index 0671813c32..b1aaf9d9ba 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py @@ -21,7 +21,7 @@ class ExtractMultiverseUsd(openpype.api.Extractor): instancers, pfx, MASH, lights, cameras, joints, connected materials, shading networks etc. including many of their attributes. - Upon publish a .usd (or .usdz) asset file will be typically written. + Upon publish a .usd (or .usdz) asset file will be typically written. """ label = "Extract Multiverse USD Asset" diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py index 45d0cad368..c85b3b6664 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py @@ -20,7 +20,7 @@ class ExtractMultiverseUsdComposition(openpype.api.Extractor): - a single Compound node with more than one layer (in this case the "Write as Compound Layers" option should be set). - Upon publish a .usda composition file will be written. + Upon publish a .usda composition file will be written. """ label = "Extract Multiverse USD Composition" diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py index 8b14ac3388..4856f0cfdb 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py @@ -18,7 +18,7 @@ class ExtractMultiverseUsdOverride(openpype.api.Extractor): - a single Multiverse Compound node with any number of overrides (typically set in MEOW) - Upon publish a .usda override file will be written. + Upon publish a .usda override file will be written. """ label = "Extract Multiverse USD Override" From 45e0e39ea1e262044e1764f546943f4b436dc926 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Tue, 31 May 2022 11:39:03 +0200 Subject: [PATCH 288/350] :sparkles: add support for skeletalMesh and staticMesh to loaders --- openpype/hosts/unreal/plugins/load/load_rig.py | 2 +- openpype/hosts/unreal/plugins/load/load_staticmeshfbx.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/unreal/plugins/load/load_rig.py b/openpype/hosts/unreal/plugins/load/load_rig.py index c27bd23aaf..227c5c9292 100644 --- a/openpype/hosts/unreal/plugins/load/load_rig.py +++ b/openpype/hosts/unreal/plugins/load/load_rig.py @@ -14,7 +14,7 @@ import unreal # noqa class SkeletalMeshFBXLoader(plugin.Loader): """Load Unreal SkeletalMesh from FBX.""" - families = ["rig"] + families = ["rig", "skeletalMesh"] label = "Import FBX Skeletal Mesh" representations = ["fbx"] icon = "cube" diff --git a/openpype/hosts/unreal/plugins/load/load_staticmeshfbx.py b/openpype/hosts/unreal/plugins/load/load_staticmeshfbx.py index 282d249947..351c686095 100644 --- a/openpype/hosts/unreal/plugins/load/load_staticmeshfbx.py +++ b/openpype/hosts/unreal/plugins/load/load_staticmeshfbx.py @@ -14,7 +14,7 @@ import unreal # noqa class StaticMeshFBXLoader(plugin.Loader): """Load Unreal StaticMesh from FBX.""" - families = ["model", "unrealStaticMesh"] + families = ["model", "staticMesh"] label = "Import FBX Static Mesh" representations = ["fbx"] icon = "cube" From 9c1b1f11e97dfb7deff3c3b76a6ed9058771451b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 31 May 2022 13:52:29 +0200 Subject: [PATCH 289/350] updated windows oiio tool to v 2.3.10 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 47d678b5e8..6b98178aa8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -126,7 +126,7 @@ url = "https://distribute.openpype.io/thirdparty/ffmpeg-4.4-macos.tgz" hash = "95f43568338c275f80dc0cab1e1836a2e2270f856f0e7b204440d881dd74fbdb" [openpype.thirdparty.oiio.windows] -url = "https://distribute.openpype.io/thirdparty/oiio_tools-2.2.0-windows.zip" +url = "https://distribute.openpype.io/thirdparty/oiio_tools-2.3.10-windows.zip" hash = "fd2e00278e01e85dcee7b4a6969d1a16f13016ec16700fb0366dbb1b1f3c37ad" [openpype.thirdparty.oiio.linux] From 5464fd40850ae1d25c1b467149249bd5edaaae9e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 31 May 2022 13:58:11 +0200 Subject: [PATCH 290/350] OP-2787 - fix extractors could be run on a farm --- openpype/hosts/maya/plugins/publish/extract_animation.py | 3 +++ openpype/hosts/maya/plugins/publish/extract_pointcache.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/openpype/hosts/maya/plugins/publish/extract_animation.py b/openpype/hosts/maya/plugins/publish/extract_animation.py index 1ccc8f5cfe..8f2bc26d08 100644 --- a/openpype/hosts/maya/plugins/publish/extract_animation.py +++ b/openpype/hosts/maya/plugins/publish/extract_animation.py @@ -16,11 +16,14 @@ class ExtractAnimation(openpype.api.Extractor): Positions and normals, uvs, creases are preserved, but nothing more, for plain and predictable point caches. + Plugin can run locally or remotely (on a farm - if instance is marked with + "farm" it will be skipped in local processing, but processed on farm) """ label = "Extract Animation" hosts = ["maya"] families = ["animation"] + targets = ["local", "remote"] def process(self, instance): if instance.data.get("farm"): diff --git a/openpype/hosts/maya/plugins/publish/extract_pointcache.py b/openpype/hosts/maya/plugins/publish/extract_pointcache.py index ff3d97ded1..5606ea9459 100644 --- a/openpype/hosts/maya/plugins/publish/extract_pointcache.py +++ b/openpype/hosts/maya/plugins/publish/extract_pointcache.py @@ -16,6 +16,8 @@ class ExtractAlembic(openpype.api.Extractor): Positions and normals, uvs, creases are preserved, but nothing more, for plain and predictable point caches. + Plugin can run locally or remotely (on a farm - if instance is marked with + "farm" it will be skipped in local processing, but processed on farm) """ label = "Extract Pointcache (Alembic)" @@ -23,6 +25,7 @@ class ExtractAlembic(openpype.api.Extractor): families = ["pointcache", "model", "vrayproxy"] + targets = ["local", "remote"] def process(self, instance): if instance.data.get("farm"): From 376ddc41329206173f2d8f4e9d568e0aef4cebc3 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 31 May 2022 14:01:23 +0200 Subject: [PATCH 291/350] OP-2787 - added raising error for Deadline --- openpype/lib/remote_publish.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/openpype/lib/remote_publish.py b/openpype/lib/remote_publish.py index da2497e1a5..d7884d0200 100644 --- a/openpype/lib/remote_publish.py +++ b/openpype/lib/remote_publish.py @@ -60,7 +60,7 @@ def start_webpublish_log(dbcon, batch_id, user): }).inserted_id -def publish(log, close_plugin_name=None): +def publish(log, close_plugin_name=None, raise_error=False): """Loops through all plugins, logs to console. Used for tests. Args: @@ -79,10 +79,15 @@ def publish(log, close_plugin_name=None): result["plugin"].label, record.msg)) if result["error"]: - log.error(error_format.format(**result)) + error_message = error_format.format(**result) + log.error(error_message) if close_plugin: # close host app explicitly after error context = pyblish.api.Context() close_plugin().process(context) + if raise_error: + # Fatal Error is because of Deadline + error_message = "Fatal Error: " + error_format.format(**result) + raise RuntimeError(error_message) def publish_and_log(dbcon, _id, log, close_plugin_name=None, batch_id=None): From 8de1cbf7320f792e0d6cf8e2709f918a9d8c4ddd Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 31 May 2022 14:15:05 +0200 Subject: [PATCH 292/350] OP-2787 - fixed resolution order --- openpype/hosts/maya/api/pipeline.py | 16 ++++++++-------- openpype/scripts/remote_publish.py | 3 ++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/maya/api/pipeline.py b/openpype/hosts/maya/api/pipeline.py index 6fc93e864f..0261694be2 100644 --- a/openpype/hosts/maya/api/pipeline.py +++ b/openpype/hosts/maya/api/pipeline.py @@ -66,20 +66,20 @@ def install(): log.info("Installing callbacks ... ") register_event_callback("init", on_init) - # Callbacks below are not required for headless mode, the `init` however - # is important to load referenced Alembics correctly at rendertime. + if os.environ.get("HEADLESS_PUBLISH"): + # Maya launched on farm, lib.IS_HEADLESS might be triggered locally too + # target "farm" == rendering on farm, expects OPENPYPE_PUBLISH_DATA + # target "remote" == remote execution + print("Registering pyblish target: remote") + pyblish.api.register_target("remote") + return + if lib.IS_HEADLESS: log.info(("Running in headless mode, skipping Maya " "save/open/new callback installation..")) return - if os.environ.get("HEADLESS_PUBLISH"): - # Maya launched on farm, lib.IS_HEADLESS might be triggered locally too - print("Registering pyblish target: remote") - pyblish.api.register_target("remote") - return - print("Registering pyblish target: local") pyblish.api.register_target("local") diff --git a/openpype/scripts/remote_publish.py b/openpype/scripts/remote_publish.py index b54c8d931b..8e5c91d663 100644 --- a/openpype/scripts/remote_publish.py +++ b/openpype/scripts/remote_publish.py @@ -1,6 +1,7 @@ try: from openpype.api import Logger import openpype.lib.remote_publish + import pyblish.api except ImportError as exc: # Ensure Deadline fails by output an error that contains "Fatal Error:" raise ImportError("Fatal Error: %s" % exc) @@ -8,4 +9,4 @@ except ImportError as exc: if __name__ == "__main__": # Perform remote publish with thorough error checking log = Logger.get_logger(__name__) - openpype.lib.remote_publish.publish(log) + openpype.lib.remote_publish.publish(log, raise_error=True) From 2dd79b32e7ebbc3caaf863484806569bf62ab1f3 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 31 May 2022 14:15:25 +0200 Subject: [PATCH 293/350] OP-2787 - removed unnecessary family --- .../deadline/plugins/publish/collect_publishable_instances.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/modules/deadline/plugins/publish/collect_publishable_instances.py b/openpype/modules/deadline/plugins/publish/collect_publishable_instances.py index 741a2a5af8..b00381b6cf 100644 --- a/openpype/modules/deadline/plugins/publish/collect_publishable_instances.py +++ b/openpype/modules/deadline/plugins/publish/collect_publishable_instances.py @@ -34,7 +34,6 @@ class CollectDeadlinePublishableInstances(pyblish.api.InstancePlugin): self.log.debug("Publish {}".format(subset_name)) instance.data["publish"] = True instance.data["farm"] = False - instance.data["families"].remove("deadline") else: self.log.debug("Skipping {}".format(subset_name)) instance.data["publish"] = False From d37815467a059cfa2ad2dbde6ce4025ec00def2d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 31 May 2022 14:20:50 +0200 Subject: [PATCH 294/350] OP-2787 - added extracted path to explicit cleanup --- openpype/hosts/maya/plugins/publish/extract_animation.py | 2 ++ openpype/hosts/maya/plugins/publish/extract_pointcache.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/openpype/hosts/maya/plugins/publish/extract_animation.py b/openpype/hosts/maya/plugins/publish/extract_animation.py index 8f2bc26d08..abe5ed3bf5 100644 --- a/openpype/hosts/maya/plugins/publish/extract_animation.py +++ b/openpype/hosts/maya/plugins/publish/extract_animation.py @@ -95,4 +95,6 @@ class ExtractAnimation(openpype.api.Extractor): } instance.data["representations"].append(representation) + instance.context.data["cleanupFullPaths"].append(path) + self.log.info("Extracted {} to {}".format(instance, dirname)) diff --git a/openpype/hosts/maya/plugins/publish/extract_pointcache.py b/openpype/hosts/maya/plugins/publish/extract_pointcache.py index 5606ea9459..c4c8610ebb 100644 --- a/openpype/hosts/maya/plugins/publish/extract_pointcache.py +++ b/openpype/hosts/maya/plugins/publish/extract_pointcache.py @@ -98,4 +98,6 @@ class ExtractAlembic(openpype.api.Extractor): } instance.data["representations"].append(representation) + instance.context.data["cleanupFullPaths"].append(path) + self.log.info("Extracted {} to {}".format(instance, dirname)) From 0d7d43316b94685f78fb0a7e2e39153a98996b36 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 31 May 2022 14:44:37 +0200 Subject: [PATCH 295/350] OP-2787 - changed class to api.Integrator This plugin should run only locally, not no a farm. --- .../plugins/publish/submit_maya_remote_publish_deadline.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py index 196adc5906..c31052be07 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py @@ -5,11 +5,12 @@ from maya import cmds from openpype.pipeline import legacy_io, PublishXmlValidationError from openpype.settings import get_project_settings +import openpype.api import pyblish.api -class MayaSubmitRemotePublishDeadline(pyblish.api.InstancePlugin): +class MayaSubmitRemotePublishDeadline(openpype.api.Integrator): """Submit Maya scene to perform a local publish in Deadline. Publishing in Deadline can be helpful for scenes that publish very slow. From 55a69074c6b550b4e30d99b658b9ec664d30214b Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 31 May 2022 14:46:05 +0200 Subject: [PATCH 296/350] OP-2787 - Hound --- openpype/scripts/remote_publish.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/scripts/remote_publish.py b/openpype/scripts/remote_publish.py index 8e5c91d663..d322f369d1 100644 --- a/openpype/scripts/remote_publish.py +++ b/openpype/scripts/remote_publish.py @@ -1,7 +1,6 @@ try: from openpype.api import Logger import openpype.lib.remote_publish - import pyblish.api except ImportError as exc: # Ensure Deadline fails by output an error that contains "Fatal Error:" raise ImportError("Fatal Error: %s" % exc) From 26332ef0c8e7eccc1022b95ef883c6850a907681 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 31 May 2022 15:00:15 +0200 Subject: [PATCH 297/350] fix file hash --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6b98178aa8..d398257f6b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -127,7 +127,7 @@ hash = "95f43568338c275f80dc0cab1e1836a2e2270f856f0e7b204440d881dd74fbdb" [openpype.thirdparty.oiio.windows] url = "https://distribute.openpype.io/thirdparty/oiio_tools-2.3.10-windows.zip" -hash = "fd2e00278e01e85dcee7b4a6969d1a16f13016ec16700fb0366dbb1b1f3c37ad" +hash = "b9950f5d2fa3720b52b8be55bacf5f56d33f9e029d38ee86534995f3d8d253d2" [openpype.thirdparty.oiio.linux] url = "https://distribute.openpype.io/thirdparty/oiio_tools-2.2.12-linux.tgz" From b073853a0b1d056a0976b5a3f983184bfb195d2e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 31 May 2022 18:58:13 +0200 Subject: [PATCH 298/350] Update openpype/settings/entities/schemas/projects_schema/schema_project_maya.json Co-authored-by: Milan Kolar --- .../entities/schemas/projects_schema/schema_project_maya.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json index f9523b1baa..f7d92c385e 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json @@ -25,7 +25,7 @@ { "type": "boolean", "key": "use_env_var_as_root", - "label": "Use env var placeholder in referenced url", + "label": "Use env var placeholder in referenced paths", "docstring": "Use ${} placeholder instead of physical value of root when storing into workfile metadata." }, { From 6530fbd918f795077f0a715827e101c97b4bc8ea Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 31 May 2022 18:58:28 +0200 Subject: [PATCH 299/350] Update openpype/settings/entities/schemas/projects_schema/schema_project_maya.json Co-authored-by: Milan Kolar --- .../entities/schemas/projects_schema/schema_project_maya.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json index f7d92c385e..40e98b0333 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json @@ -26,7 +26,7 @@ "type": "boolean", "key": "use_env_var_as_root", "label": "Use env var placeholder in referenced paths", - "docstring": "Use ${} placeholder instead of physical value of root when storing into workfile metadata." + "docstring": "Use ${} placeholder instead of absolute value of a root in referenced filepaths." }, { "type": "boolean", From 5be6f27eb19c76e78ec197358930f2d3de417c4d Mon Sep 17 00:00:00 2001 From: OpenPype Date: Wed, 1 Jun 2022 04:12:29 +0000 Subject: [PATCH 300/350] [Automated] Bump version --- CHANGELOG.md | 29 +++++++++++++---------------- openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a5e1f1067..6613985ccf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,20 +1,28 @@ # Changelog -## [3.10.1-nightly.1](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.10.1-nightly.2](https://github.com/pypeclub/OpenPype/tree/HEAD) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.10.0...HEAD) **🚀 Enhancements** +- General: Updated windows oiio tool [\#3268](https://github.com/pypeclub/OpenPype/pull/3268) - TVPaint: Init file for TVPaint worker also handle guideline images [\#3250](https://github.com/pypeclub/OpenPype/pull/3250) -- Support for Unreal 5 [\#3122](https://github.com/pypeclub/OpenPype/pull/3122) +- Nuke: Change default icon path in settings [\#3247](https://github.com/pypeclub/OpenPype/pull/3247) **🐛 Bug fixes** +- Nuke: bake reformat was failing on string type [\#3261](https://github.com/pypeclub/OpenPype/pull/3261) +- Maya: hotfix Pxr multitexture in looks [\#3260](https://github.com/pypeclub/OpenPype/pull/3260) - Unreal: Fix Camera Loading if Layout is missing [\#3255](https://github.com/pypeclub/OpenPype/pull/3255) - Unreal: Fixed Animation loading in UE5 [\#3240](https://github.com/pypeclub/OpenPype/pull/3240) - Unreal: Fixed Render creation in UE5 [\#3239](https://github.com/pypeclub/OpenPype/pull/3239) - Unreal: Fixed Camera loading in UE5 [\#3238](https://github.com/pypeclub/OpenPype/pull/3238) +- Flame: debugging [\#3224](https://github.com/pypeclub/OpenPype/pull/3224) + +**Merged pull requests:** + +- Nuke: add pointcache and animation to loader [\#3186](https://github.com/pypeclub/OpenPype/pull/3186) ## [3.10.0](https://github.com/pypeclub/OpenPype/tree/3.10.0) (2022-05-26) @@ -25,7 +33,6 @@ - General: OpenPype modules publish plugins are registered in host [\#3180](https://github.com/pypeclub/OpenPype/pull/3180) - General: Creator plugins from addons can be registered [\#3179](https://github.com/pypeclub/OpenPype/pull/3179) - Ftrack: Single image reviewable [\#3157](https://github.com/pypeclub/OpenPype/pull/3157) -- Nuke: Expose write attributes to settings [\#3123](https://github.com/pypeclub/OpenPype/pull/3123) **🚀 Enhancements** @@ -45,8 +52,6 @@ - Houdini: Add loader for alembic through Alembic Archive node [\#3140](https://github.com/pypeclub/OpenPype/pull/3140) - Publisher: UI Modifications and fixes [\#3139](https://github.com/pypeclub/OpenPype/pull/3139) - General: Simplified OP modules/addons import [\#3137](https://github.com/pypeclub/OpenPype/pull/3137) -- Terminal: Tweak coloring of TrayModuleManager logging enabled states [\#3133](https://github.com/pypeclub/OpenPype/pull/3133) -- General: Cleanup some Loader docstrings [\#3131](https://github.com/pypeclub/OpenPype/pull/3131) **🐛 Bug fixes** @@ -70,17 +75,18 @@ - General: Oiio conversion for ffmpeg checks for invalid characters [\#3166](https://github.com/pypeclub/OpenPype/pull/3166) - Fix for attaching render to subset [\#3164](https://github.com/pypeclub/OpenPype/pull/3164) - Harmony: fixed missing task name in render instance [\#3163](https://github.com/pypeclub/OpenPype/pull/3163) +- add silent audio to slate [\#3162](https://github.com/pypeclub/OpenPype/pull/3162) - Ftrack: Action delete old versions formatting works [\#3152](https://github.com/pypeclub/OpenPype/pull/3152) +- nuke: adding extract thumbnail settings [\#3148](https://github.com/pypeclub/OpenPype/pull/3148) - Deadline: fix the output directory [\#3144](https://github.com/pypeclub/OpenPype/pull/3144) - General: New Session schema [\#3141](https://github.com/pypeclub/OpenPype/pull/3141) - General: Missing version on headless mode crash properly [\#3136](https://github.com/pypeclub/OpenPype/pull/3136) - TVPaint: Composite layers in reversed order [\#3135](https://github.com/pypeclub/OpenPype/pull/3135) -- Nuke: fix anatomy imageio regex default [\#3119](https://github.com/pypeclub/OpenPype/pull/3119) +- TVPaint: Composite layers in reversed order [\#3134](https://github.com/pypeclub/OpenPype/pull/3134) **🔀 Refactored code** - Avalon repo removed from Jobs workflow [\#3193](https://github.com/pypeclub/OpenPype/pull/3193) -- General: Remove remaining imports from avalon [\#3130](https://github.com/pypeclub/OpenPype/pull/3130) **Merged pull requests:** @@ -128,7 +134,6 @@ **🐛 Bug fixes** - Ftrack: Action delete old versions formatting works [\#3154](https://github.com/pypeclub/OpenPype/pull/3154) -- nuke: adding extract thumbnail settings [\#3148](https://github.com/pypeclub/OpenPype/pull/3148) **Merged pull requests:** @@ -138,14 +143,6 @@ [Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.9.5...3.9.6) -**🆕 New features** - -- Nuke: render instance with subset name filtered overrides \(3.9.x\) [\#3125](https://github.com/pypeclub/OpenPype/pull/3125) - -**🐛 Bug fixes** - -- TVPaint: Composite layers in reversed order [\#3134](https://github.com/pypeclub/OpenPype/pull/3134) - ## [3.9.5](https://github.com/pypeclub/OpenPype/tree/3.9.5) (2022-04-25) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.10.0-nightly.2...3.9.5) diff --git a/openpype/version.py b/openpype/version.py index 12f25cdcea..1d8ef28225 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.10.1-nightly.1" +__version__ = "3.10.1-nightly.2" diff --git a/pyproject.toml b/pyproject.toml index d398257f6b..27b32cf53b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.10.1-nightly.1" # OpenPype +version = "3.10.1-nightly.2" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From a10bbbcc79b5a369d51bb4716164611edcb4dbfa Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 1 Jun 2022 12:33:09 +0200 Subject: [PATCH 301/350] OP-3068 - better handling of legacy review subsets in Maya Multiple reviews from a Maya workfile are blocked by legacy subset names without variant. These names could be used in later process so we cannot replace them. Unique subset name validator was added, check for existing subset in DB too. --- .../maya/plugins/publish/collect_review.py | 17 +++++---- .../validate_review_subset_uniqueness.xml | 28 +++++++++++++++ .../validate_review_subset_uniqueness.py | 36 +++++++++++++++++++ 3 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 openpype/hosts/maya/plugins/publish/help/validate_review_subset_uniqueness.xml create mode 100644 openpype/hosts/maya/plugins/publish/validate_review_subset_uniqueness.py diff --git a/openpype/hosts/maya/plugins/publish/collect_review.py b/openpype/hosts/maya/plugins/publish/collect_review.py index 1af92c3bfc..e9e0d74c03 100644 --- a/openpype/hosts/maya/plugins/publish/collect_review.py +++ b/openpype/hosts/maya/plugins/publish/collect_review.py @@ -77,15 +77,14 @@ class CollectReview(pyblish.api.InstancePlugin): instance.data['remove'] = True self.log.debug('isntance data {}'.format(instance.data)) else: - if self.legacy: - instance.data['subset'] = task + 'Review' - else: - subset = "{}{}{}".format( - task, - instance.data["subset"][0].upper(), - instance.data["subset"][1:] - ) - instance.data['subset'] = subset + legacy_subset_name = task + 'Review' + asset_doc_id = instance.context.data['assetEntity']["_id"] + subsets = legacy_io.find({"type": "subset", + "name": legacy_subset_name, + "parent": asset_doc_id}).distinct("_id") + if len(list(subsets)) > 0: + self.log.debug("Existing subsets found, keep legacy name.") + instance.data['subset'] = legacy_subset_name instance.data['review_camera'] = camera instance.data['frameStartFtrack'] = \ diff --git a/openpype/hosts/maya/plugins/publish/help/validate_review_subset_uniqueness.xml b/openpype/hosts/maya/plugins/publish/help/validate_review_subset_uniqueness.xml new file mode 100644 index 0000000000..fd1bf4cbaa --- /dev/null +++ b/openpype/hosts/maya/plugins/publish/help/validate_review_subset_uniqueness.xml @@ -0,0 +1,28 @@ + + + + Review subsets not unique + + ## Non unique subset name found + + Non unique subset names: '{non_unique}' + + ### __Detailed Info__ (optional) + + This might happen if you already published for this asset + review subset with legacy name {task}Review. + This legacy name limits possibility of publishing of multiple + reviews from a single workfile. Proper review subset name should + now + contain variant also (as 'Main', 'Default' etc.). That would + result in completely new subset though, so this situation must + be handled manually. + + ### How to repair? + + Legacy subsets must be removed from Openpype DB, please ask admin + to do that. Please provide them asset and subset names. + + + + \ No newline at end of file diff --git a/openpype/hosts/maya/plugins/publish/validate_review_subset_uniqueness.py b/openpype/hosts/maya/plugins/publish/validate_review_subset_uniqueness.py new file mode 100644 index 0000000000..d70096ee45 --- /dev/null +++ b/openpype/hosts/maya/plugins/publish/validate_review_subset_uniqueness.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +import collections +import pyblish.api +import openpype.api +from openpype.pipeline import PublishXmlValidationError + + +class ValidateReviewSubsetUniqueness(pyblish.api.ContextPlugin): + """Validates that nodes has common root.""" + + order = openpype.api.ValidateContentsOrder + hosts = ["maya"] + families = ["review"] + label = "Validate Review Subset Unique" + + def process(self, context): + subset_names = [] + + for instance in context: + self.log.info("instance:: {}".format(instance.data)) + if instance.data.get('publish'): + subset_names.append(instance.data.get('subset')) + + non_unique = \ + [item + for item, count in collections.Counter(subset_names).items() + if count > 1] + msg = ("Instance subset names {} are not unique. ".format(non_unique) + + "Ask admin to remove subset from DB for multiple reviews.") + formatting_data = { + "non_unique": ",".join(non_unique) + } + + if non_unique: + raise PublishXmlValidationError(self, msg, + formatting_data=formatting_data) From 6a5fa89348bb822e1f2c8748fa867f19e2f70a8d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 1 Jun 2022 14:27:55 +0200 Subject: [PATCH 302/350] Fix - change default of use_env_var_as_root True was there only for testing, false is more sane default. --- openpype/settings/defaults/project_settings/maya.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index a42f889e85..efd22e13c8 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -8,7 +8,7 @@ "yetiRig": "ma" }, "maya-dirmap": { - "use_env_var_as_root": true, + "use_env_var_as_root": false, "enabled": false, "paths": { "source-path": [], From 8b43c5e733117d528a164f45a6112b6d76a53e42 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 4 May 2022 12:16:19 +0200 Subject: [PATCH 303/350] add a tab in nuke project settings for gizmos --- openpype/hosts/nuke/startup/menu.py | 1 - .../defaults/project_settings/nuke.json | 22 ++++++++++ .../projects_schema/schema_project_nuke.json | 4 ++ .../schemas/schema_nuke_scriptsgizmo.json | 42 +++++++++++++++++++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsgizmo.json diff --git a/openpype/hosts/nuke/startup/menu.py b/openpype/hosts/nuke/startup/menu.py index 49edb22a89..eea2d940f8 100644 --- a/openpype/hosts/nuke/startup/menu.py +++ b/openpype/hosts/nuke/startup/menu.py @@ -31,7 +31,6 @@ nuke.addFilenameFilter(dirmap_file_name_filter) log.info('Automatic syncing of write file knob to script version') - def add_scripts_menu(): try: from scriptsmenu import launchfornuke diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index dc8ffcebff..a10b88464c 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -290,5 +290,27 @@ } ] }, + "gizmo": [ + { + "toolbar_menu_name": "FixStudio", + "toolbar_icon_path": "{QUAD_PLUGIN_PATH}/nuke/icons/fixstudio.png", + "gizmo_path": ["{QUAD_PLUGIN_PATH}/nuke/gizmos"], + "gizmo_definition": [ + { + "type": "menu", + "title": "3D", + "items": [ + { + "type": "action", + "command": "nuke.createNode('Camera_Smoother')", + "sourcetype": "python", + "title": "Camera_Smoother" + } + + ] + } + ] + } + ], "filters": {} } \ No newline at end of file diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json index 1ae4efd8ea..03d67a57ba 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json @@ -83,6 +83,10 @@ "type": "schema", "name": "schema_scriptsmenu" }, + { + "type": "schema", + "name": "schema_nuke_scriptsgizmo" + }, { "type": "dict", "collapsible": true, diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsgizmo.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsgizmo.json new file mode 100644 index 0000000000..c1e67842ce --- /dev/null +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsgizmo.json @@ -0,0 +1,42 @@ +{ + "type": "list", + "key": "gizmo", + "label": "Gizmo Menu", + "is_group": true, + "use_label_wrap": true, + "object_type": { + "type": "dict", + "children": [ + { + "type": "text", + "key": "toolbar_menu_name", + "label": "Toolbar Menu Name" + }, + { + "type": "path", + "key": "toolbar_icon_path", + "label": "Toolbar Icon Path", + "multipath": false + }, + { + "type": "splitter" + }, + { + "type": "label", + "label": "Absolute path to gizmo folders." + }, + { + "type": "path", + "key": "gizmo_path", + "label": "Gizmo Path", + "multipath": true + }, + { + "type": "raw-json", + "key": "gizmo_definition", + "label": "Gizmo definition", + "is_list": true + } + ] + } +} \ No newline at end of file From 25518a1c42ff9958f9bb9763b0792dd28e8cc691 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 4 May 2022 17:01:32 +0200 Subject: [PATCH 304/350] generate toolbar menu from openpype project settings --- openpype/hosts/nuke/api/lib.py | 48 +++++++++++++++ openpype/hosts/nuke/startup/menu.py | 59 ++++++++++++++++++- .../defaults/project_settings/nuke.json | 9 ++- 3 files changed, 110 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index f40425eefc..a1ac50ae1a 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -30,6 +30,8 @@ from openpype.pipeline import ( legacy_io, ) +from . import gizmo_menu + from .workio import ( save_file, open_file @@ -2498,6 +2500,52 @@ def recreate_instance(origin_node, avalon_data=None): return new_node +def find_scripts_gizmo(title, parent): + """ + Check if the menu exists with the given title in the parent + + Args: + title (str): the title name of the scripts menu + + parent (QtWidgets.QMenuBar): the menubar to check + + Returns: + QtWidgets.QMenu or None + + """ + + menu = None + search = [i for i in parent.items() if + isinstance(i, gizmo_menu.GizmoMenu) + and i.title() == title] + + if search: + assert len(search) < 2, ("Multiple instances of menu '{}' " + "in toolbar".format(title)) + menu = search[0] + + return menu + + +def gizmo_creation(title="Gizmos", parent=None, objectName=None, icon=None): + try: + toolbar = find_scripts_gizmo(title, parent) + if not toolbar: + log.info("Attempting to build toolbar...") + object_name = objectName or title.lower() + toolbar = gizmo_menu.GizmoMenu( + title=title, + parent=parent, + objectName=object_name, + icon=icon + ) + except Exception as e: + log.error(e) + return + + return toolbar + + class NukeDirmap(HostDirmap): def __init__(self, host_name, project_settings, sync_module, file_name): """ diff --git a/openpype/hosts/nuke/startup/menu.py b/openpype/hosts/nuke/startup/menu.py index eea2d940f8..0f587fc62a 100644 --- a/openpype/hosts/nuke/startup/menu.py +++ b/openpype/hosts/nuke/startup/menu.py @@ -2,7 +2,7 @@ import nuke import os from openpype.api import Logger -from openpype.pipeline import install_host +from openpype.settings import get_project_settings from openpype.hosts.nuke import api from openpype.hosts.nuke.api.lib import ( on_script_load, @@ -31,6 +31,7 @@ nuke.addFilenameFilter(dirmap_file_name_filter) log.info('Automatic syncing of write file knob to script version') + def add_scripts_menu(): try: from scriptsmenu import launchfornuke @@ -58,3 +59,59 @@ def add_scripts_menu(): add_scripts_menu() + + +def add_scripts_gizmo(): + try: + from openpype.hosts.nuke.api import lib + except ImportError: + log.warning( + "Skipping studio.gizmo install, because " + "'scriptsgizmo' module seems unavailable." + ) + return + + for gizmo in project_settings["nuke"]["gizmo"]: + config = gizmo["gizmo_definition"] + toolbar_name = gizmo["toolbar_menu_name"] + gizmo_path = gizmo["gizmo_path"] + icon = gizmo['toolbar_icon_path'] + + if not any(gizmo_path): + log.warning("Skipping studio gizmo, no gizmo path found.") + return + + if not config: + log.warning("Skipping studio gizmo, no definition found.") + return + + try: + icon = icon.format(**os.environ) + except KeyError as e: + log.warning(f"This environment variable doesn't exist: {e}") + + for gizmo in gizmo_path: + try: + gizmo = gizmo.format(**os.environ) + gizmo_path.append(gizmo) + gizmo_path.pop(0) + except KeyError as e: + log.warning(f"This environment variable doesn't exist: {e}") + + nuke_toolbar = nuke.menu("Nodes") + toolbar = nuke_toolbar.addMenu(toolbar_name, icon=icon) + + # run the launcher for Nuke toolbar + studio_menu = lib.gizmo_creation( + title=toolbar_name, + parent=toolbar, + objectName=toolbar_name.lower().replace(" ", "_"), + icon=icon + ) + + # apply configuration + studio_menu.add_gizmo_path(gizmo_path) + studio_menu.build_from_configuration(toolbar, config) + + +add_scripts_gizmo() diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index a10b88464c..48bbbf0dcc 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -293,8 +293,8 @@ "gizmo": [ { "toolbar_menu_name": "FixStudio", - "toolbar_icon_path": "{QUAD_PLUGIN_PATH}/nuke/icons/fixstudio.png", - "gizmo_path": ["{QUAD_PLUGIN_PATH}/nuke/gizmos"], + "toolbar_icon_path": "openpype/modules/quad/nuke/icons/fixstudio.png", + "gizmo_path": ["openpype/modules/quad/nuke/gizmos/3D"], "gizmo_definition": [ { "type": "menu", @@ -302,11 +302,10 @@ "items": [ { "type": "action", - "command": "nuke.createNode('Camera_Smoother')", "sourcetype": "python", - "title": "Camera_Smoother" + "title": "Camera Smoother", + "command": "nuke.createNodes('Camera_Smoother)" } - ] } ] From af259d215e08d54cca7dd01754a03f8b0863aefe Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Mon, 9 May 2022 15:12:16 +0200 Subject: [PATCH 305/350] refactor default gizmo --- openpype/settings/defaults/project_settings/nuke.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 48bbbf0dcc..d9b443c958 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -293,8 +293,8 @@ "gizmo": [ { "toolbar_menu_name": "FixStudio", - "toolbar_icon_path": "openpype/modules/quad/nuke/icons/fixstudio.png", - "gizmo_path": ["openpype/modules/quad/nuke/gizmos/3D"], + "toolbar_icon_path": "path/to/nuke/icon.png", + "gizmo_path": ["path/to/nuke/gizmo"], "gizmo_definition": [ { "type": "menu", @@ -304,7 +304,7 @@ "type": "action", "sourcetype": "python", "title": "Camera Smoother", - "command": "nuke.createNodes('Camera_Smoother)" + "command": "nuke.createNode('Camera_Smoother')" } ] } From 5bc741d993b67a3e9ebfd74b5cc711caa56e06fb Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Mon, 9 May 2022 15:13:50 +0200 Subject: [PATCH 306/350] add gizmo_menu module --- openpype/hosts/nuke/api/gizmo_menu.py | 77 +++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 openpype/hosts/nuke/api/gizmo_menu.py diff --git a/openpype/hosts/nuke/api/gizmo_menu.py b/openpype/hosts/nuke/api/gizmo_menu.py new file mode 100644 index 0000000000..56532ed1dc --- /dev/null +++ b/openpype/hosts/nuke/api/gizmo_menu.py @@ -0,0 +1,77 @@ +import os +import logging +import nuke + +log = logging.getLogger(__name__) + + +class GizmoMenu(): + def __init__(self, *args, **kwargs): + self._script_actions = [] + + def build_from_configuration(self, parent, configuration): + for item in configuration: + assert isinstance(item, dict), "Configuration is wrong!" + + # skip items which have no `type` key + item_type = item.get('type', None) + if not item_type: + log.warning("Missing 'type' from configuration item") + continue + + if item_type == "action": + # filter out `type` from the item dict + config = {key: value for key, value in + item.items() if key != "type"} + + command = config['command'] + + if command.find('{pipe_path}') > -1: + command = command.format( + pipe_path=os.environ['QUAD_PLUGIN_PATH'] + ) + + icon = config.get('icon', None) + if icon: + try: + icon = icon.format(**os.environ) + except KeyError as e: + log.warning(f"This environment variable doesn't exist: {e}'") + + hotkey = config.get('hotkey', None) + + parent.addCommand( + config['title'], + command=command, + icon=icon, + shortcut=hotkey + ) + + # add separator + # Special behavior for separators + if item_type == "separator": + parent.addSeparator() + + # add submenu + # items should hold a collection of submenu items (dict) + elif item_type == "menu": + assert "items" in item, "Menu is missing 'items' key" + + icon = item.get('icon', None) + if icon: + try: + icon = icon.format(**os.environ) + except KeyError as e: + log.warning(f"This environment variable doesn't exist: {e}'") + menu = parent.addMenu(item['title'], icon=icon) + self.build_from_configuration(menu, item["items"]) + + def add_gizmo_path(self, gizmo_paths): + for gizmo_path in gizmo_paths: + if os.path.isdir(gizmo_path): + for folder in os.listdir(gizmo_path): + if os.path.isdir(os.path.join(gizmo_path, folder)): + nuke.pluginAddPath(os.path.join(gizmo_path, folder)) + nuke.pluginAddPath(gizmo_path) + else: + log.warning(f"This path doesn't exist: {gizmo_path}") From 94356faa9c16f359dca2e94a726e79f16253e1d3 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 11 May 2022 11:46:57 +0200 Subject: [PATCH 307/350] fix install_host import --- openpype/hosts/nuke/startup/menu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/startup/menu.py b/openpype/hosts/nuke/startup/menu.py index 0f587fc62a..88c727aaa6 100644 --- a/openpype/hosts/nuke/startup/menu.py +++ b/openpype/hosts/nuke/startup/menu.py @@ -2,7 +2,7 @@ import nuke import os from openpype.api import Logger -from openpype.settings import get_project_settings +from openpype.pipeline import install_host from openpype.hosts.nuke import api from openpype.hosts.nuke.api.lib import ( on_script_load, From 0696d505c2cf9eb53c10afe2c2ffa6b73f3cbe7b Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Thu, 12 May 2022 11:12:08 +0200 Subject: [PATCH 308/350] set the default gizmo to a sticky note --- .../settings/defaults/project_settings/nuke.json | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index d9b443c958..06679ac314 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -292,21 +292,15 @@ }, "gizmo": [ { - "toolbar_menu_name": "FixStudio", + "toolbar_menu_name": "OpenPype Gizmo", "toolbar_icon_path": "path/to/nuke/icon.png", "gizmo_path": ["path/to/nuke/gizmo"], "gizmo_definition": [ { - "type": "menu", - "title": "3D", - "items": [ - { - "type": "action", - "sourcetype": "python", - "title": "Camera Smoother", - "command": "nuke.createNode('Camera_Smoother')" - } - ] + "type": "action", + "sourcetype": "python", + "title": "Gizmo Note", + "command": "nuke.nodes.StickyNote(label='You can create your own toolbar menu in the Nuke GizmoMenu of OpenPype')" } ] } From bd7243f8aa1dd64d3bad4ef822eb24e4ee70e4d4 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Thu, 12 May 2022 11:20:55 +0200 Subject: [PATCH 309/350] add the docs for the gizmo menu --- website/docs/admin_hosts_nuke.md | 4 ++++ website/docs/assets/nuke-admin_gizmomenu.png | Bin 0 -> 34803 bytes 2 files changed, 4 insertions(+) create mode 100644 website/docs/assets/nuke-admin_gizmomenu.png diff --git a/website/docs/admin_hosts_nuke.md b/website/docs/admin_hosts_nuke.md index 46f596a2dc..bab63223ce 100644 --- a/website/docs/admin_hosts_nuke.md +++ b/website/docs/admin_hosts_nuke.md @@ -12,3 +12,7 @@ You can add your custom tools menu into Nuke by extending definitions in **Nuke This is still work in progress. Menu definition will be handled more friendly with widgets and not raw json. ::: + +## Gizmo Menu +You can add your custom toolbar menu into Nuke by setting your gizmo path and extending definitions in **Nuke -> Gizmo Menu**. +![Custom menu definition](assets/nuke-admin_gizmomenu.png) diff --git a/website/docs/assets/nuke-admin_gizmomenu.png b/website/docs/assets/nuke-admin_gizmomenu.png new file mode 100644 index 0000000000000000000000000000000000000000..81e63b20418896173bf5f6417ce2515780e2bcdf GIT binary patch literal 34803 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 KXW7E9J^v4^Goq*f literal 0 HcmV?d00001 From 08e04911b3c100ca1dba8d1107a33cf689c98e79 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Thu, 12 May 2022 15:55:11 +0200 Subject: [PATCH 310/350] fix string format for python2 --- openpype/hosts/nuke/api/gizmo_menu.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/api/gizmo_menu.py b/openpype/hosts/nuke/api/gizmo_menu.py index 56532ed1dc..c1132792d0 100644 --- a/openpype/hosts/nuke/api/gizmo_menu.py +++ b/openpype/hosts/nuke/api/gizmo_menu.py @@ -36,7 +36,8 @@ class GizmoMenu(): try: icon = icon.format(**os.environ) except KeyError as e: - log.warning(f"This environment variable doesn't exist: {e}'") + log.warning("This environment variable doesn't exist: " + "{}".format(e)) hotkey = config.get('hotkey', None) @@ -62,7 +63,8 @@ class GizmoMenu(): try: icon = icon.format(**os.environ) except KeyError as e: - log.warning(f"This environment variable doesn't exist: {e}'") + log.warning("This environment variable doesn't exist: " + "{}".format(e)) menu = parent.addMenu(item['title'], icon=icon) self.build_from_configuration(menu, item["items"]) @@ -74,4 +76,4 @@ class GizmoMenu(): nuke.pluginAddPath(os.path.join(gizmo_path, folder)) nuke.pluginAddPath(gizmo_path) else: - log.warning(f"This path doesn't exist: {gizmo_path}") + log.warning("This path doesn't exist: {}".format(gizmo_path)) From eb590602c329b90d8b1e40aeda4ae04287e01a06 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Wed, 1 Jun 2022 17:31:19 +0200 Subject: [PATCH 311/350] make it works on nuke 12 --- openpype/hosts/nuke/api/gizmo_menu.py | 2 +- openpype/hosts/nuke/startup/menu.py | 11 +++++++++-- openpype/settings/defaults/project_settings/nuke.json | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/nuke/api/gizmo_menu.py b/openpype/hosts/nuke/api/gizmo_menu.py index c1132792d0..a541fd3ab1 100644 --- a/openpype/hosts/nuke/api/gizmo_menu.py +++ b/openpype/hosts/nuke/api/gizmo_menu.py @@ -24,7 +24,7 @@ class GizmoMenu(): config = {key: value for key, value in item.items() if key != "type"} - command = config['command'] + command = str(config['command']) if command.find('{pipe_path}') > -1: command = command.format( diff --git a/openpype/hosts/nuke/startup/menu.py b/openpype/hosts/nuke/startup/menu.py index 88c727aaa6..6c076fc87b 100644 --- a/openpype/hosts/nuke/startup/menu.py +++ b/openpype/hosts/nuke/startup/menu.py @@ -71,6 +71,9 @@ def add_scripts_gizmo(): ) return + # load configuration of custom menu + project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) + for gizmo in project_settings["nuke"]["gizmo"]: config = gizmo["gizmo_definition"] toolbar_name = gizmo["toolbar_menu_name"] @@ -88,7 +91,9 @@ def add_scripts_gizmo(): try: icon = icon.format(**os.environ) except KeyError as e: - log.warning(f"This environment variable doesn't exist: {e}") + log.warning( + "This environment variable doesn't exist: {}".format(e) + ) for gizmo in gizmo_path: try: @@ -96,7 +101,9 @@ def add_scripts_gizmo(): gizmo_path.append(gizmo) gizmo_path.pop(0) except KeyError as e: - log.warning(f"This environment variable doesn't exist: {e}") + log.warning( + "This environment variable doesn't exist: {}".format(e) + ) nuke_toolbar = nuke.menu("Nodes") toolbar = nuke_toolbar.addMenu(toolbar_name, icon=icon) diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 06679ac314..6c6454de36 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -306,4 +306,4 @@ } ], "filters": {} -} \ No newline at end of file +} From 8f9c08549292a58b7beccf3ae8a9477b2aac1020 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Wed, 1 Jun 2022 20:40:28 +0200 Subject: [PATCH 312/350] beter loop check --- openpype/hosts/nuke/startup/menu.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/startup/menu.py b/openpype/hosts/nuke/startup/menu.py index 6c076fc87b..715bab8ea5 100644 --- a/openpype/hosts/nuke/startup/menu.py +++ b/openpype/hosts/nuke/startup/menu.py @@ -95,15 +95,21 @@ def add_scripts_gizmo(): "This environment variable doesn't exist: {}".format(e) ) + existing_gizmo_path = [] for gizmo in gizmo_path: try: gizmo = gizmo.format(**os.environ) - gizmo_path.append(gizmo) - gizmo_path.pop(0) except KeyError as e: log.warning( "This environment variable doesn't exist: {}".format(e) ) + continue + if not os.path.exists(gizmo): + log.warning( + "The source of gizmo `{}` does not exists".format(gizmo) + ) + continue + existing_gizmo_path.append(gizmo) nuke_toolbar = nuke.menu("Nodes") toolbar = nuke_toolbar.addMenu(toolbar_name, icon=icon) @@ -117,7 +123,7 @@ def add_scripts_gizmo(): ) # apply configuration - studio_menu.add_gizmo_path(gizmo_path) + studio_menu.add_gizmo_path(existing_gizmo_path) studio_menu.build_from_configuration(toolbar, config) From 0fcfdf7fa8250d400a7da772be12972b59c667fd Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Wed, 1 Jun 2022 20:44:10 +0200 Subject: [PATCH 313/350] remove studio operation --- openpype/hosts/nuke/api/gizmo_menu.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/openpype/hosts/nuke/api/gizmo_menu.py b/openpype/hosts/nuke/api/gizmo_menu.py index a541fd3ab1..dd04f4a42e 100644 --- a/openpype/hosts/nuke/api/gizmo_menu.py +++ b/openpype/hosts/nuke/api/gizmo_menu.py @@ -26,11 +26,6 @@ class GizmoMenu(): command = str(config['command']) - if command.find('{pipe_path}') > -1: - command = command.format( - pipe_path=os.environ['QUAD_PLUGIN_PATH'] - ) - icon = config.get('icon', None) if icon: try: From 7d3b76cc0a1d9856bfd2a0479600d867412b133c Mon Sep 17 00:00:00 2001 From: DMO Date: Thu, 2 Jun 2022 09:50:53 +0900 Subject: [PATCH 314/350] Removed lib for hound. --- openpype/hosts/maya/plugins/create/create_multiverse_look.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/create/create_multiverse_look.py b/openpype/hosts/maya/plugins/create/create_multiverse_look.py index 3fc834a700..f47c88a93b 100644 --- a/openpype/hosts/maya/plugins/create/create_multiverse_look.py +++ b/openpype/hosts/maya/plugins/create/create_multiverse_look.py @@ -1,4 +1,4 @@ -from openpype.hosts.maya.api import plugin, lib +from openpype.hosts.maya.api import plugin class CreateMultiverseLook(plugin.Creator): From 7afa319b25ce94cb3cb64b1c050ad23eeb1cd873 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 3 Jun 2022 12:54:27 +0200 Subject: [PATCH 315/350] add subdir 'bin' when oiio path is prepared --- openpype/lib/vendor_bin_utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/lib/vendor_bin_utils.py b/openpype/lib/vendor_bin_utils.py index 23e28ea304..e5ab2872a0 100644 --- a/openpype/lib/vendor_bin_utils.py +++ b/openpype/lib/vendor_bin_utils.py @@ -116,7 +116,10 @@ def get_oiio_tools_path(tool="oiiotool"): tool (string): Tool name (oiiotool, maketx, ...). Default is "oiiotool". """ + oiio_dir = get_vendor_bin_path("oiio") + if platform.system().lower() == "linux": + oiio_dir = os.path.join(oiio_dir, "bin") return find_executable(os.path.join(oiio_dir, tool)) From 0034d7495cebc18f0cee2466d1109d69cf52a234 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 3 Jun 2022 12:14:23 +0200 Subject: [PATCH 316/350] Hiero: add support for task tags and collecting tags in general --- openpype/hosts/hiero/api/__init__.py | 2 ++ openpype/hosts/hiero/api/lib.py | 25 +++++++++++++++++++ .../collect_tag_tasks.py | 6 ++--- .../plugins/publish/precollect_instances.py | 5 +++- 4 files changed, 34 insertions(+), 4 deletions(-) rename openpype/hosts/hiero/plugins/{publish_old_workflow => publish}/collect_tag_tasks.py (91%) diff --git a/openpype/hosts/hiero/api/__init__.py b/openpype/hosts/hiero/api/__init__.py index fc2d017f04..781f846bbe 100644 --- a/openpype/hosts/hiero/api/__init__.py +++ b/openpype/hosts/hiero/api/__init__.py @@ -29,6 +29,7 @@ from .lib import ( get_current_sequence, get_timeline_selection, get_current_track, + get_track_item_tags, get_track_item_pype_tag, set_track_item_pype_tag, get_track_item_pype_data, @@ -83,6 +84,7 @@ __all__ = [ "get_current_sequence", "get_timeline_selection", "get_current_track", + "get_track_item_tags", "get_track_item_pype_tag", "set_track_item_pype_tag", "get_track_item_pype_data", diff --git a/openpype/hosts/hiero/api/lib.py b/openpype/hosts/hiero/api/lib.py index 761a36bd0f..06dfd2f2ee 100644 --- a/openpype/hosts/hiero/api/lib.py +++ b/openpype/hosts/hiero/api/lib.py @@ -274,6 +274,31 @@ def _validate_all_atrributes( ]) +def get_track_item_tags(track_item): + """ + Get track item tags excluded openpype tag + + Attributes: + trackItem (hiero.core.TrackItem): hiero object + + Returns: + hiero.core.Tag: hierarchy, orig clip attributes + """ + returning_tag_data = [] + # get all tags from track item + _tags = track_item.tags() + if not _tags: + return [] + + # collect all tags which are not openpype tag + returning_tag_data.extend( + tag for tag in _tags + if tag.name() != self.pype_tag_name + ) + + return returning_tag_data + + def get_track_item_pype_tag(track_item): """ Get pype track item tag created by creator or loader plugin. diff --git a/openpype/hosts/hiero/plugins/publish_old_workflow/collect_tag_tasks.py b/openpype/hosts/hiero/plugins/publish/collect_tag_tasks.py similarity index 91% rename from openpype/hosts/hiero/plugins/publish_old_workflow/collect_tag_tasks.py rename to openpype/hosts/hiero/plugins/publish/collect_tag_tasks.py index 70891d5b45..27968060e1 100644 --- a/openpype/hosts/hiero/plugins/publish_old_workflow/collect_tag_tasks.py +++ b/openpype/hosts/hiero/plugins/publish/collect_tag_tasks.py @@ -4,16 +4,16 @@ from pyblish import api class CollectClipTagTasks(api.InstancePlugin): """Collect Tags from selected track items.""" - order = api.CollectorOrder + order = api.CollectorOrder - 0.077 label = "Collect Tag Tasks" hosts = ["hiero"] - families = ['clip'] + families = ["shot"] def process(self, instance): # gets tags tags = instance.data["tags"] - tasks = dict() + tasks = {} for tag in tags: t_metadata = dict(tag.metadata()) t_family = t_metadata.get("tag.family", "") diff --git a/openpype/hosts/hiero/plugins/publish/precollect_instances.py b/openpype/hosts/hiero/plugins/publish/precollect_instances.py index e54d050f0d..b891a37d9d 100644 --- a/openpype/hosts/hiero/plugins/publish/precollect_instances.py +++ b/openpype/hosts/hiero/plugins/publish/precollect_instances.py @@ -106,7 +106,10 @@ class PrecollectInstances(pyblish.api.ContextPlugin): # clip's effect "clipEffectItems": subtracks, - "clipAnnotations": annotations + "clipAnnotations": annotations, + + # add all additional tags + "tags": phiero.get_track_item_tags(track_item) }) # otio clip data From 3464a7c5d7bceb1174237aeecc25e9d12c178638 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 3 Jun 2022 13:48:41 +0200 Subject: [PATCH 317/350] global: hierarchy publishing only to active instances filter --- .../publish/integrate_hierarchy_ftrack.py | 47 +++++++++++-- openpype/plugins/publish/collect_hierarchy.py | 4 -- .../publish/extract_hierarchy_avalon.py | 70 +++++++++---------- 3 files changed, 76 insertions(+), 45 deletions(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_hierarchy_ftrack.py b/openpype/modules/ftrack/plugins/publish/integrate_hierarchy_ftrack.py index cf90c11b65..73398941eb 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_hierarchy_ftrack.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_hierarchy_ftrack.py @@ -2,7 +2,7 @@ import sys import collections import six import pyblish.api - +from copy import deepcopy from openpype.pipeline import legacy_io # Copy of constant `openpype_modules.ftrack.lib.avalon_sync.CUST_ATTR_AUTO_SYNC` @@ -72,7 +72,8 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): if "hierarchyContext" not in self.context.data: return - hierarchy_context = self.context.data["hierarchyContext"] + hierarchy_context = self._get_active_assets(context) + self.log.debug("__ hierarchy_context: {}".format(hierarchy_context)) self.session = self.context.data["ftrackSession"] project_name = self.context.data["projectEntity"]["name"] @@ -86,15 +87,13 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): self.ft_project = None - input_data = hierarchy_context - # disable termporarily ftrack project's autosyncing if auto_sync_state: self.auto_sync_off(project) try: # import ftrack hierarchy - self.import_to_ftrack(input_data) + self.import_to_ftrack(hierarchy_context) except Exception: raise finally: @@ -355,3 +354,41 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): self.session.rollback() self.session._configure_locations() six.reraise(tp, value, tb) + + def _get_active_assets(self, context): + """ Returns only asset dictionary. + Usually the last part of deep dictionary which + is not having any children + """ + def get_pure_hierarchy_data(input_dict): + input_dict_copy = deepcopy(input_dict) + for key in input_dict.keys(): + self.log.debug("__ key: {}".format(key)) + # check if child key is available + if input_dict[key].get("childs"): + # loop deeper + input_dict_copy[ + key]["childs"] = get_pure_hierarchy_data( + input_dict[key]["childs"]) + elif key not in active_assets: + input_dict_copy.pop(key, None) + return input_dict_copy + + hierarchy_context = context.data["hierarchyContext"] + + active_assets = [] + # filter only the active publishing insatnces + for instance in context: + if instance.data.get("publish") is False: + continue + + if not instance.data.get("asset"): + continue + + active_assets.append(instance.data["asset"]) + + # remove duplicity in list + active_assets = list(set(active_assets)) + self.log.debug("__ active_assets: {}".format(active_assets)) + + return get_pure_hierarchy_data(hierarchy_context) diff --git a/openpype/plugins/publish/collect_hierarchy.py b/openpype/plugins/publish/collect_hierarchy.py index 8398a2815a..91d5162d62 100644 --- a/openpype/plugins/publish/collect_hierarchy.py +++ b/openpype/plugins/publish/collect_hierarchy.py @@ -33,10 +33,6 @@ class CollectHierarchy(pyblish.api.ContextPlugin): family = instance.data["family"] families = instance.data["families"] - # filter out all unepropriate instances - if not instance.data["publish"]: - continue - # exclude other families then self.families with intersection if not set(self.families).intersection(set(families + [family])): continue diff --git a/openpype/plugins/publish/extract_hierarchy_avalon.py b/openpype/plugins/publish/extract_hierarchy_avalon.py index 2f528d4469..1f7ce839ed 100644 --- a/openpype/plugins/publish/extract_hierarchy_avalon.py +++ b/openpype/plugins/publish/extract_hierarchy_avalon.py @@ -1,7 +1,5 @@ from copy import deepcopy - import pyblish.api - from openpype.pipeline import legacy_io @@ -17,33 +15,16 @@ class ExtractHierarchyToAvalon(pyblish.api.ContextPlugin): if "hierarchyContext" not in context.data: self.log.info("skipping IntegrateHierarchyToAvalon") return - hierarchy_context = deepcopy(context.data["hierarchyContext"]) if not legacy_io.Session: legacy_io.install() - active_assets = [] - # filter only the active publishing insatnces - for instance in context: - if instance.data.get("publish") is False: - continue - - if not instance.data.get("asset"): - continue - - active_assets.append(instance.data["asset"]) - - # remove duplicity in list - self.active_assets = list(set(active_assets)) - self.log.debug("__ self.active_assets: {}".format(self.active_assets)) - - hierarchy_context = self._get_assets(hierarchy_context) - + hierarchy_context = self._get_active_assets(context) self.log.debug("__ hierarchy_context: {}".format(hierarchy_context)) - input_data = context.data["hierarchyContext"] = hierarchy_context self.project = None - self.import_to_avalon(input_data) + self.import_to_avalon(hierarchy_context) + def import_to_avalon(self, input_data, parent=None): for name in input_data: @@ -183,23 +164,40 @@ class ExtractHierarchyToAvalon(pyblish.api.ContextPlugin): return legacy_io.find_one({"_id": entity_id}) - def _get_assets(self, input_dict): + def _get_active_assets(self, context): """ Returns only asset dictionary. Usually the last part of deep dictionary which is not having any children """ - input_dict_copy = deepcopy(input_dict) - - for key in input_dict.keys(): - self.log.debug("__ key: {}".format(key)) - # check if child key is available - if input_dict[key].get("childs"): - # loop deeper - input_dict_copy[key]["childs"] = self._get_assets( - input_dict[key]["childs"]) - else: - # filter out unwanted assets - if key not in self.active_assets: + def get_pure_hierarchy_data(input_dict): + input_dict_copy = deepcopy(input_dict) + for key in input_dict.keys(): + self.log.debug("__ key: {}".format(key)) + # check if child key is available + if input_dict[key].get("childs"): + # loop deeper + input_dict_copy[ + key]["childs"] = get_pure_hierarchy_data( + input_dict[key]["childs"]) + elif key not in active_assets: input_dict_copy.pop(key, None) + return input_dict_copy - return input_dict_copy + hierarchy_context = context.data["hierarchyContext"] + + active_assets = [] + # filter only the active publishing insatnces + for instance in context: + if instance.data.get("publish") is False: + continue + + if not instance.data.get("asset"): + continue + + active_assets.append(instance.data["asset"]) + + # remove duplicity in list + active_assets = list(set(active_assets)) + self.log.debug("__ active_assets: {}".format(active_assets)) + + return get_pure_hierarchy_data(hierarchy_context) From a9fdcd80aaee0db6dddc0e777e9dd021459f04c2 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 3 Jun 2022 14:44:11 +0200 Subject: [PATCH 318/350] OP-3231 - return only active projects in webpublisher ProjectsEndpoing --- .../webserver_service/webpublish_routes.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/webpublisher/webserver_service/webpublish_routes.py b/openpype/hosts/webpublisher/webserver_service/webpublish_routes.py index e82ba7f2b8..70324fc39c 100644 --- a/openpype/hosts/webpublisher/webserver_service/webpublish_routes.py +++ b/openpype/hosts/webpublisher/webserver_service/webpublish_routes.py @@ -71,16 +71,12 @@ class ProjectsEndpoint(_RestApiEndpoint): """Returns list of dict with project info (id, name).""" async def get(self) -> Response: output = [] - for project_name in self.dbcon.database.collection_names(): - project_doc = self.dbcon.database[project_name].find_one({ - "type": "project" - }) - if project_doc: - ret_val = { - "id": project_doc["_id"], - "name": project_doc["name"] - } - output.append(ret_val) + for project_doc in self.dbcon.projects(): + ret_val = { + "id": project_doc["_id"], + "name": project_doc["name"] + } + output.append(ret_val) return Response( status=200, body=self.resource.encode(output), From 98504a205210471242f0c955d3f549561ec392df Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 3 Jun 2022 14:45:05 +0200 Subject: [PATCH 319/350] implemented action that can tranfer values of 1 hierarchical attribute to another --- .../action_translate_hierarchical_values.py | 331 ++++++++++++++++++ 1 file changed, 331 insertions(+) create mode 100644 openpype/modules/ftrack/event_handlers_server/action_translate_hierarchical_values.py diff --git a/openpype/modules/ftrack/event_handlers_server/action_translate_hierarchical_values.py b/openpype/modules/ftrack/event_handlers_server/action_translate_hierarchical_values.py new file mode 100644 index 0000000000..fd10005fad --- /dev/null +++ b/openpype/modules/ftrack/event_handlers_server/action_translate_hierarchical_values.py @@ -0,0 +1,331 @@ +import copy +import json +import collections + +import ftrack_api + +from openpype_modules.ftrack.lib import ( + ServerAction, + statics_icon, +) +from openpype_modules.ftrack.lib.avalon_sync import create_chunks + + +class TranslateHierarchicalValues(ServerAction): + """Transfer values across hierarhcical attributes. + + Aalso gives ability to convert types meanwhile. That is limited to + conversions between numbers and strings + - int <-> float + - in, float -> string + """ + + identifier = "translate.hierarchical.values" + label = "OpenPype Admin" + variant = "- Translate values between 2 custom attributes" + description = ( + "Move values from a hierarchical attribute to" + " second hierarchical attribute." + ) + icon = statics_icon("ftrack", "action_icons", "OpenPypeAdmin.svg") + + all_project_entities_query = ( + "select id, name, parent_id, link" + " from TypedContext where project_id is \"{}\"" + ) + cust_attr_query = ( + "select value, entity_id from CustomAttributeValue" + " where entity_id in ({}) and configuration_id is \"{}\"" + ) + settings_key = "clean_hierarchical_attr" + + def discover(self, session, entities, event): + """Show anywhere.""" + + return self.valid_roles(session, entities, event) + + def _selection_interface(self, session, event_values=None): + title = "Translate hierarchical values" + + attr_confs = session.query( + ( + "select id, key from CustomAttributeConfiguration" + " where is_hierarchical is true" + ) + ).all() + attr_items = [] + for attr_conf in attr_confs: + attr_items.append({ + "value": attr_conf["id"], + "label": attr_conf["key"] + }) + + if len(attr_items) < 2: + return { + "title": title, + "items": [{ + "type": "label", + "value": ( + "Didn't found custom attributes" + " that can be translated." + ) + }] + } + + attr_items = sorted(attr_items, key=lambda item: item["label"]) + items = [] + item_splitter = {"type": "label", "value": "---"} + items.append({ + "type": "label", + "value": ( + "

Please select source and destination" + " Custom attribute

" + ) + }) + items.append({ + "type": "label", + "value": ( + "WARNING: This will take affect for all projects!" + ) + }) + if event_values: + items.append({ + "type": "label", + "value": ( + "Note: Please select 2 different custom attributes." + ) + }) + + items.append(item_splitter) + + src_item = { + "type": "enumerator", + "label": "Source", + "name": "src_attr_id", + "data": copy.deepcopy(attr_items) + } + dst_item = { + "type": "enumerator", + "label": "Destination", + "name": "dst_attr_id", + "data": copy.deepcopy(attr_items) + } + delete_item = { + "type": "boolean", + "name": "delete_dst_attr_first", + "label": "Delete first", + "value": False + } + if event_values: + src_item["value"] = event_values["src_attr_id"] + dst_item["value"] = event_values["dst_attr_id"] + delete_item["value"] = event_values["delete_dst_attr_first"] + + items.append(src_item) + items.append(dst_item) + items.append(item_splitter) + items.append({ + "type": "label", + "value": ( + "WARNING: All values from destination" + " Custom Attribute will be removed if this is enabled." + ) + }) + items.append(delete_item) + + return { + "title": title, + "items": items + } + + def interface(self, session, entities, event): + if event["data"].get("values", {}): + return None + + return self._selection_interface(session) + + def launch(self, session, entities, event): + values = event["data"].get("values", {}) + if not values: + return None + src_attr_id = values["src_attr_id"] + dst_attr_id = values["dst_attr_id"] + delete_dst_values = values["delete_dst_attr_first"] + + if not src_attr_id or not dst_attr_id: + return { + "success": True, + "message": "Nothing to do" + } + + if src_attr_id == dst_attr_id: + return self._selection_interface(session, values) + + # Query custom attrbutes + src_conf = session.query(( + "select id from CustomAttributeConfiguration where id is {}" + ).format(src_attr_id)).one() + dst_conf = session.query(( + "select id from CustomAttributeConfiguration where id is {}" + ).format(dst_attr_id)).one() + src_type_name = src_conf["type"]["name"] + dst_type_name = dst_conf["type"]["name"] + # Limit conversion to + # - same type -> same type (there is no need to do conversion) + # - number -> number (int to float and back) + # - number -> str (any number can be converted to str) + src_type = None + dst_type = None + if src_type_name == "number" or src_type_name != dst_type_name: + src_type = self._get_attr_type(dst_conf) + dst_type = self._get_attr_type(dst_conf) + valid = False + # Can convert numbers + if src_type in (int, float) and dst_type in (int, float): + valid = True + # Can convert numbers to string + elif dst_type is str: + valid = True + + if not valid: + return { + "message": ( + "Don't know how to properly convert" + " custom attribute types {} > {}" + ).format(src_type_name, dst_type_name), + "success": False + } + + # Query source values + src_attr_values = session.query( + ( + "select value, entity_id" + " from CustomAttributeValue" + " where configuration_id is {}" + ).format(src_attr_id) + ).all() + + value_by_id = {} + failed_entity_ids = [] + for attr_value in src_attr_values: + entity_id = attr_value["entity_id"] + value = attr_value["value"] + if value is not None: + try: + if dst_type is not None: + value = dst_type(value) + value_by_id[entity_id] = value + except Exception: + failed_entity_ids.append(entity_id) + + if failed_entity_ids: + return { + "success": False, + "message": ( + "Couldn't convert some values to destination attribute" + ) + } + + + # Delete destination custom attributes first + if delete_dst_values: + self.log.info("Deleting destination custom attribute values first") + self._delete_custom_attribute_values(session, dst_attr_id) + + self._apply_values(session, value_by_id, dst_attr_id) + return True + + def _delete_custom_attribute_values(self, session, dst_attr_id): + dst_attr_values = session.query( + ( + "select configuration_id, entity_id" + " from CustomAttributeValue" + " where configuration_id is {}" + ).format(dst_attr_id) + ).all() + delete_operations = [] + for attr_value in dst_attr_values: + entity_id = attr_value["entity_id"] + configuration_id = attr_value["configuration_id"] + entity_key = collections.OrderedDict(( + ("configuration_id", configuration_id), + ("entity_id", entity_id) + )) + delete_operations.append( + ftrack_api.operation.DeleteEntityOperation( + "CustomAttributeValue", + entity_key + ) + ) + + if not delete_operations: + return + + for chunk in create_chunks(delete_operations, 500): + for operation in chunk: + session.recorded_operations.push(operation) + session.commit() + + def _apply_values(self, session, value_by_id, dst_attr_id): + dst_attr_values = session.query( + ( + "select configuration_id, entity_id" + " from CustomAttributeValue" + " where configuration_id is {}" + ).format(dst_attr_id) + ).all() + + dst_entity_ids_with_value = { + item["entity_id"] + for item in dst_attr_values + } + operations = [] + for entity_id, value in value_by_id.items(): + entity_key = collections.OrderedDict(( + ("configuration_id", dst_attr_id), + ("entity_id", entity_id) + )) + if entity_id in dst_entity_ids_with_value: + operations.append( + ftrack_api.operation.UpdateEntityOperation( + "CustomAttributeValue", + entity_key, + "value", + ftrack_api.symbol.NOT_SET, + value + ) + ) + else: + operations.append( + ftrack_api.operation.CreateEntityOperation( + "CustomAttributeValue", + entity_key, + {"value": value} + ) + ) + + if not operations: + return + + for chunk in create_chunks(operations, 500): + for operation in chunk: + session.recorded_operations.push(operation) + session.commit() + + def _get_attr_type(self, conf_def): + type_name = conf_def["type"]["name"] + if type_name == "text": + return str + + if type_name == "number": + config = json.loads(conf_def["config"]) + if config["isdecimal"]: + return float + return int + return None + + +def register(session): + '''Register plugin. Called when used as an plugin.''' + + TranslateHierarchicalValues(session).register() From 8e7358a33b9da4a97681a1dae4119e30b238a24a Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 3 Jun 2022 14:51:21 +0200 Subject: [PATCH 320/350] changed translate to transfer --- .../action_translate_hierarchical_values.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openpype/modules/ftrack/event_handlers_server/action_translate_hierarchical_values.py b/openpype/modules/ftrack/event_handlers_server/action_translate_hierarchical_values.py index fd10005fad..8cc6fa3a57 100644 --- a/openpype/modules/ftrack/event_handlers_server/action_translate_hierarchical_values.py +++ b/openpype/modules/ftrack/event_handlers_server/action_translate_hierarchical_values.py @@ -11,7 +11,7 @@ from openpype_modules.ftrack.lib import ( from openpype_modules.ftrack.lib.avalon_sync import create_chunks -class TranslateHierarchicalValues(ServerAction): +class TransferHierarchicalValues(ServerAction): """Transfer values across hierarhcical attributes. Aalso gives ability to convert types meanwhile. That is limited to @@ -20,9 +20,9 @@ class TranslateHierarchicalValues(ServerAction): - in, float -> string """ - identifier = "translate.hierarchical.values" + identifier = "transfer.hierarchical.values" label = "OpenPype Admin" - variant = "- Translate values between 2 custom attributes" + variant = "- Transfer values between 2 custom attributes" description = ( "Move values from a hierarchical attribute to" " second hierarchical attribute." @@ -37,7 +37,7 @@ class TranslateHierarchicalValues(ServerAction): "select value, entity_id from CustomAttributeValue" " where entity_id in ({}) and configuration_id is \"{}\"" ) - settings_key = "clean_hierarchical_attr" + settings_key = "transfer_values_of_hierarchical_attributes" def discover(self, session, entities, event): """Show anywhere.""" @@ -45,7 +45,7 @@ class TranslateHierarchicalValues(ServerAction): return self.valid_roles(session, entities, event) def _selection_interface(self, session, event_values=None): - title = "Translate hierarchical values" + title = "Transfer hierarchical values" attr_confs = session.query( ( @@ -67,7 +67,7 @@ class TranslateHierarchicalValues(ServerAction): "type": "label", "value": ( "Didn't found custom attributes" - " that can be translated." + " that can be transfered." ) }] } @@ -328,4 +328,4 @@ class TranslateHierarchicalValues(ServerAction): def register(session): '''Register plugin. Called when used as an plugin.''' - TranslateHierarchicalValues(session).register() + TransferHierarchicalValues(session).register() From 3da8536f968c932811a7979680cc27980594c2fe Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 3 Jun 2022 14:51:32 +0200 Subject: [PATCH 321/350] added settings for new action --- .../defaults/project_settings/ftrack.json | 7 +++++++ .../schema_project_ftrack.json | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/openpype/settings/defaults/project_settings/ftrack.json b/openpype/settings/defaults/project_settings/ftrack.json index f9d16d6476..9d59deea3d 100644 --- a/openpype/settings/defaults/project_settings/ftrack.json +++ b/openpype/settings/defaults/project_settings/ftrack.json @@ -109,6 +109,13 @@ "Omitted" ], "name_sorting": false + }, + "transfer_values_of_hierarchical_attributes": { + "enabled": true, + "role_list": [ + "Administrator", + "Project manager" + ] } }, "user_handlers": { diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json index 7db490b114..16cab49d5d 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json @@ -369,6 +369,25 @@ "key": "name_sorting" } ] + }, + { + "type": "dict", + "key": "transfer_values_of_hierarchical_attributes", + "label": "Action to transfer hierarchical attribute values", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "list", + "key": "role_list", + "label": "Roles", + "object_type": "text" + } + ] } ] }, From d37497df10d6883f3b154f076ce91e7163c9d89b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 3 Jun 2022 14:54:33 +0200 Subject: [PATCH 322/350] changed filename --- ...erarchical_values.py => action_tranfer_hierarchical_values.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename openpype/modules/ftrack/event_handlers_server/{action_translate_hierarchical_values.py => action_tranfer_hierarchical_values.py} (100%) diff --git a/openpype/modules/ftrack/event_handlers_server/action_translate_hierarchical_values.py b/openpype/modules/ftrack/event_handlers_server/action_tranfer_hierarchical_values.py similarity index 100% rename from openpype/modules/ftrack/event_handlers_server/action_translate_hierarchical_values.py rename to openpype/modules/ftrack/event_handlers_server/action_tranfer_hierarchical_values.py From 078a47e32f39b02c4c6c5db8860c2c7a6de886b5 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 3 Jun 2022 14:58:59 +0200 Subject: [PATCH 323/350] added some logs --- .../action_tranfer_hierarchical_values.py | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/openpype/modules/ftrack/event_handlers_server/action_tranfer_hierarchical_values.py b/openpype/modules/ftrack/event_handlers_server/action_tranfer_hierarchical_values.py index 8cc6fa3a57..9df3b67969 100644 --- a/openpype/modules/ftrack/event_handlers_server/action_tranfer_hierarchical_values.py +++ b/openpype/modules/ftrack/event_handlers_server/action_tranfer_hierarchical_values.py @@ -153,12 +153,17 @@ class TransferHierarchicalValues(ServerAction): delete_dst_values = values["delete_dst_attr_first"] if not src_attr_id or not dst_attr_id: + self.log.info("Attributes were not filled. Nothing to do.") return { "success": True, "message": "Nothing to do" } if src_attr_id == dst_attr_id: + self.log.info(( + "Same attributes were selected {}, {}." + " Showing interface again." + ).format(src_attr_id, dst_attr_id)) return self._selection_interface(session, values) # Query custom attrbutes @@ -188,6 +193,10 @@ class TransferHierarchicalValues(ServerAction): valid = True if not valid: + self.log.info(( + "Don't know how to properly convert" + " custom attribute types {} > {}" + ).format(src_type_name, dst_type_name)) return { "message": ( "Don't know how to properly convert" @@ -205,20 +214,26 @@ class TransferHierarchicalValues(ServerAction): ).format(src_attr_id) ).all() - value_by_id = {} + self.log.debug("Queried source values.") failed_entity_ids = [] - for attr_value in src_attr_values: - entity_id = attr_value["entity_id"] - value = attr_value["value"] - if value is not None: - try: - if dst_type is not None: - value = dst_type(value) - value_by_id[entity_id] = value - except Exception: - failed_entity_ids.append(entity_id) + if dst_type is not None: + self.log.debug("Converting source values to desctination type") + value_by_id = {} + for attr_value in src_attr_values: + entity_id = attr_value["entity_id"] + value = attr_value["value"] + if value is not None: + try: + if dst_type is not None: + value = dst_type(value) + value_by_id[entity_id] = value + except Exception: + failed_entity_ids.append(entity_id) if failed_entity_ids: + self.log.info( + "Couldn't convert some values to destination attribute" + ) return { "success": False, "message": ( @@ -232,6 +247,7 @@ class TransferHierarchicalValues(ServerAction): self.log.info("Deleting destination custom attribute values first") self._delete_custom_attribute_values(session, dst_attr_id) + self.log.info("Applying source values on destination custom attribute") self._apply_values(session, value_by_id, dst_attr_id) return True From 7500097cc47b18f8d9422547d13500e89427dd0f Mon Sep 17 00:00:00 2001 From: murphy Date: Fri, 3 Jun 2022 14:54:53 +0200 Subject: [PATCH 324/350] added Royal Render and Multiverse updated Nuke Studio icon, Flame moved to integrations --- website/src/pages/index.js | 22 ++++++++++++++++------ website/static/img/app_flame.png | Bin 74845 -> 39096 bytes website/static/img/app_hiero.png | Bin 40175 -> 33079 bytes website/static/img/app_multiverse.png | Bin 0 -> 4814 bytes website/static/img/app_nuke.png | Bin 25887 -> 32869 bytes website/static/img/app_nukestudio.png | Bin 0 -> 37527 bytes website/static/img/app_royalrender.png | Bin 0 -> 11650 bytes 7 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 website/static/img/app_multiverse.png create mode 100644 website/static/img/app_nukestudio.png create mode 100644 website/static/img/app_royalrender.png diff --git a/website/src/pages/index.js b/website/src/pages/index.js index d9bbc3eaa0..f57fd1002a 100644 --- a/website/src/pages/index.js +++ b/website/src/pages/index.js @@ -299,6 +299,11 @@ function Home() { Maya
+ + + + Flame + @@ -306,7 +311,7 @@ function Home() { - + Nuke Studio @@ -374,12 +379,17 @@ function Home() { Deadline - + Muster + + + Royal Render + + Slack @@ -390,10 +400,10 @@ function Home() {

In development by us or OpenPype community.

- - - - Flame + + + + Multiverse diff --git a/website/static/img/app_flame.png b/website/static/img/app_flame.png index ba9b69e45fa73d3f9298e77ec4a167a38f7ecf7b..188153e573f64ae8f66d9a27092cb47b7049fc23 100644 GIT binary patch literal 39096 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 literal 40175 zcmc$_1yr0%)+mZ=a1GkHb>r^t7J^%_#t|LC5?3f`!S>C58fX*=Xvz>8dCTnmakLnp!xSfmyvAoT1P#Fv4P9&Zg#eU^jpn z*viIHg!-htiyB~KAwsRgqr$G@ECsfOb%bLcjlRW}^oD0peySLM`!|AV60|9U$cd0Rwngc|qnJ+&ln20agxP zE^Yw%bK^#VD%()=BRG}zS~V&m*);${kKSe2UJn{pFtfQ{(^ROlktF3`5V9g zEn-(qZ)Y%@2H4ff9byia@c=uz(fpm5tD6S+AL9N8!=d1R4R*G6a&vOEcKR2B{nhJ`+k+jTjJZN#IsOvP&BpRyF!#IXzn}$s+58L8-#veUItxlc zz@~0a5KSj1`@h?c`rqXMNJ;&+6#)RFj*X**lcy`wZ$15O3|QLK4J<+lZBHx6vtoFB*@DH=HucKFars2bDDuHIk-(h0s{Qz zAYL;tk0~cuz=EF>{C8|>5F4mJo7(>~*56!NKrsq%v-5Cr2?&6AcrCynZgy@ikbs#b z7l@mW!_gjdIG9?2*_<7%r~$t%LlDXxR8rI5z9>Qs1^uH@_qPk! zyZ_n9$H@+T*f@T_|E*u|-}L{ZTg%Y~N|cit@Y}Wo|6u<$G|WNSgwpz>P2I)|Y_BVA z168=|A53ulCi9Ojz5lK2cg%BehR%|_jVshTz5f=KUV~l!_RZb~@Q14lnwtM9fcbAb z23t`7t=ZVGiqKfzp`EZsa!Az%qBsDA&I|M35l|FHcl{#{Ky z{%7tjP0cwix!8F@{N_+oGBf7}g9O0lzkSJqlbw@CfY+S&FX{hpasM~vnp>MXT7jWS zi;enU%3}eB*!+`3&ZZDkXr=-~Tt%qOog6*D5a?t9EFn$~fWM3t;N}D{b#}J5G5^C- z**qLA{+1X1@{NB@@89Z=pVN{9EFi!Gvf$+61#y^jL;aeE&kV$2%3;aD!^sEc;Nbqd z_573men%@VO%6Umb{;_<2oSfX;&>a3JH%|X=v+nQk z^;dBDt0a(smKDF#j_coowWO)lUtwGHzpoXz`8mLxru@*rVrgLk;uPTK0GXPxbAv3* zxHi;=kd>C^lj7y$ zX8*S%dH>Hx3dnLxaY;+^@bmHWL22>|K#5B5aR_kB^6_%=bN(~8fAIaM64?G{ZT$iH zPnADZ)IXY_%ZcA#|60dDfBdx)0y{!82?V;%K_8NChJi^iQ;?R>^!jmRgzTr;i#KNE zbMkpLoX{qO@vV_2e${tznW_hgXfp|H-xC!1`k)XLW;l|hY-4$G$&=4F*@=*wm9apN zo6qe^@~zGp?Fe(LCl`{CqtDBa9+nzmtue9rB*ewVvD1T~4*&=Y3oD@u z2Yo{75Pm@d3DOCuDe{|fyl_&-Dc3I0#eeyLe2!H9?p)I>1?XI25 z$?KlgoPY?;_yWCFl3FL8d(6xBiIZ<#23IGf4xPs4O)gcubB6)5ZftuZT!y#J`{o+k z{;}?{wdX>B*|{*y8$%9%50!bdDzNd~bv8YUglOtoTZj8>GsM&)t}lh72}tRKzz7Lo6az zCxce?evEVqCDwb1NIYbJZwg<3p928?<|`Y^)aLBQ@z$x$8ONE0H9zk5LiRzVM?A1I zn|O>qWy&aTFzR9Kyi+f48+78C{wdIdNHbqwW@3X1d>^xZ_`!@n>5XzckdYqwi81|V z4Ej=LN%vG`PH#?NfkJBm9qu1Cf@;$|mDf&WR$W)C%plIj90F~{nYql&^mL0cNsZB{ zO&u?+bOwd`R_L7Wt3LWU2UtNWTDWpoS6@cCGmf=_4zqWgaJ(_z#obY`x1jalhS8x^ z?%~eq`W-1g+$)k{`GxHjpKD?@>iZ1HrC%oAJWRk3U5~<)LvRF|dE&_Qa_LWq3+QXf z^XaR7fJ(;CVu{iBL5&-hiP3GrjStL;Xf+5-T_VI6i&Q^CIM@g#ktRuETdP?yFPjcU zH12#ie3cN%PcH<6HNS@kUJp?Ks=Z%qVX%dC{L*`Hq?z7Yo}L;w>)__^Vu*v$Q)7-l zPP}>i5lS|G1WPC62rCuEV0^Rl@Z(H$U@8Y{@}{Ugwt`^<5jT%)-^|dcwK^roP7ah* z39r&_o@O%0R7oXY>@XxxA21Bv2Np0o`Ix`!I7-2_IS>L=`%(<lu=XllS%+#DAQ^4J?YmdH2sFZ&w$n&_)uehPf^>Y=~qOSn;8u`(w z9Bege+?({jjUb&HW#4hnF@)=tFew&mW?mukm}Lr5gXD2Ww@FcYXF z31gGz63FPPy&XR_ZqgX8g}M~o$UxfQLAjXnnDPk2)OY5V)X9>Zl1{Q7N(lOr3)ZOM zW*2t-i}7(qiQSP^CcG|lOE`x1OY5i4u9LqEy!qtq?n66V_y>f#q}vZl7S7WXWQ%5b z(3r`Tp|#{ z{aK77_x(*h!qD}z%-G2tZs1euvW_HUJ|5JLm9Xb}andP+gi%hI5VPgBQxpcr-Xv9F z1_7TH;w@KHuSWy&atDySSGf~E#Y%)o-mo@vv6_H!a)1nZW*p^nN-XFHC8E1|2zH%1 ziaacJCFjkw0Y@{l-{hFOg!E0ugF24j6S1CB?)yUJzYZbi_n@!3PsWQJte7FOdG zTO#l0;H@i$M2CVWfRo?*7{7`ZbdFqan6VS%Xx1$_vJ4ZlP`mHC*aEWH>A!hNUyYL& z%-wQ0<6#S4A5kn577EqOSD-_FR!p1g`feDwdXFaZtlt zm8l8%^Mk75HQ=NE)0n(LJ@bOU5~rTE#+SHV(JtU%sJzeE?HDxmcLwe~3Khb7=z(^%PX1Tec}b7&CEuh zZWnXWWKC64y4&0`Ab(n6awSL~SzjfK2sKjAoF|c_-3m0?HTJmx4* zzjO198R2R*xQ=+RjZu4?ro95+_fY99QL@pas7dI9PRC#K@$D7uVnOacfS4&qN;_#* zoU!)xYN;_?BYKoppysjBrxkneS6jxgeIYdf0x{V0PvbYqTy}HAkwmf7_W?&J1pP=w z!=3Ou{TgH+vB{LwerE?(_ntOb27itXO7`5VbTvW`s)!WVwWYZi4OTxWydSX>qa6{= zjgcvYt?HTbWPV7vXQ)}}XlO*e)s!L#`LaX8$eCQkNrTEfji*wko32R%ERcF*uD%l5 znL!6TcinoGwA+i5`O7srtDDn($Y0GYC;W2tGc>#g@GXeAb7+#SzMY#Bgm_F#@vAks zywF+C{DcGbnF9^lD!J1qARL_7JG$A(T>VMPSh}tuIj(?oPrq06)!t~u4~{Lm$*I$z z;oek@{*ZPQNJVfaF~`~ohF)qI_FlS0%C`VHR9Oum?Z71L7S%Zp;_V5XpJ6=X42=dW z!lOa(`I6suQ>);`j^*50>k!Yt9Cp@ddM2GW-I-r)E{nLni;(;Qa%hL=j{u0}vM_BW z8pQF!nLYOxQolPBt|r?by2I$9J{4Zc@h`T2BgnLHEv6B0Xym;*awe}S9yOG?n8fxX zo2Hjg70vVU5G3P^GS3ywk-p0YA8X@~Vv+ zM-`+Pl!A`8_B{lF|5OL=uz>On;{DIwuakir3m1&LcDr`qUwVi`zEd}r1@CuEXiKfO zWV`V0$6ji6vC*tlRn(L}qA0&{e=!3LT+%GQVgtCSfav6=8P@y+B!&`{B|9R_AMkJ& zE`Fyf9yO>8%quCLYY!_)yH6mx65prfnI)kh5YdJZ@U{*k61Jsm#5QV1K927ltKbPOm|2$t zBVuTom59{pdB0O@p$wJjszO-ZdoL|3Q9&fh881pRXnT%Z&(wu^&k${)c?Ja~+2NQ;X(x-czp#(qWezIb;?66;)8%())HGfzE zPtUuk2v6#K*j8#}N|u3zxJPGPt0817s#jOr;l146lNKr^+<<~zN%?5H5?1NKDa3ER zN)UI;4D{+`jfcfAjR?A8B1nXOxUeb4n86%sw_j5{y`&OUYbH475JUV(kQvImrE-!3~I93myG{zQFGaS=I4Be_372X?pR@dZ z+sEUm;=ZyiQUl}WaHEPfuUGax!rsTlqDp>*fk_#dog47GnC~gMtIfnan5V+5xX`r- zw)Qjt2zcdnR6zAAFX;U1YlVd``RW0?Z~boBpq1e!>yo~}(KO3(_|t}=Xm~2^l~qh& zWlSPcgWe(Xt9aJw`tYba7a!orGb3529~Dae!4YD!n_GApKqZe>BC0n{vQnIiHm%Um z@DM(&yKz=b&ER=Q8lkNl!=cGK&b!Ad6wdS*dA;tqRM%tl^2hAG__7>c`Mev}M|%KU zN_*xAFHKZibdGGW-|l$R`IwV$$oipi;?P{E<`er^N~QCdG%Bj7MRdi zfR#8Ug1+V7bxGZyL7v9VN$s#15r9~#FbU-Q zvZYeqlkW_%<|@5k$Srb}`<>bQancVl!bbXb92j;!VbSb->O|S$ElA<(>@1+C$d2z- z>E9xHDLr0A5?Vg8CHHt~UC<_u07CIO?7A8E(mmDV?|4k5T!NG!OGjE$bw{RXewHpQ z9K=gcTTL$?XKQbr#OTf1#OU{5cXPkoapjCt{f^=!d39x%b;_Q~QDjE^5r=sk z@+%h?vROzoHqme_4JtJsgcI%ku|=kHJ!x6c%R&$*lFFno4o{XZU^d@y> z^BgQ(H0!qdkwnsXR-T1Rru;$~h6!u=oBMdEpWA{gMA!;jK#xCSjGQ-86T{~ZR)g!P zPf3X0fzwpRY62rP$%g5X1IE*zeJxTnovYuirs~4K;_1#F+L*)huafUyrX<2qngMPx zAzKmBiTB+)dmShQwp4#)XpEIgKCjuvS2f4ft1zPT2ZTARi%N-c3xQx<2MyK=fVJm1EMeZbh`NF`m_gpF_ z%_luctv`sqoO5HSB0baA9o8c{8L4Pfz*B%+T)%$`!22aD&U|3--535+YczzWPj0_s z+=8kuj83TL8KP!>E=okQ)cIV(O47V&U{B_%Owzs1~F}oU94`KS3mOd+G8^dU7OI&VRaiKRca-DlA(@QjACQo*CkCw^RGiI#q6M*DiJ_00w=JhL{TF{ zZO#-;o0DG^WEIC2HGR_(!FU&ro2#}~U+q7g*wPT0G~MeYxgB-m^8PT~wc+z`ySc(6 zq|yn|6eXa%S*IE3clAnY$bRh(`%16i)JD;8L^~Bd{dEj8PI_EiSO(=;=oaHBqI3yP z*v7<6)c%byq0yPdjnCJRaq9H}G1TaD1ac*#Sr-RqlCXVx`g&YSHynwTvr%@4Eh2&I zx4dNh^=Cooj#QWyx+zCtf=)J4Nqa%iR36@zzgVct9f%NC(?68X7|6imPre0t$2=$> zmW!Hnx)CahjrXCt;VXJZtxYbke!QGlAyWRqb}w(nNAA9+T%|4cjUn4z8#8yin1fse z7RoAGxeQ{LF^wKUbV#poZptro(zM@X5jh>*>0-9b^{`SlTT`~HPYNujTC)^*rUS`cYA7pywZlkY%G=%Ze-;?$UoeZznDr(N0ze_33spx}(IX zifdN9dPEndqu*Bo=3peO>eON=2SK%aD+HHZ+x$MLFWAhR##qz{n32d}-wru>` zMA8#}uc?90dDul@663wqFjv!W@9?TmrE_uJX4%n2==^a9aH)N0m=eyJQRYxjh zz3tPn7QzX_E2Fk=?kaYCw_YaLhxvH@y@=?S!h18euoA;2e$i7fgm2oB~a%80czDt%LN(?D(Icr-Z>V<@)}GKMsK8L4b%rvEddwl5YTQF{q> ztJ_|D9-G)kVVj%l$y7o&gA*DJ(2*akG}^2H&=jQo;~Yt~P@52gmo%})q@ga^YcqnH zoJ>(EEQ&1x8nF%Sgeizx{4}TpcbiVH(7#yQFl1I&k5s^g%<+9&Ll&Pw2l#fvGYUO0 zC5=5}6%Q4-)T~B_ZO13v&`2Vf8sUcZnrY7mpB<7x99;t;K=bGh(=q|@m(&*(AG51y z)2h(i_>+>0y!5$WbdD1}2(vi|5W%v{P^T7@3ttB1uc%)d;S-;GNwlY?&A?1eWrb5N zkf~T!e3*)73(j2?3MW>&53Tnj8N0E<>DtJhht~PmVKU3&5Db0o=j7Kc6tr?gY8i8) zQp#r)F$zdp-HlUR$$Ik{2aD}d)1tv766OY6ePP|L;0|>4w2@n7mY7nId`up|(Z3*Z zYI$1WE(uwpqOd`3J``wE!6SncHmi&>OoTj&H5iR)!pEM@O3#3POdt7kJV{&3xZFe2 zM%`5-hP5}gYT}#Nr6;xDtvw8_to64Z{4%^G2@>K*FPOuejPCPKnI&lsD$14m_DUFi zR!vCW7o=&s93xaEO{-FuWU%Xi3a)F0&7CdkCXG@c@ zJd$TEz;)^{U?Fo%zN6=R4ibvC$cd6Q1?Jfz8k)q)Jqxb*e0(0Xh!!(>oY(DLBG$jH=s{tVUr`U>4jwu#_g&eYk5 z3Iaj?m(A|a2{0EWhO*kpKHa)9$503ay9(92brfT(h1adJg*73u@j1$ z3Mw)%zs32Y8K6U%XE%lQPLG3=V6*>_eg1q_GwXIdh>=ugY8Eu(YYl%s#sIO1hT{*N36-8UWY6?+=?Y@$F^4KTx;~b~DSd{e> z2!~kc8$P@APPzg-5p-Eot)==m+VhmmtzlL7+$yX*>3-pM5DL3|h{UwEgzgwE(6gqC z^)ZD06oygkyt?topEjS6P(txQgNT+6FKfbtQ8l-R@_msfADgKbD*v}1ZJ%QpEYxDn zFd*gpg-eB1UU^gILG+w&khi*>V74Pag{)uBix=7*Q3r+8k&!hgi=2IIra}rmdr&*C zaq7;TR;{nn=LU`|9yJ;kMlLD5n%HDkgQ^`R~DXL#?6?LIOMf=w!ajoocxMu6TSsTw7nPNkI~Ez2+3uAQq{jV zM4bPs+NjFJJq=xuGr(1&kK_iW&k`JafIb$H=r)=?o5|dBE0&r`Si~t|6A8)M``MFi z{sMvc+^||pWLQAOv9v7Qo9;i~?ZxW)*<+kvkFz*`_KQ5YL^Tu>TN7;4!%jDM?9TK0 z+9mmdb~~~&skzf`MWt%MjIYe1_q@st7%BqYD>s}U`&wfG#u)T!Zx5<1MfYkuD-bb6 z4CY4EjgQHI`^7by1)2UXdW=C=&04(#@HeD=?W2CtSZr^{wUO486o?@vfWR4kBa%v4 zRx+Ch0N(di57^!6^-FO2NnfiptD{$oam<*!a+E?>v+>{<^>1x@y_t&?aogTKO1`|F zWYDobnBU2MD=J1j*H0O-e1b)DkJ!yHj@-a1NGVD>5D;)uF7CBQ^>7dWbl94({1e{O z{VF6AJE`u6ZsA~e^BS>;M-JPIj()Y5833{j052=0SieNzlbZ>kL#cmPB9J)RoPSMK z%bvg#u zbhU$@@fQ_t=SxBazD9Rs&-p&|Z>!!-L{-0-2zMN#^`xitr-rs%jBMPWArP;1^)lf* z`kK-+d0it!s8ps#hz-K1%&M_ekwh=jwZ%$a$j2a+uueo|G%i_==X!ZnMLN9)hRvNh zvOlMwPV}0-aWBY9c>el|I2F3>t<~1rr+wy6ScSG-P++3YfF=Wh#-rfWsecaT0 zkN3XePCu`-R}+FKv2rb{1tgEQxI*#)Hu~)-O6XoAj-g}*^WCUG0-lwCj#?#y=KIHNwk*{A!y(nxkDeWX+-g(+fcSOhJ0I@HWlE>_z5K`%K$KeDZ~9b9Uj z@+(GAA--LnY$9xtPo`!-1dOU;%!WfV_R=~hdX>h zGRxEPfD&U7Vkkgde7AWDh;tn_BSVMUeV)1>Sdx!cv(> z$1{s##O3(s#9%Gt>^FBmE33FACi|$6vTPa4v6Q(=jNfLz$zG ztZ3-7E`JbaCU%=7X-`hue(~wt3 z(K?9!>4|XIureB~K%dkX5u221lRoz0*^<>i3G2l& zR-wcvA5{%h9ajq@@cAdahPN#?_9l>)2zog3=?fmJ9VSPru+&(Uzk#ush1i=1(19m1 zS7inN)H2&+4oXW~lfnC@wa2|YI zf1P^XqzyQF@DUOkfRi-W@1p5IG&Lf7hb^`qMFTSq^{W2l5}*HB*l=xO#dt}1ymIa(-NDB1h2nnAME8Bf%X;V6$ZGBF^%-^( zMnv0ift^G{a6coI7yA@v)ww2?M9J=>mn?3tOTAFR)NzgJkQJ}zov1r1)AE9(XoJ^>%hgA((D(Z~ zCUwpwyERg3koe~u6t(M1SU#QmQns=!oEX;b1e(zA-#C6)8)*s5j;!681^QtlRc{y~ znl7NuGzIvI1MHY3-G5;memmOeSHkd{UK3)Pks1qQl#g|GX!Oxc^V&1?+O>4zzx526 zl2o=j_RZ8wu#;E&?h-Ia8UfF=+yuSqfC;z2PBEXK0jP?gBDUCjojCM{p5d7kRPF8Y zx#H@p5VwJxZsXPm=-I8UGr-H2Ta|@%*32&B5L2d+RIw=ksPRfI`%}8-@F3ykOphENbR0I6VZpU@hH3k2%5L2!;RQbPuGIM~ zC2|7?Bf5GS)r*33KO9VuIcdF9At%ns@lQmCy*-o8u||VMN!{e+jY8F@_I7WyD-@yp zpXbR$I`Yr-xyUQiDOJi?W#dDNW`qWaPY=h_0UvmsqFDF*nJe&y@^^2srYfK6n`{ea@AJa1XqHovq3xUEzUALC5jt429zTj1F zAgZn59nZ)x0V(A^z3$GV&{6UpJY4_;qM*;bz152N!V6FUc!kdp?}3L zzITk*Lijo>T!ywwi7x_7ig&-}+kx5VdNGjHt21eI z$>O4-DwAM^JsgQ2<_>EN4+mW-jVzz96nGS}Fy;_QSC`=x-zg4XIh(mq$BOGrd>ySy zTFwk!)OOL&ya+%kAbY9sDUVwZ8@j6ve>?>(XTna!=Gk3zJ!rSB8W#NEt1^iLo1i@OZA%%)fS`>>=| zvKP0roTRA3Q{*GlU-o1aP7T@E=vin~QAiUS%e*#!zA;;f=-<%waNg7Nfo}tsC?&6* zE&7rDoT@ybJS+`9`zobtud2nER;A&#RxWjZtrncSyo6NTkR`95!Z!N4Cx)Ri>8)|` z`3&g1v*0wMseZz;wmp4#3yttY_lK90yJ$ZATihyn#9!|xs5SLP-&?_Y4)!f)6@1?% zzH`i`uuD$GvF?z<^XJwdqzr@88>7?RQobk4mRD4ryIl{)CMYgXZr(xhy!mi_TxZEl z^!T2{xT;KaI$B>!pUh~2e2eB8D2Z;v?ju?NID65GFipa`Va9JN^0xLlH&_3v{c=@m z38;l9bD&^qBA~V_nAczM=HLJ;xHIlVwETpeVi!)VlhBMcrfxFNWKIvs6FH85a;K9L ziRwuo$KI*RMRVZm{4k>I^#$0xzm0W~21KW{AfE(;Fv#{mPXow2hLm;~!n>N$J1!I1 zQYVVP`vrtJlD{mi<6(60r(8Qsx9iqD=YY|pKCjCp2`!>bV!?y1ySdJf6}-68dVbpb zKZcd$zaZQhV6zRcNZ_qhDah-ZVlW>6 z1U=V?LH@xL*VUqBXLb5Hz}2$PW0>}_MJ~cPaW|cJceVh+Y;gzEV?CbZQM}4h1rr@LOyQjc@h!x z0mHW223mzzWyU@wRdKc`Nt!dEizS4W0jdE6$a>V=@{fDnFl8g#c{cV_oFARfvVI`x zuRZ%wjBS|!vFypV&t;M9Odsk1iDl99st^(P8bS0TF+bxk?&2OQzcMv*y>RCFXGd%k zCXA^iZiXT@oD$>Il2eBJ6)GuA7d|yc>gUaAed<*p$v*LYejBWM#of)}t(YFhQ&>uLm_^j@F+K$Lc>4yN zH5~2n{1O>!d3QZgF%Xt(qsOQyk;!rG-I!`aXHd(Sh2=3W$=RbdI)_|B$=r;aRH$P) zW$w88<&S+gZ_o@G=cYJw8~N5Fmlz#EKc!@|GaYq@g!UYrxUMNc3BAl)VXW#=i#b5^ zm3f(vM+wpb7lfFS$cFCUE_1=FG0iS$$=}f_Jf>V8p?+MIbmpOoZ6R7ze;% z0Pdd{V?;z7%A5hdVtTu$Htv3z7{b4OTvnHlcXQFl@jdX;nOlg|*Xw95BG5Zs=)hso z*JDuVt#=V0fS1=*ayg240~ZE%*KS8*`$g|JT5x_GC8s>9evq6{Usq$j^p;{a;JicZ zVCrD^bz>L`2Jn$HSx;(8#yWUjzcH^iawyj#^VIAu6Cp#g47r@{<;2gsl@;e?iemil z{j;U%e6Hw8b-W|7!R@tI&R#g}+gGo&aN0a}WexbKDz&v)ES2SDJcIo#Ce@11m8}fB zBQ=l}7e18@yUWn8o6%R8NGS5IWDmgs&xlkjuINLG#4mvx zch5-j#?5Grc$x*OykJDD7>zY`eYh7Li~W~+(5)#?jWW}=hnl*0UKY@XhJ<#n&pu6+ z+sf-g3q9(ND#o|`Q#_3worLu@i8l`1uD&YF)C)Z1uja72AryNl3}()SP><6bKu zsg<*TXMV7xDpB@a4;h@?{b?KSzFmb>xk8fps7g$n)|m`kn4&liz+@x8x6woiyKUvx zr@^xo*Z;USg4&p9zR!Hw+$c?AbOXH?65A(&Lh z7`5ch<1kP7_2XBrl*8nPo_5N;_1zEz=%;MDSZ7f#h582DVJb~jrE-pu zx5%w6l;U?qp)D)$6FzMOs7#+;;%Vn~+P|2dgUys+ju&Hg@(;}5xItrO%1P7c5-K}X z@0~VV^PoE!dL@)f(pWtBj!kR>qcq)le#RPE;H9E&1bDwm<|}#LGPyP_i#pf45T4T; z1{`}lDuF@X{(5D^U*5N()(UDQIB>@`V^OnN+#hS4Lm!wX?N?^WBemu&(C4~!nRn5) z)(Y&po#`>>FI543?X0gd)F}`k+qmrM#mQ4g{kn^+KAgI0HG>EHQj4l1V68QQkAHr38Obm(BT3`2G00lCY&J)^+Tb z(HgJTWuFS(-Cry~6eU)`aH!0q1P47>Y%7p!p2baN1^<1Ec$j+;4B&6!t~L z5Z=O;mp1Og^8u52fK_D`%XIx|G`NIZ`^(4WZ^0o>K*g!22Xk_%m509v~ zG6CtWczcQ(`t1F)7na)hM+PxaqY{~t$_v?M=aVH}uLlpT(%GmAyPX<4VH5JvfH$TN zH+JM=0E2)$WmSSB*@SWs?i@93NpOZfsEEb*yGdgmVRDMh(RPzm{8=uG|8f|3!8RbA z;zJkC(1^PnW&;>=7<%=nryQ{(Eu-23T&3Ms57q`k&+olUNa1FAOA&|$NQk}=eyk1& z&_Y4qQT5iw^%J2T;2tAk=sl2pG&13AE9LH>(#zMKXL_HD(#R3pao_H0!Y?Pomr*3a zxvPQRh9%pR9WvgUkjtoR4&1fn=F6Cv)r*k{O>6AFyX`^n`jAokbyJAhG#ts=bc!X| zWI)BTckJ33*_%DR9rZ#CGjv9}gkKwBDG!sxoJ5G5cuQDcUuuwk^7;~KpJQwHyBFIN zCvFdX?havv-EKXFsIv)$4n&>6l@0%{a-|9m)p3+dmQkz@Y9#Lgq*B>dFDkFu9x4_Cnww6~}`irlI`v-t~tVw!0O8pU1{rLUOwtT}0Es|fh7;6*p0EevSaG zD+b|~EgW2#Vt?NnPPZ%2ansnPP&hdWo$)IhFG?{+9Rx&8$@KjZKOMJKPd^%oyE8&@ z6As*Y&x|3ab&*}n&M2ZQ2C#*>aYhA^@qCEtPW$BbLcQ~FT0Z8RiHZf~rey1q_TZ-T zhQx`{#-zHbRzay>EzY}D^1E#@w^}Lnb#VShCg;Oc_OUag3PYdr>N2(BNLM?szEXAf zd*goJcQ;-g3w6IKvWwfcn3dC2ekFqpIZNTpUFJree`=T4oi}DCoHKh^RK(F5^1)#;S`=< zjLe%7=&;r_pSxcXV#wdwVpLIepa$}!2hV$YyrRDBTJCo%X60PUL7Ktq5URZnYMLIE zd%jN0DI%qqK6;akB6WPh+soRd3PERbx$62#sz}JtZ~|`pK%S|A4?4+)QTMJP^-*8l z&{wmwB%DKBI2u$gOGqr*l4g~^o6m`1vKwr#n0gCo#hiP>htJdZ;g74b&N???mWd^U&NbZGUN+}1JGF47O!#Fb3-2AOO1MX<9B zn!$l|b6wsT1~j!*~?Y1_m=4ek>L5}Hk_cxfRFidJr4R8lD{#M?p3L_{I z=EZRHzhdN7xi>|M?=0KkEmFAb-lSkXPOJTRKuR&#E)8w-c}-${?a7o~Homfrk+15E ztYxmhU!+W;g@H}j`_|H1=1eTHbw=b_}XuvS3%%fRtmmdJ>lcd)Q<8`=S}?h zg0nRd(yte)$&8?F5IRHRLFogTnBSr|^A7 z+j@BFPl7j=+Zb|)x5a4OS>p$sqCEu^`>i#*UrK)=>r$*qs5DH7TVu~|YbK%9u1GbAU5+`_U}_2tDjDOiFd9YLYReY7%5UW^r; zwar}yzwXuk>pU%oY$g**>ohsGk~iWx2%wRYg*6$UMNpOP;N;As;I$|9@>~Dbh1xO3{PhzV*?TZ1 z=5Yn`Q*0#ZVtbB(H&0NmArCdpN>a-sv)Xq-mh_nA1wpKeJVLH!?455yYIjmW2{F@E zK!Wn9nz~@RB(lS zPo4rYFIV9o!s_Db%WZeeZKJ0=*3rA(T0p+V)3aQCw0=23^o))mDI~P0pcpYr`SWya zY|or#a@(zG_{s+15Y1LE9BJa$D~zS3N%#PNme_;(h3q3^b074K+`F9%c3HwPMWES;N;u2z`VSTHRJWK_{Gn0eV{hM_S@4*ZIGHk&AZdNIfE*Z+z^N$xXYx*x$9X~~bwb;HMB z%%`8B_kM$}zS!+vP44WQH%{=(!XF?14A(B?6JA}^=~gB7YG&*B^_I<#lO5(m9A-q5 zm<-23W_%9Sw5WxLka}70;gPiVY}1OhKeIbe$955XNrco008EC9~|nG26dA8mWlHZ(Or!7iiN<@mV&} za%7??cA%68D6LW}EC=hpCuUQ5NKM2|w_l>C9PZQ;W%mqeY-2mI(KdLfP$Up~GZE;I zk13izhQ~K8)7lNq-(G2*)hQZH6w}_UI&`dWp?6P1Yjqxn%F|WgkuEQTjV?A}v`ZLc z7zbxu^l|IN8d9p2^BaS!I6+!M8Ya+N6%+4MN~cj{9OJqA!}Q-0&ApaVc%7CW9@JsV zF5WvhIDp7Ug>@({%^f*5?o~1+%bt56aXp^TNU+qcinC7(Y*Mi8q)>$3kHJEN(?QPZ zOW$%1^i=!K&6VC?TQ$}8i8VmR6Zqq&&FN=j%jwnVs4VDaeV|wZjBYtRQ$KZ)nx1lq z$zcroP#FnMa>YRcq3ht3wAZJMHz~WLw_mtmowaQY4ck9_mRS=K!7bj149eBJ0bxT} zAl;T*A*b}lO7fb9;m=PpD7h5HpI$Gco81vom1$67Ol#!!ii~mC)j2+AW zBIz9b@_gGczHDpRwd%>Xm#rsb**2E#dX}~9#btY0t5wUkx!(KtdH;g$>T_TBbspz& zd=F*%Yh6+bWkH9?cu31u#!>* zspIY-2`a$Q59fC<^h0S$^EOvYW-~Vr7k?dncN9B|Es)v?icXsAY*6h(r^Gd3g%FM+ zqsoD-{>CQM!>>nyJ#)o)I%n~^d@Pt&_XPomZ%FqZTZ>QOW7YJzO7xPMklb9GY!2aH zfr2Ejoz<;mHl%xr)RJH%gm_&-j$c=JKSo)h%q!J5J9#ZOiV=U_BOmC9x;uOi=bkU} z@eHyI$Su^r64>gTqPWQJM)NVjz7|v2!>pCV(Uvh^pe{B);NCrj^pto^b7~|nBOKdK z_n3(*u}t;cPRPo}%G0^+wfUou`zJlTDe7th z^6TI)C^&67aiq_)a<V5b2|FnU+Zk@~LC*|46Sr*=4Vp?t zmMVc=_bh#;7pAW7f7r~8zht~h)r48t1mhkSa0z2=1o8CR=yr2m*d33m(pAIz_;$Fz zYI)JwQck{6kWhsX%~6QK{O$gTy2tN7_wjT_PqDy8LOoS>mf7Ih1GY(NfsdYiV*8*q z5A`djf{!DOU8|0jpxG(si?^~9KcuQA=bajdXc~Wd4tcgw&@kW zQ_L_oOj@&_Q9c;PTJH72@dBm&QULkcnt4}cJFp|Cq>;JaL44SKxq4JF>>&@`e&!(> zeO7`eox9M(kY8?18ZXR4PEXgK^plc@7a-iJtnFJgxRV%Wl?HAA*24Nox+KO10h$h$ zJ$T^>c$0B7dXy|Q)2+o>h$vpyF7t)O45Oo4gr9I&GZox_i6;@>pMvfMP5A9gDr;Lq zDm%z$GoKb+vA3HY-i7hWx>hER=gFUQ{OUX+-`x8_%dye{go8gA=O=RufjNAXfmQ$l z_y9cI!?*Lzz$|ZjRu;0vjK~oWH#z&;( zCbiodLlOlrmzqbvg19Q=d(LplpR%p5YHck+q8On(NO$BqRYBi9BFKdgFb>i!@jh>% z8?CYwnvH3w7ZC4@=7%*p@=VcGFS)QJ{qulz(?Iip93CoKc&TqRi+QR%q4*RCn;{e# zYT#dH1L~VMuqJQR^e6xLP1>cu2&ye>be!r^8Np@)!4#8xKZkc>Uj(1g8? zl?i*afzh3^m!e%l#o`z?&VCFH!B`rp<~B~4$C17+sPCsNLblbgSe@Nk&JuJS)xtDf zAR$g=HB!#BZgVbfWmtMh;+fdS^^z!sf?*O457jEyUU!(F?A};QvHd%v&CsMgTA}N% zZls5_Tbi}p6kr9Oc#MXh`FWyMnxK#$>0IXv?=JOI#ZM+ zUR2Q`y+9~~NN2lorBB+D|K<5RD!`1V5n*_hH0eXjffBM_xO#PAsQ)PSD5o%wQ7%6} zoahF9n%=c7yLayK<}l%iHQoy(Mp{>2Kd!;jNT;$kJE{r@C{$FVPv;=+0iMR@XLzL+ z3&G)L;zPfSqdMy!bb6NkaJJL=ilo1Ps<+52!A&y!R&a(-;Tt1#A=qb- zRnf#|jj4c+CkB}{-M5rMieaW0-kdcaR!9AJCtGNO*0GILc8FDYHpXg7o#RYH;lq;8t)+uq837 z{9fB9SmznJonPcb4bekV;0J%V6BdR>szOOhIh*`iA6HTZqz5amHwcG@Up-~Pvv=5# ztg-VBkBtMS~F9e!gl7dottd%0>uvfm|+&W*MW94IWHxP zPN1uvVm73FBhHG|((y^4HI?4p{|hx*(Z4SSKF|j8)Mev>^mxQK>NV8WsCnSF-B{VT! zkOF%*%WFSrLn$aL>apEQg%!^Pc0C?Y-;Xkn;xCc#Vo7yhh#Si7l6aDpUif~|aB4KN zK;TR*q=LhSk@@ogTejT=YsGZ}U`cZTBJdgz!Hu{l@-T_mj|7pJkaj;HYi6=`DMkS& zfV1*Dv>x2s#Rm6ZW=oGAT<1`XjqgDAvXE;e>+RCHu3nf2x4Bq~2(1jiIA1o($rQ1w zq&kb6vdQs#VSMVH2YY)UcYcS0at$spfU`L7noXfU2EP4%k2)3@YJK_zI`md=G%B0k zn1CZ!{$`;aNx?yg9mPrBzC09B!RK9>d5yx!3>M{?(^SaM{dRKSQ1#P>cmFia((;Vm z^__dLzJPDJ22biU8|pKD#^B(_B*;(0^bWE@iqMe z@CtQ`IaL)RVgO?)QGBz9ZL~GzCdgnVB(aa%L1=RrJ@0aKa^rGi{-3O+TJ>wp?(wm6 zHjzj^O$l-__Sj_&RN%e{1U=4bc09Gt2+?ebW}&iIKet}*tH1L`i8L5;=i*LKsJGPD z9iLB8HvFM{kMo&5CzpI|8PxX8|JuJ`LWp)s;@$ont>w<;nBDF`85B?~%lD5fL)%=a$b#oe6u=9o zx2{h9-&AR=Wh(Z8bEu^bGsK-DLMl1Ys5`{p}}2 ztiL&!Ai4W1@?eO}pM|bKFbj1!OCl73RLQb~E<`^wTp3 zflim=^t9*)0|4cEDCk>o+ zFk@_&a;{eYclxO`8l%9Ok*3ciD}>J$wx$+H{jSKS6)*wjhwf>;=REKRBG z%!*w4={|v~>BPV_JI$9P2!*F<^>fPj5StLZLz4+sc4rO08+NWY172Eb@q(kTrSZQ7 z{w@@60+y_St)A^n^eoExdnt2<)K<^$Ec^ed&`QKAW#CiRSPcmj;Rh0BuraD9s%eFz zUO^&?|E<9XVpt8lz?L&}S_bL$+kk@rO!Va@?6UC5A^G+UAFFfMU1%rKF`Q&tKRPO_ z>%rML7pxhoCI0BqI+4{6-)7Px?{0wCAq`dq2mQFRv&SKhE;Nr{Bm`!Cn0PL<5{wP>!u`%}d$-c(Av!9Jlb9}*ZuD+K$9$>Xh>(5k?sr8BCgG5^-3eZo1&*T>c!shB z)ZqFLBf#k@X}CTN6H_MLINfTs5jVCjJy)bVt~u!r(;juS)4w&1A!&Nw0X;R$>I4Vu z8sYoC0TF6I<3HS38Zh57jtlqD(P90~o;{%lL{YPDC+y{|Jyf&6kj!@RLSriAvm!J526 z_!vX{jh=d_#f&x_362kY2S?Dr$ER`L$#o1*)VR76RT;nCh#?Id--_=Q$F}` z;*gzU`IUS)hqw!}eKsC~;h&%SXRZ}DX`a^qEEEy5 zM|c!|l^X4e=8DIkWI?cA{^k&Ym1^Cy>?nT z3JLi{wn}~hA78O~pnMA;MGAw*&onEJuQ`Ux!qBx~5U>pQU3%-VBj$B`ip8s0d-qDj zASq&Av9?vLL1_zIlra0AXI7dRW2=<1Ec9W&im3HXF&_rDe8V6q z;7|--YN~XC8ZIfMz%xWBJ~eTpsE%3OJuTIAwUuVK(A{Zp1};W-BlR;ntO_b&>~An6 z0-uhHi`#fH3@)H#{;99^{~A6yWtwT))=8^JY&R}>ya4zZA6S{z#62XHlx8G`d6Pl# zObkf*!}fo=G4wI`5SSXg103$SU?OYKnn7iCqHann!4h3z;dcJIxU%o-XvNpNjJshi zQU6UYaaBM7TyE^%tfHJa@JZE?&T{xBw(=;AEfqnC!6u%VY^`8W*pG@|9Ys3zduFqa zpCEOx!Z@vF7{O8UTdnAJ!7{fa-9!-&io%y48RREhNF4`*3^C+mJP&Y5i)bW0(;Gfl zY@6r@<(%N{0jp54DJ3%oe6IXUiT*hT+3hgt4wae!qF!(d3O^<6l?z~Xr8=WXFZ)Af zQ_zQDa3q{EfAhup!M;rgxexV|*dWu6| z0t*{|vI*c|!<0Wl`Vzdc?+!nqr)m3RFD@~R37eZBshCjT75iITv)%UB%Y4t&NXUt?0x;tdl>i53brJrNzN-~EaDc=Y&ntbA4UE2+RE&h4f} z+?+O2Q4H*hx=|=@!B6B7*@hcLg-Kd1dHUcLosiD6??Fi@?G*I(QcX7PVQ`pnvc0Sw z$hu2nD@!CDbBpKr4F(|6>L&)G^TX}^Cc_dp1?K8ZqA%mect4wvVmpi(>JirK=pApk zrUjMWmKJMr4NU*k`PY7IuxB0FLQs`Eb-z69L1Jr4th13^u^d7G-??fGnA4v31}@7JHMY$dr>MXoL+=QkuAO5T8daQ z335+j$jNGZrt%4i61cKt<-phL_qBet+-}N(444p!0`Csm)f~wKL6Dkk`re*E;m9ox>0d`AfqSTtRK zRZ~^-CH?cm9IbfQ>|dQ*0K`e`B}<>b)l=8C_h-7?r4^xCIEl*sVj(@z#yKlH!cIv zC5IvP8dG@s2KjyD#2GY%x&3`R{E`5+K;>bNn7Tb44gNkBN~%>DLOy_na)H;lFd z>O7r6m5mm;Rx9TGgbI`@7zO!V;McWzn?jQcfz&u09T9yp&Km5VZYN}SUgjp#TA;{* z3UVUIxYOoSxT!F-(bSz@VGzRkst3;g4E0d~B?(0cGm%mvo5R!tmLjt7+Faq2V7;Q= zJM1KCmfNB&^{E0ccGz^J4#6 zlkJtVV4-Yjt08gq#ivVRp8jn_<^xuva4M^r`b6RN+n768l2P`L5*yFwJfF2e7)&Mq zsMm{dAyE&T@nogMWiAr+SF_o|rU+;}_$9wfM5>L7)U$OExfp5YE8MBvo-p1?F#ti| zVNpnfxmx?mvHp4FqjbsAeY=L7T%E}^k8E+>0}7kIwsMT|tlinl5L(M*40|;8Qcgo5 zHogu41i2jw@C+>%=oIZe9JnG(~EfydmSe|$X5+QpsTS- zO5Zm|8_m{G=hQ_w5}%p6NN0o+E1GChMjd~KEe{#hOs1JZR7DDr*Tyl3n*SUr=9*SI zZmG50S>SfPl`XUdd-gG}u8PBxfcsvaAARv_nOnZ)pTB;&t@GPDM6oCSSK{P+_fA5h za5Z zPT`IIl^j5s>w#aDXaHx+0HX({#|`S$axVcZte6EEIr*3b=>kvx_LB*U2+EfbpQ#vQ z-QlC*9zZc)G4L!qCjkxh7d3F$ksL3A0&633b`rD;>Ha8Izdz5ZU+O(@2L? z_>Z7$bETt-o+K~d#1-MpRJSn?-ujO8O%Uq*?0k_XYkXs73a@2qmw6)21F~Dr56NlT z%{7*@Hk_0?87KFlAS!eKFko$zwI3?_5ex@(uM=3)!fP9U@)@4V$I7!H$A9thvnDy8 zuFA(dJ%PrFK-hXIZc+59Ro-h^SJrqKaSf8wWtAeNL^DtB7_ z4TTHs(~J6!PR+LAR$byi#-iz{Vhf7tl{*<}wlT2WlTa+*>G-UbXspIQF~*7@ZlO#i z2v|_@oK;|L7OBOQaXX{%waK|OTS5$uBAiXF+u1>((A3QhEvat$&!aC^7^yKY4Fc3v z+hDGlRs)Qxz^Diwq^YqH_4WR2!FI_jAb)~cQ=eYXG5M^Z7;4j&a5QQ>KfK-i4NRD>!jB&fY(cn%?i?2XLSIwA)QsUt}G=+`!ZmJVIUKOIPCG+BBR6_ zQ$jgrV8P_-w+pi7_L*(`4NONk&7YVj^!`}Jf~Q65mRu1o?U{(cr70pov-wOOHIwyN zAeWEry7?`ABP<4|2J2#?qgzet_^$cHtb)`joy?^v;;8YRyLvCBt7Bshs#xGAUH&LZ z%|YA|pw(D>X5sJfQYJB|BB?>)5-x{$nuWoac9RW;&JeaR#mdtukRJF3lUdHy9$@K} zS+rK!O^~nm{Reg8XotVK?W8K03Y*0h$-ilb;^z`2=HHYwc;VIm$TAsGzkrLN_xQ-p ze?2YWt5!;3Xy^jc&JN%I#Nq$^TNcO(yV;Tesgs!)k2N`Szd@FUM|RJ#l>b)Gtz$6@ z$V^po;_5O2KX1( z^sP2NYK2E=1D~$#5x|{t#fIsPv>Y%6Co}^JITso-Wsp6PN&2#qs4(<))sKVMs;c8h zqOiy?zTDUMgycM;m8YybdaS(6p^Op~__4oX!{$_?W&Q|L!KOF*>MV*P3dzOjEJN(= zT>Twz#{4Rhl3o^??U!gMY5q9f_2)*0WNl`uOU{5vxMYo85E8&zi))~hM;L%!N14{z zjiMUZN$%R~OjF*uF9{|9gOe2GTe@Tu4sO$1gG|&k%BzGEN^m9SPtB>@O)o@uF#7%} zThmmq>(umI{ba48Hy0nZe<|j^+_4wN4IqHiX?7(DTZC1?*7c3eM~NdP0+)={*5vvY zqt;%Ey_m4PazJkn80K1nWANGS?=n=TG;#6~$sp{QqNpVIe? zbc>Me+I2?$Qs{Jte54@H(K7vITk?r_;o@%<)L6+E>VkOe3{S{}yPJ#(-zaplz)iAe z3n@0d%ZNxb8x~pHicFFePQ0;)%^vd64wYhVqJuWR)(zT?yEECr3}6Hb?n%6nfIg1-M<^U=eA?bHhMm0zY;Drg4$X_P~21s->Of?85z`LyR_jfGu^9cYN0 z)YsF_*v@~Ef)@IM+mQatO=_q_E#mZ_tok%?5ufl_2zw#8peYa=!K*ji2z=nc@2bos z@YbCir`<~0P>vCy4--ts| z>|IOf>4T~nb*JQKPg3dzGGj^_rT@VGDjRgCod4ym2g|zh9dTn@Rc=botfsMHSQ8zg*-7lcs+#Syn`2#E&ho3tlSm;=?F3+ zSqrFXt*_5QT$sz?K_UWQ!g(Pm#nYY6+6W}#f1w}vX&StFR^hUGRL~AtJuxs{`R&}Y zgnD#G3Of4vBRLaMeS=#}d2eSfvcoyI6^_c#YpXANAx9aB@LX-&-H3jKgH8^Pcl5NW zKB2cmH=I4Q8B4V56INd5`Urz=FWpuPAMfKuDU>XV{>2D~{GjS8WXQ#w6PV`E_A%`+i!`Uy z9xLvpm*FgwwMuoBN`eP2PJ@*SyNY(Mzivz0O^(@vuY|M+|Di-5bpW)S=0H;pNE-Q5 zZjQmMw#cQR91wb_UB` zb*b#Ue{6lTK3rVXz|_VOmnuN{6(E{pmt}QQxvOf}B$zR!->o71NG=mmeSWHF_!XuN2x^ zoM_4=S(Eo@s%qV2C+_2h)B^e*ALNZUkyX)L_&tXb#_C6$vIQed zhZQWZa57{%8SSH}lS3rZ-7@KAW|Cch+I#av_^iro)eO{mBMeKy4o)IWL`~Xi;0JE* zn!Ru@XpLk|?cB{5Z9RL|qC0&wSZ_Zr_X;mDc42C8RA0(mW^Ar?75oY~K-~_}xBJ6D zNobNR<>dB|<}j_sjePil%$~8M=4fD>Towms2qx!rBdH?mXPoJ4D~Z0mrv8UcZc-Dj zFDt!P-b*px-Vz!Dqt@|rQ_4t$7TeMKf^JQMeqenO4!GCi%0ksWas9S7m9xE2$|4J1 zdLq9FV-J?KD&zbQFICe8d!Jhkfhv0=jPV`cU4sb!+!utRd@m5cRwNyk=cEPcBEwfu zK@~S>s|G$cX}F2fU1ZMOovNp$685|NL1Mqh}X^ z7?YmPt<(#05^qmee2%Cyaf%j^*@qN$XW&63h1t~aB93JB-ga|SJqg_e8H*SD1(;%6 z@JFQI`U6CiiBH9h(NZjFP}J31XH0f%3VqdOzaXlMOim)fdjVOwGxMZU!kMWl8S5#- zLNn<)^l{YT+c z<_vDW5IJH=W@q)VN#u^Bo4+JN=3glZ+mK#R8@FuM-qv!E%~v&>OAjP4nytm+~rUEi!B0!HqVTpM*Ywd#cig)Rg~NE?+uKO}KP* zmN2!Ey%2OBVAR{`^J~87`ofKUD$K-zn4`IS_oZGv!N`pzI2CiNoby~T9kG?P~-;*=$F#4V&%tiSC{l2uqzP26B%QSs*bxj%t&PZO?6Tl8@6o*nBjyb>M zDXY<3iTkHusxGHfYE8N^KH<7^;ucDOnoV5i{w`N3`g>~CoA%n|C85qU)cg@D>I%Io z>KL06WNRT!m5_AvA~4ZW=Ff!Ze!zgfatHfYY4QB0AnuH}SVo0`%!vup$x}zgsVwxg zsjj78Ze}s$s9^CkZKj{63y{!9HnZ{Xk3n1PpR1$FtS4(0iSzu_vz_vHOtB;2G>HQ7 z(#1b7x2;nVrl-)uVw6{3#}$HiPSISeEsVIkJDx9Ac?jEZ^@*x`|SbEj{crr zAWNa|M%sx5r-hf^65yO7doWVicl9Avgx)nRow7h7q`oQ2gr*wWf8ECC@9oX-nzH<5 zmqnL0r1(@Xt%;*MnuEL2xmf>Wm>_Kp!gr*a0vh;L1G~@BiFwL+Gy~)p;hY50Nzq@b zF+`mRyle7VbEbD!bz1OS6~;3f^nT+ps9qY<7}Qy}cJLQ^i;DE)38x@h9xWPo0$>l4 zUvV%1?LkbW{ZzvY6o9yVCQno7tU>&|uLO>WFk|jMhvRE?=xn+tbVvDed}atP`2|I< zP1vqhCvrT|v`i|kcWi|kH2Qa8?hn}>F{8D=>HIC2ZkkDUNE}6A4R1dXcetJViVOD7 zx_Bz@*9(3NDNL!zpL|@Kj=F{7ZWGo6+P-==U3=wU(2`0V$j4QE&e3S9US|9CtO5?p zDhNb*pFZU(qfxqTTTH6 zH>C1ivJIi&XYid7!O3H_)#uPAD-N-hWV@M+$B$8+yG5hNb2QcCg^$l(z0RdQoi~4^ z0chr(=h6=vkmX82xSOXg6%NgJC~pDlcsadeIh76?-)C&w9zKYf1(qH-{-Yq*2ML%k z{ofg}FMY(Fo3}mqP)8s^Ol>;Rp;8-c!0+PzJL0<? zP>0Dk)W6c2vUXzmXHmJ(;IT&E{`|KY@2d|Pu)~dlz|a|vC0yJvGT`3YPaT1PF$4TAvmrJW`&2# zXs29Zr2Rq_u6T~l^2CU`O7m0T6*jw6b*6UPp1MSOVnsU#k)!M0oNh+u{`Eugsj5Cr z4%P?rOX*atR65WfHf(mn^?{Au%O1hFr*(^cq9q*vRz;lRi%k#KKCchCXkJc*lfuKL~KyMiedNMNNQ1rXds zN>k9c@K+zgF7xcVHhW+B@)RN=QA+0pdzPX2f1;bDeztae8^c@RE5e33*quRm-89K6 zI!HG%UdagGz;i%N{ewPQ$e&I@c;0{a$fT$9hQ-oSIED?WA^02toecSEFH3vCL&}4{ zF8(vFVTy4Qq~W+Ujtds0Ch|4hajb<};F@BftebTWW;I6Kq{YaT;~5dF?7+JbK@GCs=z0i=+v16}^2;$c|oKPwwpV<={Czpr! zh@gLQA@e)D(Z@fS7iu4?gOvcr<+VQ9H9o5@!r?T#ig20vkJZ_szSfP5c2e5k5FgqPYmcD(XWOS;@^S9q8woM3XT`h zU3fUp2ocm*lG)*b948rUP-cxw__ZUo&alvTRtiR)uWGNMTFWb1v z%#O|su<;j1uF7Uv!#==fKag1>Cl7SH3hNm`w*3$BW|aBul&Z(D5i{~8R57mPJU|33RM?2(wUi;!p~{C|D^y>c6>7@sJP-A^+&>O zHb<62gF(xgAeynyHio(km8JV{O|yNVKDD3W_l-Zc zKtdX2YLc=R0G6M(Ex`a$Sv$vs6dQD=1!Zk{BA|WyPq6Cls7EP8s^woLA1#Mm0GmO%u@WeY{I$$0fxC+7sDlP)T6s+lEf7(^zyV8BGhat)ukU3TRSsSN?+!v;`m(l@Z)9juyOf0!U}Y2>t2n8nRrt}VsH{Xy$C z4YzFrKuX~he<}Oni$3;lqSsjguerGEbojA?|La=&_R=dr8gfpsAzCacS+97xE8tka z`c=uvMUxwm{&z5h{ep-B;oy9rSrFdb=OYmkK!-bX^fve$RwDlR)jlKsLNqF8{W-Yl zJjehyUv38cEx%-#pnL&A7_a@^mn_UFjz=%KulDldU<<_4k4plQRd{1r>P=fs>PsxQ zaek~23=g+pMLFps7BYQtVz1^8D+#CNHt`2ZVl2Fso$u`%e*yTfiJyPeE)JL=^8~c z4f=-cq_dl*QBB1>&yX6(Xf6Cv@8U4>RbHRm?JM9E zqc6ntpyRxMFBjL&f|s^D9Bla2V6!KN1yo?{s6a;FnQ8*iN86MnGx2lnGa_pB&A%sU z&C^wXZZ}aj&29Scq42vkpN%*)H_vq+18^IWZGK76B(BoKON|`1d!Dl$46uFD{l$z+#ANPh zXezuTk)Jvuj^V+WG^qXWBi!`*85)#G)@RzP7CF7goi|lB{7>8I+WDVP6l-n|BUF^l zVQOn?K3x0Bf_?Gru){2L45EwgXalE+RXwfCo1Q$v>yJg*tFw@%cXZR+UU%y~I$Pwe ztX@2^Ji|L`uR=^8UV2BSpZ;^%^*dd_59DA-IL|GjKDUZuasEY)U`2rIz3B?bFiP#H zqR1MifC^}00^)_dot(WG-GpSLVXuKY!-b_k3WL5+KivvN?3 zLPV{npCh%m7Lxl^^ClI7P-7}1@5(Zx?Z1C}_=ifNrFz0hyu8rrsbu=of1b!TB{9hBD@;$0@ZS{7#E`_2bI)or^$!=8xD^21LzgU4rNPlz|2-DU2#D zG4m1=dNcCDB6<_HxXmG8k`OU+f+%E{;9}W$8xmV0;%C`>9Gv6+EP2=`o?6=S6fM}P zZ~)v>m^S_i?|AYlV#&Ob6DY9At)9r1fngAR#ztwvIg*rG2LA37IrY}~EE^`*WdHm? z{1EivJzl05bnPT<%f&%;?e0*PB{k$3Rj^_AEO1zGT8)nfz={+CRoBa-3A#|79 zd3S~^!uDf)%(TIyxTHy_=zMEsDEe|K^&cj7K^ui91;ys*9A!G}TL9PPoMfPL+&FI) zb2~?BH3buQ0A+Yxbf+T)d4?gB*j!qCH|L*6QgQ8&dd0)9vXXWurT{R$vdPhe;bvYb z_>rb+k@6@(8s-X6DcJ*Pv?$e+AYTW@#wECKrD>{mP_T8s8aDiTA8+~`E>2l>s+rUh zq$VF{q2UrQ5@%;AQj{vWTuA}aI8wG7G^44B96j15FWHt+00a7OUP)uSWnwbEa$I99 zgUwSW4dC-f;%jI7GmXMrh42P``;?nH{3}A9_rxcUs(F~FOHYC^LA@;_5;GQy850<^ zrYJ!~VJhPNdQtn1#!rV0NW*wu-zrC1wQ18U(R7&wa#bn2TM-@`>C%dxLcdaLslv>n zk*w%YGVR0D@qDdzw^VhwZ=Qw>tW53%iy0d*q09;^xI7X8X)-9&S;fbt$0xTdmk<10 z51ckn%xm_R(sN@=dp5eT9GQMU`LKr3k-iQhQfAT5j6Rv*SD*mg;oiY_&524=-P7?L z8CFTX^~9u9>3j-Z;m{Lv7JX_dR{$%|g*Xwum-@jUO?^eX;hiAqx;?XMu0{#O9h^r- zCn@(C`;{++?wc(UbDQSowI|eKJR5(EXFJkv1&Shj8aeW!inhSUYucoXwD4`uOEAf_ zFY)rI>Y%#;xnVjt72-rinARRw$eSQe&xjBk#Gm#e4^`cf{>Da5Qcl6cAg-7}uVRiui??bomtrgM16fD89w2UzT zYbxY4TCEeXYggyfEy`$D5|``g#8o?fXn5E8P?2M)XAxrG*@CPK)CM$!0pzTdrRm4q zJc>P;z;xckZ5TUwpBdeBEGJ0G)|hV-;oy|$_GZw-v$#}J>F_UesNm;@Wt%)>VEJe| zz}oo*!wvP+flMpKq=oI3*+*C5E-|qO7 zRNijGvRrDb`d8i~lpF513+o0aUQ#uOSfyCLs!`NUr+z9m6L4+qZ=miuiori8;%}pQ^AHioepn?$DKl!*s(A%yo~Ol|cujwg*N(a5iiB4uA8lk4b1ZF6abX{^v8r(ejv(cncvROch$5?%s>+ z(0`&?OO0ZTr+q30ii{X?Xvf2nNU`v$x)19>DMBj%^6<7~6%8MB>!9KCr6czOc zc6ImyXy*RSTXlCRonzha$dVD^30k4mjM5&I)ab?Afno_(-Jxy|77$$d;*(rR>Hq2U z?*SNQ(A3N;-WhbiCbSovOHm4Ta?qv8yyj6g7)mp{shhpz(bFfrtBt3dVA>Qa zYKYTlQF0BR1sdj7^S>+YsN6h&S3?%rnG_m|__bXWH^6!iLP;7--D1m5h*K*JVsXM% zkYb>7a{);~+Us=#$C*kACIO>};rW$CWhIm*Yv{;HwmoLW<*( zCo+kW$>dba=m0`Iais#S{w_j68ONFXmSZTYWh7c2mp?qnlq%~aY{QVMan=t2ieaO9 zBn%59ao*{Ai*-V_B0R}3cXj-{aDz*k_3e)vc21ymTJOL97zo)M{flHDx3^|qE_=|$ zVL`j{`!@xzYVt$rR&-}A#o6QarwXBe)U`F;d`|CD4eePKsX%2+HB#)7Zb=B}4W;1~ zGmSKh(dp%|oc)5aqxfH}+ueU?&A_EWQLgWm=0eh`?xym!zAh?uP zx4M619!_tty-#1|xesFe#mCBtMF04o8e7qLcT^gjh6S9SwX|1AXAr*fWCN9fPU5D} zTjcbtJi&iuWeeM?l?LsIbvu-1pj@Vl>@k7e>+VR1g%Fw>js>@*QH{(Xl2P=#(VZk} z=hE`GbX)H><4^l^Gff3id0yBD3`+V*&Iy)V(^vip$Uw7_1s&*_MEIX0nbCx9&POrjec}?}%couO*Vg1% z^3IX~)FNFX1v%MVo0A&N!$hhRK89(xW)`%-zN(?aESuAQ%jD@Lb?xB=y$C>0f%XMX zlCsTHmLUy9>Ih)wpHpkSG)o|f4WV}IDF-s7Fw_x#aIl*T-ZyTD!GG1RmC^MEX=@Ow z&G!H~`4;rl)-DWnWtqT1e<&Mn&B?SfaoH6E^)Tgssj)af$Ot#ica2_YZ^U$bw6kex_&#=a*z8G95B*%>=iGInDR z6Onx@8Kms`KYqRWpEu8&^E{t(?>*<<``mlZ_getVAj@4XUaICK0_OA@#sb|o*VuJO zJbh>0u515Iv%m|XaM*zfG0RDI_LP1iY_uGDkh7qlsMR!O$-_;lVd_>y zlRU7vB7^QzQZ>7x)&;6TLOlY`Pn2htqHeWh(6=cgsqYUZ&6+{HdbwWJ#>TEF6Y&dh zaE+nX8{ldpIx@2PDGa!GT!Ba13c%(1ov2W^X405-zx^y@zYK~4ugF5H`Q_JyglUp; z6uNIaboDNCK1%VI4+=V0h(EScG$DJ|CC-zFN?W8}`^j3wxhZB)`CX7Lc|>&fOLZKa z3m}BdGKo=5Pk;@?Ob~nnI8I+^1w&c06L$4MI;-HxNgS$V=53SXJ9j`OIj1+{^n>K#p1Hn`m9^TnXg?ibiukMvwmxz>4mpp@{=(e{&Q2gr~fywxF0k z71@ghizj+!I(I}=Cu$R%gm{6xWC-iIkMyn4k1;;q{Rj>OM%!xX${7=WUQs+w3u3%& z%S0MIEwY@J{ciO33$4NWpswAtf*bw>_Cbvx37xk0XnsU%ywYO?)`drfE!)XD9m6oT z+_}13G=^E4R=;?o&Z(!7Ff~&c$v;pznh*s5Zvq%P^j8Vo8{r^|v(5frjjs^g(APXt zq)&BU&qFxIpH{ClfPeC^=()lJ(po-#NG~uKC)%7~=wX(~E?qiLD4!z-)&&UPS2FF; zRDyFjlvem=Z2*{C+8Bb*tBc$isk>$}$26bWf_&~t5ffCbk*R8!n@$DBwhk~iv?m0n z`D1H^1fLm`QMGn6OSSmE_@X~TLTHZ_Gt4H6EGI^m$M%#ci+DOFNOw5PCsD;wKeU5M zUGq815sf`!t}Y*m+M8_OaxRtD655`gxjU<^ z_u6YzCe_D6mSVl^3S-Vavx0YDH zO*8$?2Vdwlw@TzQesOZhbn!uSC$FQ)E1K~vusccUUY(N#Ux9T_Og=fyo6o^& zcquY`_@NO~)C*@I8{SF~Sq3Mh6>io&g%@kI- zAWt?B(1OZ+a_wA|KEa;+z@HtoE`GQ1v6HWn0J8UHk}*nc;aPb{pyER_tLS;Ea)txL zj_SHVoOj6BHQCHJ>rFpe0%4~n>`CE5w4~pDlH;tGDFDu^Jztz)=>B();yz65l+^5L z#igu>XlwW(lgzvb?M|63POa8!Crtr%s7efw&~;~cQxD0$Wp|vF(ymZ5oK$TK$s)n> zAK&6#$VMWLG}o3`H{TpMaEvCN(Jn6a`O|KWn8l|(_0hQU=ofShs_d5`;LBZG^z|Qf z!Cm^3Msh}I({F#scXt*>Vy8s@#_8;?B|>W`0d~EH>g};9$KlVs7_T6%ZdG`Q;x+e6 z4hDws+k^nkZJfbH$nwYCT~F00(x?zo(@j2C#OG$7anC6PYw2`Ok=ey>Y6C~)A|h-v zxV^2rGW8S_!x(MbRYtcnwaqx17 z3XZkZc)SpZdQ)+~XaPl1Q;5L%>cyIOz^hmlYmGuySDBSHFr4RD;f3a)kvi#k& zW?Zp0_Ky^QLkI|C1rh5Z0bwMz#_BcXs#iqD1geVwzlOhF%B&1W*uuKHkMyWI6IPSY%Z0p&LGzCx$Z5QKVAI#WyP zmXK@&lBXVxS1K)4Hc!zb&r;UUwMoa*(htDSQ9mhmY zFK6I$m*#Uy&&wsV#>j}qZO4M0mc3W(TGq1_9bZs!axWPbt+QT-qJ}xxNjW4DimpqV zdP5K!oqPqhV?9EjO5aDT#|mi1F)V! zERtDrCg09CyjF*TJq;TBd+D5qmW8mXThDGx;T&RbH;gDn_gsVa8V8*hc_^}AGhl3$ z6rvLu82#(!#!k@uLUkLXb=fTQ3`1{l;&v21(`w{H1GAz@#~5EKPnKgD^RM=Z#&*^L z>5p={y487FYg*q=WqZD2v>Rw|OVk8-DH+CJg;JGv1YlZoSHE4zhKQ7||>Ogs)akS7t zIW)uY;pbH_|8Ha8+1l&ypT7XqtTqy@fCqi`#pUGUYaoF6!rN6gKuuBJCLuQIz``hHnl769uhDY0<+Ylh7X3)u*g&2A)U6sW9DhARb|Mlv z!9#y)?{lIY;hQi`>uDO`xPbq0H+wAF;#aR(8TNe#@xbt$o4yg9g^yjWnuDQYKpKu3 zvHsyRyLS*rWWp-*r$9L{K3FsEec_BWtn%&olx94@W@1CiZoQ1HFC$9#xS_JwzQ<@Q$a1@_U6*nmm7;aDEaz{X_V&P-JqxCQ0I9WNu?Fkb}L&FfBzmP5Oc8Z6)iDlm!oNytKk(aDaQF zfGuM&+5at}>knxNzDScYop)$33R&g<&s`T39=9DnX?9&OR00tEmHE zfJ&(2gYpFbq>oQks8F%#8_(kxjLH2Ol3i4P-lbX7nB(yd@(VW%dnezHdw>e=#otE2Z$}?Jqv|MA3G4B#txT%C zijJr{fvh?{FWD969^;UojDdJ{E{Wll2Ym?!?;Os!P6Gdot$lI_j=;$PfG?M4GE_iW z=cl|Ll*2TvCToa{Z{pF-($%nO9=BD3M$-(@=`pj9(SuJD9)_B6SAyFyR0PC?|z_*GY7Vf-t&Pgw6mzQn_PY9~^g-GH|Do_SHXon3C)G7!k}yiU?lD z2LFv1bjlW1!BK~RXMdAh-^-g#@`DGPWV>%M`uXWS3nF!Xx{3z^)#xJdo)#R(=GCYi z<xjz#IbWiwt$w`1j(MJsV~X^ZzA z-7ANQt~>%*@xYkLr43Bk z$&$<;i^jvf4+nd)W(?i4$;Y>)6E$bM>~l#0B&-!mjk0y{~%lCY|3`RG{>M&KbRAjulM@RPyFq(M9FNv;Tg`AyrQ5 zFq2MsOAXps7fYfV1s6Kj`=-+5^mN=!A)Wf4A6I(Q@ZsNH`RX-5bmLmdfd|lOS7J*} zMh5U`(*hF10Re8Hx2eo3k#Q*>R diff --git a/website/static/img/app_multiverse.png b/website/static/img/app_multiverse.png new file mode 100644 index 0000000000000000000000000000000000000000..c0d80e4f1bf6cec0d95451fe51172cd8e4a36333 GIT binary patch literal 4814 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 literal 0 HcmV?d00001 diff --git a/website/static/img/app_nuke.png b/website/static/img/app_nuke.png index 4b3797af7aea30fb37b43c7d94d91a249da013bf..1465da8ce823d72303087250d3fa74453c13aa83 100644 GIT binary patch literal 32869 zcmb??V|!&y*KKTcY;|ngws!2KW7~Ge>G+O~9e1aL9ox>1ZQJO)dCqS*AF9?>^{H0X zm~+$`bF3IO6+X2vm7FDF6fnB-8&I0^HY(Z(yS5*8|cWAS(g6GRhSEH9&Nc z({qP_K*suCgM`S=#fN|hL6Vme*YwFf&x6;+*1?M^8FD&j_9}~;^T#=Fv|q@=*I3ZR2-3e`(_gns# z_cq0Ul<$5?nIuQ^pGAuN|KHBDAwE7Hw@gpRfReTjIj3MTb5xPb@-C%j{0!R; z;M8aD;5r2FpguJ1p#G}TO#Z-SkW4&*OCwvz#vG+ZiCsS2085XtZy!GL$v=u)ekG

FeTI>>8KOkPC^ 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 literal 25887 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ⅆgv-9FWR6p~| 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 diff --git a/website/static/img/app_nukestudio.png b/website/static/img/app_nukestudio.png new file mode 100644 index 0000000000000000000000000000000000000000..dfc2ad5a9745a5010589f7292a8c16f1097294f6 GIT binary patch literal 37527 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 literal 0 HcmV?d00001 diff --git a/website/static/img/app_royalrender.png b/website/static/img/app_royalrender.png new file mode 100644 index 0000000000000000000000000000000000000000..0e49519227003bcc031b8267315266c7da9e3f9d GIT binary patch literal 11650 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 Date: Fri, 3 Jun 2022 15:04:20 +0200 Subject: [PATCH 325/350] hound fix --- .../event_handlers_server/action_tranfer_hierarchical_values.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/modules/ftrack/event_handlers_server/action_tranfer_hierarchical_values.py b/openpype/modules/ftrack/event_handlers_server/action_tranfer_hierarchical_values.py index 9df3b67969..d160b7200d 100644 --- a/openpype/modules/ftrack/event_handlers_server/action_tranfer_hierarchical_values.py +++ b/openpype/modules/ftrack/event_handlers_server/action_tranfer_hierarchical_values.py @@ -241,7 +241,6 @@ class TransferHierarchicalValues(ServerAction): ) } - # Delete destination custom attributes first if delete_dst_values: self.log.info("Deleting destination custom attribute values first") From 12579501c16120fcea663e97db93f5dfb8dd012c Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 3 Jun 2022 17:37:45 +0200 Subject: [PATCH 326/350] global: fixing color metrix scale argument --- openpype/plugins/publish/extract_review_slate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index a2cbc1b704..01a7b0f592 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -189,7 +189,6 @@ class ExtractReviewSlate(openpype.api.Extractor): # make sure colors are correct output_args.extend([ - "-vf", "scale=out_color_matrix=bt709", "-color_primaries", "bt709", "-color_trc", "bt709", "-colorspace", "bt709", @@ -230,6 +229,7 @@ class ExtractReviewSlate(openpype.api.Extractor): scaling_arg = ( "scale={0}x{1}:flags=lanczos" + ":out_color_matrix=bt709" ",pad={2}:{3}:{4}:{5}:black" ",setsar=1" ",fps={6}" From 248d3bd1a36630adc42d9ca090f73c6557498d1b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 3 Jun 2022 17:38:29 +0200 Subject: [PATCH 327/350] Global: removing duplicate timecode argument - this will be applied at the end in concating stage --- openpype/plugins/publish/extract_review_slate.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 01a7b0f592..cff71f67ac 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -173,7 +173,6 @@ class ExtractReviewSlate(openpype.api.Extractor): self.log.debug("Slate Timecode: `{}`".format( offset_timecode )) - input_args.extend(["-timecode", str(offset_timecode)]) if use_legacy_code: format_args = [] From d1ff95129f447b52c46aa158c24b2c5d9ecac325 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Sat, 4 Jun 2022 03:43:28 +0000 Subject: [PATCH 328/350] [Automated] Bump version --- CHANGELOG.md | 18 ++++++++---------- openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6613985ccf..50cb1d423e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,19 @@ # Changelog -## [3.10.1-nightly.2](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.10.1-nightly.3](https://github.com/pypeclub/OpenPype/tree/HEAD) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.10.0...HEAD) **🚀 Enhancements** - General: Updated windows oiio tool [\#3268](https://github.com/pypeclub/OpenPype/pull/3268) +- Maya: reference loaders could store placeholder in referenced url [\#3264](https://github.com/pypeclub/OpenPype/pull/3264) - TVPaint: Init file for TVPaint worker also handle guideline images [\#3250](https://github.com/pypeclub/OpenPype/pull/3250) - Nuke: Change default icon path in settings [\#3247](https://github.com/pypeclub/OpenPype/pull/3247) **🐛 Bug fixes** +- Webpublisher: return only active projects in ProjectsEndpoint [\#3281](https://github.com/pypeclub/OpenPype/pull/3281) - Nuke: bake reformat was failing on string type [\#3261](https://github.com/pypeclub/OpenPype/pull/3261) - Maya: hotfix Pxr multitexture in looks [\#3260](https://github.com/pypeclub/OpenPype/pull/3260) - Unreal: Fix Camera Loading if Layout is missing [\#3255](https://github.com/pypeclub/OpenPype/pull/3255) @@ -19,9 +21,12 @@ - Unreal: Fixed Render creation in UE5 [\#3239](https://github.com/pypeclub/OpenPype/pull/3239) - Unreal: Fixed Camera loading in UE5 [\#3238](https://github.com/pypeclub/OpenPype/pull/3238) - Flame: debugging [\#3224](https://github.com/pypeclub/OpenPype/pull/3224) +- Ftrack: Push hierarchical attributes action works [\#3210](https://github.com/pypeclub/OpenPype/pull/3210) +- add silent audio to slate [\#3162](https://github.com/pypeclub/OpenPype/pull/3162) **Merged pull requests:** +- Maya: better handling of legacy review subsets names [\#3269](https://github.com/pypeclub/OpenPype/pull/3269) - Nuke: add pointcache and animation to loader [\#3186](https://github.com/pypeclub/OpenPype/pull/3186) ## [3.10.0](https://github.com/pypeclub/OpenPype/tree/3.10.0) (2022-05-26) @@ -49,9 +54,6 @@ - General: Add 'dataclasses' to required python modules [\#3149](https://github.com/pypeclub/OpenPype/pull/3149) - Hooks: Tweak logging grammar [\#3147](https://github.com/pypeclub/OpenPype/pull/3147) - Nuke: settings for reformat node in CreateWriteRender node [\#3143](https://github.com/pypeclub/OpenPype/pull/3143) -- Houdini: Add loader for alembic through Alembic Archive node [\#3140](https://github.com/pypeclub/OpenPype/pull/3140) -- Publisher: UI Modifications and fixes [\#3139](https://github.com/pypeclub/OpenPype/pull/3139) -- General: Simplified OP modules/addons import [\#3137](https://github.com/pypeclub/OpenPype/pull/3137) **🐛 Bug fixes** @@ -64,7 +66,6 @@ - Hiero: debugging frame range and other 3.10 [\#3222](https://github.com/pypeclub/OpenPype/pull/3222) - Project Manager: Fix persistent editors on project change [\#3218](https://github.com/pypeclub/OpenPype/pull/3218) - Deadline: instance data overwrite fix [\#3214](https://github.com/pypeclub/OpenPype/pull/3214) -- Ftrack: Push hierarchical attributes action works [\#3210](https://github.com/pypeclub/OpenPype/pull/3210) - Standalone Publisher: Always create new representation for thumbnail [\#3203](https://github.com/pypeclub/OpenPype/pull/3203) - Photoshop: skip collector when automatic testing [\#3202](https://github.com/pypeclub/OpenPype/pull/3202) - Nuke: render/workfile version sync doesn't work on farm [\#3185](https://github.com/pypeclub/OpenPype/pull/3185) @@ -75,14 +76,9 @@ - General: Oiio conversion for ffmpeg checks for invalid characters [\#3166](https://github.com/pypeclub/OpenPype/pull/3166) - Fix for attaching render to subset [\#3164](https://github.com/pypeclub/OpenPype/pull/3164) - Harmony: fixed missing task name in render instance [\#3163](https://github.com/pypeclub/OpenPype/pull/3163) -- add silent audio to slate [\#3162](https://github.com/pypeclub/OpenPype/pull/3162) - Ftrack: Action delete old versions formatting works [\#3152](https://github.com/pypeclub/OpenPype/pull/3152) -- nuke: adding extract thumbnail settings [\#3148](https://github.com/pypeclub/OpenPype/pull/3148) - Deadline: fix the output directory [\#3144](https://github.com/pypeclub/OpenPype/pull/3144) - General: New Session schema [\#3141](https://github.com/pypeclub/OpenPype/pull/3141) -- General: Missing version on headless mode crash properly [\#3136](https://github.com/pypeclub/OpenPype/pull/3136) -- TVPaint: Composite layers in reversed order [\#3135](https://github.com/pypeclub/OpenPype/pull/3135) -- TVPaint: Composite layers in reversed order [\#3134](https://github.com/pypeclub/OpenPype/pull/3134) **🔀 Refactored code** @@ -93,6 +89,7 @@ - Harmony: message length in 21.1 [\#3257](https://github.com/pypeclub/OpenPype/pull/3257) - Harmony: 21.1 fix [\#3249](https://github.com/pypeclub/OpenPype/pull/3249) - Maya: added jpg to filter for Image Plane Loader [\#3223](https://github.com/pypeclub/OpenPype/pull/3223) +- Maya: added jpg to filter for Image Plane Loader [\#3221](https://github.com/pypeclub/OpenPype/pull/3221) - Webpublisher: replace space by underscore in subset names [\#3160](https://github.com/pypeclub/OpenPype/pull/3160) ## [3.9.8](https://github.com/pypeclub/OpenPype/tree/3.9.8) (2022-05-19) @@ -134,6 +131,7 @@ **🐛 Bug fixes** - Ftrack: Action delete old versions formatting works [\#3154](https://github.com/pypeclub/OpenPype/pull/3154) +- nuke: adding extract thumbnail settings [\#3148](https://github.com/pypeclub/OpenPype/pull/3148) **Merged pull requests:** diff --git a/openpype/version.py b/openpype/version.py index 1d8ef28225..e5dfc2bb8f 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.10.1-nightly.2" +__version__ = "3.10.1-nightly.3" diff --git a/pyproject.toml b/pyproject.toml index 27b32cf53b..7a620aec8f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.10.1-nightly.2" # OpenPype +version = "3.10.1-nightly.3" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From 7b16c6837b1c02defd73fcba984909d085cce61e Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Mon, 6 Jun 2022 17:08:37 +0200 Subject: [PATCH 329/350] refacto code to have simpler menu --- openpype/hosts/nuke/api/gizmo_menu.py | 90 ++++++++------ openpype/hosts/nuke/api/lib.py | 109 ++++++++++------ openpype/hosts/nuke/startup/menu.py | 70 +---------- .../defaults/project_settings/nuke.json | 8 +- .../schemas/schema_nuke_scriptsgizmo.json | 117 +++++++++++++++--- 5 files changed, 222 insertions(+), 172 deletions(-) diff --git a/openpype/hosts/nuke/api/gizmo_menu.py b/openpype/hosts/nuke/api/gizmo_menu.py index dd04f4a42e..7f8121372c 100644 --- a/openpype/hosts/nuke/api/gizmo_menu.py +++ b/openpype/hosts/nuke/api/gizmo_menu.py @@ -1,67 +1,75 @@ import os -import logging +import re import nuke -log = logging.getLogger(__name__) +from openpype.api import Logger + +log = Logger.get_logger(__name__) class GizmoMenu(): - def __init__(self, *args, **kwargs): + def __init__(self, title, icon=None): + + self.toolbar = self._create_toolbar_menu( + title, + icon=icon + ) + self._script_actions = [] - def build_from_configuration(self, parent, configuration): + def _create_toolbar_menu(self, name, icon=None): + nuke_node_menu = nuke.menu("Nodes") + return nuke_node_menu.addMenu( + name, + icon=icon + ) + + def _make_menu_path(self, path, icon=None): + parent = self.toolbar + for folder in re.split(r"/|\\",path): + if not folder: + continue + existing_menu = parent.findItem(folder) + if existing_menu: + parent = existing_menu + else: + parent = parent.addMenu(folder, icon=icon) + + return parent + + def build_from_configuration(self, configuration): for item in configuration: assert isinstance(item, dict), "Configuration is wrong!" - # skip items which have no `type` key - item_type = item.get('type', None) - if not item_type: - log.warning("Missing 'type' from configuration item") - continue + # Construct parent path else parent is toolbar + parent = self.toolbar + gizmo_toolbar_path = item.get("gizmo_toolbar_path") + if gizmo_toolbar_path: + parent = self._make_menu_path(gizmo_toolbar_path) - if item_type == "action": - # filter out `type` from the item dict - config = {key: value for key, value in - item.items() if key != "type"} - - command = str(config['command']) - - icon = config.get('icon', None) - if icon: - try: - icon = icon.format(**os.environ) - except KeyError as e: - log.warning("This environment variable doesn't exist: " - "{}".format(e)) - - hotkey = config.get('hotkey', None) + item_type = item.get("sourcetype") + if item_type == ("python" or "file"): parent.addCommand( - config['title'], - command=command, - icon=icon, - shortcut=hotkey + item['title'], + command=str(item["command"]), + icon=item.get("icon"), + shortcut=item.get('hotkey') ) # add separator # Special behavior for separators - if item_type == "separator": + elif item_type == "separator": parent.addSeparator() # add submenu # items should hold a collection of submenu items (dict) elif item_type == "menu": - assert "items" in item, "Menu is missing 'items' key" - - icon = item.get('icon', None) - if icon: - try: - icon = icon.format(**os.environ) - except KeyError as e: - log.warning("This environment variable doesn't exist: " - "{}".format(e)) - menu = parent.addMenu(item['title'], icon=icon) - self.build_from_configuration(menu, item["items"]) + # assert "items" in item, "Menu is missing 'items' key" + parent.addMenu( + item['title'], + icon=item.get('icon') + ) def add_gizmo_path(self, gizmo_paths): for gizmo_path in gizmo_paths: diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index a1ac50ae1a..335e7190a0 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -2500,50 +2500,77 @@ def recreate_instance(origin_node, avalon_data=None): return new_node -def find_scripts_gizmo(title, parent): - """ - Check if the menu exists with the given title in the parent - - Args: - title (str): the title name of the scripts menu - - parent (QtWidgets.QMenuBar): the menubar to check - - Returns: - QtWidgets.QMenu or None - - """ - - menu = None - search = [i for i in parent.items() if - isinstance(i, gizmo_menu.GizmoMenu) - and i.title() == title] - - if search: - assert len(search) < 2, ("Multiple instances of menu '{}' " - "in toolbar".format(title)) - menu = search[0] - - return menu - - -def gizmo_creation(title="Gizmos", parent=None, objectName=None, icon=None): +def add_scripts_gizmo(): try: - toolbar = find_scripts_gizmo(title, parent) - if not toolbar: - log.info("Attempting to build toolbar...") - object_name = objectName or title.lower() - toolbar = gizmo_menu.GizmoMenu( - title=title, - parent=parent, - objectName=object_name, - icon=icon - ) - except Exception as e: - log.error(e) + from openpype.hosts.nuke.api import lib + except ImportError: + log.warning( + "Skipping studio.gizmo install, because " + "'scriptsgizmo' module seems unavailable." + ) return - return toolbar + # load configuration of custom menu + project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) + platform_name = platform.system().lower() + + for gizmo_settings in project_settings["nuke"]["gizmo"]: + gizmo_list_definition = gizmo_settings["gizmo_definition"] + print(1, gizmo_list_definition) + toolbar_name = gizmo_settings["toolbar_menu_name"] + # gizmo_toolbar_path = gizmo_settings["gizmo_toolbar_path"] + gizmo_source_dir = gizmo_settings.get( + "gizmo_source_dir", {}).get(platform_name) + toolbar_icon_path = gizmo_settings.get( + "toolbar_icon_path", {}).get(platform_name) + + if not gizmo_source_dir: + log.debug("Skipping studio gizmo `{}`, no gizmo path found.".format( + toolbar_name + )) + return + + if not gizmo_list_definition: + log.debug("Skipping studio gizmo `{}`, no definition found.".format( + toolbar_name + )) + return + + if toolbar_icon_path: + try: + toolbar_icon_path = toolbar_icon_path.format(**os.environ) + except KeyError as e: + log.error( + "This environment variable doesn't exist: {}".format(e) + ) + + existing_gizmo_path = [] + for source_dir in gizmo_source_dir: + try: + resolve_source_dir = source_dir.format(**os.environ) + except KeyError as e: + log.error( + "This environment variable doesn't exist: {}".format(e) + ) + continue + if not os.path.exists(resolve_source_dir): + log.warning( + "The source of gizmo `{}` does not exists".format( + resolve_source_dir + ) + ) + continue + existing_gizmo_path.append(resolve_source_dir) + + # run the launcher for Nuke toolbar + toolbar_menu = gizmo_menu.GizmoMenu( + title=toolbar_name, + icon=toolbar_icon_path + ) + + # apply configuration + toolbar_menu.add_gizmo_path(existing_gizmo_path) + toolbar_menu.build_from_configuration(gizmo_list_definition) class NukeDirmap(HostDirmap): diff --git a/openpype/hosts/nuke/startup/menu.py b/openpype/hosts/nuke/startup/menu.py index 715bab8ea5..1461d41385 100644 --- a/openpype/hosts/nuke/startup/menu.py +++ b/openpype/hosts/nuke/startup/menu.py @@ -8,7 +8,8 @@ from openpype.hosts.nuke.api.lib import ( on_script_load, check_inventory_versions, WorkfileSettings, - dirmap_file_name_filter + dirmap_file_name_filter, + add_scripts_gizmo ) from openpype.settings import get_project_settings @@ -60,71 +61,4 @@ def add_scripts_menu(): add_scripts_menu() - -def add_scripts_gizmo(): - try: - from openpype.hosts.nuke.api import lib - except ImportError: - log.warning( - "Skipping studio.gizmo install, because " - "'scriptsgizmo' module seems unavailable." - ) - return - - # load configuration of custom menu - project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) - - for gizmo in project_settings["nuke"]["gizmo"]: - config = gizmo["gizmo_definition"] - toolbar_name = gizmo["toolbar_menu_name"] - gizmo_path = gizmo["gizmo_path"] - icon = gizmo['toolbar_icon_path'] - - if not any(gizmo_path): - log.warning("Skipping studio gizmo, no gizmo path found.") - return - - if not config: - log.warning("Skipping studio gizmo, no definition found.") - return - - try: - icon = icon.format(**os.environ) - except KeyError as e: - log.warning( - "This environment variable doesn't exist: {}".format(e) - ) - - existing_gizmo_path = [] - for gizmo in gizmo_path: - try: - gizmo = gizmo.format(**os.environ) - except KeyError as e: - log.warning( - "This environment variable doesn't exist: {}".format(e) - ) - continue - if not os.path.exists(gizmo): - log.warning( - "The source of gizmo `{}` does not exists".format(gizmo) - ) - continue - existing_gizmo_path.append(gizmo) - - nuke_toolbar = nuke.menu("Nodes") - toolbar = nuke_toolbar.addMenu(toolbar_name, icon=icon) - - # run the launcher for Nuke toolbar - studio_menu = lib.gizmo_creation( - title=toolbar_name, - parent=toolbar, - objectName=toolbar_name.lower().replace(" ", "_"), - icon=icon - ) - - # apply configuration - studio_menu.add_gizmo_path(existing_gizmo_path) - studio_menu.build_from_configuration(toolbar, config) - - add_scripts_gizmo() diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 6c6454de36..63978ad1be 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -293,8 +293,12 @@ "gizmo": [ { "toolbar_menu_name": "OpenPype Gizmo", - "toolbar_icon_path": "path/to/nuke/icon.png", - "gizmo_path": ["path/to/nuke/gizmo"], + "gizmo_path": { + "windows": [], + "darwin": [], + "linux": [] + }, + "toolbar_icon_path": {}, "gizmo_definition": [ { "type": "action", diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsgizmo.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsgizmo.json index c1e67842ce..80fda56175 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsgizmo.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsgizmo.json @@ -14,28 +14,105 @@ }, { "type": "path", - "key": "toolbar_icon_path", - "label": "Toolbar Icon Path", - "multipath": false + "key": "gizmo_source_dir", + "label": "Gizmo directory path", + "multipath": true, + "multiplatform": true }, { - "type": "splitter" - }, - { - "type": "label", - "label": "Absolute path to gizmo folders." - }, - { - "type": "path", - "key": "gizmo_path", - "label": "Gizmo Path", - "multipath": true - }, - { - "type": "raw-json", - "key": "gizmo_definition", - "label": "Gizmo definition", - "is_list": true + "type": "collapsible-wrap", + "label": "Options", + "collapsible": true, + "collapsed": true, + "children": [ + { + "type": "path", + "key": "toolbar_icon_path", + "label": "Toolbar Icon Path", + "multipath": false, + "multiplatform": true + }, + { + "type": "splitter" + }, + { + "type": "list", + "key": "gizmo_definition", + "label": "Gizmo definitions", + "use_label_wrap": true, + "object_type": { + "type": "dict-conditional", + "enum_key": "sourcetype", + "enum_label": "Type of usage", + "enum_children": [ + { + "key": "python", + "label": "Python", + "children": [ + { + "type": "text", + "key": "title", + "label": "Title" + }, + { + "type": "text", + "key": "gizmo_toolbar_path", + "label": "Toolbar path" + }, + { + "type": "text", + "key": "command", + "label": "Python command" + }, + { + "type": "text", + "key": "shortcut", + "label": "Hotkey" + } + ] + }, + { + "key": "file", + "label": "File", + "children": [ + { + "type": "text", + "key": "title", + "label": "Title" + }, + { + "type": "text", + "key": "gizmo_toolbar_path", + "label": "Toolbar path" + }, + { + "type": "text", + "key": "file_name", + "label": "Gizmo file name" + }, + { + "type": "text", + "key": "shortcut", + "label": "Hotkey" + } + + ] + }, + { + "key": "separator", + "label": "Separator", + "children": [ + { + "type": "text", + "key": "gizmo_toolbar_path", + "label": "Toolbar path" + } + ] + } + ] + } + } + ] } ] } From b77cb4ba1a367e5974342e670241d19137fb2a3e Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Mon, 6 Jun 2022 19:17:34 +0200 Subject: [PATCH 330/350] Add global menu from settings --- openpype/hosts/nuke/api/gizmo_menu.py | 52 +++---- openpype/hosts/nuke/api/lib.py | 1 - .../defaults/project_settings/nuke.json | 13 +- .../schemas/schema_nuke_scriptsgizmo.json | 133 +++++++++--------- 4 files changed, 106 insertions(+), 93 deletions(-) diff --git a/openpype/hosts/nuke/api/gizmo_menu.py b/openpype/hosts/nuke/api/gizmo_menu.py index 7f8121372c..42b5812360 100644 --- a/openpype/hosts/nuke/api/gizmo_menu.py +++ b/openpype/hosts/nuke/api/gizmo_menu.py @@ -38,38 +38,42 @@ class GizmoMenu(): return parent def build_from_configuration(self, configuration): - for item in configuration: - assert isinstance(item, dict), "Configuration is wrong!" - + for menu in configuration: # Construct parent path else parent is toolbar parent = self.toolbar - gizmo_toolbar_path = item.get("gizmo_toolbar_path") + gizmo_toolbar_path = menu.get("gizmo_toolbar_path") if gizmo_toolbar_path: parent = self._make_menu_path(gizmo_toolbar_path) - item_type = item.get("sourcetype") + for item in menu["sub_gizmo_list"]: + assert isinstance(item, dict), "Configuration is wrong!" - if item_type == ("python" or "file"): - parent.addCommand( - item['title'], - command=str(item["command"]), - icon=item.get("icon"), - shortcut=item.get('hotkey') - ) + if not item.get("title"): + continue - # add separator - # Special behavior for separators - elif item_type == "separator": - parent.addSeparator() + item_type = item.get("sourcetype") - # add submenu - # items should hold a collection of submenu items (dict) - elif item_type == "menu": - # assert "items" in item, "Menu is missing 'items' key" - parent.addMenu( - item['title'], - icon=item.get('icon') - ) + if item_type == ("python" or "file"): + parent.addCommand( + item["title"], + command=str(item["command"]), + icon=item.get("icon"), + shortcut=item.get("hotkey") + ) + + # add separator + # Special behavior for separators + elif item_type == "separator": + parent.addSeparator() + + # add submenu + # items should hold a collection of submenu items (dict) + elif item_type == "menu": + # assert "items" in item, "Menu is missing 'items' key" + parent.addMenu( + item['title'], + icon=item.get('icon') + ) def add_gizmo_path(self, gizmo_paths): for gizmo_path in gizmo_paths: diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 335e7190a0..0d766c8459 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -2516,7 +2516,6 @@ def add_scripts_gizmo(): for gizmo_settings in project_settings["nuke"]["gizmo"]: gizmo_list_definition = gizmo_settings["gizmo_definition"] - print(1, gizmo_list_definition) toolbar_name = gizmo_settings["toolbar_menu_name"] # gizmo_toolbar_path = gizmo_settings["gizmo_toolbar_path"] gizmo_source_dir = gizmo_settings.get( diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 63978ad1be..c609a0927a 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -301,10 +301,15 @@ "toolbar_icon_path": {}, "gizmo_definition": [ { - "type": "action", - "sourcetype": "python", - "title": "Gizmo Note", - "command": "nuke.nodes.StickyNote(label='You can create your own toolbar menu in the Nuke GizmoMenu of OpenPype')" + "gizmo_toolbar_path": "/path/to/menu", + "sub_gizmo_list": [ + { + "sourcetype": "python", + "title": "Gizmo Note", + "command": "nuke.nodes.StickyNote(label='You can create your own toolbar menu in the Nuke GizmoMenu of OpenPype')", + "shortcut": "" + } + ] } ] } diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsgizmo.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsgizmo.json index 80fda56175..abe14970c5 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsgizmo.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_scriptsgizmo.json @@ -41,73 +41,78 @@ "label": "Gizmo definitions", "use_label_wrap": true, "object_type": { - "type": "dict-conditional", - "enum_key": "sourcetype", - "enum_label": "Type of usage", - "enum_children": [ + "type": "dict", + "children": [ { - "key": "python", - "label": "Python", - "children": [ - { - "type": "text", - "key": "title", - "label": "Title" - }, - { - "type": "text", - "key": "gizmo_toolbar_path", - "label": "Toolbar path" - }, - { - "type": "text", - "key": "command", - "label": "Python command" - }, - { - "type": "text", - "key": "shortcut", - "label": "Hotkey" - } - ] + "type": "text", + "key": "gizmo_toolbar_path", + "label": "Gizmo Menu Path" }, { - "key": "file", - "label": "File", - "children": [ - { - "type": "text", - "key": "title", - "label": "Title" - }, - { - "type": "text", - "key": "gizmo_toolbar_path", - "label": "Toolbar path" - }, - { - "type": "text", - "key": "file_name", - "label": "Gizmo file name" - }, - { - "type": "text", - "key": "shortcut", - "label": "Hotkey" - } - - ] - }, - { - "key": "separator", - "label": "Separator", - "children": [ - { - "type": "text", - "key": "gizmo_toolbar_path", - "label": "Toolbar path" - } - ] + "type": "list", + "key": "sub_gizmo_list", + "label": "Sub Gizmo List", + "use_label_wrap": true, + "object_type": { + "type": "dict-conditional", + "enum_key": "sourcetype", + "enum_label": "Type of usage", + "enum_children": [ + { + "key": "python", + "label": "Python", + "children": [ + { + "type": "text", + "key": "title", + "label": "Title" + }, + { + "type": "text", + "key": "command", + "label": "Python command" + }, + { + "type": "text", + "key": "shortcut", + "label": "Hotkey" + } + ] + }, + { + "key": "file", + "label": "File", + "children": [ + { + "type": "text", + "key": "title", + "label": "Title" + }, + { + "type": "text", + "key": "file_name", + "label": "Gizmo file name" + }, + { + "type": "text", + "key": "shortcut", + "label": "Hotkey" + } + ] + }, + { + "key": "separator", + "label": "Separator", + "children": [ + { + "type": "text", + "key": "gizmo_toolbar_path", + "label": "Toolbar path" + } + ] + } + ] + } } ] } From 25e9ee617e798e14cffb6e2090e1a4dbdb88214c Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Mon, 6 Jun 2022 21:00:24 +0200 Subject: [PATCH 331/350] linter correction --- openpype/hosts/nuke/api/gizmo_menu.py | 2 +- openpype/hosts/nuke/api/lib.py | 20 ++++++-------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/openpype/hosts/nuke/api/gizmo_menu.py b/openpype/hosts/nuke/api/gizmo_menu.py index 42b5812360..0f1a3e03fc 100644 --- a/openpype/hosts/nuke/api/gizmo_menu.py +++ b/openpype/hosts/nuke/api/gizmo_menu.py @@ -26,7 +26,7 @@ class GizmoMenu(): def _make_menu_path(self, path, icon=None): parent = self.toolbar - for folder in re.split(r"/|\\",path): + for folder in re.split(r"/|\\", path): if not folder: continue existing_menu = parent.findItem(folder) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 0d766c8459..2c5989309b 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -2501,14 +2501,6 @@ def recreate_instance(origin_node, avalon_data=None): def add_scripts_gizmo(): - try: - from openpype.hosts.nuke.api import lib - except ImportError: - log.warning( - "Skipping studio.gizmo install, because " - "'scriptsgizmo' module seems unavailable." - ) - return # load configuration of custom menu project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) @@ -2524,15 +2516,15 @@ def add_scripts_gizmo(): "toolbar_icon_path", {}).get(platform_name) if not gizmo_source_dir: - log.debug("Skipping studio gizmo `{}`, no gizmo path found.".format( - toolbar_name - )) + log.debug("Skipping studio gizmo `{}`, " + "no gizmo path found.".format(toolbar_name) + ) return if not gizmo_list_definition: - log.debug("Skipping studio gizmo `{}`, no definition found.".format( - toolbar_name - )) + log.debug("Skipping studio gizmo `{}`, " + "no definition found.".format(toolbar_name) + ) return if toolbar_icon_path: From e2d6d903e99120048d92cb7fbabe42b111df373c Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 7 Jun 2022 11:23:45 +0000 Subject: [PATCH 332/350] docs: update README.md [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b6966adbc4..b8c04f8b49 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -[![All Contributors](https://img.shields.io/badge/all_contributors-26-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-27-orange.svg?style=flat-square)](#contributors-) OpenPype ==== @@ -328,6 +328,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Malthaldar

💻
Sven Neve

💻
zafrs

💻 +
Félix David

💻 📖 From 884fce81ce10c6f31e8738b1e7c6f178787ba9df Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 7 Jun 2022 11:23:46 +0000 Subject: [PATCH 333/350] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index a3b85cae68..b30f3b2499 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -309,7 +309,18 @@ "contributions": [ "code" ] + }, + { + "login": "Tilix4", + "name": "Félix David", + "avatar_url": "https://avatars.githubusercontent.com/u/22875539?v=4", + "profile": "http://felixdavid.com/", + "contributions": [ + "code", + "doc" + ] } ], - "contributorsPerLine": 7 -} \ No newline at end of file + "contributorsPerLine": 7, + "skipCi": true +} From 1819c66e7bed0b3e9af91cf1d408bd91f8adb7b2 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Wed, 8 Jun 2022 03:51:00 +0000 Subject: [PATCH 334/350] [Automated] Bump version --- CHANGELOG.md | 42 +++++++++++++----------------------------- openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 15 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50cb1d423e..1d7798cb48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,19 +1,28 @@ # Changelog -## [3.10.1-nightly.3](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.11.0-nightly.1](https://github.com/pypeclub/OpenPype/tree/HEAD) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.10.0...HEAD) +### 📖 Documentation + +- doc: adding royal render and multiverse to the web site [\#3285](https://github.com/pypeclub/OpenPype/pull/3285) + **🚀 Enhancements** - General: Updated windows oiio tool [\#3268](https://github.com/pypeclub/OpenPype/pull/3268) +- Unreal: add support for skeletalMesh and staticMesh to loaders [\#3267](https://github.com/pypeclub/OpenPype/pull/3267) - Maya: reference loaders could store placeholder in referenced url [\#3264](https://github.com/pypeclub/OpenPype/pull/3264) - TVPaint: Init file for TVPaint worker also handle guideline images [\#3250](https://github.com/pypeclub/OpenPype/pull/3250) - Nuke: Change default icon path in settings [\#3247](https://github.com/pypeclub/OpenPype/pull/3247) **🐛 Bug fixes** +- Global: extract review slate issues [\#3286](https://github.com/pypeclub/OpenPype/pull/3286) - Webpublisher: return only active projects in ProjectsEndpoint [\#3281](https://github.com/pypeclub/OpenPype/pull/3281) +- Hiero: add support for task tags 3.10.x [\#3279](https://github.com/pypeclub/OpenPype/pull/3279) +- General: Fix Oiio tool path resolving [\#3278](https://github.com/pypeclub/OpenPype/pull/3278) +- Maya: Fix udim support for e.g. uppercase \ tag [\#3266](https://github.com/pypeclub/OpenPype/pull/3266) - Nuke: bake reformat was failing on string type [\#3261](https://github.com/pypeclub/OpenPype/pull/3261) - Maya: hotfix Pxr multitexture in looks [\#3260](https://github.com/pypeclub/OpenPype/pull/3260) - Unreal: Fix Camera Loading if Layout is missing [\#3255](https://github.com/pypeclub/OpenPype/pull/3255) @@ -21,13 +30,14 @@ - Unreal: Fixed Render creation in UE5 [\#3239](https://github.com/pypeclub/OpenPype/pull/3239) - Unreal: Fixed Camera loading in UE5 [\#3238](https://github.com/pypeclub/OpenPype/pull/3238) - Flame: debugging [\#3224](https://github.com/pypeclub/OpenPype/pull/3224) -- Ftrack: Push hierarchical attributes action works [\#3210](https://github.com/pypeclub/OpenPype/pull/3210) - add silent audio to slate [\#3162](https://github.com/pypeclub/OpenPype/pull/3162) **Merged pull requests:** - Maya: better handling of legacy review subsets names [\#3269](https://github.com/pypeclub/OpenPype/pull/3269) +- Deadline: publishing of animation and pointcache on a farm [\#3225](https://github.com/pypeclub/OpenPype/pull/3225) - Nuke: add pointcache and animation to loader [\#3186](https://github.com/pypeclub/OpenPype/pull/3186) +- Add a gizmo menu to nuke [\#3172](https://github.com/pypeclub/OpenPype/pull/3172) ## [3.10.0](https://github.com/pypeclub/OpenPype/tree/3.10.0) (2022-05-26) @@ -37,7 +47,6 @@ - General: OpenPype modules publish plugins are registered in host [\#3180](https://github.com/pypeclub/OpenPype/pull/3180) - General: Creator plugins from addons can be registered [\#3179](https://github.com/pypeclub/OpenPype/pull/3179) -- Ftrack: Single image reviewable [\#3157](https://github.com/pypeclub/OpenPype/pull/3157) **🚀 Enhancements** @@ -50,10 +59,6 @@ - Maya: added clean\_import option to Import loader [\#3181](https://github.com/pypeclub/OpenPype/pull/3181) - Add the scripts menu definition to nuke [\#3168](https://github.com/pypeclub/OpenPype/pull/3168) - Maya: add maya 2023 to default applications [\#3167](https://github.com/pypeclub/OpenPype/pull/3167) -- Compressed bgeo publishing in SAP and Houdini loader [\#3153](https://github.com/pypeclub/OpenPype/pull/3153) -- General: Add 'dataclasses' to required python modules [\#3149](https://github.com/pypeclub/OpenPype/pull/3149) -- Hooks: Tweak logging grammar [\#3147](https://github.com/pypeclub/OpenPype/pull/3147) -- Nuke: settings for reformat node in CreateWriteRender node [\#3143](https://github.com/pypeclub/OpenPype/pull/3143) **🐛 Bug fixes** @@ -66,6 +71,7 @@ - Hiero: debugging frame range and other 3.10 [\#3222](https://github.com/pypeclub/OpenPype/pull/3222) - Project Manager: Fix persistent editors on project change [\#3218](https://github.com/pypeclub/OpenPype/pull/3218) - Deadline: instance data overwrite fix [\#3214](https://github.com/pypeclub/OpenPype/pull/3214) +- Ftrack: Push hierarchical attributes action works [\#3210](https://github.com/pypeclub/OpenPype/pull/3210) - Standalone Publisher: Always create new representation for thumbnail [\#3203](https://github.com/pypeclub/OpenPype/pull/3203) - Photoshop: skip collector when automatic testing [\#3202](https://github.com/pypeclub/OpenPype/pull/3202) - Nuke: render/workfile version sync doesn't work on farm [\#3185](https://github.com/pypeclub/OpenPype/pull/3185) @@ -76,9 +82,6 @@ - General: Oiio conversion for ffmpeg checks for invalid characters [\#3166](https://github.com/pypeclub/OpenPype/pull/3166) - Fix for attaching render to subset [\#3164](https://github.com/pypeclub/OpenPype/pull/3164) - Harmony: fixed missing task name in render instance [\#3163](https://github.com/pypeclub/OpenPype/pull/3163) -- Ftrack: Action delete old versions formatting works [\#3152](https://github.com/pypeclub/OpenPype/pull/3152) -- Deadline: fix the output directory [\#3144](https://github.com/pypeclub/OpenPype/pull/3144) -- General: New Session schema [\#3141](https://github.com/pypeclub/OpenPype/pull/3141) **🔀 Refactored code** @@ -89,7 +92,6 @@ - Harmony: message length in 21.1 [\#3257](https://github.com/pypeclub/OpenPype/pull/3257) - Harmony: 21.1 fix [\#3249](https://github.com/pypeclub/OpenPype/pull/3249) - Maya: added jpg to filter for Image Plane Loader [\#3223](https://github.com/pypeclub/OpenPype/pull/3223) -- Maya: added jpg to filter for Image Plane Loader [\#3221](https://github.com/pypeclub/OpenPype/pull/3221) - Webpublisher: replace space by underscore in subset names [\#3160](https://github.com/pypeclub/OpenPype/pull/3160) ## [3.9.8](https://github.com/pypeclub/OpenPype/tree/3.9.8) (2022-05-19) @@ -119,24 +121,6 @@ [Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.9.6...3.9.7) -**🆕 New features** - -- Ftrack: Single image reviewable [\#3158](https://github.com/pypeclub/OpenPype/pull/3158) - -**🚀 Enhancements** - -- Deadline output dir issue to 3.9x [\#3155](https://github.com/pypeclub/OpenPype/pull/3155) -- nuke: removing redundant code from startup [\#3142](https://github.com/pypeclub/OpenPype/pull/3142) - -**🐛 Bug fixes** - -- Ftrack: Action delete old versions formatting works [\#3154](https://github.com/pypeclub/OpenPype/pull/3154) -- nuke: adding extract thumbnail settings [\#3148](https://github.com/pypeclub/OpenPype/pull/3148) - -**Merged pull requests:** - -- Webpublisher: replace space by underscore in subset names [\#3159](https://github.com/pypeclub/OpenPype/pull/3159) - ## [3.9.6](https://github.com/pypeclub/OpenPype/tree/3.9.6) (2022-05-03) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.9.5...3.9.6) diff --git a/openpype/version.py b/openpype/version.py index e5dfc2bb8f..4c78a6e0a1 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.10.1-nightly.3" +__version__ = "3.11.0-nightly.1" diff --git a/pyproject.toml b/pyproject.toml index 5649ff2073..362f6a62d8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.10.1-nightly.3" # OpenPype +version = "3.11.0-nightly.1" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From 24cb024dd9d27e5c68fcd6f7d9097297031d7845 Mon Sep 17 00:00:00 2001 From: Felix Wang Date: Wed, 8 Jun 2022 00:45:15 -0700 Subject: [PATCH 335/350] Maya: Look assigner UI improvements (#3208) Co-authored-by: felix.wang --- openpype/hosts/maya/api/lib.py | 5 ++++- openpype/tools/utils/host_tools.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 088304ab05..bce03a648b 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -1737,8 +1737,11 @@ def apply_shaders(relationships, shadernodes, nodes): log.warning("No nodes found for shading engine " "'{0}'".format(id_shading_engines[0])) continue + try: + cmds.sets(filtered_nodes, forceElement=id_shading_engines[0]) + except RuntimeError as rte: + log.error("Error during shader assignment: {}".format(rte)) - cmds.sets(filtered_nodes, forceElement=id_shading_engines[0]) # endregion apply_attributes(attributes, nodes_by_id) diff --git a/openpype/tools/utils/host_tools.py b/openpype/tools/utils/host_tools.py index d8f4570120..9dbbe25fda 100644 --- a/openpype/tools/utils/host_tools.py +++ b/openpype/tools/utils/host_tools.py @@ -105,6 +105,7 @@ class HostToolsHelper: loader_tool.show() loader_tool.raise_() loader_tool.activateWindow() + loader_tool.showNormal() if use_context is None: use_context = False @@ -180,6 +181,7 @@ class HostToolsHelper: # Pull window to the front. scene_inventory_tool.raise_() scene_inventory_tool.activateWindow() + scene_inventory_tool.showNormal() def get_library_loader_tool(self, parent): """Create, cache and return library loader tool window.""" @@ -200,8 +202,10 @@ class HostToolsHelper: library_loader_tool.show() library_loader_tool.raise_() library_loader_tool.activateWindow() + library_loader_tool.showNormal() library_loader_tool.refresh() + def show_publish(self, parent=None): """Try showing the most desirable publish GUI @@ -243,6 +247,11 @@ class HostToolsHelper: look_assigner_tool = self.get_look_assigner_tool(parent) look_assigner_tool.show() + # Pull window to the front. + look_assigner_tool.raise_() + look_assigner_tool.activateWindow() + look_assigner_tool.showNormal() + def get_experimental_tools_dialog(self, parent=None): """Dialog of experimental tools. @@ -270,6 +279,7 @@ class HostToolsHelper: dialog.show() dialog.raise_() dialog.activateWindow() + dialog.showNormal() def get_tool_by_name(self, tool_name, parent=None, *args, **kwargs): """Show tool by it's name. From 964504eb7706eaf2f0ac9013f31a72192c840845 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Wed, 8 Jun 2022 10:23:43 +0200 Subject: [PATCH 336/350] add app key to documentation --- website/docs/admin_settings_project_anatomy.md | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/admin_settings_project_anatomy.md b/website/docs/admin_settings_project_anatomy.md index b98819cd8a..6e0b49f152 100644 --- a/website/docs/admin_settings_project_anatomy.md +++ b/website/docs/admin_settings_project_anatomy.md @@ -67,6 +67,7 @@ We have a few required anatomy templates for OpenPype to work properly, however | `ext` | File extension | | `representation` | Representation name | | `frame` | Frame number for sequence files. | +| `app` | Application Name | | `output` | | | `comment` | | From 016baf166b1646c06cb8b1c7b40d6ccb9a5be2e1 Mon Sep 17 00:00:00 2001 From: DMO Date: Wed, 8 Jun 2022 18:45:31 +0900 Subject: [PATCH 337/350] Renaming `usdX` families to `mvUsdX`, that is `usd`->`mvUsd`, `usdComposition`->`mvUsdComposition`, `usdOverride`->`usdOverride`, specifically within multiverse files. I have left the `usd` family in `integrate_new.py` because that is being used in a bunch of different places (eg: houdini's host integration), and have just added `mvUsd` as a new family. --- .../hosts/maya/plugins/create/create_multiverse_usd.py | 4 ++-- .../maya/plugins/create/create_multiverse_usd_comp.py | 4 ++-- .../maya/plugins/create/create_multiverse_usd_over.py | 4 ++-- openpype/hosts/maya/plugins/load/load_multiverse_usd.py | 2 +- .../hosts/maya/plugins/publish/extract_multiverse_usd.py | 2 +- .../maya/plugins/publish/extract_multiverse_usd_comp.py | 2 +- .../maya/plugins/publish/extract_multiverse_usd_over.py | 2 +- openpype/plugins/publish/integrate_new.py | 7 ++++--- 8 files changed, 14 insertions(+), 13 deletions(-) diff --git a/openpype/hosts/maya/plugins/create/create_multiverse_usd.py b/openpype/hosts/maya/plugins/create/create_multiverse_usd.py index a82a73cbdb..034714d51b 100644 --- a/openpype/hosts/maya/plugins/create/create_multiverse_usd.py +++ b/openpype/hosts/maya/plugins/create/create_multiverse_usd.py @@ -4,9 +4,9 @@ from openpype.hosts.maya.api import plugin, lib class CreateMultiverseUsd(plugin.Creator): """Create Multiverse USD Asset""" - name = "usdMain" + name = "mvUsdMain" label = "Multiverse USD Asset" - family = "usd" + family = "mvUsd" icon = "cubes" def __init__(self, *args, **kwargs): diff --git a/openpype/hosts/maya/plugins/create/create_multiverse_usd_comp.py b/openpype/hosts/maya/plugins/create/create_multiverse_usd_comp.py index 9d00ad1cfa..ed466a8068 100644 --- a/openpype/hosts/maya/plugins/create/create_multiverse_usd_comp.py +++ b/openpype/hosts/maya/plugins/create/create_multiverse_usd_comp.py @@ -4,9 +4,9 @@ from openpype.hosts.maya.api import plugin, lib class CreateMultiverseUsdComp(plugin.Creator): """Create Multiverse USD Composition""" - name = "usdCompositionMain" + name = "mvUsdCompositionMain" label = "Multiverse USD Composition" - family = "usdComposition" + family = "mvUsdComposition" icon = "cubes" def __init__(self, *args, **kwargs): diff --git a/openpype/hosts/maya/plugins/create/create_multiverse_usd_over.py b/openpype/hosts/maya/plugins/create/create_multiverse_usd_over.py index 9477cd7fed..06e22df295 100644 --- a/openpype/hosts/maya/plugins/create/create_multiverse_usd_over.py +++ b/openpype/hosts/maya/plugins/create/create_multiverse_usd_over.py @@ -4,9 +4,9 @@ from openpype.hosts.maya.api import plugin, lib class CreateMultiverseUsdOver(plugin.Creator): """Create Multiverse USD Override""" - name = "usdOverrideMain" + name = "mvUsdOverrideMain" label = "Multiverse USD Override" - family = "usdOverride" + family = "mvUsdOverride" icon = "cubes" def __init__(self, *args, **kwargs): diff --git a/openpype/hosts/maya/plugins/load/load_multiverse_usd.py b/openpype/hosts/maya/plugins/load/load_multiverse_usd.py index ed0ffc8ef1..3350dc6ac9 100644 --- a/openpype/hosts/maya/plugins/load/load_multiverse_usd.py +++ b/openpype/hosts/maya/plugins/load/load_multiverse_usd.py @@ -16,7 +16,7 @@ from openpype.hosts.maya.api.pipeline import containerise class MultiverseUsdLoader(load.LoaderPlugin): """Read USD data in a Multiverse Compound""" - families = ["model", "usd", "usdComposition", "usdOverride", + families = ["model", "mvUsd", "mvUsdComposition", "mvUsdOverride", "pointcache", "animation"] representations = ["usd", "usda", "usdc", "usdz", "abc"] diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py index b1aaf9d9ba..3654be7b34 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py @@ -26,7 +26,7 @@ class ExtractMultiverseUsd(openpype.api.Extractor): label = "Extract Multiverse USD Asset" hosts = ["maya"] - families = ["usd"] + families = ["mvUsd"] scene_type = "usd" file_formats = ["usd", "usda", "usdz"] diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py index c85b3b6664..ad9303657f 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py @@ -25,7 +25,7 @@ class ExtractMultiverseUsdComposition(openpype.api.Extractor): label = "Extract Multiverse USD Composition" hosts = ["maya"] - families = ["usdComposition"] + families = ["mvUsdComposition"] scene_type = "usd" # Order of `fileFormat` must match create_multiverse_usd_comp.py file_formats = ["usda", "usd"] diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py index 4856f0cfdb..d44e3878b8 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py @@ -23,7 +23,7 @@ class ExtractMultiverseUsdOverride(openpype.api.Extractor): label = "Extract Multiverse USD Override" hosts = ["maya"] - families = ["usdOverride"] + families = ["mvUsdOverride"] scene_type = "usd" # Order of `fileFormat` must match create_multiverse_usd_over.py file_formats = ["usda", "usd"] diff --git a/openpype/plugins/publish/integrate_new.py b/openpype/plugins/publish/integrate_new.py index 4712c2e6bb..59b80f5cc1 100644 --- a/openpype/plugins/publish/integrate_new.py +++ b/openpype/plugins/publish/integrate_new.py @@ -106,12 +106,13 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): "effect", "xgen", "hda", - "mvLook", "usd", "staticMesh", "skeletalMesh", - "usdComposition", - "usdOverride", + "mvLook", + "mvUsd", + "mvUsdComposition", + "mvUsdOverride", "simpleUnrealTexture" ] exclude_families = ["clip", "render.farm"] From eba5691a2db74da0ff994299d9c252f03dcea021 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 8 Jun 2022 13:23:14 +0200 Subject: [PATCH 338/350] use width for width and height for height in maya render --- openpype/hosts/maya/plugins/publish/collect_render.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_render.py b/openpype/hosts/maya/plugins/publish/collect_render.py index fbd2e81279..8b911a867d 100644 --- a/openpype/hosts/maya/plugins/publish/collect_render.py +++ b/openpype/hosts/maya/plugins/publish/collect_render.py @@ -340,10 +340,10 @@ class CollectMayaRender(pyblish.api.ContextPlugin): "expectedFiles": full_exp_files, "publishRenderMetadataFolder": common_publish_meta_path, "resolutionWidth": lib.get_attr_in_layer( - "defaultResolution.height", layer=layer_name + "defaultResolution.width", layer=layer_name ), "resolutionHeight": lib.get_attr_in_layer( - "defaultResolution.width", layer=layer_name + "defaultResolution.height", layer=layer_name ), "pixelAspect": lib.get_attr_in_layer( "defaultResolution.pixelAspect", layer=layer_name From a45795526698b9a668df876a01ce002a5a05024f Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 8 Jun 2022 13:33:26 +0200 Subject: [PATCH 339/350] add missing default settings for nuke gizmo --- .../defaults/project_settings/nuke.json | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index c609a0927a..16348bec85 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -27,6 +27,34 @@ } ] }, + "gizmo": [ + { + "toolbar_menu_name": "OpenPype Gizmo", + "gizmo_source_dir": { + "windows": [], + "darwin": [], + "linux": [] + }, + "toolbar_icon_path": { + "windows": "", + "darwin": "", + "linux": "" + }, + "gizmo_definition": [ + { + "gizmo_toolbar_path": "/path/to/menu", + "sub_gizmo_list": [ + { + "sourcetype": "python", + "title": "Gizmo Note", + "command": "nuke.nodes.StickyNote(label='You can create your own toolbar menu in the Nuke GizmoMenu of OpenPype')", + "shortcut": "" + } + ] + } + ] + } + ], "create": { "CreateWriteRender": { "fpath_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}", @@ -290,29 +318,5 @@ } ] }, - "gizmo": [ - { - "toolbar_menu_name": "OpenPype Gizmo", - "gizmo_path": { - "windows": [], - "darwin": [], - "linux": [] - }, - "toolbar_icon_path": {}, - "gizmo_definition": [ - { - "gizmo_toolbar_path": "/path/to/menu", - "sub_gizmo_list": [ - { - "sourcetype": "python", - "title": "Gizmo Note", - "command": "nuke.nodes.StickyNote(label='You can create your own toolbar menu in the Nuke GizmoMenu of OpenPype')", - "shortcut": "" - } - ] - } - ] - } - ], "filters": {} -} +} \ No newline at end of file From 56a3dae94b39ce90e5afc701ae8efb3aa130896e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 8 Jun 2022 14:46:16 +0200 Subject: [PATCH 340/350] Fix - added local targets to install host By default when host is started, it should register targets to 'local', only if specific env var is set (OPENPYPE_REMOTE_PUBLISH) it should be 'remote'. This means farm is using host to collect/validate/extract and publish on behalf of artist. --- openpype/hosts/maya/api/pipeline.py | 2 +- .../publish/submit_maya_remote_publish_deadline.py | 2 +- openpype/pipeline/context_tools.py | 8 ++++++++ openpype/plugin.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/api/pipeline.py b/openpype/hosts/maya/api/pipeline.py index 0261694be2..836445a970 100644 --- a/openpype/hosts/maya/api/pipeline.py +++ b/openpype/hosts/maya/api/pipeline.py @@ -66,7 +66,7 @@ def install(): log.info("Installing callbacks ... ") register_event_callback("init", on_init) - if os.environ.get("HEADLESS_PUBLISH"): + if os.environ.get("OPENPYPE_REMOTE_PUBLISH"): # Maya launched on farm, lib.IS_HEADLESS might be triggered locally too # target "farm" == rendering on farm, expects OPENPYPE_PUBLISH_DATA # target "remote" == remote execution diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py index c31052be07..4f82818d6d 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py @@ -115,7 +115,7 @@ class MayaSubmitRemotePublishDeadline(openpype.api.Integrator): environment["OPENPYPE_REMOTE_JOB"] = "1" environment["OPENPYPE_USERNAME"] = instance.context.data["user"] environment["OPENPYPE_PUBLISH_SUBSET"] = instance.data["subset"] - environment["HEADLESS_PUBLISH"] = "1" + environment["OPENPYPE_REMOTE_PUBLISH"] = "1" payload["JobInfo"].update({ "EnvironmentKeyValue%d" % index: "{key}={value}".format( diff --git a/openpype/pipeline/context_tools.py b/openpype/pipeline/context_tools.py index e849f5b0d1..c6e09cfba1 100644 --- a/openpype/pipeline/context_tools.py +++ b/openpype/pipeline/context_tools.py @@ -104,6 +104,14 @@ def install_host(host): MessageHandler.emit = modified_emit + if os.environ.get("OPENPYPE_REMOTE_PUBLISH"): + # target "farm" == rendering on farm, expects OPENPYPE_PUBLISH_DATA + # target "remote" == remote execution, installs host + print("Registering pyblish target: remote") + pyblish.api.register_target("remote") + else: + pyblish.api.register_target("local") + install_openpype_plugins() diff --git a/openpype/plugin.py b/openpype/plugin.py index f1ee626ffb..6637ad1d8b 100644 --- a/openpype/plugin.py +++ b/openpype/plugin.py @@ -23,7 +23,7 @@ class Integrator(InstancePlugin): Wraps pyblish instance plugin. Targets set to "local" which means all integrators should run on "local" publishes, by default. - "farm" targets could be used for integrators that should run on a farm. + "remote" targets could be used for integrators that should run externally. """ targets = ["local"] From a63299d57e8856408ec9a2eeb6fe60ebb57483e2 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 8 Jun 2022 15:00:54 +0200 Subject: [PATCH 341/350] Removed explicit targets registering install_host registers targets implicitly for all hosts --- openpype/hosts/maya/api/pipeline.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/openpype/hosts/maya/api/pipeline.py b/openpype/hosts/maya/api/pipeline.py index 836445a970..d9276ddf4a 100644 --- a/openpype/hosts/maya/api/pipeline.py +++ b/openpype/hosts/maya/api/pipeline.py @@ -66,23 +66,12 @@ def install(): log.info("Installing callbacks ... ") register_event_callback("init", on_init) - if os.environ.get("OPENPYPE_REMOTE_PUBLISH"): - # Maya launched on farm, lib.IS_HEADLESS might be triggered locally too - # target "farm" == rendering on farm, expects OPENPYPE_PUBLISH_DATA - # target "remote" == remote execution - print("Registering pyblish target: remote") - pyblish.api.register_target("remote") - return - if lib.IS_HEADLESS: log.info(("Running in headless mode, skipping Maya " "save/open/new callback installation..")) return - print("Registering pyblish target: local") - pyblish.api.register_target("local") - _set_project() _register_callbacks() From 5f3395683ac38bbb01d16880a1e063b0f9f39554 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 8 Jun 2022 16:02:08 +0200 Subject: [PATCH 342/350] added 'requests' and its dependencies into python 2 vendor --- .../python/python_2/chardet/__init__.py | 83 + .../python/python_2/chardet/big5freq.py | 386 + .../python/python_2/chardet/big5prober.py | 47 + .../python_2/chardet/chardistribution.py | 233 + .../python_2/chardet/charsetgroupprober.py | 107 + .../python/python_2/chardet/charsetprober.py | 145 + .../python/python_2/chardet/cli/__init__.py | 1 + .../python/python_2/chardet/cli/chardetect.py | 84 + .../python_2/chardet/codingstatemachine.py | 88 + .../vendor/python/python_2/chardet/compat.py | 36 + .../python/python_2/chardet/cp949prober.py | 49 + .../vendor/python/python_2/chardet/enums.py | 76 + .../python/python_2/chardet/escprober.py | 101 + .../vendor/python/python_2/chardet/escsm.py | 246 + .../python/python_2/chardet/eucjpprober.py | 92 + .../python/python_2/chardet/euckrfreq.py | 195 + .../python/python_2/chardet/euckrprober.py | 47 + .../python/python_2/chardet/euctwfreq.py | 387 + .../python/python_2/chardet/euctwprober.py | 46 + .../python/python_2/chardet/gb2312freq.py | 283 + .../python/python_2/chardet/gb2312prober.py | 46 + .../python/python_2/chardet/hebrewprober.py | 292 + .../vendor/python/python_2/chardet/jisfreq.py | 325 + .../vendor/python/python_2/chardet/jpcntx.py | 233 + .../python_2/chardet/langbulgarianmodel.py | 4650 +++++++++ .../python/python_2/chardet/langgreekmodel.py | 4398 +++++++++ .../python_2/chardet/langhebrewmodel.py | 4383 +++++++++ .../python_2/chardet/langhungarianmodel.py | 4650 +++++++++ .../python_2/chardet/langrussianmodel.py | 5718 +++++++++++ .../python/python_2/chardet/langthaimodel.py | 4383 +++++++++ .../python_2/chardet/langturkishmodel.py | 4383 +++++++++ .../python/python_2/chardet/latin1prober.py | 145 + .../python_2/chardet/mbcharsetprober.py | 91 + .../python_2/chardet/mbcsgroupprober.py | 54 + .../vendor/python/python_2/chardet/mbcssm.py | 572 ++ .../python_2/chardet/metadata/__init__.py | 0 .../python_2/chardet/metadata/languages.py | 310 + .../python_2/chardet/sbcharsetprober.py | 145 + .../python_2/chardet/sbcsgroupprober.py | 83 + .../python/python_2/chardet/sjisprober.py | 92 + .../python_2/chardet/universaldetector.py | 286 + .../python/python_2/chardet/utf8prober.py | 82 + .../vendor/python/python_2/chardet/version.py | 9 + .../vendor/python/python_2/idna/__init__.py | 2 + openpype/vendor/python/python_2/idna/codec.py | 118 + .../vendor/python/python_2/idna/compat.py | 12 + openpype/vendor/python/python_2/idna/core.py | 400 + .../vendor/python/python_2/idna/idnadata.py | 2050 ++++ .../vendor/python/python_2/idna/intranges.py | 53 + .../python/python_2/idna/package_data.py | 2 + .../vendor/python/python_2/idna/uts46data.py | 8357 +++++++++++++++++ .../python/python_2/requests/__init__.py | 152 + .../python/python_2/requests/__version__.py | 14 + .../python_2/requests/_internal_utils.py | 42 + .../python/python_2/requests/adapters.py | 538 ++ .../vendor/python/python_2/requests/api.py | 159 + .../vendor/python/python_2/requests/auth.py | 305 + .../vendor/python/python_2/requests/certs.py | 18 + .../vendor/python/python_2/requests/compat.py | 81 + .../python/python_2/requests/cookies.py | 549 ++ .../python/python_2/requests/exceptions.py | 133 + .../vendor/python/python_2/requests/help.py | 135 + .../vendor/python/python_2/requests/hooks.py | 34 + .../vendor/python/python_2/requests/models.py | 973 ++ .../python/python_2/requests/packages.py | 26 + .../python/python_2/requests/sessions.py | 771 ++ .../python/python_2/requests/status_codes.py | 123 + .../python/python_2/requests/structures.py | 105 + .../vendor/python/python_2/requests/utils.py | 1060 +++ .../python/python_2/urllib3/__init__.py | 85 + .../python/python_2/urllib3/_collections.py | 337 + .../python/python_2/urllib3/_version.py | 2 + .../python/python_2/urllib3/connection.py | 567 ++ .../python/python_2/urllib3/connectionpool.py | 1108 +++ .../python_2/urllib3/contrib/__init__.py | 0 .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../contrib/_securetransport/bindings.py | 519 + .../contrib/_securetransport/low_level.py | 397 + .../python_2/urllib3/contrib/appengine.py | 314 + .../python_2/urllib3/contrib/ntlmpool.py | 130 + .../python_2/urllib3/contrib/pyopenssl.py | 511 + .../urllib3/contrib/securetransport.py | 922 ++ .../python/python_2/urllib3/contrib/socks.py | 216 + .../python/python_2/urllib3/exceptions.py | 323 + .../vendor/python/python_2/urllib3/fields.py | 274 + .../python/python_2/urllib3/filepost.py | 98 + .../python_2/urllib3/packages/__init__.py | 0 .../urllib3/packages/backports/__init__.py | 0 .../urllib3/packages/backports/makefile.py | 51 + .../python/python_2/urllib3/packages/six.py | 1077 +++ .../python/python_2/urllib3/poolmanager.py | 537 ++ .../vendor/python/python_2/urllib3/request.py | 170 + .../python/python_2/urllib3/response.py | 824 ++ .../python/python_2/urllib3/util/__init__.py | 49 + .../python_2/urllib3/util/connection.py | 149 + .../python/python_2/urllib3/util/proxy.py | 57 + .../python/python_2/urllib3/util/queue.py | 22 + .../python/python_2/urllib3/util/request.py | 146 + .../python/python_2/urllib3/util/response.py | 107 + .../python/python_2/urllib3/util/retry.py | 620 ++ .../python/python_2/urllib3/util/ssl_.py | 495 + .../urllib3/util/ssl_match_hostname.py | 159 + .../python_2/urllib3/util/ssltransport.py | 221 + .../python/python_2/urllib3/util/timeout.py | 268 + .../python/python_2/urllib3/util/url.py | 432 + .../python/python_2/urllib3/util/wait.py | 153 + 107 files changed, 65650 insertions(+) create mode 100644 openpype/vendor/python/python_2/chardet/__init__.py create mode 100644 openpype/vendor/python/python_2/chardet/big5freq.py create mode 100644 openpype/vendor/python/python_2/chardet/big5prober.py create mode 100644 openpype/vendor/python/python_2/chardet/chardistribution.py create mode 100644 openpype/vendor/python/python_2/chardet/charsetgroupprober.py create mode 100644 openpype/vendor/python/python_2/chardet/charsetprober.py create mode 100644 openpype/vendor/python/python_2/chardet/cli/__init__.py create mode 100644 openpype/vendor/python/python_2/chardet/cli/chardetect.py create mode 100644 openpype/vendor/python/python_2/chardet/codingstatemachine.py create mode 100644 openpype/vendor/python/python_2/chardet/compat.py create mode 100644 openpype/vendor/python/python_2/chardet/cp949prober.py create mode 100644 openpype/vendor/python/python_2/chardet/enums.py create mode 100644 openpype/vendor/python/python_2/chardet/escprober.py create mode 100644 openpype/vendor/python/python_2/chardet/escsm.py create mode 100644 openpype/vendor/python/python_2/chardet/eucjpprober.py create mode 100644 openpype/vendor/python/python_2/chardet/euckrfreq.py create mode 100644 openpype/vendor/python/python_2/chardet/euckrprober.py create mode 100644 openpype/vendor/python/python_2/chardet/euctwfreq.py create mode 100644 openpype/vendor/python/python_2/chardet/euctwprober.py create mode 100644 openpype/vendor/python/python_2/chardet/gb2312freq.py create mode 100644 openpype/vendor/python/python_2/chardet/gb2312prober.py create mode 100644 openpype/vendor/python/python_2/chardet/hebrewprober.py create mode 100644 openpype/vendor/python/python_2/chardet/jisfreq.py create mode 100644 openpype/vendor/python/python_2/chardet/jpcntx.py create mode 100644 openpype/vendor/python/python_2/chardet/langbulgarianmodel.py create mode 100644 openpype/vendor/python/python_2/chardet/langgreekmodel.py create mode 100644 openpype/vendor/python/python_2/chardet/langhebrewmodel.py create mode 100644 openpype/vendor/python/python_2/chardet/langhungarianmodel.py create mode 100644 openpype/vendor/python/python_2/chardet/langrussianmodel.py create mode 100644 openpype/vendor/python/python_2/chardet/langthaimodel.py create mode 100644 openpype/vendor/python/python_2/chardet/langturkishmodel.py create mode 100644 openpype/vendor/python/python_2/chardet/latin1prober.py create mode 100644 openpype/vendor/python/python_2/chardet/mbcharsetprober.py create mode 100644 openpype/vendor/python/python_2/chardet/mbcsgroupprober.py create mode 100644 openpype/vendor/python/python_2/chardet/mbcssm.py create mode 100644 openpype/vendor/python/python_2/chardet/metadata/__init__.py create mode 100644 openpype/vendor/python/python_2/chardet/metadata/languages.py create mode 100644 openpype/vendor/python/python_2/chardet/sbcharsetprober.py create mode 100644 openpype/vendor/python/python_2/chardet/sbcsgroupprober.py create mode 100644 openpype/vendor/python/python_2/chardet/sjisprober.py create mode 100644 openpype/vendor/python/python_2/chardet/universaldetector.py create mode 100644 openpype/vendor/python/python_2/chardet/utf8prober.py create mode 100644 openpype/vendor/python/python_2/chardet/version.py create mode 100644 openpype/vendor/python/python_2/idna/__init__.py create mode 100644 openpype/vendor/python/python_2/idna/codec.py create mode 100644 openpype/vendor/python/python_2/idna/compat.py create mode 100644 openpype/vendor/python/python_2/idna/core.py create mode 100644 openpype/vendor/python/python_2/idna/idnadata.py create mode 100644 openpype/vendor/python/python_2/idna/intranges.py create mode 100644 openpype/vendor/python/python_2/idna/package_data.py create mode 100644 openpype/vendor/python/python_2/idna/uts46data.py create mode 100644 openpype/vendor/python/python_2/requests/__init__.py create mode 100644 openpype/vendor/python/python_2/requests/__version__.py create mode 100644 openpype/vendor/python/python_2/requests/_internal_utils.py create mode 100644 openpype/vendor/python/python_2/requests/adapters.py create mode 100644 openpype/vendor/python/python_2/requests/api.py create mode 100644 openpype/vendor/python/python_2/requests/auth.py create mode 100644 openpype/vendor/python/python_2/requests/certs.py create mode 100644 openpype/vendor/python/python_2/requests/compat.py create mode 100644 openpype/vendor/python/python_2/requests/cookies.py create mode 100644 openpype/vendor/python/python_2/requests/exceptions.py create mode 100644 openpype/vendor/python/python_2/requests/help.py create mode 100644 openpype/vendor/python/python_2/requests/hooks.py create mode 100644 openpype/vendor/python/python_2/requests/models.py create mode 100644 openpype/vendor/python/python_2/requests/packages.py create mode 100644 openpype/vendor/python/python_2/requests/sessions.py create mode 100644 openpype/vendor/python/python_2/requests/status_codes.py create mode 100644 openpype/vendor/python/python_2/requests/structures.py create mode 100644 openpype/vendor/python/python_2/requests/utils.py create mode 100644 openpype/vendor/python/python_2/urllib3/__init__.py create mode 100644 openpype/vendor/python/python_2/urllib3/_collections.py create mode 100644 openpype/vendor/python/python_2/urllib3/_version.py create mode 100644 openpype/vendor/python/python_2/urllib3/connection.py create mode 100644 openpype/vendor/python/python_2/urllib3/connectionpool.py create mode 100644 openpype/vendor/python/python_2/urllib3/contrib/__init__.py create mode 100644 openpype/vendor/python/python_2/urllib3/contrib/_appengine_environ.py create mode 100644 openpype/vendor/python/python_2/urllib3/contrib/_securetransport/__init__.py create mode 100644 openpype/vendor/python/python_2/urllib3/contrib/_securetransport/bindings.py create mode 100644 openpype/vendor/python/python_2/urllib3/contrib/_securetransport/low_level.py create mode 100644 openpype/vendor/python/python_2/urllib3/contrib/appengine.py create mode 100644 openpype/vendor/python/python_2/urllib3/contrib/ntlmpool.py create mode 100644 openpype/vendor/python/python_2/urllib3/contrib/pyopenssl.py create mode 100644 openpype/vendor/python/python_2/urllib3/contrib/securetransport.py create mode 100644 openpype/vendor/python/python_2/urllib3/contrib/socks.py create mode 100644 openpype/vendor/python/python_2/urllib3/exceptions.py create mode 100644 openpype/vendor/python/python_2/urllib3/fields.py create mode 100644 openpype/vendor/python/python_2/urllib3/filepost.py create mode 100644 openpype/vendor/python/python_2/urllib3/packages/__init__.py create mode 100644 openpype/vendor/python/python_2/urllib3/packages/backports/__init__.py create mode 100644 openpype/vendor/python/python_2/urllib3/packages/backports/makefile.py create mode 100644 openpype/vendor/python/python_2/urllib3/packages/six.py create mode 100644 openpype/vendor/python/python_2/urllib3/poolmanager.py create mode 100644 openpype/vendor/python/python_2/urllib3/request.py create mode 100644 openpype/vendor/python/python_2/urllib3/response.py create mode 100644 openpype/vendor/python/python_2/urllib3/util/__init__.py create mode 100644 openpype/vendor/python/python_2/urllib3/util/connection.py create mode 100644 openpype/vendor/python/python_2/urllib3/util/proxy.py create mode 100644 openpype/vendor/python/python_2/urllib3/util/queue.py create mode 100644 openpype/vendor/python/python_2/urllib3/util/request.py create mode 100644 openpype/vendor/python/python_2/urllib3/util/response.py create mode 100644 openpype/vendor/python/python_2/urllib3/util/retry.py create mode 100644 openpype/vendor/python/python_2/urllib3/util/ssl_.py create mode 100644 openpype/vendor/python/python_2/urllib3/util/ssl_match_hostname.py create mode 100644 openpype/vendor/python/python_2/urllib3/util/ssltransport.py create mode 100644 openpype/vendor/python/python_2/urllib3/util/timeout.py create mode 100644 openpype/vendor/python/python_2/urllib3/util/url.py create mode 100644 openpype/vendor/python/python_2/urllib3/util/wait.py diff --git a/openpype/vendor/python/python_2/chardet/__init__.py b/openpype/vendor/python/python_2/chardet/__init__.py new file mode 100644 index 0000000000..80ad2546d7 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/__init__.py @@ -0,0 +1,83 @@ +######################## 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 ######################### + + +from .universaldetector import UniversalDetector +from .enums import InputState +from .version import __version__, VERSION + + +__all__ = ['UniversalDetector', 'detect', 'detect_all', '__version__', 'VERSION'] + + +def detect(byte_str): + """ + Detect the encoding of the given byte string. + + :param byte_str: The byte sequence to examine. + :type byte_str: ``bytes`` or ``bytearray`` + """ + if not isinstance(byte_str, bytearray): + if not isinstance(byte_str, bytes): + raise TypeError('Expected object of type bytes or bytearray, got: ' + '{}'.format(type(byte_str))) + else: + byte_str = bytearray(byte_str) + detector = UniversalDetector() + detector.feed(byte_str) + return detector.close() + + +def detect_all(byte_str): + """ + Detect all the possible encodings of the given byte string. + + :param byte_str: The byte sequence to examine. + :type byte_str: ``bytes`` or ``bytearray`` + """ + if not isinstance(byte_str, bytearray): + if not isinstance(byte_str, bytes): + raise TypeError('Expected object of type bytes or bytearray, got: ' + '{}'.format(type(byte_str))) + else: + byte_str = bytearray(byte_str) + + detector = UniversalDetector() + detector.feed(byte_str) + detector.close() + + if detector._input_state == InputState.HIGH_BYTE: + results = [] + for prober in detector._charset_probers: + if prober.get_confidence() > detector.MINIMUM_THRESHOLD: + charset_name = prober.charset_name + lower_charset_name = prober.charset_name.lower() + # Use Windows encoding name instead of ISO-8859 if we saw any + # extra Windows-specific bytes + if lower_charset_name.startswith('iso-8859'): + if detector._has_win_bytes: + charset_name = detector.ISO_WIN_MAP.get(lower_charset_name, + charset_name) + results.append({ + 'encoding': charset_name, + 'confidence': prober.get_confidence(), + 'language': prober.language, + }) + if len(results) > 0: + return sorted(results, key=lambda result: -result['confidence']) + + return [detector.result] diff --git a/openpype/vendor/python/python_2/chardet/big5freq.py b/openpype/vendor/python/python_2/chardet/big5freq.py new file mode 100644 index 0000000000..38f32517aa --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/big5freq.py @@ -0,0 +1,386 @@ +######################## 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 + +BIG5_CHAR_TO_FREQ_ORDER = ( + 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 +) + diff --git a/openpype/vendor/python/python_2/chardet/big5prober.py b/openpype/vendor/python/python_2/chardet/big5prober.py new file mode 100644 index 0000000000..98f9970122 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/big5prober.py @@ -0,0 +1,47 @@ +######################## 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 BIG5_SM_MODEL + + +class Big5Prober(MultiByteCharSetProber): + def __init__(self): + super(Big5Prober, self).__init__() + self.coding_sm = CodingStateMachine(BIG5_SM_MODEL) + self.distribution_analyzer = Big5DistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "Big5" + + @property + def language(self): + return "Chinese" diff --git a/openpype/vendor/python/python_2/chardet/chardistribution.py b/openpype/vendor/python/python_2/chardet/chardistribution.py new file mode 100644 index 0000000000..c0395f4a45 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/chardistribution.py @@ -0,0 +1,233 @@ +######################## 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 .euctwfreq import (EUCTW_CHAR_TO_FREQ_ORDER, EUCTW_TABLE_SIZE, + EUCTW_TYPICAL_DISTRIBUTION_RATIO) +from .euckrfreq import (EUCKR_CHAR_TO_FREQ_ORDER, EUCKR_TABLE_SIZE, + EUCKR_TYPICAL_DISTRIBUTION_RATIO) +from .gb2312freq import (GB2312_CHAR_TO_FREQ_ORDER, GB2312_TABLE_SIZE, + GB2312_TYPICAL_DISTRIBUTION_RATIO) +from .big5freq import (BIG5_CHAR_TO_FREQ_ORDER, BIG5_TABLE_SIZE, + BIG5_TYPICAL_DISTRIBUTION_RATIO) +from .jisfreq import (JIS_CHAR_TO_FREQ_ORDER, JIS_TABLE_SIZE, + JIS_TYPICAL_DISTRIBUTION_RATIO) + + +class CharDistributionAnalysis(object): + ENOUGH_DATA_THRESHOLD = 1024 + SURE_YES = 0.99 + SURE_NO = 0.01 + MINIMUM_DATA_THRESHOLD = 3 + + def __init__(self): + # Mapping table to get frequency order from char order (get from + # GetOrder()) + self._char_to_freq_order = None + self._table_size = None # Size of above table + # 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.typical_distribution_ratio = None + self._done = None + self._total_chars = None + self._freq_chars = None + self.reset() + + def reset(self): + """reset analyser, clear any state""" + # If this flag is set to True, detection is done and conclusion has + # been made + self._done = False + self._total_chars = 0 # Total characters encountered + # The number of characters whose frequency order is less than 512 + self._freq_chars = 0 + + def feed(self, char, char_len): + """feed a character with known length""" + if char_len == 2: + # we only care about 2-bytes character in our distribution analysis + order = self.get_order(char) + else: + order = -1 + if order >= 0: + self._total_chars += 1 + # order is valid + if order < self._table_size: + if 512 > self._char_to_freq_order[order]: + self._freq_chars += 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._total_chars <= 0 or self._freq_chars <= self.MINIMUM_DATA_THRESHOLD: + return self.SURE_NO + + if self._total_chars != self._freq_chars: + r = (self._freq_chars / ((self._total_chars - self._freq_chars) + * self.typical_distribution_ratio)) + if r < self.SURE_YES: + return r + + # normalize confidence (we don't want to be 100% sure) + return self.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._total_chars > self.ENOUGH_DATA_THRESHOLD + + def get_order(self, byte_str): + # 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): + super(EUCTWDistributionAnalysis, self).__init__() + self._char_to_freq_order = EUCTW_CHAR_TO_FREQ_ORDER + self._table_size = EUCTW_TABLE_SIZE + self.typical_distribution_ratio = EUCTW_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # 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 + first_char = byte_str[0] + if first_char >= 0xC4: + return 94 * (first_char - 0xC4) + byte_str[1] - 0xA1 + else: + return -1 + + +class EUCKRDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(EUCKRDistributionAnalysis, self).__init__() + self._char_to_freq_order = EUCKR_CHAR_TO_FREQ_ORDER + self._table_size = EUCKR_TABLE_SIZE + self.typical_distribution_ratio = EUCKR_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # 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 + first_char = byte_str[0] + if first_char >= 0xB0: + return 94 * (first_char - 0xB0) + byte_str[1] - 0xA1 + else: + return -1 + + +class GB2312DistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(GB2312DistributionAnalysis, self).__init__() + self._char_to_freq_order = GB2312_CHAR_TO_FREQ_ORDER + self._table_size = GB2312_TABLE_SIZE + self.typical_distribution_ratio = GB2312_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # 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 + first_char, second_char = byte_str[0], byte_str[1] + if (first_char >= 0xB0) and (second_char >= 0xA1): + return 94 * (first_char - 0xB0) + second_char - 0xA1 + else: + return -1 + + +class Big5DistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(Big5DistributionAnalysis, self).__init__() + self._char_to_freq_order = BIG5_CHAR_TO_FREQ_ORDER + self._table_size = BIG5_TABLE_SIZE + self.typical_distribution_ratio = BIG5_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # 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 + first_char, second_char = byte_str[0], byte_str[1] + if first_char >= 0xA4: + if second_char >= 0xA1: + return 157 * (first_char - 0xA4) + second_char - 0xA1 + 63 + else: + return 157 * (first_char - 0xA4) + second_char - 0x40 + else: + return -1 + + +class SJISDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(SJISDistributionAnalysis, self).__init__() + self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER + self._table_size = JIS_TABLE_SIZE + self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # 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 + first_char, second_char = byte_str[0], byte_str[1] + if (first_char >= 0x81) and (first_char <= 0x9F): + order = 188 * (first_char - 0x81) + elif (first_char >= 0xE0) and (first_char <= 0xEF): + order = 188 * (first_char - 0xE0 + 31) + else: + return -1 + order = order + second_char - 0x40 + if second_char > 0x7F: + order = -1 + return order + + +class EUCJPDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(EUCJPDistributionAnalysis, self).__init__() + self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER + self._table_size = JIS_TABLE_SIZE + self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # 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 + char = byte_str[0] + if char >= 0xA0: + return 94 * (char - 0xA1) + byte_str[1] - 0xa1 + else: + return -1 diff --git a/openpype/vendor/python/python_2/chardet/charsetgroupprober.py b/openpype/vendor/python/python_2/chardet/charsetgroupprober.py new file mode 100644 index 0000000000..5812cef0b5 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/charsetgroupprober.py @@ -0,0 +1,107 @@ +######################## 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 .enums import ProbingState +from .charsetprober import CharSetProber + + +class CharSetGroupProber(CharSetProber): + def __init__(self, lang_filter=None): + super(CharSetGroupProber, self).__init__(lang_filter=lang_filter) + self._active_num = 0 + self.probers = [] + self._best_guess_prober = None + + def reset(self): + super(CharSetGroupProber, self).reset() + self._active_num = 0 + for prober in self.probers: + if prober: + prober.reset() + prober.active = True + self._active_num += 1 + self._best_guess_prober = None + + @property + def charset_name(self): + if not self._best_guess_prober: + self.get_confidence() + if not self._best_guess_prober: + return None + return self._best_guess_prober.charset_name + + @property + def language(self): + if not self._best_guess_prober: + self.get_confidence() + if not self._best_guess_prober: + return None + return self._best_guess_prober.language + + def feed(self, byte_str): + for prober in self.probers: + if not prober: + continue + if not prober.active: + continue + state = prober.feed(byte_str) + if not state: + continue + if state == ProbingState.FOUND_IT: + self._best_guess_prober = prober + self._state = ProbingState.FOUND_IT + return self.state + elif state == ProbingState.NOT_ME: + prober.active = False + self._active_num -= 1 + if self._active_num <= 0: + self._state = ProbingState.NOT_ME + return self.state + return self.state + + def get_confidence(self): + state = self.state + if state == ProbingState.FOUND_IT: + return 0.99 + elif state == ProbingState.NOT_ME: + return 0.01 + best_conf = 0.0 + self._best_guess_prober = None + for prober in self.probers: + if not prober: + continue + if not prober.active: + self.logger.debug('%s not active', prober.charset_name) + continue + conf = prober.get_confidence() + self.logger.debug('%s %s confidence = %s', prober.charset_name, prober.language, conf) + if best_conf < conf: + best_conf = conf + self._best_guess_prober = prober + if not self._best_guess_prober: + return 0.0 + return best_conf diff --git a/openpype/vendor/python/python_2/chardet/charsetprober.py b/openpype/vendor/python/python_2/chardet/charsetprober.py new file mode 100644 index 0000000000..eac4e59865 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/charsetprober.py @@ -0,0 +1,145 @@ +######################## 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 logging +import re + +from .enums import ProbingState + + +class CharSetProber(object): + + SHORTCUT_THRESHOLD = 0.95 + + def __init__(self, lang_filter=None): + self._state = None + self.lang_filter = lang_filter + self.logger = logging.getLogger(__name__) + + def reset(self): + self._state = ProbingState.DETECTING + + @property + def charset_name(self): + return None + + def feed(self, buf): + pass + + @property + def state(self): + return self._state + + def get_confidence(self): + return 0.0 + + @staticmethod + def filter_high_byte_only(buf): + buf = re.sub(b'([\x00-\x7F])+', b' ', buf) + return buf + + @staticmethod + def filter_international_words(buf): + """ + We define three types of bytes: + alphabet: english alphabets [a-zA-Z] + international: international characters [\x80-\xFF] + marker: everything else [^a-zA-Z\x80-\xFF] + + The input buffer can be thought to contain a series of words delimited + by markers. This function works to filter all words that contain at + least one international character. All contiguous sequences of markers + are replaced by a single space ascii character. + + This filter applies to all scripts which do not use English characters. + """ + filtered = bytearray() + + # This regex expression filters out only words that have at-least one + # international character. The word may include one marker character at + # the end. + words = re.findall(b'[a-zA-Z]*[\x80-\xFF]+[a-zA-Z]*[^a-zA-Z\x80-\xFF]?', + buf) + + for word in words: + filtered.extend(word[:-1]) + + # If the last character in the word is a marker, replace it with a + # space as markers shouldn't affect our analysis (they are used + # similarly across all languages and may thus have similar + # frequencies). + last_char = word[-1:] + if not last_char.isalpha() and last_char < b'\x80': + last_char = b' ' + filtered.extend(last_char) + + return filtered + + @staticmethod + def filter_with_english_letters(buf): + """ + Returns a copy of ``buf`` that retains only the sequences of English + alphabet and high byte characters that are not between <> characters. + Also retains English alphabet and high byte characters immediately + before occurrences of >. + + This filter can be applied to all scripts which contain both English + characters and extended ASCII characters, but is currently only used by + ``Latin1Prober``. + """ + filtered = bytearray() + in_tag = False + prev = 0 + + for curr in range(len(buf)): + # Slice here to get bytes instead of an int with Python 3 + buf_char = buf[curr:curr + 1] + # Check if we're coming out of or entering an HTML tag + if buf_char == b'>': + in_tag = False + elif buf_char == b'<': + in_tag = True + + # If current character is not extended-ASCII and not alphabetic... + if buf_char < b'\x80' and not buf_char.isalpha(): + # ...and we're not in a tag + if curr > prev and not in_tag: + # Keep everything after last non-extended-ASCII, + # non-alphabetic character + filtered.extend(buf[prev:curr]) + # Output a space to delimit stretch we kept + filtered.extend(b' ') + prev = curr + 1 + + # If we're not in a tag... + if not in_tag: + # Keep everything after last non-extended-ASCII, non-alphabetic + # character + filtered.extend(buf[prev:]) + + return filtered diff --git a/openpype/vendor/python/python_2/chardet/cli/__init__.py b/openpype/vendor/python/python_2/chardet/cli/__init__.py new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/cli/__init__.py @@ -0,0 +1 @@ + diff --git a/openpype/vendor/python/python_2/chardet/cli/chardetect.py b/openpype/vendor/python/python_2/chardet/cli/chardetect.py new file mode 100644 index 0000000000..e1d8cd69ac --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/cli/chardetect.py @@ -0,0 +1,84 @@ +""" +Script which takes one or more file paths and reports on their detected +encodings + +Example:: + + % chardetect somefile someotherfile + somefile: windows-1252 with confidence 0.5 + someotherfile: ascii with confidence 1.0 + +If no paths are provided, it takes its input from stdin. + +""" + +from __future__ import absolute_import, print_function, unicode_literals + +import argparse +import sys + +from chardet import __version__ +from chardet.compat import PY2 +from chardet.universaldetector import UniversalDetector + + +def description_of(lines, name='stdin'): + """ + Return a string describing the probable encoding of a file or + list of strings. + + :param lines: The lines to get the encoding of. + :type lines: Iterable of bytes + :param name: Name of file or collection of lines + :type name: str + """ + u = UniversalDetector() + for line in lines: + line = bytearray(line) + u.feed(line) + # shortcut out of the loop to save reading further - particularly useful if we read a BOM. + if u.done: + break + u.close() + result = u.result + if PY2: + name = name.decode(sys.getfilesystemencoding(), 'ignore') + if result['encoding']: + return '{}: {} with confidence {}'.format(name, result['encoding'], + result['confidence']) + else: + return '{}: no result'.format(name) + + +def main(argv=None): + """ + Handles command line arguments and gets things started. + + :param argv: List of arguments, as if specified on the command-line. + If None, ``sys.argv[1:]`` is used instead. + :type argv: list of str + """ + # Get command line arguments + parser = argparse.ArgumentParser( + description="Takes one or more file paths and reports their detected \ + encodings") + parser.add_argument('input', + help='File whose encoding we would like to determine. \ + (default: stdin)', + type=argparse.FileType('rb'), nargs='*', + default=[sys.stdin if PY2 else sys.stdin.buffer]) + parser.add_argument('--version', action='version', + version='%(prog)s {}'.format(__version__)) + args = parser.parse_args(argv) + + for f in args.input: + if f.isatty(): + print("You are running chardetect interactively. Press " + + "CTRL-D twice at the start of a blank line to signal the " + + "end of your input. If you want help, run chardetect " + + "--help\n", file=sys.stderr) + print(description_of(f, f.name)) + + +if __name__ == '__main__': + main() diff --git a/openpype/vendor/python/python_2/chardet/codingstatemachine.py b/openpype/vendor/python/python_2/chardet/codingstatemachine.py new file mode 100644 index 0000000000..68fba44f14 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/codingstatemachine.py @@ -0,0 +1,88 @@ +######################## 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 logging + +from .enums import MachineState + + +class CodingStateMachine(object): + """ + A state machine to verify a byte sequence for a particular encoding. For + each byte the detector receives, it will feed that byte to every active + state machine available, one byte at a time. The state machine changes its + state based on its previous state and the byte it receives. There are 3 + states in a state machine that are of interest to an auto-detector: + + START state: This is the state to start with, or a legal byte sequence + (i.e. a valid code point) for character has been identified. + + ME state: This indicates that the state machine identified a byte sequence + that is specific to the charset it is designed for and that + there is no other possible encoding which can contain this byte + sequence. This will to lead to an immediate positive answer for + the detector. + + ERROR state: This indicates the state machine identified an illegal byte + sequence for that encoding. This will lead to an immediate + negative answer for this encoding. Detector will exclude this + encoding from consideration from here on. + """ + def __init__(self, sm): + self._model = sm + self._curr_byte_pos = 0 + self._curr_char_len = 0 + self._curr_state = None + self.logger = logging.getLogger(__name__) + self.reset() + + def reset(self): + self._curr_state = MachineState.START + + def next_state(self, c): + # for each byte we get its class + # if it is first byte, we also get byte length + byte_class = self._model['class_table'][c] + if self._curr_state == MachineState.START: + self._curr_byte_pos = 0 + self._curr_char_len = self._model['char_len_table'][byte_class] + # from byte's class and state_table, we get its next state + curr_state = (self._curr_state * self._model['class_factor'] + + byte_class) + self._curr_state = self._model['state_table'][curr_state] + self._curr_byte_pos += 1 + return self._curr_state + + def get_current_charlen(self): + return self._curr_char_len + + def get_coding_state_machine(self): + return self._model['name'] + + @property + def language(self): + return self._model['language'] diff --git a/openpype/vendor/python/python_2/chardet/compat.py b/openpype/vendor/python/python_2/chardet/compat.py new file mode 100644 index 0000000000..8941572b3e --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/compat.py @@ -0,0 +1,36 @@ +######################## BEGIN LICENSE BLOCK ######################## +# Contributor(s): +# Dan Blanchard +# Ian Cordasco +# +# 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 sys + + +if sys.version_info < (3, 0): + PY2 = True + PY3 = False + string_types = (str, unicode) + text_type = unicode + iteritems = dict.iteritems +else: + PY2 = False + PY3 = True + string_types = (bytes, str) + text_type = str + iteritems = dict.items diff --git a/openpype/vendor/python/python_2/chardet/cp949prober.py b/openpype/vendor/python/python_2/chardet/cp949prober.py new file mode 100644 index 0000000000..efd793abca --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/cp949prober.py @@ -0,0 +1,49 @@ +######################## 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 .chardistribution import EUCKRDistributionAnalysis +from .codingstatemachine import CodingStateMachine +from .mbcharsetprober import MultiByteCharSetProber +from .mbcssm import CP949_SM_MODEL + + +class CP949Prober(MultiByteCharSetProber): + def __init__(self): + super(CP949Prober, self).__init__() + self.coding_sm = CodingStateMachine(CP949_SM_MODEL) + # NOTE: CP949 is a superset of EUC-KR, so the distribution should be + # not different. + self.distribution_analyzer = EUCKRDistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "CP949" + + @property + def language(self): + return "Korean" diff --git a/openpype/vendor/python/python_2/chardet/enums.py b/openpype/vendor/python/python_2/chardet/enums.py new file mode 100644 index 0000000000..0451207225 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/enums.py @@ -0,0 +1,76 @@ +""" +All of the Enums that are used throughout the chardet package. + +:author: Dan Blanchard (dan.blanchard@gmail.com) +""" + + +class InputState(object): + """ + This enum represents the different states a universal detector can be in. + """ + PURE_ASCII = 0 + ESC_ASCII = 1 + HIGH_BYTE = 2 + + +class LanguageFilter(object): + """ + This enum represents the different language filters we can apply to a + ``UniversalDetector``. + """ + CHINESE_SIMPLIFIED = 0x01 + CHINESE_TRADITIONAL = 0x02 + JAPANESE = 0x04 + KOREAN = 0x08 + NON_CJK = 0x10 + ALL = 0x1F + CHINESE = CHINESE_SIMPLIFIED | CHINESE_TRADITIONAL + CJK = CHINESE | JAPANESE | KOREAN + + +class ProbingState(object): + """ + This enum represents the different states a prober can be in. + """ + DETECTING = 0 + FOUND_IT = 1 + NOT_ME = 2 + + +class MachineState(object): + """ + This enum represents the different states a state machine can be in. + """ + START = 0 + ERROR = 1 + ITS_ME = 2 + + +class SequenceLikelihood(object): + """ + This enum represents the likelihood of a character following the previous one. + """ + NEGATIVE = 0 + UNLIKELY = 1 + LIKELY = 2 + POSITIVE = 3 + + @classmethod + def get_num_categories(cls): + """:returns: The number of likelihood categories in the enum.""" + return 4 + + +class CharacterCategory(object): + """ + This enum represents the different categories language models for + ``SingleByteCharsetProber`` put characters into. + + Anything less than CONTROL is considered a letter. + """ + UNDEFINED = 255 + LINE_BREAK = 254 + SYMBOL = 253 + DIGIT = 252 + CONTROL = 251 diff --git a/openpype/vendor/python/python_2/chardet/escprober.py b/openpype/vendor/python/python_2/chardet/escprober.py new file mode 100644 index 0000000000..c70493f2b1 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/escprober.py @@ -0,0 +1,101 @@ +######################## 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 .charsetprober import CharSetProber +from .codingstatemachine import CodingStateMachine +from .enums import LanguageFilter, ProbingState, MachineState +from .escsm import (HZ_SM_MODEL, ISO2022CN_SM_MODEL, ISO2022JP_SM_MODEL, + ISO2022KR_SM_MODEL) + + +class EscCharSetProber(CharSetProber): + """ + This CharSetProber uses a "code scheme" approach for detecting encodings, + whereby easily recognizable escape or shift sequences are relied on to + identify these encodings. + """ + + def __init__(self, lang_filter=None): + super(EscCharSetProber, self).__init__(lang_filter=lang_filter) + self.coding_sm = [] + if self.lang_filter & LanguageFilter.CHINESE_SIMPLIFIED: + self.coding_sm.append(CodingStateMachine(HZ_SM_MODEL)) + self.coding_sm.append(CodingStateMachine(ISO2022CN_SM_MODEL)) + if self.lang_filter & LanguageFilter.JAPANESE: + self.coding_sm.append(CodingStateMachine(ISO2022JP_SM_MODEL)) + if self.lang_filter & LanguageFilter.KOREAN: + self.coding_sm.append(CodingStateMachine(ISO2022KR_SM_MODEL)) + self.active_sm_count = None + self._detected_charset = None + self._detected_language = None + self._state = None + self.reset() + + def reset(self): + super(EscCharSetProber, self).reset() + for coding_sm in self.coding_sm: + if not coding_sm: + continue + coding_sm.active = True + coding_sm.reset() + self.active_sm_count = len(self.coding_sm) + self._detected_charset = None + self._detected_language = None + + @property + def charset_name(self): + return self._detected_charset + + @property + def language(self): + return self._detected_language + + def get_confidence(self): + if self._detected_charset: + return 0.99 + else: + return 0.00 + + def feed(self, byte_str): + for c in byte_str: + for coding_sm in self.coding_sm: + if not coding_sm or not coding_sm.active: + continue + coding_state = coding_sm.next_state(c) + if coding_state == MachineState.ERROR: + coding_sm.active = False + self.active_sm_count -= 1 + if self.active_sm_count <= 0: + self._state = ProbingState.NOT_ME + return self.state + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + self._detected_charset = coding_sm.get_coding_state_machine() + self._detected_language = coding_sm.language + return self.state + + return self.state diff --git a/openpype/vendor/python/python_2/chardet/escsm.py b/openpype/vendor/python/python_2/chardet/escsm.py new file mode 100644 index 0000000000..0069523a04 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/escsm.py @@ -0,0 +1,246 @@ +######################## 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 .enums import MachineState + +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 = ( +MachineState.START,MachineState.ERROR, 3,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START, 4,MachineState.ERROR,# 10-17 + 5,MachineState.ERROR, 6,MachineState.ERROR, 5, 5, 4,MachineState.ERROR,# 18-1f + 4,MachineState.ERROR, 4, 4, 4,MachineState.ERROR, 4,MachineState.ERROR,# 20-27 + 4,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 28-2f +) + +HZ_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) + +HZ_SM_MODEL = {'class_table': HZ_CLS, + 'class_factor': 6, + 'state_table': HZ_ST, + 'char_len_table': HZ_CHAR_LEN_TABLE, + 'name': "HZ-GB-2312", + 'language': 'Chinese'} + +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 = ( +MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 +MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f +MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,# 18-1f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 20-27 + 5, 6,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 28-2f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 30-37 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,# 38-3f +) + +ISO2022CN_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0) + +ISO2022CN_SM_MODEL = {'class_table': ISO2022CN_CLS, + 'class_factor': 9, + 'state_table': ISO2022CN_ST, + 'char_len_table': ISO2022CN_CHAR_LEN_TABLE, + 'name': "ISO-2022-CN", + 'language': 'Chinese'} + +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 = ( +MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 +MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,# 18-1f +MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 20-27 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 6,MachineState.ITS_ME,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,# 28-2f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,# 30-37 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 38-3f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,MachineState.START,# 40-47 +) + +ISO2022JP_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + +ISO2022JP_SM_MODEL = {'class_table': ISO2022JP_CLS, + 'class_factor': 10, + 'state_table': ISO2022JP_ST, + 'char_len_table': ISO2022JP_CHAR_LEN_TABLE, + 'name': "ISO-2022-JP", + 'language': 'Japanese'} + +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 = ( +MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 10-17 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 18-1f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 20-27 +) + +ISO2022KR_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) + +ISO2022KR_SM_MODEL = {'class_table': ISO2022KR_CLS, + 'class_factor': 6, + 'state_table': ISO2022KR_ST, + 'char_len_table': ISO2022KR_CHAR_LEN_TABLE, + 'name': "ISO-2022-KR", + 'language': 'Korean'} + + diff --git a/openpype/vendor/python/python_2/chardet/eucjpprober.py b/openpype/vendor/python/python_2/chardet/eucjpprober.py new file mode 100644 index 0000000000..20ce8f7d15 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/eucjpprober.py @@ -0,0 +1,92 @@ +######################## 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 .enums import ProbingState, MachineState +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCJPDistributionAnalysis +from .jpcntx import EUCJPContextAnalysis +from .mbcssm import EUCJP_SM_MODEL + + +class EUCJPProber(MultiByteCharSetProber): + def __init__(self): + super(EUCJPProber, self).__init__() + self.coding_sm = CodingStateMachine(EUCJP_SM_MODEL) + self.distribution_analyzer = EUCJPDistributionAnalysis() + self.context_analyzer = EUCJPContextAnalysis() + self.reset() + + def reset(self): + super(EUCJPProber, self).reset() + self.context_analyzer.reset() + + @property + def charset_name(self): + return "EUC-JP" + + @property + def language(self): + return "Japanese" + + def feed(self, byte_str): + for i in range(len(byte_str)): + # PY3K: byte_str is a byte array, so byte_str[i] is an int, not a byte + coding_state = self.coding_sm.next_state(byte_str[i]) + if coding_state == MachineState.ERROR: + self.logger.debug('%s %s prober hit error at byte %s', + self.charset_name, self.language, i) + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + char_len = self.coding_sm.get_current_charlen() + if i == 0: + self._last_char[1] = byte_str[0] + self.context_analyzer.feed(self._last_char, char_len) + self.distribution_analyzer.feed(self._last_char, char_len) + else: + self.context_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + self.distribution_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + + self._last_char[0] = byte_str[-1] + + if self.state == ProbingState.DETECTING: + if (self.context_analyzer.got_enough_data() and + (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + context_conf = self.context_analyzer.get_confidence() + distrib_conf = self.distribution_analyzer.get_confidence() + return max(context_conf, distrib_conf) diff --git a/openpype/vendor/python/python_2/chardet/euckrfreq.py b/openpype/vendor/python/python_2/chardet/euckrfreq.py new file mode 100644 index 0000000000..b68078cb96 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/euckrfreq.py @@ -0,0 +1,195 @@ +######################## 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 , +EUCKR_CHAR_TO_FREQ_ORDER = ( + 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 +) + diff --git a/openpype/vendor/python/python_2/chardet/euckrprober.py b/openpype/vendor/python/python_2/chardet/euckrprober.py new file mode 100644 index 0000000000..345a060d02 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/euckrprober.py @@ -0,0 +1,47 @@ +######################## 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 EUCKR_SM_MODEL + + +class EUCKRProber(MultiByteCharSetProber): + def __init__(self): + super(EUCKRProber, self).__init__() + self.coding_sm = CodingStateMachine(EUCKR_SM_MODEL) + self.distribution_analyzer = EUCKRDistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "EUC-KR" + + @property + def language(self): + return "Korean" diff --git a/openpype/vendor/python/python_2/chardet/euctwfreq.py b/openpype/vendor/python/python_2/chardet/euctwfreq.py new file mode 100644 index 0000000000..ed7a995a3a --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/euctwfreq.py @@ -0,0 +1,387 @@ +######################## 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 = 5376 + +EUCTW_CHAR_TO_FREQ_ORDER = ( + 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 +) + diff --git a/openpype/vendor/python/python_2/chardet/euctwprober.py b/openpype/vendor/python/python_2/chardet/euctwprober.py new file mode 100644 index 0000000000..35669cc4dd --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/euctwprober.py @@ -0,0 +1,46 @@ +######################## 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 EUCTW_SM_MODEL + +class EUCTWProber(MultiByteCharSetProber): + def __init__(self): + super(EUCTWProber, self).__init__() + self.coding_sm = CodingStateMachine(EUCTW_SM_MODEL) + self.distribution_analyzer = EUCTWDistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "EUC-TW" + + @property + def language(self): + return "Taiwan" diff --git a/openpype/vendor/python/python_2/chardet/gb2312freq.py b/openpype/vendor/python/python_2/chardet/gb2312freq.py new file mode 100644 index 0000000000..697837bd9a --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/gb2312freq.py @@ -0,0 +1,283 @@ +######################## 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 + +GB2312_CHAR_TO_FREQ_ORDER = ( +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 +) + diff --git a/openpype/vendor/python/python_2/chardet/gb2312prober.py b/openpype/vendor/python/python_2/chardet/gb2312prober.py new file mode 100644 index 0000000000..8446d2dd95 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/gb2312prober.py @@ -0,0 +1,46 @@ +######################## 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 GB2312_SM_MODEL + +class GB2312Prober(MultiByteCharSetProber): + def __init__(self): + super(GB2312Prober, self).__init__() + self.coding_sm = CodingStateMachine(GB2312_SM_MODEL) + self.distribution_analyzer = GB2312DistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "GB2312" + + @property + def language(self): + return "Chinese" diff --git a/openpype/vendor/python/python_2/chardet/hebrewprober.py b/openpype/vendor/python/python_2/chardet/hebrewprober.py new file mode 100644 index 0000000000..b0e1bf4926 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/hebrewprober.py @@ -0,0 +1,292 @@ +######################## 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 .enums import ProbingState + +# 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". + +class HebrewProber(CharSetProber): + # windows-1255 / ISO-8859-8 code points of interest + FINAL_KAF = 0xea + NORMAL_KAF = 0xeb + FINAL_MEM = 0xed + NORMAL_MEM = 0xee + FINAL_NUN = 0xef + NORMAL_NUN = 0xf0 + FINAL_PE = 0xf3 + NORMAL_PE = 0xf4 + FINAL_TSADI = 0xf5 + NORMAL_TSADI = 0xf6 + + # 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" + + def __init__(self): + super(HebrewProber, self).__init__() + self._final_char_logical_score = None + self._final_char_visual_score = None + self._prev = None + self._before_prev = None + self._logical_prober = None + self._visual_prober = None + self.reset() + + def reset(self): + self._final_char_logical_score = 0 + self._final_char_visual_score = 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._prev = ' ' + self._before_prev = ' ' + # These probers are owned by the group prober. + + def set_model_probers(self, logicalProber, visualProber): + self._logical_prober = logicalProber + self._visual_prober = visualProber + + def is_final(self, c): + return c in [self.FINAL_KAF, self.FINAL_MEM, self.FINAL_NUN, + self.FINAL_PE, self.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 [self.NORMAL_KAF, self.NORMAL_MEM, + self.NORMAL_NUN, self.NORMAL_PE] + + def feed(self, byte_str): + # 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.state == ProbingState.NOT_ME: + # Both model probers say it's not them. No reason to continue. + return ProbingState.NOT_ME + + byte_str = self.filter_high_byte_only(byte_str) + + for cur in byte_str: + if cur == ' ': + # We stand on a space - a word just ended + if self._before_prev != ' ': + # next-to-last char was not a space so self._prev is not a + # 1 letter word + if self.is_final(self._prev): + # case (1) [-2:not space][-1:final letter][cur:space] + self._final_char_logical_score += 1 + elif self.is_non_final(self._prev): + # case (2) [-2:not space][-1:Non-Final letter][ + # cur:space] + self._final_char_visual_score += 1 + else: + # Not standing on a space + if ((self._before_prev == ' ') and + (self.is_final(self._prev)) and (cur != ' ')): + # case (3) [-2:space][-1:final letter][cur:not space] + self._final_char_visual_score += 1 + self._before_prev = self._prev + self._prev = cur + + # Forever detecting, till the end or until both model probers return + # ProbingState.NOT_ME (handled above) + return ProbingState.DETECTING + + @property + def 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._final_char_logical_score - self._final_char_visual_score + if finalsub >= self.MIN_FINAL_CHAR_DISTANCE: + return self.LOGICAL_HEBREW_NAME + if finalsub <= -self.MIN_FINAL_CHAR_DISTANCE: + return self.VISUAL_HEBREW_NAME + + # It's not dominant enough, try to rely on the model scores instead. + modelsub = (self._logical_prober.get_confidence() + - self._visual_prober.get_confidence()) + if modelsub > self.MIN_MODEL_DISTANCE: + return self.LOGICAL_HEBREW_NAME + if modelsub < -self.MIN_MODEL_DISTANCE: + return self.VISUAL_HEBREW_NAME + + # Still no good, back to final letter distance, maybe it'll save the + # day. + if finalsub < 0.0: + return self.VISUAL_HEBREW_NAME + + # (finalsub > 0 - Logical) or (don't know what to do) default to + # Logical. + return self.LOGICAL_HEBREW_NAME + + @property + def language(self): + return 'Hebrew' + + @property + def state(self): + # Remain active as long as any of the model probers are active. + if (self._logical_prober.state == ProbingState.NOT_ME) and \ + (self._visual_prober.state == ProbingState.NOT_ME): + return ProbingState.NOT_ME + return ProbingState.DETECTING diff --git a/openpype/vendor/python/python_2/chardet/jisfreq.py b/openpype/vendor/python/python_2/chardet/jisfreq.py new file mode 100644 index 0000000000..83fc082b54 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/jisfreq.py @@ -0,0 +1,325 @@ +######################## 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 + +JIS_CHAR_TO_FREQ_ORDER = ( + 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 +) + + diff --git a/openpype/vendor/python/python_2/chardet/jpcntx.py b/openpype/vendor/python/python_2/chardet/jpcntx.py new file mode 100644 index 0000000000..20044e4bc8 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/jpcntx.py @@ -0,0 +1,233 @@ +######################## 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 ######################### + + +# 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(object): + NUM_OF_CATEGORY = 6 + DONT_KNOW = -1 + ENOUGH_REL_THRESHOLD = 100 + MAX_REL_THRESHOLD = 1000 + MINIMUM_DATA_THRESHOLD = 4 + + def __init__(self): + self._total_rel = None + self._rel_sample = None + self._need_to_skip_char_num = None + self._last_char_order = None + self._done = None + self.reset() + + def reset(self): + self._total_rel = 0 # total sequence received + # category counters, each integer counts sequence in its category + self._rel_sample = [0] * self.NUM_OF_CATEGORY + # 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._need_to_skip_char_num = 0 + self._last_char_order = -1 # The order of previous char + # If this flag is set to True, detection is done and conclusion has + # been made + self._done = False + + def feed(self, byte_str, num_bytes): + if self._done: + 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._need_to_skip_char_num + while i < num_bytes: + order, char_len = self.get_order(byte_str[i:i + 2]) + i += char_len + if i > num_bytes: + self._need_to_skip_char_num = i - num_bytes + self._last_char_order = -1 + else: + if (order != -1) and (self._last_char_order != -1): + self._total_rel += 1 + if self._total_rel > self.MAX_REL_THRESHOLD: + self._done = True + break + self._rel_sample[jp2CharContext[self._last_char_order][order]] += 1 + self._last_char_order = order + + def got_enough_data(self): + return self._total_rel > self.ENOUGH_REL_THRESHOLD + + def get_confidence(self): + # This is just one way to calculate confidence. It works well for me. + if self._total_rel > self.MINIMUM_DATA_THRESHOLD: + return (self._total_rel - self._rel_sample[0]) / self._total_rel + else: + return self.DONT_KNOW + + def get_order(self, byte_str): + return -1, 1 + +class SJISContextAnalysis(JapaneseContextAnalysis): + def __init__(self): + super(SJISContextAnalysis, self).__init__() + self._charset_name = "SHIFT_JIS" + + @property + def charset_name(self): + return self._charset_name + + def get_order(self, byte_str): + if not byte_str: + return -1, 1 + # find out current char's byte length + first_char = byte_str[0] + if (0x81 <= first_char <= 0x9F) or (0xE0 <= first_char <= 0xFC): + char_len = 2 + if (first_char == 0x87) or (0xFA <= first_char <= 0xFC): + self._charset_name = "CP932" + else: + char_len = 1 + + # return its order if it is hiragana + if len(byte_str) > 1: + second_char = byte_str[1] + if (first_char == 202) and (0x9F <= second_char <= 0xF1): + return second_char - 0x9F, char_len + + return -1, char_len + +class EUCJPContextAnalysis(JapaneseContextAnalysis): + def get_order(self, byte_str): + if not byte_str: + return -1, 1 + # find out current char's byte length + first_char = byte_str[0] + if (first_char == 0x8E) or (0xA1 <= first_char <= 0xFE): + char_len = 2 + elif first_char == 0x8F: + char_len = 3 + else: + char_len = 1 + + # return its order if it is hiragana + if len(byte_str) > 1: + second_char = byte_str[1] + if (first_char == 0xA4) and (0xA1 <= second_char <= 0xF3): + return second_char - 0xA1, char_len + + return -1, char_len + + diff --git a/openpype/vendor/python/python_2/chardet/langbulgarianmodel.py b/openpype/vendor/python/python_2/chardet/langbulgarianmodel.py new file mode 100644 index 0000000000..561bfd9051 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/langbulgarianmodel.py @@ -0,0 +1,4650 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from chardet.sbcharsetprober import SingleByteCharSetModel + + +# 3: Positive +# 2: Likely +# 1: Unlikely +# 0: Negative + +BULGARIAN_LANG_MODEL = { + 63: { # 'e' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 1, # 'б' + 9: 1, # 'в' + 20: 1, # 'г' + 11: 1, # 'д' + 3: 1, # 'е' + 23: 1, # 'ж' + 15: 1, # 'з' + 2: 0, # 'и' + 26: 1, # 'й' + 12: 1, # 'к' + 10: 1, # 'л' + 14: 1, # 'м' + 6: 1, # 'н' + 4: 1, # 'о' + 13: 1, # 'п' + 7: 1, # 'р' + 8: 1, # 'с' + 5: 1, # 'т' + 19: 0, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 45: { # '\xad' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 0, # 'Г' + 37: 1, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 0, # 'Л' + 38: 1, # 'М' + 36: 0, # 'Н' + 41: 1, # 'О' + 30: 1, # 'П' + 39: 1, # 'Р' + 28: 1, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 1, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 0, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 0, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 0, # 'о' + 13: 0, # 'п' + 7: 0, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 0, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 31: { # 'А' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 1, # 'А' + 32: 1, # 'Б' + 35: 2, # 'В' + 43: 1, # 'Г' + 37: 2, # 'Д' + 44: 2, # 'Е' + 55: 1, # 'Ж' + 47: 2, # 'З' + 40: 1, # 'И' + 59: 1, # 'Й' + 33: 1, # 'К' + 46: 2, # 'Л' + 38: 1, # 'М' + 36: 2, # 'Н' + 41: 1, # 'О' + 30: 2, # 'П' + 39: 2, # 'Р' + 28: 2, # 'С' + 34: 2, # 'Т' + 51: 1, # 'У' + 48: 2, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 1, # 'Ш' + 57: 2, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 1, # 'Я' + 1: 1, # 'а' + 18: 2, # 'б' + 9: 2, # 'в' + 20: 2, # 'г' + 11: 2, # 'д' + 3: 1, # 'е' + 23: 1, # 'ж' + 15: 2, # 'з' + 2: 0, # 'и' + 26: 2, # 'й' + 12: 2, # 'к' + 10: 3, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 0, # 'о' + 13: 2, # 'п' + 7: 2, # 'р' + 8: 2, # 'с' + 5: 2, # 'т' + 19: 1, # 'у' + 29: 2, # 'ф' + 25: 1, # 'х' + 22: 1, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 32: { # 'Б' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 2, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 2, # 'Д' + 44: 1, # 'Е' + 55: 1, # 'Ж' + 47: 2, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 2, # 'Н' + 41: 2, # 'О' + 30: 1, # 'П' + 39: 1, # 'Р' + 28: 2, # 'С' + 34: 2, # 'Т' + 51: 1, # 'У' + 48: 2, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 0, # 'Ш' + 57: 1, # 'Щ' + 61: 2, # 'Ъ' + 60: 1, # 'Ю' + 56: 1, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 2, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 2, # 'р' + 8: 1, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 2, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 35: { # 'В' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 0, # 'Г' + 37: 1, # 'Д' + 44: 2, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 1, # 'О' + 30: 1, # 'П' + 39: 2, # 'Р' + 28: 2, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 2, # 'Ф' + 49: 0, # 'Х' + 53: 1, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 1, # 'Ю' + 56: 2, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 2, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 2, # 'л' + 14: 1, # 'м' + 6: 2, # 'н' + 4: 2, # 'о' + 13: 1, # 'п' + 7: 2, # 'р' + 8: 2, # 'с' + 5: 2, # 'т' + 19: 1, # 'у' + 29: 0, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 2, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 43: { # 'Г' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 1, # 'Д' + 44: 2, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 0, # 'М' + 36: 1, # 'Н' + 41: 1, # 'О' + 30: 0, # 'П' + 39: 1, # 'Р' + 28: 1, # 'С' + 34: 0, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 1, # 'Щ' + 61: 1, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 1, # 'б' + 9: 1, # 'в' + 20: 0, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 2, # 'л' + 14: 1, # 'м' + 6: 1, # 'н' + 4: 2, # 'о' + 13: 0, # 'п' + 7: 2, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 1, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 37: { # 'Д' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 2, # 'В' + 43: 1, # 'Г' + 37: 2, # 'Д' + 44: 2, # 'Е' + 55: 2, # 'Ж' + 47: 1, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 2, # 'О' + 30: 2, # 'П' + 39: 1, # 'Р' + 28: 2, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 0, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 1, # 'Ю' + 56: 1, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 2, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 3, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 1, # 'л' + 14: 1, # 'м' + 6: 2, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 2, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 44: { # 'Е' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 1, # 'Б' + 35: 2, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 1, # 'Е' + 55: 1, # 'Ж' + 47: 1, # 'З' + 40: 1, # 'И' + 59: 1, # 'Й' + 33: 2, # 'К' + 46: 2, # 'Л' + 38: 1, # 'М' + 36: 2, # 'Н' + 41: 2, # 'О' + 30: 1, # 'П' + 39: 2, # 'Р' + 28: 2, # 'С' + 34: 2, # 'Т' + 51: 1, # 'У' + 48: 2, # 'Ф' + 49: 1, # 'Х' + 53: 2, # 'Ц' + 50: 1, # 'Ч' + 54: 1, # 'Ш' + 57: 1, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 1, # 'Я' + 1: 0, # 'а' + 18: 1, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 2, # 'д' + 3: 0, # 'е' + 23: 1, # 'ж' + 15: 1, # 'з' + 2: 0, # 'и' + 26: 1, # 'й' + 12: 2, # 'к' + 10: 2, # 'л' + 14: 2, # 'м' + 6: 2, # 'н' + 4: 0, # 'о' + 13: 1, # 'п' + 7: 2, # 'р' + 8: 2, # 'с' + 5: 1, # 'т' + 19: 1, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 55: { # 'Ж' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 0, # 'Б' + 35: 1, # 'В' + 43: 0, # 'Г' + 37: 1, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 1, # 'Н' + 41: 1, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 1, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 1, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 2, # 'о' + 13: 1, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 1, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 47: { # 'З' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 2, # 'Н' + 41: 1, # 'О' + 30: 1, # 'П' + 39: 1, # 'Р' + 28: 1, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 0, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 0, # 'Ю' + 56: 1, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 2, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 1, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 2, # 'л' + 14: 1, # 'м' + 6: 1, # 'н' + 4: 1, # 'о' + 13: 0, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 1, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 40: { # 'И' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 1, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 2, # 'Е' + 55: 1, # 'Ж' + 47: 2, # 'З' + 40: 1, # 'И' + 59: 1, # 'Й' + 33: 2, # 'К' + 46: 2, # 'Л' + 38: 2, # 'М' + 36: 2, # 'Н' + 41: 1, # 'О' + 30: 1, # 'П' + 39: 2, # 'Р' + 28: 2, # 'С' + 34: 2, # 'Т' + 51: 0, # 'У' + 48: 1, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 1, # 'Ш' + 57: 1, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 2, # 'Я' + 1: 1, # 'а' + 18: 1, # 'б' + 9: 3, # 'в' + 20: 2, # 'г' + 11: 1, # 'д' + 3: 1, # 'е' + 23: 0, # 'ж' + 15: 3, # 'з' + 2: 0, # 'и' + 26: 1, # 'й' + 12: 1, # 'к' + 10: 2, # 'л' + 14: 2, # 'м' + 6: 2, # 'н' + 4: 0, # 'о' + 13: 1, # 'п' + 7: 2, # 'р' + 8: 2, # 'с' + 5: 2, # 'т' + 19: 0, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 1, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 59: { # 'Й' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 1, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 1, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 1, # 'С' + 34: 1, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 1, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 1, # 'Я' + 1: 0, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 1, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 0, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 2, # 'о' + 13: 0, # 'п' + 7: 0, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 0, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 33: { # 'К' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 0, # 'М' + 36: 2, # 'Н' + 41: 2, # 'О' + 30: 2, # 'П' + 39: 1, # 'Р' + 28: 2, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 1, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 1, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 2, # 'е' + 23: 1, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 2, # 'л' + 14: 1, # 'м' + 6: 2, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 3, # 'р' + 8: 1, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 46: { # 'Л' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 2, # 'Г' + 37: 1, # 'Д' + 44: 2, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 0, # 'М' + 36: 1, # 'Н' + 41: 2, # 'О' + 30: 1, # 'П' + 39: 0, # 'Р' + 28: 1, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 0, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 1, # 'Ю' + 56: 1, # 'Я' + 1: 2, # 'а' + 18: 0, # 'б' + 9: 1, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 2, # 'о' + 13: 0, # 'п' + 7: 0, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 38: { # 'М' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 2, # 'В' + 43: 0, # 'Г' + 37: 1, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 2, # 'О' + 30: 1, # 'П' + 39: 1, # 'Р' + 28: 2, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 0, # 'Х' + 53: 1, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 0, # 'Ю' + 56: 1, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 2, # 'л' + 14: 0, # 'м' + 6: 2, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 36: { # 'Н' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 2, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 2, # 'Д' + 44: 2, # 'Е' + 55: 1, # 'Ж' + 47: 1, # 'З' + 40: 2, # 'И' + 59: 1, # 'Й' + 33: 2, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 2, # 'О' + 30: 1, # 'П' + 39: 1, # 'Р' + 28: 2, # 'С' + 34: 2, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 1, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 1, # 'Ю' + 56: 1, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 1, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 0, # 'р' + 8: 0, # 'с' + 5: 1, # 'т' + 19: 1, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 2, # 'ю' + 16: 2, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 41: { # 'О' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 1, # 'Б' + 35: 2, # 'В' + 43: 1, # 'Г' + 37: 2, # 'Д' + 44: 1, # 'Е' + 55: 1, # 'Ж' + 47: 1, # 'З' + 40: 1, # 'И' + 59: 1, # 'Й' + 33: 2, # 'К' + 46: 2, # 'Л' + 38: 2, # 'М' + 36: 2, # 'Н' + 41: 2, # 'О' + 30: 1, # 'П' + 39: 2, # 'Р' + 28: 2, # 'С' + 34: 2, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 1, # 'Х' + 53: 0, # 'Ц' + 50: 1, # 'Ч' + 54: 1, # 'Ш' + 57: 1, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 1, # 'Я' + 1: 1, # 'а' + 18: 2, # 'б' + 9: 2, # 'в' + 20: 2, # 'г' + 11: 1, # 'д' + 3: 1, # 'е' + 23: 1, # 'ж' + 15: 1, # 'з' + 2: 0, # 'и' + 26: 1, # 'й' + 12: 2, # 'к' + 10: 2, # 'л' + 14: 1, # 'м' + 6: 1, # 'н' + 4: 0, # 'о' + 13: 2, # 'п' + 7: 2, # 'р' + 8: 2, # 'с' + 5: 3, # 'т' + 19: 1, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 1, # 'ц' + 21: 2, # 'ч' + 27: 0, # 'ш' + 24: 2, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 30: { # 'П' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 2, # 'О' + 30: 2, # 'П' + 39: 2, # 'Р' + 28: 2, # 'С' + 34: 1, # 'Т' + 51: 2, # 'У' + 48: 1, # 'Ф' + 49: 0, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 1, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 1, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 2, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 3, # 'л' + 14: 0, # 'м' + 6: 1, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 3, # 'р' + 8: 1, # 'с' + 5: 1, # 'т' + 19: 2, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 39: { # 'Р' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 2, # 'Г' + 37: 2, # 'Д' + 44: 2, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 0, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 2, # 'О' + 30: 2, # 'П' + 39: 1, # 'Р' + 28: 1, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 1, # 'Ю' + 56: 1, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 1, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 0, # 'р' + 8: 1, # 'с' + 5: 0, # 'т' + 19: 3, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 28: { # 'С' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 3, # 'А' + 32: 2, # 'Б' + 35: 2, # 'В' + 43: 1, # 'Г' + 37: 2, # 'Д' + 44: 2, # 'Е' + 55: 1, # 'Ж' + 47: 1, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 2, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 2, # 'О' + 30: 2, # 'П' + 39: 1, # 'Р' + 28: 2, # 'С' + 34: 2, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 1, # 'Ю' + 56: 1, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 2, # 'к' + 10: 3, # 'л' + 14: 2, # 'м' + 6: 1, # 'н' + 4: 3, # 'о' + 13: 3, # 'п' + 7: 2, # 'р' + 8: 0, # 'с' + 5: 3, # 'т' + 19: 2, # 'у' + 29: 2, # 'ф' + 25: 1, # 'х' + 22: 1, # 'ц' + 21: 1, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 34: { # 'Т' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 2, # 'Б' + 35: 1, # 'В' + 43: 0, # 'Г' + 37: 1, # 'Д' + 44: 2, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 2, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 2, # 'О' + 30: 1, # 'П' + 39: 2, # 'Р' + 28: 2, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 0, # 'Х' + 53: 1, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 0, # 'Ю' + 56: 1, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 1, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 1, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 3, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 2, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 51: { # 'У' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 1, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 2, # 'Е' + 55: 1, # 'Ж' + 47: 1, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 0, # 'О' + 30: 1, # 'П' + 39: 1, # 'Р' + 28: 1, # 'С' + 34: 2, # 'Т' + 51: 0, # 'У' + 48: 1, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 1, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 1, # 'а' + 18: 1, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 1, # 'д' + 3: 2, # 'е' + 23: 1, # 'ж' + 15: 1, # 'з' + 2: 2, # 'и' + 26: 1, # 'й' + 12: 2, # 'к' + 10: 1, # 'л' + 14: 1, # 'м' + 6: 2, # 'н' + 4: 2, # 'о' + 13: 1, # 'п' + 7: 1, # 'р' + 8: 2, # 'с' + 5: 1, # 'т' + 19: 1, # 'у' + 29: 0, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 2, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 48: { # 'Ф' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 0, # 'М' + 36: 1, # 'Н' + 41: 1, # 'О' + 30: 2, # 'П' + 39: 1, # 'Р' + 28: 2, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 2, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 2, # 'о' + 13: 0, # 'п' + 7: 2, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 1, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 49: { # 'Х' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 0, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 1, # 'О' + 30: 1, # 'П' + 39: 1, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 1, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 0, # 'б' + 9: 1, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 1, # 'л' + 14: 1, # 'м' + 6: 0, # 'н' + 4: 2, # 'о' + 13: 0, # 'п' + 7: 2, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 53: { # 'Ц' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 0, # 'Б' + 35: 1, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 2, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 1, # 'Р' + 28: 2, # 'С' + 34: 0, # 'Т' + 51: 1, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 0, # 'б' + 9: 2, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 1, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 1, # 'о' + 13: 0, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 1, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 50: { # 'Ч' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 0, # 'М' + 36: 1, # 'Н' + 41: 1, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 1, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 1, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 2, # 'о' + 13: 0, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 1, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 54: { # 'Ш' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 1, # 'Н' + 41: 1, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 1, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 0, # 'б' + 9: 2, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 1, # 'л' + 14: 1, # 'м' + 6: 1, # 'н' + 4: 2, # 'о' + 13: 1, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 1, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 1, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 57: { # 'Щ' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 1, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 1, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 1, # 'о' + 13: 0, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 1, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 61: { # 'Ъ' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 0, # 'Г' + 37: 1, # 'Д' + 44: 0, # 'Е' + 55: 1, # 'Ж' + 47: 1, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 2, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 0, # 'О' + 30: 1, # 'П' + 39: 2, # 'Р' + 28: 1, # 'С' + 34: 1, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 1, # 'Ш' + 57: 1, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 0, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 0, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 1, # 'л' + 14: 0, # 'м' + 6: 1, # 'н' + 4: 0, # 'о' + 13: 0, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 0, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 60: { # 'Ю' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 1, # 'Б' + 35: 0, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 0, # 'Е' + 55: 1, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 0, # 'М' + 36: 1, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 1, # 'Р' + 28: 1, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 1, # 'б' + 9: 1, # 'в' + 20: 2, # 'г' + 11: 1, # 'д' + 3: 0, # 'е' + 23: 2, # 'ж' + 15: 1, # 'з' + 2: 1, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 1, # 'л' + 14: 1, # 'м' + 6: 1, # 'н' + 4: 0, # 'о' + 13: 1, # 'п' + 7: 1, # 'р' + 8: 1, # 'с' + 5: 1, # 'т' + 19: 0, # 'у' + 29: 0, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 56: { # 'Я' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 1, # 'С' + 34: 2, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 1, # 'б' + 9: 1, # 'в' + 20: 1, # 'г' + 11: 1, # 'д' + 3: 0, # 'е' + 23: 0, # 'ж' + 15: 1, # 'з' + 2: 1, # 'и' + 26: 1, # 'й' + 12: 1, # 'к' + 10: 1, # 'л' + 14: 2, # 'м' + 6: 2, # 'н' + 4: 0, # 'о' + 13: 2, # 'п' + 7: 1, # 'р' + 8: 1, # 'с' + 5: 1, # 'т' + 19: 0, # 'у' + 29: 0, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 1: { # 'а' + 63: 1, # 'e' + 45: 1, # '\xad' + 31: 1, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 1, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 3, # 'е' + 23: 3, # 'ж' + 15: 3, # 'з' + 2: 3, # 'и' + 26: 3, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 2, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 3, # 'у' + 29: 3, # 'ф' + 25: 3, # 'х' + 22: 3, # 'ц' + 21: 3, # 'ч' + 27: 3, # 'ш' + 24: 3, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 18: { # 'б' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 3, # 'в' + 20: 1, # 'г' + 11: 2, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 3, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 1, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 0, # 'т' + 19: 3, # 'у' + 29: 0, # 'ф' + 25: 2, # 'х' + 22: 1, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 3, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 9: { # 'в' + 63: 1, # 'e' + 45: 1, # '\xad' + 31: 0, # 'А' + 32: 1, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 1, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 0, # 'в' + 20: 2, # 'г' + 11: 3, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 3, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 2, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 2, # 'х' + 22: 2, # 'ц' + 21: 3, # 'ч' + 27: 2, # 'ш' + 24: 1, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 20: { # 'г' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 2, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 3, # 'л' + 14: 1, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 1, # 'п' + 7: 3, # 'р' + 8: 2, # 'с' + 5: 2, # 'т' + 19: 3, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 1, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 11: { # 'д' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 2, # 'б' + 9: 3, # 'в' + 20: 2, # 'г' + 11: 2, # 'д' + 3: 3, # 'е' + 23: 3, # 'ж' + 15: 2, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 1, # 'т' + 19: 3, # 'у' + 29: 1, # 'ф' + 25: 2, # 'х' + 22: 2, # 'ц' + 21: 2, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 3: { # 'е' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 2, # 'е' + 23: 3, # 'ж' + 15: 3, # 'з' + 2: 2, # 'и' + 26: 3, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 2, # 'у' + 29: 3, # 'ф' + 25: 3, # 'х' + 22: 3, # 'ц' + 21: 3, # 'ч' + 27: 3, # 'ш' + 24: 3, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 23: { # 'ж' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 3, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 3, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 2, # 'к' + 10: 1, # 'л' + 14: 1, # 'м' + 6: 3, # 'н' + 4: 2, # 'о' + 13: 1, # 'п' + 7: 1, # 'р' + 8: 1, # 'с' + 5: 1, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 1, # 'ц' + 21: 1, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 15: { # 'з' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 3, # 'у' + 29: 1, # 'ф' + 25: 2, # 'х' + 22: 2, # 'ц' + 21: 2, # 'ч' + 27: 2, # 'ш' + 24: 1, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 2, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 2: { # 'и' + 63: 1, # 'e' + 45: 1, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 1, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 1, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 1, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 3, # 'е' + 23: 3, # 'ж' + 15: 3, # 'з' + 2: 3, # 'и' + 26: 3, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 2, # 'у' + 29: 3, # 'ф' + 25: 3, # 'х' + 22: 3, # 'ц' + 21: 3, # 'ч' + 27: 3, # 'ш' + 24: 3, # 'щ' + 17: 2, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 26: { # 'й' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 1, # 'а' + 18: 2, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 2, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 2, # 'з' + 2: 1, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 2, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 2, # 'о' + 13: 1, # 'п' + 7: 2, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 1, # 'у' + 29: 2, # 'ф' + 25: 1, # 'х' + 22: 2, # 'ц' + 21: 2, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 12: { # 'к' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 1, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 3, # 'в' + 20: 2, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 2, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 3, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 1, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 3, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 3, # 'ц' + 21: 2, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 10: { # 'л' + 63: 1, # 'e' + 45: 1, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 1, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 2, # 'д' + 3: 3, # 'е' + 23: 3, # 'ж' + 15: 2, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 1, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 2, # 'п' + 7: 2, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 3, # 'у' + 29: 2, # 'ф' + 25: 2, # 'х' + 22: 2, # 'ц' + 21: 2, # 'ч' + 27: 2, # 'ш' + 24: 1, # 'щ' + 17: 3, # 'ъ' + 52: 2, # 'ь' + 42: 3, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 14: { # 'м' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 1, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 2, # 'к' + 10: 3, # 'л' + 14: 1, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 3, # 'п' + 7: 2, # 'р' + 8: 2, # 'с' + 5: 1, # 'т' + 19: 3, # 'у' + 29: 2, # 'ф' + 25: 1, # 'х' + 22: 2, # 'ц' + 21: 2, # 'ч' + 27: 2, # 'ш' + 24: 1, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 6: { # 'н' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 1, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 2, # 'б' + 9: 2, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 3, # 'е' + 23: 2, # 'ж' + 15: 2, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 2, # 'л' + 14: 1, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 1, # 'п' + 7: 2, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 3, # 'у' + 29: 3, # 'ф' + 25: 2, # 'х' + 22: 3, # 'ц' + 21: 3, # 'ч' + 27: 2, # 'ш' + 24: 1, # 'щ' + 17: 3, # 'ъ' + 52: 2, # 'ь' + 42: 2, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 4: { # 'о' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 3, # 'е' + 23: 3, # 'ж' + 15: 3, # 'з' + 2: 3, # 'и' + 26: 3, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 2, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 2, # 'у' + 29: 3, # 'ф' + 25: 3, # 'х' + 22: 3, # 'ц' + 21: 3, # 'ч' + 27: 3, # 'ш' + 24: 3, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 13: { # 'п' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 1, # 'й' + 12: 2, # 'к' + 10: 3, # 'л' + 14: 1, # 'м' + 6: 2, # 'н' + 4: 3, # 'о' + 13: 1, # 'п' + 7: 3, # 'р' + 8: 2, # 'с' + 5: 2, # 'т' + 19: 3, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 2, # 'ц' + 21: 2, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 2, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 7: { # 'р' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 3, # 'е' + 23: 3, # 'ж' + 15: 2, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 2, # 'п' + 7: 1, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 3, # 'у' + 29: 2, # 'ф' + 25: 3, # 'х' + 22: 3, # 'ц' + 21: 2, # 'ч' + 27: 3, # 'ш' + 24: 1, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 8: { # 'с' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 2, # 'б' + 9: 3, # 'в' + 20: 2, # 'г' + 11: 2, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 1, # 'с' + 5: 3, # 'т' + 19: 3, # 'у' + 29: 2, # 'ф' + 25: 2, # 'х' + 22: 2, # 'ц' + 21: 2, # 'ч' + 27: 2, # 'ш' + 24: 0, # 'щ' + 17: 3, # 'ъ' + 52: 2, # 'ь' + 42: 2, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 5: { # 'т' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 2, # 'г' + 11: 2, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 2, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 3, # 'у' + 29: 1, # 'ф' + 25: 2, # 'х' + 22: 2, # 'ц' + 21: 2, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 3, # 'ъ' + 52: 2, # 'ь' + 42: 2, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 19: { # 'у' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 2, # 'е' + 23: 3, # 'ж' + 15: 3, # 'з' + 2: 2, # 'и' + 26: 2, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 2, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 1, # 'у' + 29: 2, # 'ф' + 25: 2, # 'х' + 22: 2, # 'ц' + 21: 3, # 'ч' + 27: 3, # 'ш' + 24: 2, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 29: { # 'ф' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 1, # 'в' + 20: 1, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 2, # 'к' + 10: 2, # 'л' + 14: 1, # 'м' + 6: 1, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 2, # 'р' + 8: 2, # 'с' + 5: 2, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 2, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 25: { # 'х' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 3, # 'в' + 20: 0, # 'г' + 11: 1, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 2, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 1, # 'п' + 7: 3, # 'р' + 8: 1, # 'с' + 5: 2, # 'т' + 19: 3, # 'у' + 29: 0, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 1, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 22: { # 'ц' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 2, # 'к' + 10: 1, # 'л' + 14: 1, # 'м' + 6: 1, # 'н' + 4: 2, # 'о' + 13: 1, # 'п' + 7: 1, # 'р' + 8: 1, # 'с' + 5: 1, # 'т' + 19: 2, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 1, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 0, # 'ю' + 16: 2, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 21: { # 'ч' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 3, # 'в' + 20: 1, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 0, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 2, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 2, # 'р' + 8: 0, # 'с' + 5: 2, # 'т' + 19: 3, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 27: { # 'ш' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 2, # 'в' + 20: 0, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 2, # 'л' + 14: 1, # 'м' + 6: 3, # 'н' + 4: 2, # 'о' + 13: 2, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 1, # 'т' + 19: 2, # 'у' + 29: 1, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 1, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 24: { # 'щ' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 1, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 2, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 2, # 'т' + 19: 3, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 1, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 2, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 17: { # 'ъ' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 1, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 2, # 'е' + 23: 3, # 'ж' + 15: 3, # 'з' + 2: 1, # 'и' + 26: 2, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 1, # 'у' + 29: 1, # 'ф' + 25: 2, # 'х' + 22: 2, # 'ц' + 21: 3, # 'ч' + 27: 2, # 'ш' + 24: 3, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 2, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 52: { # 'ь' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 1, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 0, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 1, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 0, # 'р' + 8: 0, # 'с' + 5: 1, # 'т' + 19: 0, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 1, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 42: { # 'ю' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 1, # 'а' + 18: 2, # 'б' + 9: 1, # 'в' + 20: 2, # 'г' + 11: 2, # 'д' + 3: 1, # 'е' + 23: 2, # 'ж' + 15: 2, # 'з' + 2: 1, # 'и' + 26: 1, # 'й' + 12: 2, # 'к' + 10: 2, # 'л' + 14: 2, # 'м' + 6: 2, # 'н' + 4: 1, # 'о' + 13: 1, # 'п' + 7: 2, # 'р' + 8: 2, # 'с' + 5: 2, # 'т' + 19: 1, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 2, # 'ц' + 21: 3, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 16: { # 'я' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 2, # 'г' + 11: 3, # 'д' + 3: 2, # 'е' + 23: 1, # 'ж' + 15: 2, # 'з' + 2: 1, # 'и' + 26: 2, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 1, # 'о' + 13: 2, # 'п' + 7: 2, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 1, # 'у' + 29: 1, # 'ф' + 25: 3, # 'х' + 22: 2, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 2, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 58: { # 'є' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 0, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 0, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 0, # 'о' + 13: 0, # 'п' + 7: 0, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 0, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 62: { # '№' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 0, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 0, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 0, # 'о' + 13: 0, # 'п' + 7: 0, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 0, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, +} + +# 255: Undefined characters that did not exist in training text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 +# 251: Control characters + +# Character Mapping Table(s): +ISO_8859_5_BULGARIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 77, # 'A' + 66: 90, # 'B' + 67: 99, # 'C' + 68: 100, # 'D' + 69: 72, # 'E' + 70: 109, # 'F' + 71: 107, # 'G' + 72: 101, # 'H' + 73: 79, # 'I' + 74: 185, # 'J' + 75: 81, # 'K' + 76: 102, # 'L' + 77: 76, # 'M' + 78: 94, # 'N' + 79: 82, # 'O' + 80: 110, # 'P' + 81: 186, # 'Q' + 82: 108, # 'R' + 83: 91, # 'S' + 84: 74, # 'T' + 85: 119, # 'U' + 86: 84, # 'V' + 87: 96, # 'W' + 88: 111, # 'X' + 89: 187, # 'Y' + 90: 115, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 65, # 'a' + 98: 69, # 'b' + 99: 70, # 'c' + 100: 66, # 'd' + 101: 63, # 'e' + 102: 68, # 'f' + 103: 112, # 'g' + 104: 103, # 'h' + 105: 92, # 'i' + 106: 194, # 'j' + 107: 104, # 'k' + 108: 95, # 'l' + 109: 86, # 'm' + 110: 87, # 'n' + 111: 71, # 'o' + 112: 116, # 'p' + 113: 195, # 'q' + 114: 85, # 'r' + 115: 93, # 's' + 116: 97, # 't' + 117: 113, # 'u' + 118: 196, # 'v' + 119: 197, # 'w' + 120: 198, # 'x' + 121: 199, # 'y' + 122: 200, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 194, # '\x80' + 129: 195, # '\x81' + 130: 196, # '\x82' + 131: 197, # '\x83' + 132: 198, # '\x84' + 133: 199, # '\x85' + 134: 200, # '\x86' + 135: 201, # '\x87' + 136: 202, # '\x88' + 137: 203, # '\x89' + 138: 204, # '\x8a' + 139: 205, # '\x8b' + 140: 206, # '\x8c' + 141: 207, # '\x8d' + 142: 208, # '\x8e' + 143: 209, # '\x8f' + 144: 210, # '\x90' + 145: 211, # '\x91' + 146: 212, # '\x92' + 147: 213, # '\x93' + 148: 214, # '\x94' + 149: 215, # '\x95' + 150: 216, # '\x96' + 151: 217, # '\x97' + 152: 218, # '\x98' + 153: 219, # '\x99' + 154: 220, # '\x9a' + 155: 221, # '\x9b' + 156: 222, # '\x9c' + 157: 223, # '\x9d' + 158: 224, # '\x9e' + 159: 225, # '\x9f' + 160: 81, # '\xa0' + 161: 226, # 'Ё' + 162: 227, # 'Ђ' + 163: 228, # 'Ѓ' + 164: 229, # 'Є' + 165: 230, # 'Ѕ' + 166: 105, # 'І' + 167: 231, # 'Ї' + 168: 232, # 'Ј' + 169: 233, # 'Љ' + 170: 234, # 'Њ' + 171: 235, # 'Ћ' + 172: 236, # 'Ќ' + 173: 45, # '\xad' + 174: 237, # 'Ў' + 175: 238, # 'Џ' + 176: 31, # 'А' + 177: 32, # 'Б' + 178: 35, # 'В' + 179: 43, # 'Г' + 180: 37, # 'Д' + 181: 44, # 'Е' + 182: 55, # 'Ж' + 183: 47, # 'З' + 184: 40, # 'И' + 185: 59, # 'Й' + 186: 33, # 'К' + 187: 46, # 'Л' + 188: 38, # 'М' + 189: 36, # 'Н' + 190: 41, # 'О' + 191: 30, # 'П' + 192: 39, # 'Р' + 193: 28, # 'С' + 194: 34, # 'Т' + 195: 51, # 'У' + 196: 48, # 'Ф' + 197: 49, # 'Х' + 198: 53, # 'Ц' + 199: 50, # 'Ч' + 200: 54, # 'Ш' + 201: 57, # 'Щ' + 202: 61, # 'Ъ' + 203: 239, # 'Ы' + 204: 67, # 'Ь' + 205: 240, # 'Э' + 206: 60, # 'Ю' + 207: 56, # 'Я' + 208: 1, # 'а' + 209: 18, # 'б' + 210: 9, # 'в' + 211: 20, # 'г' + 212: 11, # 'д' + 213: 3, # 'е' + 214: 23, # 'ж' + 215: 15, # 'з' + 216: 2, # 'и' + 217: 26, # 'й' + 218: 12, # 'к' + 219: 10, # 'л' + 220: 14, # 'м' + 221: 6, # 'н' + 222: 4, # 'о' + 223: 13, # 'п' + 224: 7, # 'р' + 225: 8, # 'с' + 226: 5, # 'т' + 227: 19, # 'у' + 228: 29, # 'ф' + 229: 25, # 'х' + 230: 22, # 'ц' + 231: 21, # 'ч' + 232: 27, # 'ш' + 233: 24, # 'щ' + 234: 17, # 'ъ' + 235: 75, # 'ы' + 236: 52, # 'ь' + 237: 241, # 'э' + 238: 42, # 'ю' + 239: 16, # 'я' + 240: 62, # '№' + 241: 242, # 'ё' + 242: 243, # 'ђ' + 243: 244, # 'ѓ' + 244: 58, # 'є' + 245: 245, # 'ѕ' + 246: 98, # 'і' + 247: 246, # 'ї' + 248: 247, # 'ј' + 249: 248, # 'љ' + 250: 249, # 'њ' + 251: 250, # 'ћ' + 252: 251, # 'ќ' + 253: 91, # '§' + 254: 252, # 'ў' + 255: 253, # 'џ' +} + +ISO_8859_5_BULGARIAN_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-5', + language='Bulgarian', + char_to_order_map=ISO_8859_5_BULGARIAN_CHAR_TO_ORDER, + language_model=BULGARIAN_LANG_MODEL, + typical_positive_ratio=0.969392, + keep_ascii_letters=False, + alphabet='АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯабвгдежзийклмнопрстуфхцчшщъьюя') + +WINDOWS_1251_BULGARIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 77, # 'A' + 66: 90, # 'B' + 67: 99, # 'C' + 68: 100, # 'D' + 69: 72, # 'E' + 70: 109, # 'F' + 71: 107, # 'G' + 72: 101, # 'H' + 73: 79, # 'I' + 74: 185, # 'J' + 75: 81, # 'K' + 76: 102, # 'L' + 77: 76, # 'M' + 78: 94, # 'N' + 79: 82, # 'O' + 80: 110, # 'P' + 81: 186, # 'Q' + 82: 108, # 'R' + 83: 91, # 'S' + 84: 74, # 'T' + 85: 119, # 'U' + 86: 84, # 'V' + 87: 96, # 'W' + 88: 111, # 'X' + 89: 187, # 'Y' + 90: 115, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 65, # 'a' + 98: 69, # 'b' + 99: 70, # 'c' + 100: 66, # 'd' + 101: 63, # 'e' + 102: 68, # 'f' + 103: 112, # 'g' + 104: 103, # 'h' + 105: 92, # 'i' + 106: 194, # 'j' + 107: 104, # 'k' + 108: 95, # 'l' + 109: 86, # 'm' + 110: 87, # 'n' + 111: 71, # 'o' + 112: 116, # 'p' + 113: 195, # 'q' + 114: 85, # 'r' + 115: 93, # 's' + 116: 97, # 't' + 117: 113, # 'u' + 118: 196, # 'v' + 119: 197, # 'w' + 120: 198, # 'x' + 121: 199, # 'y' + 122: 200, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 206, # 'Ђ' + 129: 207, # 'Ѓ' + 130: 208, # '‚' + 131: 209, # 'ѓ' + 132: 210, # '„' + 133: 211, # '…' + 134: 212, # '†' + 135: 213, # '‡' + 136: 120, # '€' + 137: 214, # '‰' + 138: 215, # 'Љ' + 139: 216, # '‹' + 140: 217, # 'Њ' + 141: 218, # 'Ќ' + 142: 219, # 'Ћ' + 143: 220, # 'Џ' + 144: 221, # 'ђ' + 145: 78, # '‘' + 146: 64, # '’' + 147: 83, # '“' + 148: 121, # '”' + 149: 98, # '•' + 150: 117, # '–' + 151: 105, # '—' + 152: 222, # None + 153: 223, # '™' + 154: 224, # 'љ' + 155: 225, # '›' + 156: 226, # 'њ' + 157: 227, # 'ќ' + 158: 228, # 'ћ' + 159: 229, # 'џ' + 160: 88, # '\xa0' + 161: 230, # 'Ў' + 162: 231, # 'ў' + 163: 232, # 'Ј' + 164: 233, # '¤' + 165: 122, # 'Ґ' + 166: 89, # '¦' + 167: 106, # '§' + 168: 234, # 'Ё' + 169: 235, # '©' + 170: 236, # 'Є' + 171: 237, # '«' + 172: 238, # '¬' + 173: 45, # '\xad' + 174: 239, # '®' + 175: 240, # 'Ї' + 176: 73, # '°' + 177: 80, # '±' + 178: 118, # 'І' + 179: 114, # 'і' + 180: 241, # 'ґ' + 181: 242, # 'µ' + 182: 243, # '¶' + 183: 244, # '·' + 184: 245, # 'ё' + 185: 62, # '№' + 186: 58, # 'є' + 187: 246, # '»' + 188: 247, # 'ј' + 189: 248, # 'Ѕ' + 190: 249, # 'ѕ' + 191: 250, # 'ї' + 192: 31, # 'А' + 193: 32, # 'Б' + 194: 35, # 'В' + 195: 43, # 'Г' + 196: 37, # 'Д' + 197: 44, # 'Е' + 198: 55, # 'Ж' + 199: 47, # 'З' + 200: 40, # 'И' + 201: 59, # 'Й' + 202: 33, # 'К' + 203: 46, # 'Л' + 204: 38, # 'М' + 205: 36, # 'Н' + 206: 41, # 'О' + 207: 30, # 'П' + 208: 39, # 'Р' + 209: 28, # 'С' + 210: 34, # 'Т' + 211: 51, # 'У' + 212: 48, # 'Ф' + 213: 49, # 'Х' + 214: 53, # 'Ц' + 215: 50, # 'Ч' + 216: 54, # 'Ш' + 217: 57, # 'Щ' + 218: 61, # 'Ъ' + 219: 251, # 'Ы' + 220: 67, # 'Ь' + 221: 252, # 'Э' + 222: 60, # 'Ю' + 223: 56, # 'Я' + 224: 1, # 'а' + 225: 18, # 'б' + 226: 9, # 'в' + 227: 20, # 'г' + 228: 11, # 'д' + 229: 3, # 'е' + 230: 23, # 'ж' + 231: 15, # 'з' + 232: 2, # 'и' + 233: 26, # 'й' + 234: 12, # 'к' + 235: 10, # 'л' + 236: 14, # 'м' + 237: 6, # 'н' + 238: 4, # 'о' + 239: 13, # 'п' + 240: 7, # 'р' + 241: 8, # 'с' + 242: 5, # 'т' + 243: 19, # 'у' + 244: 29, # 'ф' + 245: 25, # 'х' + 246: 22, # 'ц' + 247: 21, # 'ч' + 248: 27, # 'ш' + 249: 24, # 'щ' + 250: 17, # 'ъ' + 251: 75, # 'ы' + 252: 52, # 'ь' + 253: 253, # 'э' + 254: 42, # 'ю' + 255: 16, # 'я' +} + +WINDOWS_1251_BULGARIAN_MODEL = SingleByteCharSetModel(charset_name='windows-1251', + language='Bulgarian', + char_to_order_map=WINDOWS_1251_BULGARIAN_CHAR_TO_ORDER, + language_model=BULGARIAN_LANG_MODEL, + typical_positive_ratio=0.969392, + keep_ascii_letters=False, + alphabet='АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯабвгдежзийклмнопрстуфхцчшщъьюя') + diff --git a/openpype/vendor/python/python_2/chardet/langgreekmodel.py b/openpype/vendor/python/python_2/chardet/langgreekmodel.py new file mode 100644 index 0000000000..02b94de655 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/langgreekmodel.py @@ -0,0 +1,4398 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from chardet.sbcharsetprober import SingleByteCharSetModel + + +# 3: Positive +# 2: Likely +# 1: Unlikely +# 0: Negative + +GREEK_LANG_MODEL = { + 60: { # 'e' + 60: 2, # 'e' + 55: 1, # 'o' + 58: 2, # 't' + 36: 1, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 1, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 55: { # 'o' + 60: 0, # 'e' + 55: 2, # 'o' + 58: 2, # 't' + 36: 1, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 1, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 1, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 58: { # 't' + 60: 2, # 'e' + 55: 1, # 'o' + 58: 1, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 1, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 36: { # '·' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 61: { # 'Ά' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 1, # 'γ' + 21: 2, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 1, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 46: { # 'Έ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 2, # 'β' + 20: 2, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 2, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 3, # 'ν' + 30: 2, # 'ξ' + 4: 0, # 'ο' + 9: 2, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 1, # 'σ' + 2: 2, # 'τ' + 12: 0, # 'υ' + 28: 2, # 'φ' + 23: 3, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 54: { # 'Ό' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 2, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 2, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 2, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 2, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 31: { # 'Α' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 2, # 'Β' + 43: 2, # 'Γ' + 41: 1, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 2, # 'Θ' + 47: 2, # 'Ι' + 44: 2, # 'Κ' + 53: 2, # 'Λ' + 38: 2, # 'Μ' + 49: 2, # 'Ν' + 59: 1, # 'Ξ' + 39: 0, # 'Ο' + 35: 2, # 'Π' + 48: 2, # 'Ρ' + 37: 2, # 'Σ' + 33: 2, # 'Τ' + 45: 2, # 'Υ' + 56: 2, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 2, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 1, # 'θ' + 5: 0, # 'ι' + 11: 2, # 'κ' + 16: 3, # 'λ' + 10: 2, # 'μ' + 6: 3, # 'ν' + 30: 2, # 'ξ' + 4: 0, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 2, # 'ς' + 7: 2, # 'σ' + 2: 0, # 'τ' + 12: 3, # 'υ' + 28: 2, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 2, # 'ύ' + 27: 0, # 'ώ' + }, + 51: { # 'Β' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 1, # 'Ε' + 40: 1, # 'Η' + 52: 0, # 'Θ' + 47: 1, # 'Ι' + 44: 0, # 'Κ' + 53: 1, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 2, # 'έ' + 22: 2, # 'ή' + 15: 0, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 43: { # 'Γ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 1, # 'Α' + 51: 0, # 'Β' + 43: 2, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 1, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 1, # 'Κ' + 53: 1, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 1, # 'Ο' + 35: 0, # 'Π' + 48: 2, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 2, # 'Υ' + 56: 0, # 'Φ' + 50: 1, # 'Χ' + 57: 2, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 2, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 41: { # 'Δ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 2, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 2, # 'ή' + 15: 2, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 2, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 2, # 'ω' + 19: 1, # 'ό' + 26: 2, # 'ύ' + 27: 2, # 'ώ' + }, + 34: { # 'Ε' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 2, # 'Γ' + 41: 2, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 2, # 'Κ' + 53: 2, # 'Λ' + 38: 2, # 'Μ' + 49: 2, # 'Ν' + 59: 1, # 'Ξ' + 39: 0, # 'Ο' + 35: 2, # 'Π' + 48: 2, # 'Ρ' + 37: 2, # 'Σ' + 33: 2, # 'Τ' + 45: 2, # 'Υ' + 56: 0, # 'Φ' + 50: 2, # 'Χ' + 57: 2, # 'Ω' + 17: 3, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 3, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 3, # 'γ' + 21: 2, # 'δ' + 3: 1, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 1, # 'θ' + 5: 2, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 2, # 'μ' + 6: 3, # 'ν' + 30: 2, # 'ξ' + 4: 0, # 'ο' + 9: 3, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 2, # 'σ' + 2: 2, # 'τ' + 12: 2, # 'υ' + 28: 2, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 1, # 'ύ' + 27: 0, # 'ώ' + }, + 40: { # 'Η' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 1, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 2, # 'Θ' + 47: 0, # 'Ι' + 44: 2, # 'Κ' + 53: 0, # 'Λ' + 38: 2, # 'Μ' + 49: 2, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 2, # 'Π' + 48: 2, # 'Ρ' + 37: 2, # 'Σ' + 33: 2, # 'Τ' + 45: 1, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 1, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 1, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 52: { # 'Θ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 1, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 1, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 2, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 2, # 'ύ' + 27: 0, # 'ώ' + }, + 47: { # 'Ι' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 1, # 'Β' + 43: 1, # 'Γ' + 41: 2, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 2, # 'Κ' + 53: 2, # 'Λ' + 38: 2, # 'Μ' + 49: 2, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 2, # 'Ρ' + 37: 2, # 'Σ' + 33: 2, # 'Τ' + 45: 0, # 'Υ' + 56: 2, # 'Φ' + 50: 0, # 'Χ' + 57: 2, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 2, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 1, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 2, # 'σ' + 2: 1, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 1, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 44: { # 'Κ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 1, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 1, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 2, # 'Ρ' + 37: 0, # 'Σ' + 33: 1, # 'Τ' + 45: 2, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 1, # 'Ω' + 17: 3, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 2, # 'ό' + 26: 2, # 'ύ' + 27: 2, # 'ώ' + }, + 53: { # 'Λ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 0, # 'Κ' + 53: 2, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 2, # 'Σ' + 33: 0, # 'Τ' + 45: 2, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 2, # 'Ω' + 17: 2, # 'ά' + 18: 2, # 'έ' + 22: 0, # 'ή' + 15: 2, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 1, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 2, # 'ό' + 26: 2, # 'ύ' + 27: 0, # 'ώ' + }, + 38: { # 'Μ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 2, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 2, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 2, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 2, # 'έ' + 22: 2, # 'ή' + 15: 2, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 2, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 3, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 2, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 49: { # 'Ν' + 60: 2, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 2, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 2, # 'Ω' + 17: 0, # 'ά' + 18: 2, # 'έ' + 22: 0, # 'ή' + 15: 2, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 1, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 1, # 'ω' + 19: 2, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 59: { # 'Ξ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 1, # 'Ε' + 40: 1, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 1, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 2, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 39: { # 'Ο' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 1, # 'Β' + 43: 2, # 'Γ' + 41: 2, # 'Δ' + 34: 2, # 'Ε' + 40: 1, # 'Η' + 52: 2, # 'Θ' + 47: 2, # 'Ι' + 44: 2, # 'Κ' + 53: 2, # 'Λ' + 38: 2, # 'Μ' + 49: 2, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 2, # 'Π' + 48: 2, # 'Ρ' + 37: 2, # 'Σ' + 33: 2, # 'Τ' + 45: 2, # 'Υ' + 56: 2, # 'Φ' + 50: 2, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 2, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 2, # 'κ' + 16: 2, # 'λ' + 10: 2, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 2, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 2, # 'τ' + 12: 2, # 'υ' + 28: 1, # 'φ' + 23: 1, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 2, # 'ύ' + 27: 0, # 'ώ' + }, + 35: { # 'Π' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 0, # 'Κ' + 53: 2, # 'Λ' + 38: 1, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 2, # 'Ρ' + 37: 0, # 'Σ' + 33: 1, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 1, # 'Χ' + 57: 2, # 'Ω' + 17: 2, # 'ά' + 18: 1, # 'έ' + 22: 1, # 'ή' + 15: 2, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 2, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 2, # 'χ' + 42: 0, # 'ψ' + 24: 2, # 'ω' + 19: 2, # 'ό' + 26: 0, # 'ύ' + 27: 3, # 'ώ' + }, + 48: { # 'Ρ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 1, # 'Γ' + 41: 1, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 2, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 2, # 'Ρ' + 37: 0, # 'Σ' + 33: 1, # 'Τ' + 45: 1, # 'Υ' + 56: 0, # 'Φ' + 50: 1, # 'Χ' + 57: 1, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 2, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 1, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 3, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 2, # 'ω' + 19: 0, # 'ό' + 26: 2, # 'ύ' + 27: 0, # 'ώ' + }, + 37: { # 'Σ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 1, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 2, # 'Κ' + 53: 0, # 'Λ' + 38: 2, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 2, # 'Σ' + 33: 2, # 'Τ' + 45: 2, # 'Υ' + 56: 0, # 'Φ' + 50: 2, # 'Χ' + 57: 2, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 2, # 'ή' + 15: 2, # 'ί' + 1: 2, # 'α' + 29: 2, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 2, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 2, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 0, # 'φ' + 23: 2, # 'χ' + 42: 0, # 'ψ' + 24: 2, # 'ω' + 19: 0, # 'ό' + 26: 2, # 'ύ' + 27: 2, # 'ώ' + }, + 33: { # 'Τ' + 60: 0, # 'e' + 55: 1, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 2, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 2, # 'Ρ' + 37: 0, # 'Σ' + 33: 1, # 'Τ' + 45: 1, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 2, # 'Ω' + 17: 2, # 'ά' + 18: 2, # 'έ' + 22: 0, # 'ή' + 15: 2, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 2, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 2, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 2, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 2, # 'ό' + 26: 2, # 'ύ' + 27: 3, # 'ώ' + }, + 45: { # 'Υ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 2, # 'Γ' + 41: 0, # 'Δ' + 34: 1, # 'Ε' + 40: 2, # 'Η' + 52: 2, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 1, # 'Λ' + 38: 2, # 'Μ' + 49: 2, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 2, # 'Π' + 48: 1, # 'Ρ' + 37: 2, # 'Σ' + 33: 2, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 1, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 3, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 56: { # 'Φ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 1, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 1, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 2, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 1, # 'ύ' + 27: 1, # 'ώ' + }, + 50: { # 'Χ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 1, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 1, # 'Ν' + 59: 0, # 'Ξ' + 39: 1, # 'Ο' + 35: 0, # 'Π' + 48: 2, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 1, # 'Χ' + 57: 1, # 'Ω' + 17: 2, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 2, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 2, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 57: { # 'Ω' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 1, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 1, # 'Λ' + 38: 0, # 'Μ' + 49: 2, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 2, # 'Ρ' + 37: 2, # 'Σ' + 33: 2, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 2, # 'ρ' + 14: 2, # 'ς' + 7: 2, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 1, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 17: { # 'ά' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 2, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 3, # 'β' + 20: 3, # 'γ' + 21: 3, # 'δ' + 3: 3, # 'ε' + 32: 3, # 'ζ' + 13: 0, # 'η' + 25: 3, # 'θ' + 5: 2, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 3, # 'ξ' + 4: 0, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 3, # 'φ' + 23: 3, # 'χ' + 42: 3, # 'ψ' + 24: 2, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 18: { # 'έ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 3, # 'α' + 29: 2, # 'β' + 20: 3, # 'γ' + 21: 2, # 'δ' + 3: 3, # 'ε' + 32: 2, # 'ζ' + 13: 0, # 'η' + 25: 3, # 'θ' + 5: 0, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 3, # 'ξ' + 4: 3, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 3, # 'φ' + 23: 3, # 'χ' + 42: 3, # 'ψ' + 24: 2, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 22: { # 'ή' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 1, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 3, # 'γ' + 21: 3, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 3, # 'θ' + 5: 0, # 'ι' + 11: 3, # 'κ' + 16: 2, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 2, # 'ξ' + 4: 0, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 2, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 15: { # 'ί' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 3, # 'α' + 29: 2, # 'β' + 20: 3, # 'γ' + 21: 3, # 'δ' + 3: 3, # 'ε' + 32: 3, # 'ζ' + 13: 3, # 'η' + 25: 3, # 'θ' + 5: 0, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 3, # 'ξ' + 4: 3, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 1, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 3, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 1: { # 'α' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 2, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 2, # 'έ' + 22: 0, # 'ή' + 15: 3, # 'ί' + 1: 0, # 'α' + 29: 3, # 'β' + 20: 3, # 'γ' + 21: 3, # 'δ' + 3: 2, # 'ε' + 32: 3, # 'ζ' + 13: 1, # 'η' + 25: 3, # 'θ' + 5: 3, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 3, # 'ξ' + 4: 2, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 3, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 0, # 'ω' + 19: 2, # 'ό' + 26: 2, # 'ύ' + 27: 0, # 'ώ' + }, + 29: { # 'β' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 2, # 'έ' + 22: 3, # 'ή' + 15: 2, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 2, # 'γ' + 21: 2, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 2, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 3, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 2, # 'ω' + 19: 2, # 'ό' + 26: 2, # 'ύ' + 27: 2, # 'ώ' + }, + 20: { # 'γ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 3, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 3, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 3, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 2, # 'ύ' + 27: 3, # 'ώ' + }, + 21: { # 'δ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 3, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 3, # 'ώ' + }, + 3: { # 'ε' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 2, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 3, # 'ί' + 1: 2, # 'α' + 29: 3, # 'β' + 20: 3, # 'γ' + 21: 3, # 'δ' + 3: 2, # 'ε' + 32: 2, # 'ζ' + 13: 0, # 'η' + 25: 3, # 'θ' + 5: 3, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 3, # 'ξ' + 4: 2, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 3, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 3, # 'ω' + 19: 2, # 'ό' + 26: 3, # 'ύ' + 27: 2, # 'ώ' + }, + 32: { # 'ζ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 2, # 'έ' + 22: 2, # 'ή' + 15: 2, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 1, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 2, # 'ό' + 26: 0, # 'ύ' + 27: 2, # 'ώ' + }, + 13: { # 'η' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 2, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 3, # 'γ' + 21: 2, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 3, # 'θ' + 5: 0, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 2, # 'ξ' + 4: 0, # 'ο' + 9: 2, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 2, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 25: { # 'θ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 2, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 1, # 'λ' + 10: 3, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 3, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 3, # 'ώ' + }, + 5: { # 'ι' + 60: 0, # 'e' + 55: 1, # 'o' + 58: 0, # 't' + 36: 2, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 1, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 0, # 'ί' + 1: 3, # 'α' + 29: 3, # 'β' + 20: 3, # 'γ' + 21: 3, # 'δ' + 3: 3, # 'ε' + 32: 2, # 'ζ' + 13: 3, # 'η' + 25: 3, # 'θ' + 5: 0, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 3, # 'ξ' + 4: 3, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 2, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 0, # 'ύ' + 27: 3, # 'ώ' + }, + 11: { # 'κ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 3, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 2, # 'θ' + 5: 3, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 2, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 2, # 'φ' + 23: 2, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 3, # 'ώ' + }, + 16: { # 'λ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 1, # 'β' + 20: 2, # 'γ' + 21: 1, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 2, # 'θ' + 5: 3, # 'ι' + 11: 2, # 'κ' + 16: 3, # 'λ' + 10: 2, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 3, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 2, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 3, # 'ώ' + }, + 10: { # 'μ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 1, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 3, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 3, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 3, # 'φ' + 23: 0, # 'χ' + 42: 2, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 2, # 'ύ' + 27: 2, # 'ώ' + }, + 6: { # 'ν' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 2, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 3, # 'δ' + 3: 3, # 'ε' + 32: 2, # 'ζ' + 13: 3, # 'η' + 25: 3, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 1, # 'λ' + 10: 0, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 3, # 'ώ' + }, + 30: { # 'ξ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 2, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 3, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 2, # 'ό' + 26: 3, # 'ύ' + 27: 1, # 'ώ' + }, + 4: { # 'ο' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 2, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 2, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 2, # 'α' + 29: 3, # 'β' + 20: 3, # 'γ' + 21: 3, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 3, # 'θ' + 5: 3, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 2, # 'ξ' + 4: 2, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 3, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 2, # 'ω' + 19: 1, # 'ό' + 26: 3, # 'ύ' + 27: 2, # 'ώ' + }, + 9: { # 'π' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 3, # 'λ' + 10: 0, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 2, # 'ς' + 7: 0, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 0, # 'φ' + 23: 2, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 2, # 'ύ' + 27: 3, # 'ώ' + }, + 8: { # 'ρ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 2, # 'β' + 20: 3, # 'γ' + 21: 2, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 3, # 'θ' + 5: 3, # 'ι' + 11: 3, # 'κ' + 16: 1, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 2, # 'ξ' + 4: 3, # 'ο' + 9: 2, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 2, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 3, # 'φ' + 23: 3, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 3, # 'ώ' + }, + 14: { # 'ς' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 2, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 7: { # 'σ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 2, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 3, # 'β' + 20: 0, # 'γ' + 21: 2, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 3, # 'θ' + 5: 3, # 'ι' + 11: 3, # 'κ' + 16: 2, # 'λ' + 10: 3, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 3, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 3, # 'φ' + 23: 3, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 2, # 'ώ' + }, + 2: { # 'τ' + 60: 0, # 'e' + 55: 2, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 2, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 2, # 'κ' + 16: 2, # 'λ' + 10: 3, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 2, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 3, # 'ώ' + }, + 12: { # 'υ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 2, # 'έ' + 22: 3, # 'ή' + 15: 2, # 'ί' + 1: 3, # 'α' + 29: 2, # 'β' + 20: 3, # 'γ' + 21: 2, # 'δ' + 3: 2, # 'ε' + 32: 2, # 'ζ' + 13: 2, # 'η' + 25: 3, # 'θ' + 5: 2, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 3, # 'ξ' + 4: 3, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 2, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 2, # 'ω' + 19: 2, # 'ό' + 26: 0, # 'ύ' + 27: 2, # 'ώ' + }, + 28: { # 'φ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 2, # 'η' + 25: 2, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 1, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 1, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 2, # 'ύ' + 27: 2, # 'ώ' + }, + 23: { # 'χ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 2, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 2, # 'η' + 25: 2, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 2, # 'μ' + 6: 3, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 0, # 'φ' + 23: 2, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 3, # 'ώ' + }, + 42: { # 'ψ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 2, # 'έ' + 22: 1, # 'ή' + 15: 2, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 2, # 'τ' + 12: 1, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 2, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 24: { # 'ω' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 1, # 'ά' + 18: 0, # 'έ' + 22: 2, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 2, # 'β' + 20: 3, # 'γ' + 21: 2, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 3, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 2, # 'φ' + 23: 2, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 19: { # 'ό' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 3, # 'β' + 20: 3, # 'γ' + 21: 3, # 'δ' + 3: 1, # 'ε' + 32: 2, # 'ζ' + 13: 2, # 'η' + 25: 2, # 'θ' + 5: 2, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 1, # 'ξ' + 4: 2, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 2, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 26: { # 'ύ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 2, # 'α' + 29: 2, # 'β' + 20: 2, # 'γ' + 21: 1, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 2, # 'η' + 25: 3, # 'θ' + 5: 0, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 2, # 'ξ' + 4: 3, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 2, # 'φ' + 23: 2, # 'χ' + 42: 2, # 'ψ' + 24: 2, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 27: { # 'ώ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 1, # 'β' + 20: 0, # 'γ' + 21: 3, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 1, # 'η' + 25: 2, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 1, # 'ξ' + 4: 0, # 'ο' + 9: 2, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 1, # 'φ' + 23: 1, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, +} + +# 255: Undefined characters that did not exist in training text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 +# 251: Control characters + +# Character Mapping Table(s): +WINDOWS_1253_GREEK_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 82, # 'A' + 66: 100, # 'B' + 67: 104, # 'C' + 68: 94, # 'D' + 69: 98, # 'E' + 70: 101, # 'F' + 71: 116, # 'G' + 72: 102, # 'H' + 73: 111, # 'I' + 74: 187, # 'J' + 75: 117, # 'K' + 76: 92, # 'L' + 77: 88, # 'M' + 78: 113, # 'N' + 79: 85, # 'O' + 80: 79, # 'P' + 81: 118, # 'Q' + 82: 105, # 'R' + 83: 83, # 'S' + 84: 67, # 'T' + 85: 114, # 'U' + 86: 119, # 'V' + 87: 95, # 'W' + 88: 99, # 'X' + 89: 109, # 'Y' + 90: 188, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 72, # 'a' + 98: 70, # 'b' + 99: 80, # 'c' + 100: 81, # 'd' + 101: 60, # 'e' + 102: 96, # 'f' + 103: 93, # 'g' + 104: 89, # 'h' + 105: 68, # 'i' + 106: 120, # 'j' + 107: 97, # 'k' + 108: 77, # 'l' + 109: 86, # 'm' + 110: 69, # 'n' + 111: 55, # 'o' + 112: 78, # 'p' + 113: 115, # 'q' + 114: 65, # 'r' + 115: 66, # 's' + 116: 58, # 't' + 117: 76, # 'u' + 118: 106, # 'v' + 119: 103, # 'w' + 120: 87, # 'x' + 121: 107, # 'y' + 122: 112, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 255, # '€' + 129: 255, # None + 130: 255, # '‚' + 131: 255, # 'ƒ' + 132: 255, # '„' + 133: 255, # '…' + 134: 255, # '†' + 135: 255, # '‡' + 136: 255, # None + 137: 255, # '‰' + 138: 255, # None + 139: 255, # '‹' + 140: 255, # None + 141: 255, # None + 142: 255, # None + 143: 255, # None + 144: 255, # None + 145: 255, # '‘' + 146: 255, # '’' + 147: 255, # '“' + 148: 255, # '”' + 149: 255, # '•' + 150: 255, # '–' + 151: 255, # '—' + 152: 255, # None + 153: 255, # '™' + 154: 255, # None + 155: 255, # '›' + 156: 255, # None + 157: 255, # None + 158: 255, # None + 159: 255, # None + 160: 253, # '\xa0' + 161: 233, # '΅' + 162: 61, # 'Ά' + 163: 253, # '£' + 164: 253, # '¤' + 165: 253, # '¥' + 166: 253, # '¦' + 167: 253, # '§' + 168: 253, # '¨' + 169: 253, # '©' + 170: 253, # None + 171: 253, # '«' + 172: 253, # '¬' + 173: 74, # '\xad' + 174: 253, # '®' + 175: 253, # '―' + 176: 253, # '°' + 177: 253, # '±' + 178: 253, # '²' + 179: 253, # '³' + 180: 247, # '΄' + 181: 253, # 'µ' + 182: 253, # '¶' + 183: 36, # '·' + 184: 46, # 'Έ' + 185: 71, # 'Ή' + 186: 73, # 'Ί' + 187: 253, # '»' + 188: 54, # 'Ό' + 189: 253, # '½' + 190: 108, # 'Ύ' + 191: 123, # 'Ώ' + 192: 110, # 'ΐ' + 193: 31, # 'Α' + 194: 51, # 'Β' + 195: 43, # 'Γ' + 196: 41, # 'Δ' + 197: 34, # 'Ε' + 198: 91, # 'Ζ' + 199: 40, # 'Η' + 200: 52, # 'Θ' + 201: 47, # 'Ι' + 202: 44, # 'Κ' + 203: 53, # 'Λ' + 204: 38, # 'Μ' + 205: 49, # 'Ν' + 206: 59, # 'Ξ' + 207: 39, # 'Ο' + 208: 35, # 'Π' + 209: 48, # 'Ρ' + 210: 250, # None + 211: 37, # 'Σ' + 212: 33, # 'Τ' + 213: 45, # 'Υ' + 214: 56, # 'Φ' + 215: 50, # 'Χ' + 216: 84, # 'Ψ' + 217: 57, # 'Ω' + 218: 120, # 'Ϊ' + 219: 121, # 'Ϋ' + 220: 17, # 'ά' + 221: 18, # 'έ' + 222: 22, # 'ή' + 223: 15, # 'ί' + 224: 124, # 'ΰ' + 225: 1, # 'α' + 226: 29, # 'β' + 227: 20, # 'γ' + 228: 21, # 'δ' + 229: 3, # 'ε' + 230: 32, # 'ζ' + 231: 13, # 'η' + 232: 25, # 'θ' + 233: 5, # 'ι' + 234: 11, # 'κ' + 235: 16, # 'λ' + 236: 10, # 'μ' + 237: 6, # 'ν' + 238: 30, # 'ξ' + 239: 4, # 'ο' + 240: 9, # 'π' + 241: 8, # 'ρ' + 242: 14, # 'ς' + 243: 7, # 'σ' + 244: 2, # 'τ' + 245: 12, # 'υ' + 246: 28, # 'φ' + 247: 23, # 'χ' + 248: 42, # 'ψ' + 249: 24, # 'ω' + 250: 64, # 'ϊ' + 251: 75, # 'ϋ' + 252: 19, # 'ό' + 253: 26, # 'ύ' + 254: 27, # 'ώ' + 255: 253, # None +} + +WINDOWS_1253_GREEK_MODEL = SingleByteCharSetModel(charset_name='windows-1253', + language='Greek', + char_to_order_map=WINDOWS_1253_GREEK_CHAR_TO_ORDER, + language_model=GREEK_LANG_MODEL, + typical_positive_ratio=0.982851, + keep_ascii_letters=False, + alphabet='ΆΈΉΊΌΎΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩάέήίαβγδεζηθικλμνξοπρςστυφχψωόύώ') + +ISO_8859_7_GREEK_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 82, # 'A' + 66: 100, # 'B' + 67: 104, # 'C' + 68: 94, # 'D' + 69: 98, # 'E' + 70: 101, # 'F' + 71: 116, # 'G' + 72: 102, # 'H' + 73: 111, # 'I' + 74: 187, # 'J' + 75: 117, # 'K' + 76: 92, # 'L' + 77: 88, # 'M' + 78: 113, # 'N' + 79: 85, # 'O' + 80: 79, # 'P' + 81: 118, # 'Q' + 82: 105, # 'R' + 83: 83, # 'S' + 84: 67, # 'T' + 85: 114, # 'U' + 86: 119, # 'V' + 87: 95, # 'W' + 88: 99, # 'X' + 89: 109, # 'Y' + 90: 188, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 72, # 'a' + 98: 70, # 'b' + 99: 80, # 'c' + 100: 81, # 'd' + 101: 60, # 'e' + 102: 96, # 'f' + 103: 93, # 'g' + 104: 89, # 'h' + 105: 68, # 'i' + 106: 120, # 'j' + 107: 97, # 'k' + 108: 77, # 'l' + 109: 86, # 'm' + 110: 69, # 'n' + 111: 55, # 'o' + 112: 78, # 'p' + 113: 115, # 'q' + 114: 65, # 'r' + 115: 66, # 's' + 116: 58, # 't' + 117: 76, # 'u' + 118: 106, # 'v' + 119: 103, # 'w' + 120: 87, # 'x' + 121: 107, # 'y' + 122: 112, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 255, # '\x80' + 129: 255, # '\x81' + 130: 255, # '\x82' + 131: 255, # '\x83' + 132: 255, # '\x84' + 133: 255, # '\x85' + 134: 255, # '\x86' + 135: 255, # '\x87' + 136: 255, # '\x88' + 137: 255, # '\x89' + 138: 255, # '\x8a' + 139: 255, # '\x8b' + 140: 255, # '\x8c' + 141: 255, # '\x8d' + 142: 255, # '\x8e' + 143: 255, # '\x8f' + 144: 255, # '\x90' + 145: 255, # '\x91' + 146: 255, # '\x92' + 147: 255, # '\x93' + 148: 255, # '\x94' + 149: 255, # '\x95' + 150: 255, # '\x96' + 151: 255, # '\x97' + 152: 255, # '\x98' + 153: 255, # '\x99' + 154: 255, # '\x9a' + 155: 255, # '\x9b' + 156: 255, # '\x9c' + 157: 255, # '\x9d' + 158: 255, # '\x9e' + 159: 255, # '\x9f' + 160: 253, # '\xa0' + 161: 233, # '‘' + 162: 90, # '’' + 163: 253, # '£' + 164: 253, # '€' + 165: 253, # '₯' + 166: 253, # '¦' + 167: 253, # '§' + 168: 253, # '¨' + 169: 253, # '©' + 170: 253, # 'ͺ' + 171: 253, # '«' + 172: 253, # '¬' + 173: 74, # '\xad' + 174: 253, # None + 175: 253, # '―' + 176: 253, # '°' + 177: 253, # '±' + 178: 253, # '²' + 179: 253, # '³' + 180: 247, # '΄' + 181: 248, # '΅' + 182: 61, # 'Ά' + 183: 36, # '·' + 184: 46, # 'Έ' + 185: 71, # 'Ή' + 186: 73, # 'Ί' + 187: 253, # '»' + 188: 54, # 'Ό' + 189: 253, # '½' + 190: 108, # 'Ύ' + 191: 123, # 'Ώ' + 192: 110, # 'ΐ' + 193: 31, # 'Α' + 194: 51, # 'Β' + 195: 43, # 'Γ' + 196: 41, # 'Δ' + 197: 34, # 'Ε' + 198: 91, # 'Ζ' + 199: 40, # 'Η' + 200: 52, # 'Θ' + 201: 47, # 'Ι' + 202: 44, # 'Κ' + 203: 53, # 'Λ' + 204: 38, # 'Μ' + 205: 49, # 'Ν' + 206: 59, # 'Ξ' + 207: 39, # 'Ο' + 208: 35, # 'Π' + 209: 48, # 'Ρ' + 210: 250, # None + 211: 37, # 'Σ' + 212: 33, # 'Τ' + 213: 45, # 'Υ' + 214: 56, # 'Φ' + 215: 50, # 'Χ' + 216: 84, # 'Ψ' + 217: 57, # 'Ω' + 218: 120, # 'Ϊ' + 219: 121, # 'Ϋ' + 220: 17, # 'ά' + 221: 18, # 'έ' + 222: 22, # 'ή' + 223: 15, # 'ί' + 224: 124, # 'ΰ' + 225: 1, # 'α' + 226: 29, # 'β' + 227: 20, # 'γ' + 228: 21, # 'δ' + 229: 3, # 'ε' + 230: 32, # 'ζ' + 231: 13, # 'η' + 232: 25, # 'θ' + 233: 5, # 'ι' + 234: 11, # 'κ' + 235: 16, # 'λ' + 236: 10, # 'μ' + 237: 6, # 'ν' + 238: 30, # 'ξ' + 239: 4, # 'ο' + 240: 9, # 'π' + 241: 8, # 'ρ' + 242: 14, # 'ς' + 243: 7, # 'σ' + 244: 2, # 'τ' + 245: 12, # 'υ' + 246: 28, # 'φ' + 247: 23, # 'χ' + 248: 42, # 'ψ' + 249: 24, # 'ω' + 250: 64, # 'ϊ' + 251: 75, # 'ϋ' + 252: 19, # 'ό' + 253: 26, # 'ύ' + 254: 27, # 'ώ' + 255: 253, # None +} + +ISO_8859_7_GREEK_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-7', + language='Greek', + char_to_order_map=ISO_8859_7_GREEK_CHAR_TO_ORDER, + language_model=GREEK_LANG_MODEL, + typical_positive_ratio=0.982851, + keep_ascii_letters=False, + alphabet='ΆΈΉΊΌΎΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩάέήίαβγδεζηθικλμνξοπρςστυφχψωόύώ') + diff --git a/openpype/vendor/python/python_2/chardet/langhebrewmodel.py b/openpype/vendor/python/python_2/chardet/langhebrewmodel.py new file mode 100644 index 0000000000..40fd674c4a --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/langhebrewmodel.py @@ -0,0 +1,4383 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from chardet.sbcharsetprober import SingleByteCharSetModel + + +# 3: Positive +# 2: Likely +# 1: Unlikely +# 0: Negative + +HEBREW_LANG_MODEL = { + 50: { # 'a' + 50: 0, # 'a' + 60: 1, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 2, # 'l' + 54: 2, # 'n' + 49: 0, # 'o' + 51: 2, # 'r' + 43: 1, # 's' + 44: 2, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 1, # 'ק' + 7: 0, # 'ר' + 10: 1, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 60: { # 'c' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 0, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 0, # 'n' + 49: 1, # 'o' + 51: 1, # 'r' + 43: 1, # 's' + 44: 2, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 1, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 61: { # 'd' + 50: 1, # 'a' + 60: 0, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 1, # 'n' + 49: 2, # 'o' + 51: 1, # 'r' + 43: 1, # 's' + 44: 0, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 1, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 42: { # 'e' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 2, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 2, # 'l' + 54: 2, # 'n' + 49: 1, # 'o' + 51: 2, # 'r' + 43: 2, # 's' + 44: 2, # 't' + 63: 1, # 'u' + 34: 1, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 1, # '–' + 52: 2, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 53: { # 'i' + 50: 1, # 'a' + 60: 2, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 0, # 'i' + 56: 1, # 'l' + 54: 2, # 'n' + 49: 2, # 'o' + 51: 1, # 'r' + 43: 2, # 's' + 44: 2, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 56: { # 'l' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 1, # 'd' + 42: 2, # 'e' + 53: 2, # 'i' + 56: 2, # 'l' + 54: 1, # 'n' + 49: 1, # 'o' + 51: 0, # 'r' + 43: 1, # 's' + 44: 1, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 54: { # 'n' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 1, # 'n' + 49: 1, # 'o' + 51: 0, # 'r' + 43: 1, # 's' + 44: 2, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 2, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 49: { # 'o' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 2, # 'n' + 49: 1, # 'o' + 51: 2, # 'r' + 43: 1, # 's' + 44: 1, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 51: { # 'r' + 50: 2, # 'a' + 60: 1, # 'c' + 61: 1, # 'd' + 42: 2, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 1, # 'n' + 49: 2, # 'o' + 51: 1, # 'r' + 43: 1, # 's' + 44: 1, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 2, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 43: { # 's' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 0, # 'd' + 42: 2, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 1, # 'n' + 49: 1, # 'o' + 51: 1, # 'r' + 43: 1, # 's' + 44: 2, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 2, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, + 44: { # 't' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 0, # 'd' + 42: 2, # 'e' + 53: 2, # 'i' + 56: 1, # 'l' + 54: 0, # 'n' + 49: 1, # 'o' + 51: 1, # 'r' + 43: 1, # 's' + 44: 1, # 't' + 63: 1, # 'u' + 34: 1, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 2, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 63: { # 'u' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 1, # 'n' + 49: 0, # 'o' + 51: 1, # 'r' + 43: 2, # 's' + 44: 1, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 34: { # '\xa0' + 50: 1, # 'a' + 60: 0, # 'c' + 61: 1, # 'd' + 42: 0, # 'e' + 53: 1, # 'i' + 56: 0, # 'l' + 54: 1, # 'n' + 49: 1, # 'o' + 51: 0, # 'r' + 43: 1, # 's' + 44: 1, # 't' + 63: 0, # 'u' + 34: 2, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 1, # 'ב' + 20: 1, # 'ג' + 16: 1, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 1, # 'ח' + 22: 1, # 'ט' + 1: 2, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 2, # 'מ' + 23: 0, # 'ן' + 12: 1, # 'נ' + 19: 1, # 'ס' + 13: 1, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 55: { # '´' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 1, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 2, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 1, # 'ן' + 12: 1, # 'נ' + 19: 1, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 48: { # '¼' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 1, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 39: { # '½' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 57: { # '¾' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 30: { # 'ְ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 1, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 1, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 2, # 'ב' + 20: 2, # 'ג' + 16: 2, # 'ד' + 3: 2, # 'ה' + 2: 2, # 'ו' + 24: 2, # 'ז' + 14: 2, # 'ח' + 22: 2, # 'ט' + 1: 2, # 'י' + 25: 2, # 'ך' + 15: 2, # 'כ' + 4: 2, # 'ל' + 11: 1, # 'ם' + 6: 2, # 'מ' + 23: 0, # 'ן' + 12: 2, # 'נ' + 19: 2, # 'ס' + 13: 2, # 'ע' + 26: 0, # 'ף' + 18: 2, # 'פ' + 27: 0, # 'ץ' + 21: 2, # 'צ' + 17: 2, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 59: { # 'ֱ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 1, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 1, # 'ב' + 20: 1, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 1, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 2, # 'ל' + 11: 0, # 'ם' + 6: 2, # 'מ' + 23: 0, # 'ן' + 12: 1, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 41: { # 'ֲ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 2, # 'ב' + 20: 1, # 'ג' + 16: 2, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 1, # 'ח' + 22: 1, # 'ט' + 1: 1, # 'י' + 25: 1, # 'ך' + 15: 1, # 'כ' + 4: 2, # 'ל' + 11: 0, # 'ם' + 6: 2, # 'מ' + 23: 0, # 'ן' + 12: 2, # 'נ' + 19: 1, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 2, # 'צ' + 17: 1, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 33: { # 'ִ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 1, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 1, # 'ִ' + 37: 0, # 'ֵ' + 36: 1, # 'ֶ' + 31: 0, # 'ַ' + 29: 1, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 1, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 2, # 'ב' + 20: 2, # 'ג' + 16: 2, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 2, # 'ז' + 14: 1, # 'ח' + 22: 1, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 2, # 'כ' + 4: 2, # 'ל' + 11: 2, # 'ם' + 6: 2, # 'מ' + 23: 2, # 'ן' + 12: 2, # 'נ' + 19: 2, # 'ס' + 13: 1, # 'ע' + 26: 0, # 'ף' + 18: 2, # 'פ' + 27: 1, # 'ץ' + 21: 2, # 'צ' + 17: 2, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 37: { # 'ֵ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 1, # 'ֶ' + 31: 1, # 'ַ' + 29: 1, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 2, # 'ב' + 20: 1, # 'ג' + 16: 2, # 'ד' + 3: 2, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 2, # 'ח' + 22: 1, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 1, # 'כ' + 4: 2, # 'ל' + 11: 2, # 'ם' + 6: 1, # 'מ' + 23: 2, # 'ן' + 12: 2, # 'נ' + 19: 1, # 'ס' + 13: 2, # 'ע' + 26: 1, # 'ף' + 18: 1, # 'פ' + 27: 1, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 36: { # 'ֶ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 1, # 'ֶ' + 31: 1, # 'ַ' + 29: 1, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 2, # 'ב' + 20: 1, # 'ג' + 16: 2, # 'ד' + 3: 2, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 2, # 'ח' + 22: 1, # 'ט' + 1: 2, # 'י' + 25: 2, # 'ך' + 15: 1, # 'כ' + 4: 2, # 'ל' + 11: 2, # 'ם' + 6: 2, # 'מ' + 23: 2, # 'ן' + 12: 2, # 'נ' + 19: 2, # 'ס' + 13: 1, # 'ע' + 26: 1, # 'ף' + 18: 1, # 'פ' + 27: 2, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 31: { # 'ַ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 1, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 1, # 'ֶ' + 31: 0, # 'ַ' + 29: 2, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 2, # 'ב' + 20: 2, # 'ג' + 16: 2, # 'ד' + 3: 2, # 'ה' + 2: 1, # 'ו' + 24: 2, # 'ז' + 14: 2, # 'ח' + 22: 2, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 2, # 'כ' + 4: 2, # 'ל' + 11: 2, # 'ם' + 6: 2, # 'מ' + 23: 2, # 'ן' + 12: 2, # 'נ' + 19: 2, # 'ס' + 13: 2, # 'ע' + 26: 2, # 'ף' + 18: 2, # 'פ' + 27: 1, # 'ץ' + 21: 2, # 'צ' + 17: 2, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 29: { # 'ָ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 1, # 'ַ' + 29: 2, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 1, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 2, # 'ב' + 20: 2, # 'ג' + 16: 2, # 'ד' + 3: 3, # 'ה' + 2: 2, # 'ו' + 24: 2, # 'ז' + 14: 2, # 'ח' + 22: 1, # 'ט' + 1: 2, # 'י' + 25: 2, # 'ך' + 15: 2, # 'כ' + 4: 2, # 'ל' + 11: 2, # 'ם' + 6: 2, # 'מ' + 23: 2, # 'ן' + 12: 2, # 'נ' + 19: 1, # 'ס' + 13: 2, # 'ע' + 26: 1, # 'ף' + 18: 2, # 'פ' + 27: 1, # 'ץ' + 21: 2, # 'צ' + 17: 2, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 35: { # 'ֹ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 1, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 2, # 'ב' + 20: 1, # 'ג' + 16: 2, # 'ד' + 3: 2, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 1, # 'ח' + 22: 1, # 'ט' + 1: 1, # 'י' + 25: 1, # 'ך' + 15: 2, # 'כ' + 4: 2, # 'ל' + 11: 2, # 'ם' + 6: 2, # 'מ' + 23: 2, # 'ן' + 12: 2, # 'נ' + 19: 2, # 'ס' + 13: 2, # 'ע' + 26: 1, # 'ף' + 18: 2, # 'פ' + 27: 1, # 'ץ' + 21: 2, # 'צ' + 17: 2, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 62: { # 'ֻ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 1, # 'ב' + 20: 1, # 'ג' + 16: 1, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 1, # 'ח' + 22: 0, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 2, # 'ל' + 11: 1, # 'ם' + 6: 1, # 'מ' + 23: 1, # 'ן' + 12: 1, # 'נ' + 19: 1, # 'ס' + 13: 1, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 28: { # 'ּ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 3, # 'ְ' + 59: 0, # 'ֱ' + 41: 1, # 'ֲ' + 33: 3, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 3, # 'ַ' + 29: 3, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 0, # 'ּ' + 38: 2, # 'ׁ' + 45: 1, # 'ׂ' + 9: 2, # 'א' + 8: 2, # 'ב' + 20: 1, # 'ג' + 16: 2, # 'ד' + 3: 1, # 'ה' + 2: 2, # 'ו' + 24: 1, # 'ז' + 14: 1, # 'ח' + 22: 1, # 'ט' + 1: 2, # 'י' + 25: 2, # 'ך' + 15: 2, # 'כ' + 4: 2, # 'ל' + 11: 1, # 'ם' + 6: 2, # 'מ' + 23: 1, # 'ן' + 12: 2, # 'נ' + 19: 1, # 'ס' + 13: 2, # 'ע' + 26: 1, # 'ף' + 18: 1, # 'פ' + 27: 1, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 38: { # 'ׁ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 2, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 1, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 45: { # 'ׂ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 1, # 'ֵ' + 36: 2, # 'ֶ' + 31: 1, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 0, # 'ב' + 20: 1, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 2, # 'ו' + 24: 0, # 'ז' + 14: 1, # 'ח' + 22: 0, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 1, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 1, # 'נ' + 19: 0, # 'ס' + 13: 1, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 1, # 'ר' + 10: 0, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 9: { # 'א' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 1, # '´' + 48: 1, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 2, # 'ֱ' + 41: 2, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 3, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 2, # 'ע' + 26: 3, # 'ף' + 18: 3, # 'פ' + 27: 1, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 8: { # 'ב' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 1, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 3, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 2, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 1, # 'ף' + 18: 3, # 'פ' + 27: 2, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 1, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 20: { # 'ג' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 2, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 1, # 'ִ' + 37: 1, # 'ֵ' + 36: 1, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 0, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 3, # 'ב' + 20: 2, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 2, # 'ח' + 22: 2, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 1, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 2, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 2, # 'פ' + 27: 1, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 16: { # 'ד' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 1, # 'ז' + 14: 2, # 'ח' + 22: 2, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 2, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 2, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 0, # 'ץ' + 21: 2, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 3: { # 'ה' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 1, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 0, # '´' + 48: 1, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 1, # 'ְ' + 59: 1, # 'ֱ' + 41: 2, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 3, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 0, # 'ף' + 18: 3, # 'פ' + 27: 1, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 1, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, + 2: { # 'ו' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 1, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 1, # '´' + 48: 1, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 1, # 'ֵ' + 36: 1, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 3, # 'ֹ' + 62: 0, # 'ֻ' + 28: 3, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 3, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 3, # 'ף' + 18: 3, # 'פ' + 27: 3, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 1, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, + 24: { # 'ז' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 1, # 'ֲ' + 33: 1, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 2, # 'ב' + 20: 2, # 'ג' + 16: 2, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 2, # 'ז' + 14: 2, # 'ח' + 22: 1, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 2, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 2, # 'נ' + 19: 1, # 'ס' + 13: 2, # 'ע' + 26: 1, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 2, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 1, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 14: { # 'ח' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 1, # 'ֱ' + 41: 2, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 3, # 'ב' + 20: 2, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 2, # 'ח' + 22: 2, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 2, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 1, # 'ע' + 26: 2, # 'ף' + 18: 2, # 'פ' + 27: 2, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 22: { # 'ט' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 1, # 'ֵ' + 36: 1, # 'ֶ' + 31: 2, # 'ַ' + 29: 1, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 1, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 1, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 2, # 'ז' + 14: 3, # 'ח' + 22: 2, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 2, # 'כ' + 4: 3, # 'ל' + 11: 2, # 'ם' + 6: 2, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 2, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 1, # 'ץ' + 21: 2, # 'צ' + 17: 2, # 'ק' + 7: 3, # 'ר' + 10: 2, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 1: { # 'י' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 1, # '´' + 48: 1, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 1, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 3, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 3, # 'ף' + 18: 3, # 'פ' + 27: 3, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 1, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, + 25: { # 'ך' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 2, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 1, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 1, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 1, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 15: { # 'כ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 3, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 2, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 2, # 'ט' + 1: 3, # 'י' + 25: 3, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 2, # 'ע' + 26: 3, # 'ף' + 18: 3, # 'פ' + 27: 1, # 'ץ' + 21: 2, # 'צ' + 17: 2, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 4: { # 'ל' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 3, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 3, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 2, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 1, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 11: { # 'ם' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 1, # 'ב' + 20: 1, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 1, # 'ח' + 22: 0, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 1, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 1, # 'נ' + 19: 0, # 'ס' + 13: 1, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 1, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, + 6: { # 'מ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 0, # 'ף' + 18: 3, # 'פ' + 27: 2, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 23: { # 'ן' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 0, # '´' + 48: 1, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 1, # 'ב' + 20: 1, # 'ג' + 16: 1, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 0, # 'ז' + 14: 1, # 'ח' + 22: 1, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 1, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 1, # 'נ' + 19: 1, # 'ס' + 13: 1, # 'ע' + 26: 1, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 1, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 1, # 'ת' + 32: 1, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, + 12: { # 'נ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 2, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 19: { # 'ס' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 1, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 1, # 'ָ' + 35: 1, # 'ֹ' + 62: 2, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 1, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 2, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 2, # 'ס' + 13: 3, # 'ע' + 26: 3, # 'ף' + 18: 3, # 'פ' + 27: 0, # 'ץ' + 21: 2, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 1, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 13: { # 'ע' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 1, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 1, # 'ְ' + 59: 1, # 'ֱ' + 41: 2, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 1, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 2, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 2, # 'ע' + 26: 1, # 'ף' + 18: 2, # 'פ' + 27: 2, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 26: { # 'ף' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 1, # 'ו' + 24: 0, # 'ז' + 14: 1, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 1, # 'ס' + 13: 0, # 'ע' + 26: 1, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 1, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 18: { # 'פ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 1, # 'ֵ' + 36: 2, # 'ֶ' + 31: 1, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 2, # 'ב' + 20: 3, # 'ג' + 16: 2, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 2, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 2, # 'ם' + 6: 2, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 2, # 'פ' + 27: 2, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 27: { # 'ץ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 1, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 1, # 'ר' + 10: 0, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 21: { # 'צ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 1, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 2, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 1, # 'ז' + 14: 3, # 'ח' + 22: 2, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 1, # 'כ' + 4: 3, # 'ל' + 11: 2, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 1, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 2, # 'ץ' + 21: 2, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 0, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 17: { # 'ק' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 1, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 2, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 2, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 1, # 'כ' + 4: 3, # 'ל' + 11: 2, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 2, # 'ץ' + 21: 3, # 'צ' + 17: 2, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 7: { # 'ר' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 2, # '´' + 48: 1, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 1, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 3, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 3, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, + 10: { # 'ש' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 1, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 1, # 'ִ' + 37: 1, # 'ֵ' + 36: 1, # 'ֶ' + 31: 1, # 'ַ' + 29: 1, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 3, # 'ׁ' + 45: 2, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 2, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 3, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 2, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 1, # 'ץ' + 21: 2, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 5: { # 'ת' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 0, # '´' + 48: 1, # '¼' + 39: 1, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 2, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 2, # 'ז' + 14: 3, # 'ח' + 22: 2, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 2, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 1, # 'ץ' + 21: 2, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 1, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, + 32: { # '–' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 1, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 1, # 'ב' + 20: 1, # 'ג' + 16: 1, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 0, # 'ז' + 14: 1, # 'ח' + 22: 0, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 1, # 'ס' + 13: 1, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 1, # 'צ' + 17: 0, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 52: { # '’' + 50: 1, # 'a' + 60: 0, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 1, # 'r' + 43: 2, # 's' + 44: 2, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 1, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 47: { # '“' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 1, # 'n' + 49: 1, # 'o' + 51: 1, # 'r' + 43: 1, # 's' + 44: 1, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 1, # 'ב' + 20: 1, # 'ג' + 16: 1, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 1, # 'ח' + 22: 1, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 1, # 'נ' + 19: 1, # 'ס' + 13: 1, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 46: { # '”' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 1, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 1, # 'ב' + 20: 1, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 1, # 'צ' + 17: 0, # 'ק' + 7: 1, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 58: { # '†' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 2, # '†' + 40: 0, # '…' + }, + 40: { # '…' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 0, # 'l' + 54: 1, # 'n' + 49: 0, # 'o' + 51: 1, # 'r' + 43: 1, # 's' + 44: 1, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 1, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, +} + +# 255: Undefined characters that did not exist in training text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 +# 251: Control characters + +# Character Mapping Table(s): +WINDOWS_1255_HEBREW_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 69, # 'A' + 66: 91, # 'B' + 67: 79, # 'C' + 68: 80, # 'D' + 69: 92, # 'E' + 70: 89, # 'F' + 71: 97, # 'G' + 72: 90, # 'H' + 73: 68, # 'I' + 74: 111, # 'J' + 75: 112, # 'K' + 76: 82, # 'L' + 77: 73, # 'M' + 78: 95, # 'N' + 79: 85, # 'O' + 80: 78, # 'P' + 81: 121, # 'Q' + 82: 86, # 'R' + 83: 71, # 'S' + 84: 67, # 'T' + 85: 102, # 'U' + 86: 107, # 'V' + 87: 84, # 'W' + 88: 114, # 'X' + 89: 103, # 'Y' + 90: 115, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 50, # 'a' + 98: 74, # 'b' + 99: 60, # 'c' + 100: 61, # 'd' + 101: 42, # 'e' + 102: 76, # 'f' + 103: 70, # 'g' + 104: 64, # 'h' + 105: 53, # 'i' + 106: 105, # 'j' + 107: 93, # 'k' + 108: 56, # 'l' + 109: 65, # 'm' + 110: 54, # 'n' + 111: 49, # 'o' + 112: 66, # 'p' + 113: 110, # 'q' + 114: 51, # 'r' + 115: 43, # 's' + 116: 44, # 't' + 117: 63, # 'u' + 118: 81, # 'v' + 119: 77, # 'w' + 120: 98, # 'x' + 121: 75, # 'y' + 122: 108, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 124, # '€' + 129: 202, # None + 130: 203, # '‚' + 131: 204, # 'ƒ' + 132: 205, # '„' + 133: 40, # '…' + 134: 58, # '†' + 135: 206, # '‡' + 136: 207, # 'ˆ' + 137: 208, # '‰' + 138: 209, # None + 139: 210, # '‹' + 140: 211, # None + 141: 212, # None + 142: 213, # None + 143: 214, # None + 144: 215, # None + 145: 83, # '‘' + 146: 52, # '’' + 147: 47, # '“' + 148: 46, # '”' + 149: 72, # '•' + 150: 32, # '–' + 151: 94, # '—' + 152: 216, # '˜' + 153: 113, # '™' + 154: 217, # None + 155: 109, # '›' + 156: 218, # None + 157: 219, # None + 158: 220, # None + 159: 221, # None + 160: 34, # '\xa0' + 161: 116, # '¡' + 162: 222, # '¢' + 163: 118, # '£' + 164: 100, # '₪' + 165: 223, # '¥' + 166: 224, # '¦' + 167: 117, # '§' + 168: 119, # '¨' + 169: 104, # '©' + 170: 125, # '×' + 171: 225, # '«' + 172: 226, # '¬' + 173: 87, # '\xad' + 174: 99, # '®' + 175: 227, # '¯' + 176: 106, # '°' + 177: 122, # '±' + 178: 123, # '²' + 179: 228, # '³' + 180: 55, # '´' + 181: 229, # 'µ' + 182: 230, # '¶' + 183: 101, # '·' + 184: 231, # '¸' + 185: 232, # '¹' + 186: 120, # '÷' + 187: 233, # '»' + 188: 48, # '¼' + 189: 39, # '½' + 190: 57, # '¾' + 191: 234, # '¿' + 192: 30, # 'ְ' + 193: 59, # 'ֱ' + 194: 41, # 'ֲ' + 195: 88, # 'ֳ' + 196: 33, # 'ִ' + 197: 37, # 'ֵ' + 198: 36, # 'ֶ' + 199: 31, # 'ַ' + 200: 29, # 'ָ' + 201: 35, # 'ֹ' + 202: 235, # None + 203: 62, # 'ֻ' + 204: 28, # 'ּ' + 205: 236, # 'ֽ' + 206: 126, # '־' + 207: 237, # 'ֿ' + 208: 238, # '׀' + 209: 38, # 'ׁ' + 210: 45, # 'ׂ' + 211: 239, # '׃' + 212: 240, # 'װ' + 213: 241, # 'ױ' + 214: 242, # 'ײ' + 215: 243, # '׳' + 216: 127, # '״' + 217: 244, # None + 218: 245, # None + 219: 246, # None + 220: 247, # None + 221: 248, # None + 222: 249, # None + 223: 250, # None + 224: 9, # 'א' + 225: 8, # 'ב' + 226: 20, # 'ג' + 227: 16, # 'ד' + 228: 3, # 'ה' + 229: 2, # 'ו' + 230: 24, # 'ז' + 231: 14, # 'ח' + 232: 22, # 'ט' + 233: 1, # 'י' + 234: 25, # 'ך' + 235: 15, # 'כ' + 236: 4, # 'ל' + 237: 11, # 'ם' + 238: 6, # 'מ' + 239: 23, # 'ן' + 240: 12, # 'נ' + 241: 19, # 'ס' + 242: 13, # 'ע' + 243: 26, # 'ף' + 244: 18, # 'פ' + 245: 27, # 'ץ' + 246: 21, # 'צ' + 247: 17, # 'ק' + 248: 7, # 'ר' + 249: 10, # 'ש' + 250: 5, # 'ת' + 251: 251, # None + 252: 252, # None + 253: 128, # '\u200e' + 254: 96, # '\u200f' + 255: 253, # None +} + +WINDOWS_1255_HEBREW_MODEL = SingleByteCharSetModel(charset_name='windows-1255', + language='Hebrew', + char_to_order_map=WINDOWS_1255_HEBREW_CHAR_TO_ORDER, + language_model=HEBREW_LANG_MODEL, + typical_positive_ratio=0.984004, + keep_ascii_letters=False, + alphabet='אבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ') + diff --git a/openpype/vendor/python/python_2/chardet/langhungarianmodel.py b/openpype/vendor/python/python_2/chardet/langhungarianmodel.py new file mode 100644 index 0000000000..24a097f520 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/langhungarianmodel.py @@ -0,0 +1,4650 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from chardet.sbcharsetprober import SingleByteCharSetModel + + +# 3: Positive +# 2: Likely +# 1: Unlikely +# 0: Negative + +HUNGARIAN_LANG_MODEL = { + 28: { # 'A' + 28: 0, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 2, # 'D' + 32: 1, # 'E' + 50: 1, # 'F' + 49: 2, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 2, # 'K' + 41: 2, # 'L' + 34: 1, # 'M' + 35: 2, # 'N' + 47: 1, # 'O' + 46: 2, # 'P' + 43: 2, # 'R' + 33: 2, # 'S' + 37: 2, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 2, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 2, # 'd' + 1: 1, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 1, # 'i' + 22: 1, # 'j' + 7: 2, # 'k' + 6: 2, # 'l' + 13: 2, # 'm' + 4: 2, # 'n' + 8: 0, # 'o' + 23: 2, # 'p' + 10: 2, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 1, # 'u' + 19: 1, # 'v' + 62: 1, # 'x' + 16: 0, # 'y' + 11: 3, # 'z' + 51: 1, # 'Á' + 44: 0, # 'É' + 61: 1, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 40: { # 'B' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 0, # 'M' + 35: 1, # 'N' + 47: 2, # 'O' + 46: 0, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 3, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 2, # 'i' + 22: 1, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 3, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 0, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 54: { # 'C' + 28: 1, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 1, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 0, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 2, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 0, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 1, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 1, # 'h' + 9: 1, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 3, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 1, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 45: { # 'D' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 0, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 0, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 2, # 'O' + 46: 0, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 3, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 1, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 1, # 'o' + 23: 0, # 'p' + 10: 2, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 2, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 1, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 0, # 'ű' + }, + 32: { # 'E' + 28: 1, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 1, # 'E' + 50: 1, # 'F' + 49: 2, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 2, # 'K' + 41: 2, # 'L' + 34: 2, # 'M' + 35: 2, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 2, # 'R' + 33: 2, # 'S' + 37: 2, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 1, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 2, # 'd' + 1: 1, # 'e' + 27: 1, # 'f' + 12: 3, # 'g' + 20: 1, # 'h' + 9: 1, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 2, # 'l' + 13: 2, # 'm' + 4: 2, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 2, # 's' + 3: 1, # 't' + 21: 2, # 'u' + 19: 1, # 'v' + 62: 1, # 'x' + 16: 0, # 'y' + 11: 3, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 0, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 0, # 'Ú' + 63: 1, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 1, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 50: { # 'F' + 28: 1, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 1, # 'E' + 50: 1, # 'F' + 49: 0, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 0, # 'P' + 43: 1, # 'R' + 33: 0, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 0, # 'V' + 55: 1, # 'Y' + 52: 0, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 1, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 2, # 'i' + 22: 1, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 2, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 0, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 0, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 0, # 'Ú' + 63: 1, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 2, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 49: { # 'G' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 2, # 'Y' + 52: 1, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 1, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 2, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 2, # 'y' + 11: 0, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 0, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 0, # 'ű' + }, + 38: { # 'H' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 0, # 'D' + 32: 1, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 1, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 1, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 1, # 'O' + 46: 0, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 0, # 'V' + 55: 1, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 2, # 'i' + 22: 1, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 0, # 'n' + 8: 3, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 2, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 0, # 'z' + 51: 2, # 'Á' + 44: 2, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 1, # 'é' + 30: 2, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 39: { # 'I' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 1, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 2, # 'K' + 41: 2, # 'L' + 34: 1, # 'M' + 35: 2, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 2, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 2, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 2, # 'd' + 1: 0, # 'e' + 27: 1, # 'f' + 12: 2, # 'g' + 20: 1, # 'h' + 9: 0, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 2, # 'l' + 13: 2, # 'm' + 4: 1, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 2, # 's' + 3: 2, # 't' + 21: 0, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 1, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 0, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 53: { # 'J' + 28: 2, # 'A' + 40: 0, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 1, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 1, # 'o' + 23: 0, # 'p' + 10: 0, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 2, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 0, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 0, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 1, # 'é' + 30: 0, # 'í' + 25: 2, # 'ó' + 24: 2, # 'ö' + 31: 1, # 'ú' + 29: 0, # 'ü' + 42: 1, # 'ő' + 56: 0, # 'ű' + }, + 36: { # 'K' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 0, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 2, # 'O' + 46: 0, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 0, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 1, # 'f' + 12: 0, # 'g' + 20: 1, # 'h' + 9: 3, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 2, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 0, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 2, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 2, # 'ö' + 31: 1, # 'ú' + 29: 2, # 'ü' + 42: 1, # 'ő' + 56: 0, # 'ű' + }, + 41: { # 'L' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 2, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 2, # 'O' + 46: 0, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 2, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 3, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 2, # 'i' + 22: 1, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 0, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 2, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 0, # 'z' + 51: 2, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 0, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 34: { # 'M' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 0, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 3, # 'a' + 18: 0, # 'b' + 26: 1, # 'c' + 17: 0, # 'd' + 1: 3, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 3, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 3, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 2, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 0, # 'z' + 51: 2, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 1, # 'ű' + }, + 35: { # 'N' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 2, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 2, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 2, # 'Y' + 52: 1, # 'Z' + 2: 3, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 3, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 2, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 0, # 'm' + 4: 1, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 0, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 2, # 'y' + 11: 0, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 1, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 1, # 'ő' + 56: 0, # 'ű' + }, + 47: { # 'O' + 28: 1, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 1, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 2, # 'K' + 41: 2, # 'L' + 34: 2, # 'M' + 35: 2, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 2, # 'R' + 33: 2, # 'S' + 37: 2, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 1, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 1, # 'i' + 22: 1, # 'j' + 7: 2, # 'k' + 6: 2, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 1, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 1, # 's' + 3: 2, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 1, # 'x' + 16: 0, # 'y' + 11: 1, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 0, # 'Í' + 58: 1, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 46: { # 'P' + 28: 1, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 1, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 0, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 2, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 1, # 'f' + 12: 0, # 'g' + 20: 1, # 'h' + 9: 2, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 1, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 2, # 'r' + 5: 1, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 0, # 'z' + 51: 2, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 0, # 'Ú' + 63: 1, # 'Ü' + 14: 3, # 'á' + 15: 2, # 'é' + 30: 0, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 0, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 0, # 'ű' + }, + 43: { # 'R' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 2, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 2, # 'S' + 37: 2, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 1, # 'h' + 9: 2, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 0, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 0, # 'z' + 51: 2, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 2, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 2, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 33: { # 'S' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 2, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 2, # 'S' + 37: 2, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 3, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 1, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 1, # 'h' + 9: 2, # 'i' + 22: 0, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 1, # 'p' + 10: 0, # 'r' + 5: 0, # 's' + 3: 1, # 't' + 21: 1, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 3, # 'z' + 51: 2, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 37: { # 'T' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 2, # 'O' + 46: 1, # 'P' + 43: 2, # 'R' + 33: 1, # 'S' + 37: 2, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 1, # 'h' + 9: 2, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 1, # 's' + 3: 0, # 't' + 21: 2, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 1, # 'z' + 51: 2, # 'Á' + 44: 2, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 2, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 57: { # 'U' + 28: 1, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 1, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 2, # 'S' + 37: 1, # 'T' + 57: 0, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 1, # 'e' + 27: 0, # 'f' + 12: 2, # 'g' + 20: 0, # 'h' + 9: 0, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 1, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 0, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 1, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 48: { # 'V' + 28: 2, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 0, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 2, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 0, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 0, # 'z' + 51: 2, # 'Á' + 44: 2, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 0, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 0, # 'ó' + 24: 1, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 55: { # 'Y' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 2, # 'Z' + 2: 1, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 1, # 'd' + 1: 1, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 0, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 1, # 'o' + 23: 1, # 'p' + 10: 0, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 0, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 0, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 52: { # 'Z' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 0, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 2, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 2, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 1, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 1, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 1, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 0, # 'm' + 4: 1, # 'n' + 8: 1, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 2, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 0, # 'z' + 51: 2, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 2: { # 'a' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 3, # 'b' + 26: 3, # 'c' + 17: 3, # 'd' + 1: 2, # 'e' + 27: 2, # 'f' + 12: 3, # 'g' + 20: 3, # 'h' + 9: 3, # 'i' + 22: 3, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 2, # 'o' + 23: 3, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 3, # 'v' + 62: 1, # 'x' + 16: 2, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 18: { # 'b' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 3, # 'i' + 22: 2, # 'j' + 7: 2, # 'k' + 6: 2, # 'l' + 13: 1, # 'm' + 4: 2, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 3, # 'r' + 5: 2, # 's' + 3: 1, # 't' + 21: 3, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 3, # 'ó' + 24: 2, # 'ö' + 31: 2, # 'ú' + 29: 2, # 'ü' + 42: 2, # 'ő' + 56: 1, # 'ű' + }, + 26: { # 'c' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 1, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 1, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 2, # 'a' + 18: 1, # 'b' + 26: 2, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 3, # 'h' + 9: 3, # 'i' + 22: 1, # 'j' + 7: 2, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 3, # 's' + 3: 2, # 't' + 21: 2, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 2, # 'á' + 15: 2, # 'é' + 30: 2, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 17: { # 'd' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 2, # 'b' + 26: 1, # 'c' + 17: 2, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 3, # 'j' + 7: 2, # 'k' + 6: 1, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 2, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 3, # 'í' + 25: 3, # 'ó' + 24: 3, # 'ö' + 31: 2, # 'ú' + 29: 2, # 'ü' + 42: 2, # 'ő' + 56: 1, # 'ű' + }, + 1: { # 'e' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 2, # 'a' + 18: 3, # 'b' + 26: 3, # 'c' + 17: 3, # 'd' + 1: 2, # 'e' + 27: 3, # 'f' + 12: 3, # 'g' + 20: 3, # 'h' + 9: 3, # 'i' + 22: 3, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 2, # 'o' + 23: 3, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 2, # 'u' + 19: 3, # 'v' + 62: 2, # 'x' + 16: 2, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 27: { # 'f' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 2, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 3, # 'i' + 22: 2, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 3, # 'o' + 23: 0, # 'p' + 10: 3, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 2, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 0, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 3, # 'ö' + 31: 1, # 'ú' + 29: 2, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 12: { # 'g' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 2, # 'c' + 17: 2, # 'd' + 1: 3, # 'e' + 27: 2, # 'f' + 12: 3, # 'g' + 20: 3, # 'h' + 9: 3, # 'i' + 22: 3, # 'j' + 7: 2, # 'k' + 6: 3, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 3, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 3, # 'ó' + 24: 2, # 'ö' + 31: 2, # 'ú' + 29: 2, # 'ü' + 42: 2, # 'ő' + 56: 1, # 'ű' + }, + 20: { # 'h' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 0, # 'd' + 1: 3, # 'e' + 27: 0, # 'f' + 12: 1, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 3, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 2, # 's' + 3: 1, # 't' + 21: 3, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 2, # 'y' + 11: 0, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 3, # 'í' + 25: 2, # 'ó' + 24: 2, # 'ö' + 31: 2, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 9: { # 'i' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 3, # 'c' + 17: 3, # 'd' + 1: 3, # 'e' + 27: 3, # 'f' + 12: 3, # 'g' + 20: 3, # 'h' + 9: 2, # 'i' + 22: 2, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 2, # 'o' + 23: 2, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 3, # 'v' + 62: 1, # 'x' + 16: 1, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 3, # 'ó' + 24: 1, # 'ö' + 31: 2, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 1, # 'ű' + }, + 22: { # 'j' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 2, # 'b' + 26: 1, # 'c' + 17: 3, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 2, # 'h' + 9: 1, # 'i' + 22: 2, # 'j' + 7: 2, # 'k' + 6: 2, # 'l' + 13: 1, # 'm' + 4: 2, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 2, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 1, # 'í' + 25: 3, # 'ó' + 24: 3, # 'ö' + 31: 3, # 'ú' + 29: 2, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 7: { # 'k' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 2, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 2, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 1, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 2, # 'v' + 62: 0, # 'x' + 16: 2, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 3, # 'í' + 25: 2, # 'ó' + 24: 3, # 'ö' + 31: 1, # 'ú' + 29: 3, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 6: { # 'l' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 1, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 1, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 2, # 'b' + 26: 3, # 'c' + 17: 3, # 'd' + 1: 3, # 'e' + 27: 3, # 'f' + 12: 3, # 'g' + 20: 3, # 'h' + 9: 3, # 'i' + 22: 3, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 2, # 'p' + 10: 2, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 3, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 3, # 'í' + 25: 3, # 'ó' + 24: 3, # 'ö' + 31: 2, # 'ú' + 29: 2, # 'ü' + 42: 3, # 'ő' + 56: 1, # 'ű' + }, + 13: { # 'm' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 2, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 2, # 'j' + 7: 1, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 8: 3, # 'o' + 23: 3, # 'p' + 10: 2, # 'r' + 5: 2, # 's' + 3: 2, # 't' + 21: 3, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 2, # 'ó' + 24: 2, # 'ö' + 31: 2, # 'ú' + 29: 2, # 'ü' + 42: 1, # 'ő' + 56: 2, # 'ű' + }, + 4: { # 'n' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 3, # 'c' + 17: 3, # 'd' + 1: 3, # 'e' + 27: 2, # 'f' + 12: 3, # 'g' + 20: 3, # 'h' + 9: 3, # 'i' + 22: 2, # 'j' + 7: 3, # 'k' + 6: 2, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 2, # 'p' + 10: 2, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 2, # 'v' + 62: 1, # 'x' + 16: 3, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 2, # 'ó' + 24: 3, # 'ö' + 31: 2, # 'ú' + 29: 3, # 'ü' + 42: 2, # 'ő' + 56: 1, # 'ű' + }, + 8: { # 'o' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 1, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 2, # 'a' + 18: 3, # 'b' + 26: 3, # 'c' + 17: 3, # 'd' + 1: 2, # 'e' + 27: 2, # 'f' + 12: 3, # 'g' + 20: 3, # 'h' + 9: 2, # 'i' + 22: 2, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 1, # 'o' + 23: 3, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 2, # 'u' + 19: 3, # 'v' + 62: 1, # 'x' + 16: 1, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 1, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 23: { # 'p' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 1, # 'b' + 26: 2, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 2, # 'j' + 7: 2, # 'k' + 6: 3, # 'l' + 13: 1, # 'm' + 4: 2, # 'n' + 8: 3, # 'o' + 23: 3, # 'p' + 10: 3, # 'r' + 5: 2, # 's' + 3: 2, # 't' + 21: 3, # 'u' + 19: 2, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 2, # 'ó' + 24: 2, # 'ö' + 31: 1, # 'ú' + 29: 2, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 10: { # 'r' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 3, # 'c' + 17: 3, # 'd' + 1: 3, # 'e' + 27: 2, # 'f' + 12: 3, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 3, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 2, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 3, # 'v' + 62: 1, # 'x' + 16: 2, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 3, # 'ó' + 24: 3, # 'ö' + 31: 3, # 'ú' + 29: 3, # 'ü' + 42: 2, # 'ő' + 56: 2, # 'ű' + }, + 5: { # 's' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 2, # 'c' + 17: 2, # 'd' + 1: 3, # 'e' + 27: 2, # 'f' + 12: 2, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 1, # 'j' + 7: 3, # 'k' + 6: 2, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 2, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 2, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 3, # 'í' + 25: 3, # 'ó' + 24: 3, # 'ö' + 31: 3, # 'ú' + 29: 3, # 'ü' + 42: 2, # 'ő' + 56: 1, # 'ű' + }, + 3: { # 't' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 2, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 2, # 'f' + 12: 1, # 'g' + 20: 3, # 'h' + 9: 3, # 'i' + 22: 3, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 3, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 3, # 'ó' + 24: 3, # 'ö' + 31: 3, # 'ú' + 29: 3, # 'ü' + 42: 3, # 'ő' + 56: 2, # 'ű' + }, + 21: { # 'u' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 2, # 'b' + 26: 2, # 'c' + 17: 3, # 'd' + 1: 2, # 'e' + 27: 1, # 'f' + 12: 3, # 'g' + 20: 2, # 'h' + 9: 2, # 'i' + 22: 2, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 1, # 'o' + 23: 2, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 1, # 'u' + 19: 3, # 'v' + 62: 1, # 'x' + 16: 1, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 2, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 0, # 'ö' + 31: 1, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 19: { # 'v' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 2, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 3, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 1, # 'r' + 5: 2, # 's' + 3: 2, # 't' + 21: 2, # 'u' + 19: 2, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 2, # 'ó' + 24: 2, # 'ö' + 31: 1, # 'ú' + 29: 2, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 62: { # 'x' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 0, # 'd' + 1: 1, # 'e' + 27: 1, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 1, # 'i' + 22: 0, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 1, # 'o' + 23: 1, # 'p' + 10: 1, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 0, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 16: { # 'y' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 2, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 2, # 'f' + 12: 2, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 2, # 'j' + 7: 2, # 'k' + 6: 2, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 2, # 'p' + 10: 2, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 2, # 'ó' + 24: 3, # 'ö' + 31: 2, # 'ú' + 29: 2, # 'ü' + 42: 1, # 'ő' + 56: 2, # 'ű' + }, + 11: { # 'z' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 2, # 'b' + 26: 1, # 'c' + 17: 3, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 2, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 1, # 'j' + 7: 3, # 'k' + 6: 2, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 2, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 3, # 'í' + 25: 3, # 'ó' + 24: 3, # 'ö' + 31: 2, # 'ú' + 29: 3, # 'ü' + 42: 2, # 'ő' + 56: 1, # 'ű' + }, + 51: { # 'Á' + 28: 0, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 0, # 'E' + 50: 1, # 'F' + 49: 2, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 2, # 'L' + 34: 1, # 'M' + 35: 2, # 'N' + 47: 0, # 'O' + 46: 1, # 'P' + 43: 2, # 'R' + 33: 2, # 'S' + 37: 1, # 'T' + 57: 0, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 0, # 'e' + 27: 0, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 0, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 2, # 'l' + 13: 2, # 'm' + 4: 0, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 1, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 0, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 1, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 44: { # 'É' + 28: 0, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 1, # 'E' + 50: 0, # 'F' + 49: 2, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 2, # 'L' + 34: 1, # 'M' + 35: 2, # 'N' + 47: 0, # 'O' + 46: 1, # 'P' + 43: 2, # 'R' + 33: 2, # 'S' + 37: 2, # 'T' + 57: 0, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 0, # 'e' + 27: 0, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 0, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 2, # 'l' + 13: 1, # 'm' + 4: 2, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 3, # 's' + 3: 1, # 't' + 21: 0, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 0, # 'z' + 51: 0, # 'Á' + 44: 1, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 61: { # 'Í' + 28: 0, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 0, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 1, # 'J' + 36: 0, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 0, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 0, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 0, # 'e' + 27: 0, # 'f' + 12: 2, # 'g' + 20: 0, # 'h' + 9: 0, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 1, # 'm' + 4: 0, # 'n' + 8: 0, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 0, # 's' + 3: 1, # 't' + 21: 0, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 58: { # 'Ó' + 28: 1, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 0, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 2, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 0, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 0, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 0, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 2, # 'h' + 9: 0, # 'i' + 22: 0, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 1, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 1, # 'r' + 5: 1, # 's' + 3: 0, # 't' + 21: 0, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 1, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 59: { # 'Ö' + 28: 0, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 0, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 0, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 0, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 0, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 0, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 0, # 'i' + 22: 0, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 0, # 'o' + 23: 0, # 'p' + 10: 2, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 0, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 60: { # 'Ú' + 28: 0, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 0, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 0, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 0, # 'e' + 27: 0, # 'f' + 12: 2, # 'g' + 20: 0, # 'h' + 9: 0, # 'i' + 22: 2, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 0, # 'm' + 4: 1, # 'n' + 8: 0, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 0, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 0, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 63: { # 'Ü' + 28: 0, # 'A' + 40: 1, # 'B' + 54: 0, # 'C' + 45: 1, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 0, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 0, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 0, # 'c' + 17: 1, # 'd' + 1: 0, # 'e' + 27: 0, # 'f' + 12: 1, # 'g' + 20: 0, # 'h' + 9: 0, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 1, # 'n' + 8: 0, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 0, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 14: { # 'á' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 3, # 'b' + 26: 3, # 'c' + 17: 3, # 'd' + 1: 1, # 'e' + 27: 2, # 'f' + 12: 3, # 'g' + 20: 2, # 'h' + 9: 2, # 'i' + 22: 3, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 1, # 'o' + 23: 2, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 2, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 1, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 0, # 'ó' + 24: 1, # 'ö' + 31: 0, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 15: { # 'é' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 3, # 'b' + 26: 2, # 'c' + 17: 3, # 'd' + 1: 1, # 'e' + 27: 1, # 'f' + 12: 3, # 'g' + 20: 3, # 'h' + 9: 2, # 'i' + 22: 2, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 1, # 'o' + 23: 3, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 0, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 30: { # 'í' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 2, # 'c' + 17: 1, # 'd' + 1: 0, # 'e' + 27: 1, # 'f' + 12: 3, # 'g' + 20: 0, # 'h' + 9: 0, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 2, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 3, # 'r' + 5: 2, # 's' + 3: 3, # 't' + 21: 0, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 25: { # 'ó' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 2, # 'a' + 18: 3, # 'b' + 26: 2, # 'c' + 17: 3, # 'd' + 1: 1, # 'e' + 27: 2, # 'f' + 12: 2, # 'g' + 20: 2, # 'h' + 9: 2, # 'i' + 22: 2, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 8: 1, # 'o' + 23: 2, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 1, # 'u' + 19: 2, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 0, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 24: { # 'ö' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 0, # 'a' + 18: 3, # 'b' + 26: 1, # 'c' + 17: 2, # 'd' + 1: 0, # 'e' + 27: 1, # 'f' + 12: 2, # 'g' + 20: 1, # 'h' + 9: 0, # 'i' + 22: 1, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 0, # 'o' + 23: 2, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 0, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 31: { # 'ú' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 1, # 'b' + 26: 2, # 'c' + 17: 1, # 'd' + 1: 1, # 'e' + 27: 2, # 'f' + 12: 3, # 'g' + 20: 1, # 'h' + 9: 1, # 'i' + 22: 3, # 'j' + 7: 1, # 'k' + 6: 3, # 'l' + 13: 1, # 'm' + 4: 2, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 2, # 't' + 21: 1, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 29: { # 'ü' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 2, # 'd' + 1: 1, # 'e' + 27: 1, # 'f' + 12: 3, # 'g' + 20: 2, # 'h' + 9: 1, # 'i' + 22: 1, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 1, # 'm' + 4: 3, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 2, # 's' + 3: 2, # 't' + 21: 0, # 'u' + 19: 2, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 1, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 42: { # 'ő' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 2, # 'b' + 26: 1, # 'c' + 17: 2, # 'd' + 1: 1, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 1, # 'i' + 22: 1, # 'j' + 7: 2, # 'k' + 6: 3, # 'l' + 13: 1, # 'm' + 4: 2, # 'n' + 8: 1, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 2, # 's' + 3: 2, # 't' + 21: 1, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 56: { # 'ű' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 1, # 'b' + 26: 0, # 'c' + 17: 1, # 'd' + 1: 1, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 1, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 2, # 'n' + 8: 0, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 0, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, +} + +# 255: Undefined characters that did not exist in training text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 +# 251: Control characters + +# Character Mapping Table(s): +WINDOWS_1250_HUNGARIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 28, # 'A' + 66: 40, # 'B' + 67: 54, # 'C' + 68: 45, # 'D' + 69: 32, # 'E' + 70: 50, # 'F' + 71: 49, # 'G' + 72: 38, # 'H' + 73: 39, # 'I' + 74: 53, # 'J' + 75: 36, # 'K' + 76: 41, # 'L' + 77: 34, # 'M' + 78: 35, # 'N' + 79: 47, # 'O' + 80: 46, # 'P' + 81: 72, # 'Q' + 82: 43, # 'R' + 83: 33, # 'S' + 84: 37, # 'T' + 85: 57, # 'U' + 86: 48, # 'V' + 87: 64, # 'W' + 88: 68, # 'X' + 89: 55, # 'Y' + 90: 52, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 2, # 'a' + 98: 18, # 'b' + 99: 26, # 'c' + 100: 17, # 'd' + 101: 1, # 'e' + 102: 27, # 'f' + 103: 12, # 'g' + 104: 20, # 'h' + 105: 9, # 'i' + 106: 22, # 'j' + 107: 7, # 'k' + 108: 6, # 'l' + 109: 13, # 'm' + 110: 4, # 'n' + 111: 8, # 'o' + 112: 23, # 'p' + 113: 67, # 'q' + 114: 10, # 'r' + 115: 5, # 's' + 116: 3, # 't' + 117: 21, # 'u' + 118: 19, # 'v' + 119: 65, # 'w' + 120: 62, # 'x' + 121: 16, # 'y' + 122: 11, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 161, # '€' + 129: 162, # None + 130: 163, # '‚' + 131: 164, # None + 132: 165, # '„' + 133: 166, # '…' + 134: 167, # '†' + 135: 168, # '‡' + 136: 169, # None + 137: 170, # '‰' + 138: 171, # 'Š' + 139: 172, # '‹' + 140: 173, # 'Ś' + 141: 174, # 'Ť' + 142: 175, # 'Ž' + 143: 176, # 'Ź' + 144: 177, # None + 145: 178, # '‘' + 146: 179, # '’' + 147: 180, # '“' + 148: 78, # '”' + 149: 181, # '•' + 150: 69, # '–' + 151: 182, # '—' + 152: 183, # None + 153: 184, # '™' + 154: 185, # 'š' + 155: 186, # '›' + 156: 187, # 'ś' + 157: 188, # 'ť' + 158: 189, # 'ž' + 159: 190, # 'ź' + 160: 191, # '\xa0' + 161: 192, # 'ˇ' + 162: 193, # '˘' + 163: 194, # 'Ł' + 164: 195, # '¤' + 165: 196, # 'Ą' + 166: 197, # '¦' + 167: 76, # '§' + 168: 198, # '¨' + 169: 199, # '©' + 170: 200, # 'Ş' + 171: 201, # '«' + 172: 202, # '¬' + 173: 203, # '\xad' + 174: 204, # '®' + 175: 205, # 'Ż' + 176: 81, # '°' + 177: 206, # '±' + 178: 207, # '˛' + 179: 208, # 'ł' + 180: 209, # '´' + 181: 210, # 'µ' + 182: 211, # '¶' + 183: 212, # '·' + 184: 213, # '¸' + 185: 214, # 'ą' + 186: 215, # 'ş' + 187: 216, # '»' + 188: 217, # 'Ľ' + 189: 218, # '˝' + 190: 219, # 'ľ' + 191: 220, # 'ż' + 192: 221, # 'Ŕ' + 193: 51, # 'Á' + 194: 83, # 'Â' + 195: 222, # 'Ă' + 196: 80, # 'Ä' + 197: 223, # 'Ĺ' + 198: 224, # 'Ć' + 199: 225, # 'Ç' + 200: 226, # 'Č' + 201: 44, # 'É' + 202: 227, # 'Ę' + 203: 228, # 'Ë' + 204: 229, # 'Ě' + 205: 61, # 'Í' + 206: 230, # 'Î' + 207: 231, # 'Ď' + 208: 232, # 'Đ' + 209: 233, # 'Ń' + 210: 234, # 'Ň' + 211: 58, # 'Ó' + 212: 235, # 'Ô' + 213: 66, # 'Ő' + 214: 59, # 'Ö' + 215: 236, # '×' + 216: 237, # 'Ř' + 217: 238, # 'Ů' + 218: 60, # 'Ú' + 219: 70, # 'Ű' + 220: 63, # 'Ü' + 221: 239, # 'Ý' + 222: 240, # 'Ţ' + 223: 241, # 'ß' + 224: 84, # 'ŕ' + 225: 14, # 'á' + 226: 75, # 'â' + 227: 242, # 'ă' + 228: 71, # 'ä' + 229: 82, # 'ĺ' + 230: 243, # 'ć' + 231: 73, # 'ç' + 232: 244, # 'č' + 233: 15, # 'é' + 234: 85, # 'ę' + 235: 79, # 'ë' + 236: 86, # 'ě' + 237: 30, # 'í' + 238: 77, # 'î' + 239: 87, # 'ď' + 240: 245, # 'đ' + 241: 246, # 'ń' + 242: 247, # 'ň' + 243: 25, # 'ó' + 244: 74, # 'ô' + 245: 42, # 'ő' + 246: 24, # 'ö' + 247: 248, # '÷' + 248: 249, # 'ř' + 249: 250, # 'ů' + 250: 31, # 'ú' + 251: 56, # 'ű' + 252: 29, # 'ü' + 253: 251, # 'ý' + 254: 252, # 'ţ' + 255: 253, # '˙' +} + +WINDOWS_1250_HUNGARIAN_MODEL = SingleByteCharSetModel(charset_name='windows-1250', + language='Hungarian', + char_to_order_map=WINDOWS_1250_HUNGARIAN_CHAR_TO_ORDER, + language_model=HUNGARIAN_LANG_MODEL, + typical_positive_ratio=0.947368, + keep_ascii_letters=True, + alphabet='ABCDEFGHIJKLMNOPRSTUVZabcdefghijklmnoprstuvzÁÉÍÓÖÚÜáéíóöúüŐőŰű') + +ISO_8859_2_HUNGARIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 28, # 'A' + 66: 40, # 'B' + 67: 54, # 'C' + 68: 45, # 'D' + 69: 32, # 'E' + 70: 50, # 'F' + 71: 49, # 'G' + 72: 38, # 'H' + 73: 39, # 'I' + 74: 53, # 'J' + 75: 36, # 'K' + 76: 41, # 'L' + 77: 34, # 'M' + 78: 35, # 'N' + 79: 47, # 'O' + 80: 46, # 'P' + 81: 71, # 'Q' + 82: 43, # 'R' + 83: 33, # 'S' + 84: 37, # 'T' + 85: 57, # 'U' + 86: 48, # 'V' + 87: 64, # 'W' + 88: 68, # 'X' + 89: 55, # 'Y' + 90: 52, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 2, # 'a' + 98: 18, # 'b' + 99: 26, # 'c' + 100: 17, # 'd' + 101: 1, # 'e' + 102: 27, # 'f' + 103: 12, # 'g' + 104: 20, # 'h' + 105: 9, # 'i' + 106: 22, # 'j' + 107: 7, # 'k' + 108: 6, # 'l' + 109: 13, # 'm' + 110: 4, # 'n' + 111: 8, # 'o' + 112: 23, # 'p' + 113: 67, # 'q' + 114: 10, # 'r' + 115: 5, # 's' + 116: 3, # 't' + 117: 21, # 'u' + 118: 19, # 'v' + 119: 65, # 'w' + 120: 62, # 'x' + 121: 16, # 'y' + 122: 11, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 159, # '\x80' + 129: 160, # '\x81' + 130: 161, # '\x82' + 131: 162, # '\x83' + 132: 163, # '\x84' + 133: 164, # '\x85' + 134: 165, # '\x86' + 135: 166, # '\x87' + 136: 167, # '\x88' + 137: 168, # '\x89' + 138: 169, # '\x8a' + 139: 170, # '\x8b' + 140: 171, # '\x8c' + 141: 172, # '\x8d' + 142: 173, # '\x8e' + 143: 174, # '\x8f' + 144: 175, # '\x90' + 145: 176, # '\x91' + 146: 177, # '\x92' + 147: 178, # '\x93' + 148: 179, # '\x94' + 149: 180, # '\x95' + 150: 181, # '\x96' + 151: 182, # '\x97' + 152: 183, # '\x98' + 153: 184, # '\x99' + 154: 185, # '\x9a' + 155: 186, # '\x9b' + 156: 187, # '\x9c' + 157: 188, # '\x9d' + 158: 189, # '\x9e' + 159: 190, # '\x9f' + 160: 191, # '\xa0' + 161: 192, # 'Ą' + 162: 193, # '˘' + 163: 194, # 'Ł' + 164: 195, # '¤' + 165: 196, # 'Ľ' + 166: 197, # 'Ś' + 167: 75, # '§' + 168: 198, # '¨' + 169: 199, # 'Š' + 170: 200, # 'Ş' + 171: 201, # 'Ť' + 172: 202, # 'Ź' + 173: 203, # '\xad' + 174: 204, # 'Ž' + 175: 205, # 'Ż' + 176: 79, # '°' + 177: 206, # 'ą' + 178: 207, # '˛' + 179: 208, # 'ł' + 180: 209, # '´' + 181: 210, # 'ľ' + 182: 211, # 'ś' + 183: 212, # 'ˇ' + 184: 213, # '¸' + 185: 214, # 'š' + 186: 215, # 'ş' + 187: 216, # 'ť' + 188: 217, # 'ź' + 189: 218, # '˝' + 190: 219, # 'ž' + 191: 220, # 'ż' + 192: 221, # 'Ŕ' + 193: 51, # 'Á' + 194: 81, # 'Â' + 195: 222, # 'Ă' + 196: 78, # 'Ä' + 197: 223, # 'Ĺ' + 198: 224, # 'Ć' + 199: 225, # 'Ç' + 200: 226, # 'Č' + 201: 44, # 'É' + 202: 227, # 'Ę' + 203: 228, # 'Ë' + 204: 229, # 'Ě' + 205: 61, # 'Í' + 206: 230, # 'Î' + 207: 231, # 'Ď' + 208: 232, # 'Đ' + 209: 233, # 'Ń' + 210: 234, # 'Ň' + 211: 58, # 'Ó' + 212: 235, # 'Ô' + 213: 66, # 'Ő' + 214: 59, # 'Ö' + 215: 236, # '×' + 216: 237, # 'Ř' + 217: 238, # 'Ů' + 218: 60, # 'Ú' + 219: 69, # 'Ű' + 220: 63, # 'Ü' + 221: 239, # 'Ý' + 222: 240, # 'Ţ' + 223: 241, # 'ß' + 224: 82, # 'ŕ' + 225: 14, # 'á' + 226: 74, # 'â' + 227: 242, # 'ă' + 228: 70, # 'ä' + 229: 80, # 'ĺ' + 230: 243, # 'ć' + 231: 72, # 'ç' + 232: 244, # 'č' + 233: 15, # 'é' + 234: 83, # 'ę' + 235: 77, # 'ë' + 236: 84, # 'ě' + 237: 30, # 'í' + 238: 76, # 'î' + 239: 85, # 'ď' + 240: 245, # 'đ' + 241: 246, # 'ń' + 242: 247, # 'ň' + 243: 25, # 'ó' + 244: 73, # 'ô' + 245: 42, # 'ő' + 246: 24, # 'ö' + 247: 248, # '÷' + 248: 249, # 'ř' + 249: 250, # 'ů' + 250: 31, # 'ú' + 251: 56, # 'ű' + 252: 29, # 'ü' + 253: 251, # 'ý' + 254: 252, # 'ţ' + 255: 253, # '˙' +} + +ISO_8859_2_HUNGARIAN_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-2', + language='Hungarian', + char_to_order_map=ISO_8859_2_HUNGARIAN_CHAR_TO_ORDER, + language_model=HUNGARIAN_LANG_MODEL, + typical_positive_ratio=0.947368, + keep_ascii_letters=True, + alphabet='ABCDEFGHIJKLMNOPRSTUVZabcdefghijklmnoprstuvzÁÉÍÓÖÚÜáéíóöúüŐőŰű') + diff --git a/openpype/vendor/python/python_2/chardet/langrussianmodel.py b/openpype/vendor/python/python_2/chardet/langrussianmodel.py new file mode 100644 index 0000000000..569689d0f5 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/langrussianmodel.py @@ -0,0 +1,5718 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from chardet.sbcharsetprober import SingleByteCharSetModel + + +# 3: Positive +# 2: Likely +# 1: Unlikely +# 0: Negative + +RUSSIAN_LANG_MODEL = { + 37: { # 'А' + 37: 0, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 1, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 2, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 1, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 1, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 0, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 0, # 'и' + 23: 1, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 0, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 2, # 'ф' + 26: 2, # 'х' + 28: 0, # 'ц' + 22: 1, # 'ч' + 25: 2, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 44: { # 'Б' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 1, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 2, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 33: { # 'В' + 37: 2, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 1, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 2, # 'а' + 21: 1, # 'б' + 10: 1, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 2, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 1, # 'ъ' + 18: 3, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 0, # 'ю' + 16: 1, # 'я' + }, + 46: { # 'Г' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 2, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 1, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 41: { # 'Д' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 2, # 'Е' + 56: 1, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 2, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 3, # 'ж' + 20: 1, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 48: { # 'Е' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 1, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 2, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 2, # 'Р' + 32: 2, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 0, # 'а' + 21: 0, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 2, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 0, # 'и' + 23: 2, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 1, # 'н' + 1: 0, # 'о' + 15: 1, # 'п' + 9: 1, # 'р' + 7: 3, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 2, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 56: { # 'Ж' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 1, # 'б' + 10: 0, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 2, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 1, # 'м' + 5: 0, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 2, # 'ю' + 16: 0, # 'я' + }, + 51: { # 'З' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 0, # 'г' + 13: 2, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 1, # 'л' + 12: 1, # 'м' + 5: 2, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 1, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 1, # 'я' + }, + 42: { # 'И' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 2, # 'Е' + 56: 1, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 2, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 1, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 1, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 2, # 'з' + 4: 1, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 1, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 1, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 60: { # 'Й' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 1, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 36: { # 'К' + 37: 2, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 2, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 1, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 0, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 49: { # 'Л' + 37: 2, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 1, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 1, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 0, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 0, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 1, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 1, # 'л' + 12: 0, # 'м' + 5: 1, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 2, # 'ю' + 16: 1, # 'я' + }, + 38: { # 'М' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 1, # 'Ф' + 55: 1, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 0, # 'Ь' + 47: 1, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 1, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 1, # 'л' + 12: 1, # 'м' + 5: 2, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 1, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 31: { # 'Н' + 37: 2, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 1, # 'З' + 42: 2, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 1, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 1, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 3, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 34: { # 'О' + 37: 0, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 2, # 'Д' + 48: 1, # 'Е' + 56: 1, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 2, # 'Л' + 38: 1, # 'М' + 31: 2, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 2, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 1, # 'Ф' + 55: 1, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 1, # 'а' + 21: 2, # 'б' + 10: 1, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 0, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 0, # 'и' + 23: 1, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 0, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 1, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 2, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 35: { # 'П' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 2, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 0, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 3, # 'р' + 7: 1, # 'с' + 6: 1, # 'т' + 14: 2, # 'у' + 39: 1, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 0, # 'ю' + 16: 2, # 'я' + }, + 45: { # 'Р' + 37: 2, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 2, # 'Е' + 56: 1, # 'Ж' + 51: 0, # 'З' + 42: 2, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 2, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 1, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 2, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 2, # 'я' + }, + 32: { # 'С' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 2, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 1, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 2, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 2, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 1, # 'с' + 6: 3, # 'т' + 14: 2, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 1, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 1, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 40: { # 'Т' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 2, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 1, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 1, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 1, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 52: { # 'У' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 1, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 0, # 'Я' + 3: 1, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 1, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 2, # 'и' + 23: 1, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 1, # 'н' + 1: 2, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 0, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 53: { # 'Ф' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 1, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 55: { # 'Х' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 2, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 0, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 1, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 1, # 'ь' + 30: 1, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 58: { # 'Ц' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 1, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 0, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 1, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 50: { # 'Ч' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 1, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 1, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 1, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 3, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 1, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 57: { # 'Ш' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 1, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 1, # 'н' + 1: 2, # 'о' + 15: 2, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 63: { # 'Щ' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 1, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 1, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 1, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 1, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 1, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 62: { # 'Ы' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 0, # 'Ч' + 57: 1, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 0, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 0, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 61: { # 'Ь' + 37: 0, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 1, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 1, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 1, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 0, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 0, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 0, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 47: { # 'Э' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 1, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 0, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 2, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 0, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 1, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 59: { # 'Ю' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 0, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 1, # 'б' + 10: 0, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 0, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 2, # 'н' + 1: 0, # 'о' + 15: 1, # 'п' + 9: 1, # 'р' + 7: 1, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 43: { # 'Я' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 0, # 'а' + 21: 1, # 'б' + 10: 1, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 0, # 'е' + 24: 0, # 'ж' + 20: 1, # 'з' + 4: 0, # 'и' + 23: 1, # 'й' + 11: 1, # 'к' + 8: 1, # 'л' + 12: 1, # 'м' + 5: 2, # 'н' + 1: 0, # 'о' + 15: 1, # 'п' + 9: 1, # 'р' + 7: 1, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 3: { # 'а' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 3, # 'и' + 23: 3, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 3, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 2, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 21: { # 'б' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 1, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 0, # 'ф' + 26: 2, # 'х' + 28: 1, # 'ц' + 22: 1, # 'ч' + 25: 2, # 'ш' + 29: 3, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 2, # 'ю' + 16: 3, # 'я' + }, + 10: { # 'в' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 3, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 3, # 'ш' + 29: 2, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 3, # 'я' + }, + 19: { # 'г' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 3, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 13: { # 'д' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 3, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 3, # 'ц' + 22: 2, # 'ч' + 25: 2, # 'ш' + 29: 1, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 1, # 'э' + 27: 2, # 'ю' + 16: 3, # 'я' + }, + 2: { # 'е' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 2, # 'и' + 23: 3, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 2, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 3, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 2, # 'ю' + 16: 3, # 'я' + }, + 24: { # 'ж' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 1, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 1, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 0, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 20: { # 'з' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 3, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 3, # 'я' + }, + 4: { # 'и' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 3, # 'и' + 23: 3, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 2, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 3, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 2, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 23: { # 'й' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 1, # 'а' + 21: 1, # 'б' + 10: 1, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 2, # 'з' + 4: 1, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 2, # 'ф' + 26: 1, # 'х' + 28: 2, # 'ц' + 22: 3, # 'ч' + 25: 2, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 2, # 'я' + }, + 11: { # 'к' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 3, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 2, # 'ц' + 22: 1, # 'ч' + 25: 2, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 8: { # 'л' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 3, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 1, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 2, # 'х' + 28: 1, # 'ц' + 22: 3, # 'ч' + 25: 2, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 1, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 12: { # 'м' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 1, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 2, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 2, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 3, # 'я' + }, + 5: { # 'н' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 2, # 'х' + 28: 3, # 'ц' + 22: 3, # 'ч' + 25: 2, # 'ш' + 29: 2, # 'щ' + 54: 1, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 1, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 1: { # 'о' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 3, # 'и' + 23: 3, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 2, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 2, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 15: { # 'п' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 3, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 0, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 3, # 'я' + }, + 9: { # 'р' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 2, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 3, # 'ш' + 29: 2, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 2, # 'э' + 27: 2, # 'ю' + 16: 3, # 'я' + }, + 7: { # 'с' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 1, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 3, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 3, # 'ч' + 25: 2, # 'ш' + 29: 1, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 2, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 6: { # 'т' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 3, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 2, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 2, # 'ш' + 29: 2, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 2, # 'э' + 27: 2, # 'ю' + 16: 3, # 'я' + }, + 14: { # 'у' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 2, # 'и' + 23: 2, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 2, # 'э' + 27: 3, # 'ю' + 16: 2, # 'я' + }, + 39: { # 'ф' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 0, # 'в' + 19: 1, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 2, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 1, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 2, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 26: { # 'х' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 3, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 1, # 'п' + 9: 3, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 1, # 'ч' + 25: 2, # 'ш' + 29: 0, # 'щ' + 54: 1, # 'ъ' + 18: 0, # 'ы' + 17: 1, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 28: { # 'ц' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 1, # 'л' + 12: 1, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 1, # 'т' + 14: 3, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 1, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 1, # 'ь' + 30: 0, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 22: { # 'ч' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 1, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 1, # 'ч' + 25: 2, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 3, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 25: { # 'ш' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 1, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 1, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 3, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 29: { # 'щ' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 1, # 'м' + 5: 2, # 'н' + 1: 1, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 2, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 54: { # 'ъ' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 0, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 1, # 'ю' + 16: 2, # 'я' + }, + 18: { # 'ы' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 2, # 'и' + 23: 3, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 1, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 0, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 2, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 2, # 'я' + }, + 17: { # 'ь' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 3, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 0, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 2, # 'п' + 9: 1, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 0, # 'у' + 39: 2, # 'ф' + 26: 1, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 3, # 'ш' + 29: 2, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 30: { # 'э' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 1, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 1, # 'б' + 10: 1, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 1, # 'е' + 24: 0, # 'ж' + 20: 1, # 'з' + 4: 0, # 'и' + 23: 2, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 0, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 2, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 27: { # 'ю' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 3, # 'б' + 10: 1, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 1, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 1, # 'и' + 23: 1, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 1, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 0, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 2, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 2, # 'ю' + 16: 1, # 'я' + }, + 16: { # 'я' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 2, # 'б' + 10: 3, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 2, # 'и' + 23: 2, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 0, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 1, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 2, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 2, # 'ю' + 16: 2, # 'я' + }, +} + +# 255: Undefined characters that did not exist in training text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 +# 251: Control characters + +# Character Mapping Table(s): +IBM866_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 37, # 'А' + 129: 44, # 'Б' + 130: 33, # 'В' + 131: 46, # 'Г' + 132: 41, # 'Д' + 133: 48, # 'Е' + 134: 56, # 'Ж' + 135: 51, # 'З' + 136: 42, # 'И' + 137: 60, # 'Й' + 138: 36, # 'К' + 139: 49, # 'Л' + 140: 38, # 'М' + 141: 31, # 'Н' + 142: 34, # 'О' + 143: 35, # 'П' + 144: 45, # 'Р' + 145: 32, # 'С' + 146: 40, # 'Т' + 147: 52, # 'У' + 148: 53, # 'Ф' + 149: 55, # 'Х' + 150: 58, # 'Ц' + 151: 50, # 'Ч' + 152: 57, # 'Ш' + 153: 63, # 'Щ' + 154: 70, # 'Ъ' + 155: 62, # 'Ы' + 156: 61, # 'Ь' + 157: 47, # 'Э' + 158: 59, # 'Ю' + 159: 43, # 'Я' + 160: 3, # 'а' + 161: 21, # 'б' + 162: 10, # 'в' + 163: 19, # 'г' + 164: 13, # 'д' + 165: 2, # 'е' + 166: 24, # 'ж' + 167: 20, # 'з' + 168: 4, # 'и' + 169: 23, # 'й' + 170: 11, # 'к' + 171: 8, # 'л' + 172: 12, # 'м' + 173: 5, # 'н' + 174: 1, # 'о' + 175: 15, # 'п' + 176: 191, # '░' + 177: 192, # '▒' + 178: 193, # '▓' + 179: 194, # '│' + 180: 195, # '┤' + 181: 196, # '╡' + 182: 197, # '╢' + 183: 198, # '╖' + 184: 199, # '╕' + 185: 200, # '╣' + 186: 201, # '║' + 187: 202, # '╗' + 188: 203, # '╝' + 189: 204, # '╜' + 190: 205, # '╛' + 191: 206, # '┐' + 192: 207, # '└' + 193: 208, # '┴' + 194: 209, # '┬' + 195: 210, # '├' + 196: 211, # '─' + 197: 212, # '┼' + 198: 213, # '╞' + 199: 214, # '╟' + 200: 215, # '╚' + 201: 216, # '╔' + 202: 217, # '╩' + 203: 218, # '╦' + 204: 219, # '╠' + 205: 220, # '═' + 206: 221, # '╬' + 207: 222, # '╧' + 208: 223, # '╨' + 209: 224, # '╤' + 210: 225, # '╥' + 211: 226, # '╙' + 212: 227, # '╘' + 213: 228, # '╒' + 214: 229, # '╓' + 215: 230, # '╫' + 216: 231, # '╪' + 217: 232, # '┘' + 218: 233, # '┌' + 219: 234, # '█' + 220: 235, # '▄' + 221: 236, # '▌' + 222: 237, # '▐' + 223: 238, # '▀' + 224: 9, # 'р' + 225: 7, # 'с' + 226: 6, # 'т' + 227: 14, # 'у' + 228: 39, # 'ф' + 229: 26, # 'х' + 230: 28, # 'ц' + 231: 22, # 'ч' + 232: 25, # 'ш' + 233: 29, # 'щ' + 234: 54, # 'ъ' + 235: 18, # 'ы' + 236: 17, # 'ь' + 237: 30, # 'э' + 238: 27, # 'ю' + 239: 16, # 'я' + 240: 239, # 'Ё' + 241: 68, # 'ё' + 242: 240, # 'Є' + 243: 241, # 'є' + 244: 242, # 'Ї' + 245: 243, # 'ї' + 246: 244, # 'Ў' + 247: 245, # 'ў' + 248: 246, # '°' + 249: 247, # '∙' + 250: 248, # '·' + 251: 249, # '√' + 252: 250, # '№' + 253: 251, # '¤' + 254: 252, # '■' + 255: 255, # '\xa0' +} + +IBM866_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='IBM866', + language='Russian', + char_to_order_map=IBM866_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') + +WINDOWS_1251_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 191, # 'Ђ' + 129: 192, # 'Ѓ' + 130: 193, # '‚' + 131: 194, # 'ѓ' + 132: 195, # '„' + 133: 196, # '…' + 134: 197, # '†' + 135: 198, # '‡' + 136: 199, # '€' + 137: 200, # '‰' + 138: 201, # 'Љ' + 139: 202, # '‹' + 140: 203, # 'Њ' + 141: 204, # 'Ќ' + 142: 205, # 'Ћ' + 143: 206, # 'Џ' + 144: 207, # 'ђ' + 145: 208, # '‘' + 146: 209, # '’' + 147: 210, # '“' + 148: 211, # '”' + 149: 212, # '•' + 150: 213, # '–' + 151: 214, # '—' + 152: 215, # None + 153: 216, # '™' + 154: 217, # 'љ' + 155: 218, # '›' + 156: 219, # 'њ' + 157: 220, # 'ќ' + 158: 221, # 'ћ' + 159: 222, # 'џ' + 160: 223, # '\xa0' + 161: 224, # 'Ў' + 162: 225, # 'ў' + 163: 226, # 'Ј' + 164: 227, # '¤' + 165: 228, # 'Ґ' + 166: 229, # '¦' + 167: 230, # '§' + 168: 231, # 'Ё' + 169: 232, # '©' + 170: 233, # 'Є' + 171: 234, # '«' + 172: 235, # '¬' + 173: 236, # '\xad' + 174: 237, # '®' + 175: 238, # 'Ї' + 176: 239, # '°' + 177: 240, # '±' + 178: 241, # 'І' + 179: 242, # 'і' + 180: 243, # 'ґ' + 181: 244, # 'µ' + 182: 245, # '¶' + 183: 246, # '·' + 184: 68, # 'ё' + 185: 247, # '№' + 186: 248, # 'є' + 187: 249, # '»' + 188: 250, # 'ј' + 189: 251, # 'Ѕ' + 190: 252, # 'ѕ' + 191: 253, # 'ї' + 192: 37, # 'А' + 193: 44, # 'Б' + 194: 33, # 'В' + 195: 46, # 'Г' + 196: 41, # 'Д' + 197: 48, # 'Е' + 198: 56, # 'Ж' + 199: 51, # 'З' + 200: 42, # 'И' + 201: 60, # 'Й' + 202: 36, # 'К' + 203: 49, # 'Л' + 204: 38, # 'М' + 205: 31, # 'Н' + 206: 34, # 'О' + 207: 35, # 'П' + 208: 45, # 'Р' + 209: 32, # 'С' + 210: 40, # 'Т' + 211: 52, # 'У' + 212: 53, # 'Ф' + 213: 55, # 'Х' + 214: 58, # 'Ц' + 215: 50, # 'Ч' + 216: 57, # 'Ш' + 217: 63, # 'Щ' + 218: 70, # 'Ъ' + 219: 62, # 'Ы' + 220: 61, # 'Ь' + 221: 47, # 'Э' + 222: 59, # 'Ю' + 223: 43, # 'Я' + 224: 3, # 'а' + 225: 21, # 'б' + 226: 10, # 'в' + 227: 19, # 'г' + 228: 13, # 'д' + 229: 2, # 'е' + 230: 24, # 'ж' + 231: 20, # 'з' + 232: 4, # 'и' + 233: 23, # 'й' + 234: 11, # 'к' + 235: 8, # 'л' + 236: 12, # 'м' + 237: 5, # 'н' + 238: 1, # 'о' + 239: 15, # 'п' + 240: 9, # 'р' + 241: 7, # 'с' + 242: 6, # 'т' + 243: 14, # 'у' + 244: 39, # 'ф' + 245: 26, # 'х' + 246: 28, # 'ц' + 247: 22, # 'ч' + 248: 25, # 'ш' + 249: 29, # 'щ' + 250: 54, # 'ъ' + 251: 18, # 'ы' + 252: 17, # 'ь' + 253: 30, # 'э' + 254: 27, # 'ю' + 255: 16, # 'я' +} + +WINDOWS_1251_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='windows-1251', + language='Russian', + char_to_order_map=WINDOWS_1251_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') + +IBM855_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 191, # 'ђ' + 129: 192, # 'Ђ' + 130: 193, # 'ѓ' + 131: 194, # 'Ѓ' + 132: 68, # 'ё' + 133: 195, # 'Ё' + 134: 196, # 'є' + 135: 197, # 'Є' + 136: 198, # 'ѕ' + 137: 199, # 'Ѕ' + 138: 200, # 'і' + 139: 201, # 'І' + 140: 202, # 'ї' + 141: 203, # 'Ї' + 142: 204, # 'ј' + 143: 205, # 'Ј' + 144: 206, # 'љ' + 145: 207, # 'Љ' + 146: 208, # 'њ' + 147: 209, # 'Њ' + 148: 210, # 'ћ' + 149: 211, # 'Ћ' + 150: 212, # 'ќ' + 151: 213, # 'Ќ' + 152: 214, # 'ў' + 153: 215, # 'Ў' + 154: 216, # 'џ' + 155: 217, # 'Џ' + 156: 27, # 'ю' + 157: 59, # 'Ю' + 158: 54, # 'ъ' + 159: 70, # 'Ъ' + 160: 3, # 'а' + 161: 37, # 'А' + 162: 21, # 'б' + 163: 44, # 'Б' + 164: 28, # 'ц' + 165: 58, # 'Ц' + 166: 13, # 'д' + 167: 41, # 'Д' + 168: 2, # 'е' + 169: 48, # 'Е' + 170: 39, # 'ф' + 171: 53, # 'Ф' + 172: 19, # 'г' + 173: 46, # 'Г' + 174: 218, # '«' + 175: 219, # '»' + 176: 220, # '░' + 177: 221, # '▒' + 178: 222, # '▓' + 179: 223, # '│' + 180: 224, # '┤' + 181: 26, # 'х' + 182: 55, # 'Х' + 183: 4, # 'и' + 184: 42, # 'И' + 185: 225, # '╣' + 186: 226, # '║' + 187: 227, # '╗' + 188: 228, # '╝' + 189: 23, # 'й' + 190: 60, # 'Й' + 191: 229, # '┐' + 192: 230, # '└' + 193: 231, # '┴' + 194: 232, # '┬' + 195: 233, # '├' + 196: 234, # '─' + 197: 235, # '┼' + 198: 11, # 'к' + 199: 36, # 'К' + 200: 236, # '╚' + 201: 237, # '╔' + 202: 238, # '╩' + 203: 239, # '╦' + 204: 240, # '╠' + 205: 241, # '═' + 206: 242, # '╬' + 207: 243, # '¤' + 208: 8, # 'л' + 209: 49, # 'Л' + 210: 12, # 'м' + 211: 38, # 'М' + 212: 5, # 'н' + 213: 31, # 'Н' + 214: 1, # 'о' + 215: 34, # 'О' + 216: 15, # 'п' + 217: 244, # '┘' + 218: 245, # '┌' + 219: 246, # '█' + 220: 247, # '▄' + 221: 35, # 'П' + 222: 16, # 'я' + 223: 248, # '▀' + 224: 43, # 'Я' + 225: 9, # 'р' + 226: 45, # 'Р' + 227: 7, # 'с' + 228: 32, # 'С' + 229: 6, # 'т' + 230: 40, # 'Т' + 231: 14, # 'у' + 232: 52, # 'У' + 233: 24, # 'ж' + 234: 56, # 'Ж' + 235: 10, # 'в' + 236: 33, # 'В' + 237: 17, # 'ь' + 238: 61, # 'Ь' + 239: 249, # '№' + 240: 250, # '\xad' + 241: 18, # 'ы' + 242: 62, # 'Ы' + 243: 20, # 'з' + 244: 51, # 'З' + 245: 25, # 'ш' + 246: 57, # 'Ш' + 247: 30, # 'э' + 248: 47, # 'Э' + 249: 29, # 'щ' + 250: 63, # 'Щ' + 251: 22, # 'ч' + 252: 50, # 'Ч' + 253: 251, # '§' + 254: 252, # '■' + 255: 255, # '\xa0' +} + +IBM855_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='IBM855', + language='Russian', + char_to_order_map=IBM855_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') + +KOI8_R_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 191, # '─' + 129: 192, # '│' + 130: 193, # '┌' + 131: 194, # '┐' + 132: 195, # '└' + 133: 196, # '┘' + 134: 197, # '├' + 135: 198, # '┤' + 136: 199, # '┬' + 137: 200, # '┴' + 138: 201, # '┼' + 139: 202, # '▀' + 140: 203, # '▄' + 141: 204, # '█' + 142: 205, # '▌' + 143: 206, # '▐' + 144: 207, # '░' + 145: 208, # '▒' + 146: 209, # '▓' + 147: 210, # '⌠' + 148: 211, # '■' + 149: 212, # '∙' + 150: 213, # '√' + 151: 214, # '≈' + 152: 215, # '≤' + 153: 216, # '≥' + 154: 217, # '\xa0' + 155: 218, # '⌡' + 156: 219, # '°' + 157: 220, # '²' + 158: 221, # '·' + 159: 222, # '÷' + 160: 223, # '═' + 161: 224, # '║' + 162: 225, # '╒' + 163: 68, # 'ё' + 164: 226, # '╓' + 165: 227, # '╔' + 166: 228, # '╕' + 167: 229, # '╖' + 168: 230, # '╗' + 169: 231, # '╘' + 170: 232, # '╙' + 171: 233, # '╚' + 172: 234, # '╛' + 173: 235, # '╜' + 174: 236, # '╝' + 175: 237, # '╞' + 176: 238, # '╟' + 177: 239, # '╠' + 178: 240, # '╡' + 179: 241, # 'Ё' + 180: 242, # '╢' + 181: 243, # '╣' + 182: 244, # '╤' + 183: 245, # '╥' + 184: 246, # '╦' + 185: 247, # '╧' + 186: 248, # '╨' + 187: 249, # '╩' + 188: 250, # '╪' + 189: 251, # '╫' + 190: 252, # '╬' + 191: 253, # '©' + 192: 27, # 'ю' + 193: 3, # 'а' + 194: 21, # 'б' + 195: 28, # 'ц' + 196: 13, # 'д' + 197: 2, # 'е' + 198: 39, # 'ф' + 199: 19, # 'г' + 200: 26, # 'х' + 201: 4, # 'и' + 202: 23, # 'й' + 203: 11, # 'к' + 204: 8, # 'л' + 205: 12, # 'м' + 206: 5, # 'н' + 207: 1, # 'о' + 208: 15, # 'п' + 209: 16, # 'я' + 210: 9, # 'р' + 211: 7, # 'с' + 212: 6, # 'т' + 213: 14, # 'у' + 214: 24, # 'ж' + 215: 10, # 'в' + 216: 17, # 'ь' + 217: 18, # 'ы' + 218: 20, # 'з' + 219: 25, # 'ш' + 220: 30, # 'э' + 221: 29, # 'щ' + 222: 22, # 'ч' + 223: 54, # 'ъ' + 224: 59, # 'Ю' + 225: 37, # 'А' + 226: 44, # 'Б' + 227: 58, # 'Ц' + 228: 41, # 'Д' + 229: 48, # 'Е' + 230: 53, # 'Ф' + 231: 46, # 'Г' + 232: 55, # 'Х' + 233: 42, # 'И' + 234: 60, # 'Й' + 235: 36, # 'К' + 236: 49, # 'Л' + 237: 38, # 'М' + 238: 31, # 'Н' + 239: 34, # 'О' + 240: 35, # 'П' + 241: 43, # 'Я' + 242: 45, # 'Р' + 243: 32, # 'С' + 244: 40, # 'Т' + 245: 52, # 'У' + 246: 56, # 'Ж' + 247: 33, # 'В' + 248: 61, # 'Ь' + 249: 62, # 'Ы' + 250: 51, # 'З' + 251: 57, # 'Ш' + 252: 47, # 'Э' + 253: 63, # 'Щ' + 254: 50, # 'Ч' + 255: 70, # 'Ъ' +} + +KOI8_R_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='KOI8-R', + language='Russian', + char_to_order_map=KOI8_R_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') + +MACCYRILLIC_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 37, # 'А' + 129: 44, # 'Б' + 130: 33, # 'В' + 131: 46, # 'Г' + 132: 41, # 'Д' + 133: 48, # 'Е' + 134: 56, # 'Ж' + 135: 51, # 'З' + 136: 42, # 'И' + 137: 60, # 'Й' + 138: 36, # 'К' + 139: 49, # 'Л' + 140: 38, # 'М' + 141: 31, # 'Н' + 142: 34, # 'О' + 143: 35, # 'П' + 144: 45, # 'Р' + 145: 32, # 'С' + 146: 40, # 'Т' + 147: 52, # 'У' + 148: 53, # 'Ф' + 149: 55, # 'Х' + 150: 58, # 'Ц' + 151: 50, # 'Ч' + 152: 57, # 'Ш' + 153: 63, # 'Щ' + 154: 70, # 'Ъ' + 155: 62, # 'Ы' + 156: 61, # 'Ь' + 157: 47, # 'Э' + 158: 59, # 'Ю' + 159: 43, # 'Я' + 160: 191, # '†' + 161: 192, # '°' + 162: 193, # 'Ґ' + 163: 194, # '£' + 164: 195, # '§' + 165: 196, # '•' + 166: 197, # '¶' + 167: 198, # 'І' + 168: 199, # '®' + 169: 200, # '©' + 170: 201, # '™' + 171: 202, # 'Ђ' + 172: 203, # 'ђ' + 173: 204, # '≠' + 174: 205, # 'Ѓ' + 175: 206, # 'ѓ' + 176: 207, # '∞' + 177: 208, # '±' + 178: 209, # '≤' + 179: 210, # '≥' + 180: 211, # 'і' + 181: 212, # 'µ' + 182: 213, # 'ґ' + 183: 214, # 'Ј' + 184: 215, # 'Є' + 185: 216, # 'є' + 186: 217, # 'Ї' + 187: 218, # 'ї' + 188: 219, # 'Љ' + 189: 220, # 'љ' + 190: 221, # 'Њ' + 191: 222, # 'њ' + 192: 223, # 'ј' + 193: 224, # 'Ѕ' + 194: 225, # '¬' + 195: 226, # '√' + 196: 227, # 'ƒ' + 197: 228, # '≈' + 198: 229, # '∆' + 199: 230, # '«' + 200: 231, # '»' + 201: 232, # '…' + 202: 233, # '\xa0' + 203: 234, # 'Ћ' + 204: 235, # 'ћ' + 205: 236, # 'Ќ' + 206: 237, # 'ќ' + 207: 238, # 'ѕ' + 208: 239, # '–' + 209: 240, # '—' + 210: 241, # '“' + 211: 242, # '”' + 212: 243, # '‘' + 213: 244, # '’' + 214: 245, # '÷' + 215: 246, # '„' + 216: 247, # 'Ў' + 217: 248, # 'ў' + 218: 249, # 'Џ' + 219: 250, # 'џ' + 220: 251, # '№' + 221: 252, # 'Ё' + 222: 68, # 'ё' + 223: 16, # 'я' + 224: 3, # 'а' + 225: 21, # 'б' + 226: 10, # 'в' + 227: 19, # 'г' + 228: 13, # 'д' + 229: 2, # 'е' + 230: 24, # 'ж' + 231: 20, # 'з' + 232: 4, # 'и' + 233: 23, # 'й' + 234: 11, # 'к' + 235: 8, # 'л' + 236: 12, # 'м' + 237: 5, # 'н' + 238: 1, # 'о' + 239: 15, # 'п' + 240: 9, # 'р' + 241: 7, # 'с' + 242: 6, # 'т' + 243: 14, # 'у' + 244: 39, # 'ф' + 245: 26, # 'х' + 246: 28, # 'ц' + 247: 22, # 'ч' + 248: 25, # 'ш' + 249: 29, # 'щ' + 250: 54, # 'ъ' + 251: 18, # 'ы' + 252: 17, # 'ь' + 253: 30, # 'э' + 254: 27, # 'ю' + 255: 255, # '€' +} + +MACCYRILLIC_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='MacCyrillic', + language='Russian', + char_to_order_map=MACCYRILLIC_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') + +ISO_8859_5_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 191, # '\x80' + 129: 192, # '\x81' + 130: 193, # '\x82' + 131: 194, # '\x83' + 132: 195, # '\x84' + 133: 196, # '\x85' + 134: 197, # '\x86' + 135: 198, # '\x87' + 136: 199, # '\x88' + 137: 200, # '\x89' + 138: 201, # '\x8a' + 139: 202, # '\x8b' + 140: 203, # '\x8c' + 141: 204, # '\x8d' + 142: 205, # '\x8e' + 143: 206, # '\x8f' + 144: 207, # '\x90' + 145: 208, # '\x91' + 146: 209, # '\x92' + 147: 210, # '\x93' + 148: 211, # '\x94' + 149: 212, # '\x95' + 150: 213, # '\x96' + 151: 214, # '\x97' + 152: 215, # '\x98' + 153: 216, # '\x99' + 154: 217, # '\x9a' + 155: 218, # '\x9b' + 156: 219, # '\x9c' + 157: 220, # '\x9d' + 158: 221, # '\x9e' + 159: 222, # '\x9f' + 160: 223, # '\xa0' + 161: 224, # 'Ё' + 162: 225, # 'Ђ' + 163: 226, # 'Ѓ' + 164: 227, # 'Є' + 165: 228, # 'Ѕ' + 166: 229, # 'І' + 167: 230, # 'Ї' + 168: 231, # 'Ј' + 169: 232, # 'Љ' + 170: 233, # 'Њ' + 171: 234, # 'Ћ' + 172: 235, # 'Ќ' + 173: 236, # '\xad' + 174: 237, # 'Ў' + 175: 238, # 'Џ' + 176: 37, # 'А' + 177: 44, # 'Б' + 178: 33, # 'В' + 179: 46, # 'Г' + 180: 41, # 'Д' + 181: 48, # 'Е' + 182: 56, # 'Ж' + 183: 51, # 'З' + 184: 42, # 'И' + 185: 60, # 'Й' + 186: 36, # 'К' + 187: 49, # 'Л' + 188: 38, # 'М' + 189: 31, # 'Н' + 190: 34, # 'О' + 191: 35, # 'П' + 192: 45, # 'Р' + 193: 32, # 'С' + 194: 40, # 'Т' + 195: 52, # 'У' + 196: 53, # 'Ф' + 197: 55, # 'Х' + 198: 58, # 'Ц' + 199: 50, # 'Ч' + 200: 57, # 'Ш' + 201: 63, # 'Щ' + 202: 70, # 'Ъ' + 203: 62, # 'Ы' + 204: 61, # 'Ь' + 205: 47, # 'Э' + 206: 59, # 'Ю' + 207: 43, # 'Я' + 208: 3, # 'а' + 209: 21, # 'б' + 210: 10, # 'в' + 211: 19, # 'г' + 212: 13, # 'д' + 213: 2, # 'е' + 214: 24, # 'ж' + 215: 20, # 'з' + 216: 4, # 'и' + 217: 23, # 'й' + 218: 11, # 'к' + 219: 8, # 'л' + 220: 12, # 'м' + 221: 5, # 'н' + 222: 1, # 'о' + 223: 15, # 'п' + 224: 9, # 'р' + 225: 7, # 'с' + 226: 6, # 'т' + 227: 14, # 'у' + 228: 39, # 'ф' + 229: 26, # 'х' + 230: 28, # 'ц' + 231: 22, # 'ч' + 232: 25, # 'ш' + 233: 29, # 'щ' + 234: 54, # 'ъ' + 235: 18, # 'ы' + 236: 17, # 'ь' + 237: 30, # 'э' + 238: 27, # 'ю' + 239: 16, # 'я' + 240: 239, # '№' + 241: 68, # 'ё' + 242: 240, # 'ђ' + 243: 241, # 'ѓ' + 244: 242, # 'є' + 245: 243, # 'ѕ' + 246: 244, # 'і' + 247: 245, # 'ї' + 248: 246, # 'ј' + 249: 247, # 'љ' + 250: 248, # 'њ' + 251: 249, # 'ћ' + 252: 250, # 'ќ' + 253: 251, # '§' + 254: 252, # 'ў' + 255: 255, # 'џ' +} + +ISO_8859_5_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-5', + language='Russian', + char_to_order_map=ISO_8859_5_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') + diff --git a/openpype/vendor/python/python_2/chardet/langthaimodel.py b/openpype/vendor/python/python_2/chardet/langthaimodel.py new file mode 100644 index 0000000000..d0191f241d --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/langthaimodel.py @@ -0,0 +1,4383 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from chardet.sbcharsetprober import SingleByteCharSetModel + + +# 3: Positive +# 2: Likely +# 1: Unlikely +# 0: Negative + +THAI_LANG_MODEL = { + 5: { # 'ก' + 5: 2, # 'ก' + 30: 2, # 'ข' + 24: 2, # 'ค' + 8: 2, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 3, # 'ฎ' + 57: 2, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 2, # 'ณ' + 20: 2, # 'ด' + 19: 3, # 'ต' + 44: 0, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 2, # 'น' + 17: 1, # 'บ' + 25: 2, # 'ป' + 39: 1, # 'ผ' + 62: 1, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 2, # 'ม' + 16: 1, # 'ย' + 2: 3, # 'ร' + 61: 2, # 'ฤ' + 15: 3, # 'ล' + 12: 3, # 'ว' + 42: 2, # 'ศ' + 46: 3, # 'ษ' + 18: 2, # 'ส' + 21: 2, # 'ห' + 4: 3, # 'อ' + 63: 1, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 3, # 'ำ' + 23: 3, # 'ิ' + 13: 3, # 'ี' + 40: 0, # 'ึ' + 27: 2, # 'ื' + 32: 2, # 'ุ' + 35: 1, # 'ู' + 11: 2, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 1, # 'ใ' + 33: 2, # 'ไ' + 50: 1, # 'ๆ' + 37: 3, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 30: { # 'ข' + 5: 1, # 'ก' + 30: 0, # 'ข' + 24: 1, # 'ค' + 8: 1, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 2, # 'ณ' + 20: 0, # 'ด' + 19: 2, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 2, # 'น' + 17: 1, # 'บ' + 25: 1, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 2, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 2, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 1, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 2, # 'ี' + 40: 3, # 'ึ' + 27: 1, # 'ื' + 32: 1, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 1, # '็' + 6: 2, # '่' + 7: 3, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 24: { # 'ค' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 2, # 'ค' + 8: 2, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 2, # 'ณ' + 20: 2, # 'ด' + 19: 2, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 0, # 'บ' + 25: 1, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 2, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 3, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 0, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 2, # 'า' + 36: 3, # 'ำ' + 23: 3, # 'ิ' + 13: 2, # 'ี' + 40: 0, # 'ึ' + 27: 3, # 'ื' + 32: 3, # 'ุ' + 35: 2, # 'ู' + 11: 1, # 'เ' + 28: 0, # 'แ' + 41: 3, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 1, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 3, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 8: { # 'ง' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 3, # 'ค' + 8: 2, # 'ง' + 26: 2, # 'จ' + 52: 1, # 'ฉ' + 34: 2, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 2, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 3, # 'ท' + 48: 1, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 2, # 'ป' + 39: 2, # 'ผ' + 62: 1, # 'ฝ' + 31: 2, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 2, # 'ม' + 16: 1, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 2, # 'ว' + 42: 2, # 'ศ' + 46: 1, # 'ษ' + 18: 3, # 'ส' + 21: 3, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 1, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 2, # 'ิ' + 13: 1, # 'ี' + 40: 0, # 'ึ' + 27: 1, # 'ื' + 32: 1, # 'ุ' + 35: 0, # 'ู' + 11: 3, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 3, # 'ๆ' + 37: 0, # '็' + 6: 2, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 26: { # 'จ' + 5: 2, # 'ก' + 30: 1, # 'ข' + 24: 0, # 'ค' + 8: 2, # 'ง' + 26: 3, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 2, # 'ด' + 19: 1, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 1, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 1, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 1, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 3, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 3, # 'ำ' + 23: 2, # 'ิ' + 13: 1, # 'ี' + 40: 3, # 'ึ' + 27: 1, # 'ื' + 32: 3, # 'ุ' + 35: 2, # 'ู' + 11: 1, # 'เ' + 28: 1, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 2, # '่' + 7: 2, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 52: { # 'ฉ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 3, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 3, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 1, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 1, # 'ะ' + 10: 1, # 'ั' + 1: 1, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 1, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 1, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 34: { # 'ช' + 5: 1, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 1, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 1, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 1, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 2, # 'ั' + 1: 3, # 'า' + 36: 1, # 'ำ' + 23: 3, # 'ิ' + 13: 2, # 'ี' + 40: 0, # 'ึ' + 27: 3, # 'ื' + 32: 3, # 'ุ' + 35: 1, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 1, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 51: { # 'ซ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 1, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 0, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 1, # 'ั' + 1: 1, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 2, # 'ี' + 40: 3, # 'ึ' + 27: 2, # 'ื' + 32: 1, # 'ุ' + 35: 1, # 'ู' + 11: 1, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 1, # '็' + 6: 1, # '่' + 7: 2, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 47: { # 'ญ' + 5: 1, # 'ก' + 30: 1, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 3, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 1, # 'บ' + 25: 1, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 2, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 1, # 'ะ' + 10: 2, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 1, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 1, # 'เ' + 28: 1, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 0, # 'ไ' + 50: 1, # 'ๆ' + 37: 0, # '็' + 6: 2, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 58: { # 'ฎ' + 5: 2, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 1, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 2, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 57: { # 'ฏ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 3, # 'ิ' + 13: 1, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 49: { # 'ฐ' + 5: 1, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 2, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 1, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 53: { # 'ฑ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 2, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 3, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 55: { # 'ฒ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 43: { # 'ณ' + 5: 1, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 3, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 3, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 1, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 3, # 'ะ' + 10: 0, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 2, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 1, # 'เ' + 28: 1, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 3, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 20: { # 'ด' + 5: 2, # 'ก' + 30: 2, # 'ข' + 24: 2, # 'ค' + 8: 3, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 1, # 'น' + 17: 1, # 'บ' + 25: 1, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 2, # 'ม' + 16: 3, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 2, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 2, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 3, # 'ั' + 1: 2, # 'า' + 36: 2, # 'ำ' + 23: 3, # 'ิ' + 13: 3, # 'ี' + 40: 1, # 'ึ' + 27: 2, # 'ื' + 32: 3, # 'ุ' + 35: 2, # 'ู' + 11: 2, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 2, # 'ๆ' + 37: 2, # '็' + 6: 1, # '่' + 7: 3, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 19: { # 'ต' + 5: 2, # 'ก' + 30: 1, # 'ข' + 24: 1, # 'ค' + 8: 0, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 1, # 'ต' + 44: 2, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 2, # 'น' + 17: 1, # 'บ' + 25: 1, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 2, # 'ภ' + 9: 1, # 'ม' + 16: 1, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 3, # 'ส' + 21: 0, # 'ห' + 4: 3, # 'อ' + 63: 1, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 2, # 'ำ' + 23: 3, # 'ิ' + 13: 2, # 'ี' + 40: 1, # 'ึ' + 27: 1, # 'ื' + 32: 3, # 'ุ' + 35: 2, # 'ู' + 11: 1, # 'เ' + 28: 1, # 'แ' + 41: 1, # 'โ' + 29: 1, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 2, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 44: { # 'ถ' + 5: 1, # 'ก' + 30: 0, # 'ข' + 24: 1, # 'ค' + 8: 0, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 1, # 'น' + 17: 2, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 0, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 2, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 2, # 'ิ' + 13: 1, # 'ี' + 40: 3, # 'ึ' + 27: 2, # 'ื' + 32: 2, # 'ุ' + 35: 3, # 'ู' + 11: 1, # 'เ' + 28: 1, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 2, # '่' + 7: 3, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 14: { # 'ท' + 5: 1, # 'ก' + 30: 1, # 'ข' + 24: 3, # 'ค' + 8: 1, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 2, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 3, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 2, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 2, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 3, # 'ย' + 2: 3, # 'ร' + 61: 1, # 'ฤ' + 15: 1, # 'ล' + 12: 2, # 'ว' + 42: 3, # 'ศ' + 46: 1, # 'ษ' + 18: 1, # 'ส' + 21: 0, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 3, # 'ำ' + 23: 2, # 'ิ' + 13: 3, # 'ี' + 40: 2, # 'ึ' + 27: 1, # 'ื' + 32: 3, # 'ุ' + 35: 1, # 'ู' + 11: 0, # 'เ' + 28: 1, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 1, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 48: { # 'ธ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 1, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 1, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 2, # 'า' + 36: 0, # 'ำ' + 23: 3, # 'ิ' + 13: 3, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 2, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 3, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 3: { # 'น' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 3, # 'ค' + 8: 1, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 1, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 3, # 'ด' + 19: 3, # 'ต' + 44: 2, # 'ถ' + 14: 3, # 'ท' + 48: 3, # 'ธ' + 3: 2, # 'น' + 17: 2, # 'บ' + 25: 2, # 'ป' + 39: 2, # 'ผ' + 62: 0, # 'ฝ' + 31: 2, # 'พ' + 54: 1, # 'ฟ' + 45: 1, # 'ภ' + 9: 2, # 'ม' + 16: 2, # 'ย' + 2: 2, # 'ร' + 61: 1, # 'ฤ' + 15: 2, # 'ล' + 12: 3, # 'ว' + 42: 1, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 2, # 'ห' + 4: 3, # 'อ' + 63: 1, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 3, # 'ำ' + 23: 3, # 'ิ' + 13: 3, # 'ี' + 40: 3, # 'ึ' + 27: 3, # 'ื' + 32: 3, # 'ุ' + 35: 2, # 'ู' + 11: 3, # 'เ' + 28: 2, # 'แ' + 41: 3, # 'โ' + 29: 3, # 'ใ' + 33: 3, # 'ไ' + 50: 2, # 'ๆ' + 37: 1, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 17: { # 'บ' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 2, # 'ค' + 8: 1, # 'ง' + 26: 1, # 'จ' + 52: 1, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 3, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 2, # 'ป' + 39: 2, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 1, # 'ฟ' + 45: 1, # 'ภ' + 9: 1, # 'ม' + 16: 0, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 3, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 2, # 'ห' + 4: 2, # 'อ' + 63: 1, # 'ฯ' + 22: 0, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 2, # 'ำ' + 23: 2, # 'ิ' + 13: 2, # 'ี' + 40: 0, # 'ึ' + 27: 2, # 'ื' + 32: 3, # 'ุ' + 35: 2, # 'ู' + 11: 2, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 0, # 'ๆ' + 37: 1, # '็' + 6: 2, # '่' + 7: 2, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 25: { # 'ป' + 5: 2, # 'ก' + 30: 0, # 'ข' + 24: 1, # 'ค' + 8: 0, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 1, # 'ฎ' + 57: 3, # 'ฏ' + 49: 1, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 1, # 'ต' + 44: 1, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 2, # 'น' + 17: 0, # 'บ' + 25: 1, # 'ป' + 39: 1, # 'ผ' + 62: 1, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 0, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 1, # 'ษ' + 18: 2, # 'ส' + 21: 1, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 1, # 'ะ' + 10: 3, # 'ั' + 1: 1, # 'า' + 36: 0, # 'ำ' + 23: 2, # 'ิ' + 13: 3, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 1, # 'ุ' + 35: 0, # 'ู' + 11: 1, # 'เ' + 28: 2, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 2, # 'ไ' + 50: 0, # 'ๆ' + 37: 3, # '็' + 6: 1, # '่' + 7: 2, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 39: { # 'ผ' + 5: 1, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 1, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 2, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 2, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 1, # 'ะ' + 10: 1, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 2, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 1, # 'ื' + 32: 0, # 'ุ' + 35: 3, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 1, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 62: { # 'ฝ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 1, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 1, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 1, # 'ี' + 40: 2, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 2, # '่' + 7: 1, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 31: { # 'พ' + 5: 1, # 'ก' + 30: 1, # 'ข' + 24: 1, # 'ค' + 8: 1, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 1, # 'ณ' + 20: 1, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 2, # 'ท' + 48: 1, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 0, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 2, # 'ย' + 2: 3, # 'ร' + 61: 2, # 'ฤ' + 15: 2, # 'ล' + 12: 2, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 1, # 'ห' + 4: 2, # 'อ' + 63: 1, # 'ฯ' + 22: 0, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 3, # 'ิ' + 13: 2, # 'ี' + 40: 1, # 'ึ' + 27: 3, # 'ื' + 32: 1, # 'ุ' + 35: 2, # 'ู' + 11: 1, # 'เ' + 28: 1, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 1, # '็' + 6: 0, # '่' + 7: 1, # '้' + 38: 3, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 54: { # 'ฟ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 2, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 0, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 2, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 1, # 'ี' + 40: 0, # 'ึ' + 27: 1, # 'ื' + 32: 1, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 1, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 2, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 45: { # 'ภ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 1, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 3, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 2, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 9: { # 'ม' + 5: 2, # 'ก' + 30: 2, # 'ข' + 24: 2, # 'ค' + 8: 2, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 1, # 'ณ' + 20: 2, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 1, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 2, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 3, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 2, # 'ม' + 16: 1, # 'ย' + 2: 2, # 'ร' + 61: 2, # 'ฤ' + 15: 2, # 'ล' + 12: 2, # 'ว' + 42: 1, # 'ศ' + 46: 1, # 'ษ' + 18: 3, # 'ส' + 21: 3, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 1, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 3, # 'ิ' + 13: 3, # 'ี' + 40: 0, # 'ึ' + 27: 3, # 'ื' + 32: 3, # 'ุ' + 35: 3, # 'ู' + 11: 2, # 'เ' + 28: 2, # 'แ' + 41: 2, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 1, # 'ๆ' + 37: 1, # '็' + 6: 3, # '่' + 7: 2, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 16: { # 'ย' + 5: 3, # 'ก' + 30: 1, # 'ข' + 24: 2, # 'ค' + 8: 3, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 2, # 'ช' + 51: 0, # 'ซ' + 47: 2, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 2, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 1, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 1, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 2, # 'ม' + 16: 0, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 3, # 'ว' + 42: 1, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 1, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 2, # 'ิ' + 13: 3, # 'ี' + 40: 1, # 'ึ' + 27: 2, # 'ื' + 32: 2, # 'ุ' + 35: 3, # 'ู' + 11: 2, # 'เ' + 28: 1, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 2, # 'ๆ' + 37: 1, # '็' + 6: 3, # '่' + 7: 2, # '้' + 38: 3, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 2: { # 'ร' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 2, # 'ค' + 8: 3, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 2, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 3, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 3, # 'ณ' + 20: 2, # 'ด' + 19: 2, # 'ต' + 44: 3, # 'ถ' + 14: 3, # 'ท' + 48: 1, # 'ธ' + 3: 2, # 'น' + 17: 2, # 'บ' + 25: 3, # 'ป' + 39: 2, # 'ผ' + 62: 1, # 'ฝ' + 31: 2, # 'พ' + 54: 1, # 'ฟ' + 45: 1, # 'ภ' + 9: 3, # 'ม' + 16: 2, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 3, # 'ว' + 42: 2, # 'ศ' + 46: 2, # 'ษ' + 18: 2, # 'ส' + 21: 2, # 'ห' + 4: 3, # 'อ' + 63: 1, # 'ฯ' + 22: 3, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 3, # 'ิ' + 13: 3, # 'ี' + 40: 2, # 'ึ' + 27: 3, # 'ื' + 32: 3, # 'ุ' + 35: 3, # 'ู' + 11: 3, # 'เ' + 28: 3, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 3, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 3, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 61: { # 'ฤ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 2, # 'ต' + 44: 0, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 2, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 15: { # 'ล' + 5: 2, # 'ก' + 30: 3, # 'ข' + 24: 1, # 'ค' + 8: 3, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 2, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 1, # 'น' + 17: 2, # 'บ' + 25: 2, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 1, # 'ม' + 16: 3, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 1, # 'ห' + 4: 3, # 'อ' + 63: 2, # 'ฯ' + 22: 3, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 2, # 'ำ' + 23: 3, # 'ิ' + 13: 3, # 'ี' + 40: 2, # 'ึ' + 27: 3, # 'ื' + 32: 2, # 'ุ' + 35: 3, # 'ู' + 11: 2, # 'เ' + 28: 1, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 2, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 12: { # 'ว' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 1, # 'ค' + 8: 3, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 1, # 'ณ' + 20: 2, # 'ด' + 19: 1, # 'ต' + 44: 1, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 1, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 1, # 'ฟ' + 45: 0, # 'ภ' + 9: 3, # 'ม' + 16: 3, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 2, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 3, # 'ิ' + 13: 2, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 2, # 'ุ' + 35: 0, # 'ู' + 11: 3, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 1, # 'ใ' + 33: 2, # 'ไ' + 50: 1, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 42: { # 'ศ' + 5: 1, # 'ก' + 30: 0, # 'ข' + 24: 1, # 'ค' + 8: 0, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 1, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 2, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 2, # 'ว' + 42: 1, # 'ศ' + 46: 2, # 'ษ' + 18: 1, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 2, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 2, # 'ิ' + 13: 0, # 'ี' + 40: 3, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 2, # 'ู' + 11: 0, # 'เ' + 28: 1, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 46: { # 'ษ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 2, # 'ฎ' + 57: 1, # 'ฏ' + 49: 2, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 3, # 'ณ' + 20: 0, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 1, # 'ม' + 16: 2, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 1, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 2, # 'ะ' + 10: 2, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 1, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 1, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 18: { # 'ส' + 5: 2, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 2, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 3, # 'ด' + 19: 3, # 'ต' + 44: 3, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 1, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 2, # 'ภ' + 9: 3, # 'ม' + 16: 1, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 2, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 2, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 3, # 'ำ' + 23: 3, # 'ิ' + 13: 3, # 'ี' + 40: 2, # 'ึ' + 27: 3, # 'ื' + 32: 3, # 'ุ' + 35: 3, # 'ู' + 11: 2, # 'เ' + 28: 0, # 'แ' + 41: 1, # 'โ' + 29: 0, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 1, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 21: { # 'ห' + 5: 3, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 1, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 2, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 3, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 0, # 'บ' + 25: 1, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 3, # 'ม' + 16: 2, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 2, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 1, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 1, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 1, # 'ุ' + 35: 1, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 3, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 4: { # 'อ' + 5: 3, # 'ก' + 30: 1, # 'ข' + 24: 2, # 'ค' + 8: 3, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 3, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 1, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 1, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 1, # 'ฟ' + 45: 1, # 'ภ' + 9: 3, # 'ม' + 16: 3, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 2, # 'ว' + 42: 1, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 2, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 2, # 'ำ' + 23: 2, # 'ิ' + 13: 3, # 'ี' + 40: 0, # 'ึ' + 27: 3, # 'ื' + 32: 3, # 'ุ' + 35: 0, # 'ู' + 11: 3, # 'เ' + 28: 1, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 1, # 'ๆ' + 37: 1, # '็' + 6: 2, # '่' + 7: 2, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 63: { # 'ฯ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 22: { # 'ะ' + 5: 3, # 'ก' + 30: 1, # 'ข' + 24: 2, # 'ค' + 8: 1, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 3, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 3, # 'ด' + 19: 3, # 'ต' + 44: 1, # 'ถ' + 14: 3, # 'ท' + 48: 1, # 'ธ' + 3: 2, # 'น' + 17: 3, # 'บ' + 25: 2, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 2, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 3, # 'ม' + 16: 2, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 2, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 3, # 'ส' + 21: 3, # 'ห' + 4: 2, # 'อ' + 63: 1, # 'ฯ' + 22: 1, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 3, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 10: { # 'ั' + 5: 3, # 'ก' + 30: 0, # 'ข' + 24: 1, # 'ค' + 8: 3, # 'ง' + 26: 3, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 3, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 2, # 'ฐ' + 53: 0, # 'ฑ' + 55: 3, # 'ฒ' + 43: 3, # 'ณ' + 20: 3, # 'ด' + 19: 3, # 'ต' + 44: 0, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 1, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 2, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 3, # 'ม' + 16: 3, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 3, # 'ว' + 42: 2, # 'ศ' + 46: 0, # 'ษ' + 18: 3, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 1: { # 'า' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 3, # 'ค' + 8: 3, # 'ง' + 26: 3, # 'จ' + 52: 0, # 'ฉ' + 34: 3, # 'ช' + 51: 1, # 'ซ' + 47: 2, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 3, # 'ณ' + 20: 3, # 'ด' + 19: 3, # 'ต' + 44: 1, # 'ถ' + 14: 3, # 'ท' + 48: 2, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 2, # 'ป' + 39: 1, # 'ผ' + 62: 1, # 'ฝ' + 31: 3, # 'พ' + 54: 1, # 'ฟ' + 45: 1, # 'ภ' + 9: 3, # 'ม' + 16: 3, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 3, # 'ว' + 42: 2, # 'ศ' + 46: 3, # 'ษ' + 18: 3, # 'ส' + 21: 3, # 'ห' + 4: 2, # 'อ' + 63: 1, # 'ฯ' + 22: 3, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 3, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 1, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 36: { # 'ำ' + 5: 2, # 'ก' + 30: 1, # 'ข' + 24: 3, # 'ค' + 8: 2, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 1, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 1, # 'ต' + 44: 1, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 1, # 'บ' + 25: 1, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 1, # 'ม' + 16: 0, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 3, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 3, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 23: { # 'ิ' + 5: 3, # 'ก' + 30: 1, # 'ข' + 24: 2, # 'ค' + 8: 3, # 'ง' + 26: 3, # 'จ' + 52: 0, # 'ฉ' + 34: 3, # 'ช' + 51: 0, # 'ซ' + 47: 2, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 3, # 'ด' + 19: 3, # 'ต' + 44: 1, # 'ถ' + 14: 3, # 'ท' + 48: 3, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 2, # 'ป' + 39: 2, # 'ผ' + 62: 0, # 'ฝ' + 31: 3, # 'พ' + 54: 1, # 'ฟ' + 45: 2, # 'ภ' + 9: 3, # 'ม' + 16: 2, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 3, # 'ว' + 42: 3, # 'ศ' + 46: 2, # 'ษ' + 18: 2, # 'ส' + 21: 3, # 'ห' + 4: 1, # 'อ' + 63: 1, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 3, # 'เ' + 28: 1, # 'แ' + 41: 1, # 'โ' + 29: 1, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 2, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 13: { # 'ี' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 2, # 'ค' + 8: 0, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 2, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 1, # 'น' + 17: 2, # 'บ' + 25: 2, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 2, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 3, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 2, # 'ว' + 42: 1, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 1, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 2, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 1, # 'ใ' + 33: 1, # 'ไ' + 50: 1, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 40: { # 'ึ' + 5: 3, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 3, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 27: { # 'ื' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 2, # 'น' + 17: 3, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 32: { # 'ุ' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 3, # 'ค' + 8: 3, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 2, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 1, # 'ฒ' + 43: 3, # 'ณ' + 20: 3, # 'ด' + 19: 3, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 1, # 'ธ' + 3: 2, # 'น' + 17: 2, # 'บ' + 25: 2, # 'ป' + 39: 2, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 3, # 'ม' + 16: 1, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 1, # 'ว' + 42: 1, # 'ศ' + 46: 2, # 'ษ' + 18: 1, # 'ส' + 21: 1, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 1, # 'เ' + 28: 0, # 'แ' + 41: 1, # 'โ' + 29: 0, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 2, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 35: { # 'ู' + 5: 3, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 2, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 2, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 1, # 'ณ' + 20: 2, # 'ด' + 19: 2, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 2, # 'น' + 17: 0, # 'บ' + 25: 3, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 0, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 1, # 'เ' + 28: 1, # 'แ' + 41: 1, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 11: { # 'เ' + 5: 3, # 'ก' + 30: 3, # 'ข' + 24: 3, # 'ค' + 8: 2, # 'ง' + 26: 3, # 'จ' + 52: 3, # 'ฉ' + 34: 3, # 'ช' + 51: 2, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 1, # 'ณ' + 20: 3, # 'ด' + 19: 3, # 'ต' + 44: 1, # 'ถ' + 14: 3, # 'ท' + 48: 1, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 3, # 'ป' + 39: 2, # 'ผ' + 62: 1, # 'ฝ' + 31: 3, # 'พ' + 54: 1, # 'ฟ' + 45: 3, # 'ภ' + 9: 3, # 'ม' + 16: 2, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 3, # 'ว' + 42: 2, # 'ศ' + 46: 0, # 'ษ' + 18: 3, # 'ส' + 21: 3, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 28: { # 'แ' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 2, # 'ค' + 8: 1, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 2, # 'ด' + 19: 3, # 'ต' + 44: 2, # 'ถ' + 14: 3, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 2, # 'ป' + 39: 3, # 'ผ' + 62: 0, # 'ฝ' + 31: 2, # 'พ' + 54: 2, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 2, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 2, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 3, # 'ส' + 21: 3, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 41: { # 'โ' + 5: 2, # 'ก' + 30: 1, # 'ข' + 24: 2, # 'ค' + 8: 0, # 'ง' + 26: 1, # 'จ' + 52: 1, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 3, # 'ด' + 19: 2, # 'ต' + 44: 0, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 1, # 'บ' + 25: 3, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 1, # 'ฟ' + 45: 1, # 'ภ' + 9: 1, # 'ม' + 16: 2, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 0, # 'ว' + 42: 1, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 0, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 29: { # 'ใ' + 5: 2, # 'ก' + 30: 0, # 'ข' + 24: 1, # 'ค' + 8: 0, # 'ง' + 26: 3, # 'จ' + 52: 0, # 'ฉ' + 34: 3, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 3, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 1, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 3, # 'ส' + 21: 3, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 33: { # 'ไ' + 5: 1, # 'ก' + 30: 2, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 3, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 3, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 1, # 'บ' + 25: 3, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 2, # 'ฟ' + 45: 0, # 'ภ' + 9: 3, # 'ม' + 16: 0, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 3, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 2, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 50: { # 'ๆ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 37: { # '็' + 5: 2, # 'ก' + 30: 1, # 'ข' + 24: 2, # 'ค' + 8: 2, # 'ง' + 26: 3, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 1, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 2, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 1, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 2, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 0, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 1, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 6: { # '่' + 5: 2, # 'ก' + 30: 1, # 'ข' + 24: 2, # 'ค' + 8: 3, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 1, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 1, # 'ธ' + 3: 3, # 'น' + 17: 1, # 'บ' + 25: 2, # 'ป' + 39: 2, # 'ผ' + 62: 1, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 3, # 'ม' + 16: 3, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 3, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 1, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 1, # 'ะ' + 10: 0, # 'ั' + 1: 3, # 'า' + 36: 2, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 3, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 1, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 7: { # '้' + 5: 2, # 'ก' + 30: 1, # 'ข' + 24: 2, # 'ค' + 8: 3, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 2, # 'ป' + 39: 2, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 1, # 'ฟ' + 45: 0, # 'ภ' + 9: 3, # 'ม' + 16: 2, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 3, # 'ว' + 42: 1, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 2, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 3, # 'า' + 36: 2, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 2, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 38: { # '์' + 5: 2, # 'ก' + 30: 1, # 'ข' + 24: 1, # 'ค' + 8: 0, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 2, # 'ด' + 19: 1, # 'ต' + 44: 1, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 1, # 'น' + 17: 1, # 'บ' + 25: 1, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 1, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 0, # 'ย' + 2: 1, # 'ร' + 61: 1, # 'ฤ' + 15: 1, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 1, # 'ห' + 4: 2, # 'อ' + 63: 1, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 2, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 1, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 56: { # '๑' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 2, # '๑' + 59: 1, # '๒' + 60: 1, # '๕' + }, + 59: { # '๒' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 1, # '๑' + 59: 1, # '๒' + 60: 3, # '๕' + }, + 60: { # '๕' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 2, # '๑' + 59: 1, # '๒' + 60: 0, # '๕' + }, +} + +# 255: Undefined characters that did not exist in training text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 +# 251: Control characters + +# Character Mapping Table(s): +TIS_620_THAI_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 182, # 'A' + 66: 106, # 'B' + 67: 107, # 'C' + 68: 100, # 'D' + 69: 183, # 'E' + 70: 184, # 'F' + 71: 185, # 'G' + 72: 101, # 'H' + 73: 94, # 'I' + 74: 186, # 'J' + 75: 187, # 'K' + 76: 108, # 'L' + 77: 109, # 'M' + 78: 110, # 'N' + 79: 111, # 'O' + 80: 188, # 'P' + 81: 189, # 'Q' + 82: 190, # 'R' + 83: 89, # 'S' + 84: 95, # 'T' + 85: 112, # 'U' + 86: 113, # 'V' + 87: 191, # 'W' + 88: 192, # 'X' + 89: 193, # 'Y' + 90: 194, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 64, # 'a' + 98: 72, # 'b' + 99: 73, # 'c' + 100: 114, # 'd' + 101: 74, # 'e' + 102: 115, # 'f' + 103: 116, # 'g' + 104: 102, # 'h' + 105: 81, # 'i' + 106: 201, # 'j' + 107: 117, # 'k' + 108: 90, # 'l' + 109: 103, # 'm' + 110: 78, # 'n' + 111: 82, # 'o' + 112: 96, # 'p' + 113: 202, # 'q' + 114: 91, # 'r' + 115: 79, # 's' + 116: 84, # 't' + 117: 104, # 'u' + 118: 105, # 'v' + 119: 97, # 'w' + 120: 98, # 'x' + 121: 92, # 'y' + 122: 203, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 209, # '\x80' + 129: 210, # '\x81' + 130: 211, # '\x82' + 131: 212, # '\x83' + 132: 213, # '\x84' + 133: 88, # '\x85' + 134: 214, # '\x86' + 135: 215, # '\x87' + 136: 216, # '\x88' + 137: 217, # '\x89' + 138: 218, # '\x8a' + 139: 219, # '\x8b' + 140: 220, # '\x8c' + 141: 118, # '\x8d' + 142: 221, # '\x8e' + 143: 222, # '\x8f' + 144: 223, # '\x90' + 145: 224, # '\x91' + 146: 99, # '\x92' + 147: 85, # '\x93' + 148: 83, # '\x94' + 149: 225, # '\x95' + 150: 226, # '\x96' + 151: 227, # '\x97' + 152: 228, # '\x98' + 153: 229, # '\x99' + 154: 230, # '\x9a' + 155: 231, # '\x9b' + 156: 232, # '\x9c' + 157: 233, # '\x9d' + 158: 234, # '\x9e' + 159: 235, # '\x9f' + 160: 236, # None + 161: 5, # 'ก' + 162: 30, # 'ข' + 163: 237, # 'ฃ' + 164: 24, # 'ค' + 165: 238, # 'ฅ' + 166: 75, # 'ฆ' + 167: 8, # 'ง' + 168: 26, # 'จ' + 169: 52, # 'ฉ' + 170: 34, # 'ช' + 171: 51, # 'ซ' + 172: 119, # 'ฌ' + 173: 47, # 'ญ' + 174: 58, # 'ฎ' + 175: 57, # 'ฏ' + 176: 49, # 'ฐ' + 177: 53, # 'ฑ' + 178: 55, # 'ฒ' + 179: 43, # 'ณ' + 180: 20, # 'ด' + 181: 19, # 'ต' + 182: 44, # 'ถ' + 183: 14, # 'ท' + 184: 48, # 'ธ' + 185: 3, # 'น' + 186: 17, # 'บ' + 187: 25, # 'ป' + 188: 39, # 'ผ' + 189: 62, # 'ฝ' + 190: 31, # 'พ' + 191: 54, # 'ฟ' + 192: 45, # 'ภ' + 193: 9, # 'ม' + 194: 16, # 'ย' + 195: 2, # 'ร' + 196: 61, # 'ฤ' + 197: 15, # 'ล' + 198: 239, # 'ฦ' + 199: 12, # 'ว' + 200: 42, # 'ศ' + 201: 46, # 'ษ' + 202: 18, # 'ส' + 203: 21, # 'ห' + 204: 76, # 'ฬ' + 205: 4, # 'อ' + 206: 66, # 'ฮ' + 207: 63, # 'ฯ' + 208: 22, # 'ะ' + 209: 10, # 'ั' + 210: 1, # 'า' + 211: 36, # 'ำ' + 212: 23, # 'ิ' + 213: 13, # 'ี' + 214: 40, # 'ึ' + 215: 27, # 'ื' + 216: 32, # 'ุ' + 217: 35, # 'ู' + 218: 86, # 'ฺ' + 219: 240, # None + 220: 241, # None + 221: 242, # None + 222: 243, # None + 223: 244, # '฿' + 224: 11, # 'เ' + 225: 28, # 'แ' + 226: 41, # 'โ' + 227: 29, # 'ใ' + 228: 33, # 'ไ' + 229: 245, # 'ๅ' + 230: 50, # 'ๆ' + 231: 37, # '็' + 232: 6, # '่' + 233: 7, # '้' + 234: 67, # '๊' + 235: 77, # '๋' + 236: 38, # '์' + 237: 93, # 'ํ' + 238: 246, # '๎' + 239: 247, # '๏' + 240: 68, # '๐' + 241: 56, # '๑' + 242: 59, # '๒' + 243: 65, # '๓' + 244: 69, # '๔' + 245: 60, # '๕' + 246: 70, # '๖' + 247: 80, # '๗' + 248: 71, # '๘' + 249: 87, # '๙' + 250: 248, # '๚' + 251: 249, # '๛' + 252: 250, # None + 253: 251, # None + 254: 252, # None + 255: 253, # None +} + +TIS_620_THAI_MODEL = SingleByteCharSetModel(charset_name='TIS-620', + language='Thai', + char_to_order_map=TIS_620_THAI_CHAR_TO_ORDER, + language_model=THAI_LANG_MODEL, + typical_positive_ratio=0.926386, + keep_ascii_letters=False, + alphabet='กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛') + diff --git a/openpype/vendor/python/python_2/chardet/langturkishmodel.py b/openpype/vendor/python/python_2/chardet/langturkishmodel.py new file mode 100644 index 0000000000..8ba93224de --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/langturkishmodel.py @@ -0,0 +1,4383 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from chardet.sbcharsetprober import SingleByteCharSetModel + + +# 3: Positive +# 2: Likely +# 1: Unlikely +# 0: Negative + +TURKISH_LANG_MODEL = { + 23: { # 'A' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 1, # 'g' + 25: 1, # 'h' + 3: 1, # 'i' + 24: 0, # 'j' + 10: 2, # 'k' + 5: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 1, # 'r' + 8: 1, # 's' + 9: 1, # 't' + 14: 1, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 0, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 37: { # 'B' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 2, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 1, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 1, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 2, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 0, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 0, # 'ı' + 40: 1, # 'Ş' + 19: 1, # 'ş' + }, + 47: { # 'C' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 1, # 'L' + 20: 0, # 'M' + 46: 1, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 1, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 2, # 'j' + 10: 1, # 'k' + 5: 2, # 'l' + 13: 2, # 'm' + 4: 2, # 'n' + 15: 1, # 'o' + 26: 0, # 'p' + 7: 2, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 1, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 39: { # 'D' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 1, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 2, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 1, # 'l' + 13: 3, # 'm' + 4: 0, # 'n' + 15: 1, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 1, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 0, # 'İ' + 6: 1, # 'ı' + 40: 1, # 'Ş' + 19: 0, # 'ş' + }, + 29: { # 'E' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 1, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 1, # 'g' + 25: 0, # 'h' + 3: 1, # 'i' + 24: 1, # 'j' + 10: 0, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 1, # 's' + 9: 1, # 't' + 14: 1, # 'u' + 32: 1, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 52: { # 'F' + 23: 0, # 'A' + 37: 1, # 'B' + 47: 1, # 'C' + 39: 1, # 'D' + 29: 1, # 'E' + 52: 2, # 'F' + 36: 0, # 'G' + 45: 2, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 1, # 'N' + 42: 1, # 'O' + 48: 2, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 1, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 2, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 1, # 'b' + 28: 1, # 'c' + 12: 1, # 'd' + 2: 0, # 'e' + 18: 1, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 2, # 'i' + 24: 1, # 'j' + 10: 0, # 'k' + 5: 0, # 'l' + 13: 1, # 'm' + 4: 2, # 'n' + 15: 1, # 'o' + 26: 0, # 'p' + 7: 2, # 'r' + 8: 1, # 's' + 9: 1, # 't' + 14: 1, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 1, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 1, # 'Ö' + 55: 2, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 2, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 1, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 2, # 'ş' + }, + 36: { # 'G' + 23: 1, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 2, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 2, # 'N' + 42: 1, # 'O' + 48: 1, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 2, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 1, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 1, # 'j' + 10: 1, # 'k' + 5: 0, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 0, # 'r' + 8: 1, # 's' + 9: 1, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 2, # 'Ö' + 55: 0, # 'Ü' + 59: 1, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 1, # 'İ' + 6: 2, # 'ı' + 40: 2, # 'Ş' + 19: 1, # 'ş' + }, + 45: { # 'H' + 23: 0, # 'A' + 37: 1, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 2, # 'G' + 45: 1, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 1, # 'L' + 20: 0, # 'M' + 46: 1, # 'N' + 42: 1, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 2, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 2, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 2, # 'i' + 24: 0, # 'j' + 10: 1, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 0, # 'n' + 15: 1, # 'o' + 26: 1, # 'p' + 7: 1, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 2, # 'ğ' + 41: 1, # 'İ' + 6: 0, # 'ı' + 40: 2, # 'Ş' + 19: 1, # 'ş' + }, + 53: { # 'I' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 2, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 2, # 'l' + 13: 2, # 'm' + 4: 0, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 0, # 'ı' + 40: 1, # 'Ş' + 19: 1, # 'ş' + }, + 60: { # 'J' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 1, # 'd' + 2: 0, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 1, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 1, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 1, # 's' + 9: 0, # 't' + 14: 0, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 0, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 16: { # 'K' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 3, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 2, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 1, # 'e' + 18: 3, # 'f' + 27: 3, # 'g' + 25: 3, # 'h' + 3: 3, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 0, # 'u' + 32: 3, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 2, # 'ü' + 30: 0, # 'ğ' + 41: 1, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 49: { # 'L' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 2, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 2, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 0, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 2, # 'i' + 24: 0, # 'j' + 10: 1, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 2, # 'n' + 15: 1, # 'o' + 26: 1, # 'p' + 7: 1, # 'r' + 8: 1, # 's' + 9: 1, # 't' + 14: 0, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 2, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 1, # 'ü' + 30: 1, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 20: { # 'M' + 23: 1, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 1, # 'g' + 25: 1, # 'h' + 3: 2, # 'i' + 24: 2, # 'j' + 10: 2, # 'k' + 5: 2, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 3, # 'r' + 8: 0, # 's' + 9: 2, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 3, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 46: { # 'N' + 23: 0, # 'A' + 37: 1, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 1, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 1, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 2, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 1, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 2, # 'j' + 10: 1, # 'k' + 5: 1, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 15: 1, # 'o' + 26: 1, # 'p' + 7: 1, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 1, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 1, # 'İ' + 6: 2, # 'ı' + 40: 1, # 'Ş' + 19: 1, # 'ş' + }, + 42: { # 'O' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 0, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 1, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 2, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 0, # 'n' + 15: 1, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 2, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 2, # 'İ' + 6: 1, # 'ı' + 40: 1, # 'Ş' + 19: 1, # 'ş' + }, + 48: { # 'P' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 2, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 1, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 1, # 'N' + 42: 1, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 1, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 2, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 1, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 0, # 'n' + 15: 2, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 2, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 2, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 2, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 1, # 'İ' + 6: 0, # 'ı' + 40: 2, # 'Ş' + 19: 1, # 'ş' + }, + 44: { # 'R' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 1, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 1, # 'k' + 5: 2, # 'l' + 13: 2, # 'm' + 4: 0, # 'n' + 15: 1, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 1, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 1, # 'ü' + 30: 1, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 1, # 'Ş' + 19: 1, # 'ş' + }, + 35: { # 'S' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 1, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 1, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 1, # 'k' + 5: 1, # 'l' + 13: 2, # 'm' + 4: 1, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 1, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 2, # 'Ç' + 50: 2, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 3, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 2, # 'Ş' + 19: 1, # 'ş' + }, + 31: { # 'T' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 0, # 'c' + 12: 1, # 'd' + 2: 3, # 'e' + 18: 2, # 'f' + 27: 2, # 'g' + 25: 0, # 'h' + 3: 1, # 'i' + 24: 1, # 'j' + 10: 2, # 'k' + 5: 2, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 2, # 'p' + 7: 2, # 'r' + 8: 0, # 's' + 9: 2, # 't' + 14: 2, # 'u' + 32: 1, # 'v' + 57: 1, # 'w' + 58: 1, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 51: { # 'U' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 1, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 1, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 1, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 1, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 2, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 1, # 'k' + 5: 1, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 1, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 38: { # 'V' + 23: 1, # 'A' + 37: 1, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 1, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 2, # 'l' + 13: 2, # 'm' + 4: 0, # 'n' + 15: 2, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 1, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 1, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 1, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 1, # 'İ' + 6: 3, # 'ı' + 40: 2, # 'Ş' + 19: 1, # 'ş' + }, + 62: { # 'W' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 0, # 'd' + 2: 0, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 0, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 0, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 43: { # 'Y' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 0, # 'G' + 45: 1, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 2, # 'N' + 42: 0, # 'O' + 48: 2, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 2, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 1, # 'j' + 10: 1, # 'k' + 5: 1, # 'l' + 13: 3, # 'm' + 4: 0, # 'n' + 15: 2, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 2, # 'Ö' + 55: 1, # 'Ü' + 59: 1, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 1, # 'İ' + 6: 0, # 'ı' + 40: 2, # 'Ş' + 19: 1, # 'ş' + }, + 56: { # 'Z' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 2, # 'Z' + 1: 2, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 2, # 'i' + 24: 1, # 'j' + 10: 0, # 'k' + 5: 0, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 1, # 'r' + 8: 1, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 1, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 1: { # 'a' + 23: 3, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 3, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 1, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 3, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 2, # 'Z' + 1: 2, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 2, # 'e' + 18: 3, # 'f' + 27: 3, # 'g' + 25: 3, # 'h' + 3: 3, # 'i' + 24: 3, # 'j' + 10: 3, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 15: 1, # 'o' + 26: 3, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 3, # 'v' + 57: 2, # 'w' + 58: 0, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 1, # 'î' + 34: 1, # 'ö' + 17: 3, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 21: { # 'b' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 3, # 'g' + 25: 1, # 'h' + 3: 3, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 3, # 'p' + 7: 1, # 'r' + 8: 2, # 's' + 9: 2, # 't' + 14: 2, # 'u' + 32: 1, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 28: { # 'c' + 23: 0, # 'A' + 37: 1, # 'B' + 47: 1, # 'C' + 39: 1, # 'D' + 29: 2, # 'E' + 52: 0, # 'F' + 36: 2, # 'G' + 45: 2, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 1, # 'N' + 42: 1, # 'O' + 48: 2, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 2, # 'T' + 51: 2, # 'U' + 38: 2, # 'V' + 62: 0, # 'W' + 43: 3, # 'Y' + 56: 0, # 'Z' + 1: 1, # 'a' + 21: 1, # 'b' + 28: 2, # 'c' + 12: 2, # 'd' + 2: 1, # 'e' + 18: 1, # 'f' + 27: 2, # 'g' + 25: 2, # 'h' + 3: 3, # 'i' + 24: 1, # 'j' + 10: 3, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 15: 2, # 'o' + 26: 2, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 1, # 'u' + 32: 0, # 'v' + 57: 1, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 1, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 1, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 1, # 'î' + 34: 2, # 'ö' + 17: 2, # 'ü' + 30: 2, # 'ğ' + 41: 1, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 2, # 'ş' + }, + 12: { # 'd' + 23: 1, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 2, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 1, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 1, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 1, # 'f' + 27: 3, # 'g' + 25: 3, # 'h' + 3: 2, # 'i' + 24: 3, # 'j' + 10: 2, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 1, # 'o' + 26: 2, # 'p' + 7: 3, # 'r' + 8: 2, # 's' + 9: 2, # 't' + 14: 3, # 'u' + 32: 1, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 3, # 'y' + 22: 1, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 2: { # 'e' + 23: 2, # 'A' + 37: 0, # 'B' + 47: 2, # 'C' + 39: 0, # 'D' + 29: 3, # 'E' + 52: 1, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 1, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 1, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 1, # 'R' + 35: 0, # 'S' + 31: 3, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 2, # 'e' + 18: 3, # 'f' + 27: 3, # 'g' + 25: 3, # 'h' + 3: 3, # 'i' + 24: 3, # 'j' + 10: 3, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 15: 1, # 'o' + 26: 3, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 3, # 'v' + 57: 2, # 'w' + 58: 0, # 'x' + 11: 3, # 'y' + 22: 1, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 3, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 18: { # 'f' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 2, # 'f' + 27: 1, # 'g' + 25: 1, # 'h' + 3: 1, # 'i' + 24: 1, # 'j' + 10: 1, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 2, # 'p' + 7: 1, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 1, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 1, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 1, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 27: { # 'g' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 1, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 2, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 1, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 2, # 'g' + 25: 1, # 'h' + 3: 2, # 'i' + 24: 3, # 'j' + 10: 2, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 2, # 'r' + 8: 2, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 1, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 1, # 'y' + 22: 0, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 25: { # 'h' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 1, # 'g' + 25: 2, # 'h' + 3: 2, # 'i' + 24: 3, # 'j' + 10: 3, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 1, # 'o' + 26: 1, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 2, # 't' + 14: 3, # 'u' + 32: 2, # 'v' + 57: 1, # 'w' + 58: 0, # 'x' + 11: 1, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 3: { # 'i' + 23: 2, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 0, # 'N' + 42: 1, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 1, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 2, # 'f' + 27: 3, # 'g' + 25: 1, # 'h' + 3: 3, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 1, # 'o' + 26: 3, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 2, # 'v' + 57: 1, # 'w' + 58: 1, # 'x' + 11: 3, # 'y' + 22: 1, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 1, # 'Ü' + 59: 0, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 3, # 'ü' + 30: 0, # 'ğ' + 41: 1, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 24: { # 'j' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 1, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 2, # 'f' + 27: 1, # 'g' + 25: 1, # 'h' + 3: 2, # 'i' + 24: 1, # 'j' + 10: 2, # 'k' + 5: 2, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 2, # 'r' + 8: 3, # 's' + 9: 2, # 't' + 14: 3, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 2, # 'x' + 11: 1, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 10: { # 'k' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 3, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 3, # 'e' + 18: 1, # 'f' + 27: 2, # 'g' + 25: 2, # 'h' + 3: 3, # 'i' + 24: 2, # 'j' + 10: 2, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 3, # 'p' + 7: 2, # 'r' + 8: 2, # 's' + 9: 2, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 3, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 3, # 'ü' + 30: 1, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 5: { # 'l' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 3, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 1, # 'e' + 18: 3, # 'f' + 27: 3, # 'g' + 25: 2, # 'h' + 3: 3, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 1, # 'l' + 13: 1, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 2, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 2, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 2, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 13: { # 'm' + 23: 1, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 3, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 3, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 2, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 2, # 'e' + 18: 3, # 'f' + 27: 3, # 'g' + 25: 3, # 'h' + 3: 3, # 'i' + 24: 3, # 'j' + 10: 3, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 15: 1, # 'o' + 26: 2, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 2, # 'u' + 32: 2, # 'v' + 57: 1, # 'w' + 58: 0, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 3, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 4: { # 'n' + 23: 1, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 2, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 1, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 1, # 'f' + 27: 2, # 'g' + 25: 3, # 'h' + 3: 2, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 1, # 'o' + 26: 3, # 'p' + 7: 2, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 2, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 2, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 1, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 15: { # 'o' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 1, # 'G' + 45: 1, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 2, # 'L' + 20: 0, # 'M' + 46: 2, # 'N' + 42: 1, # 'O' + 48: 2, # 'P' + 44: 1, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 1, # 'i' + 24: 2, # 'j' + 10: 1, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 15: 2, # 'o' + 26: 0, # 'p' + 7: 1, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 2, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 2, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 3, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 2, # 'ğ' + 41: 2, # 'İ' + 6: 3, # 'ı' + 40: 2, # 'Ş' + 19: 2, # 'ş' + }, + 26: { # 'p' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 1, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 1, # 'g' + 25: 1, # 'h' + 3: 2, # 'i' + 24: 3, # 'j' + 10: 1, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 15: 0, # 'o' + 26: 2, # 'p' + 7: 2, # 'r' + 8: 1, # 's' + 9: 1, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 1, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 3, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 7: { # 'r' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 2, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 1, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 2, # 'g' + 25: 3, # 'h' + 3: 2, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 2, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 3, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 8: { # 's' + 23: 1, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 1, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 2, # 'g' + 25: 2, # 'h' + 3: 2, # 'i' + 24: 3, # 'j' + 10: 3, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 3, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 2, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 2, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 9: { # 't' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 2, # 'f' + 27: 2, # 'g' + 25: 2, # 'h' + 3: 2, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 2, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 3, # 'v' + 57: 0, # 'w' + 58: 2, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 3, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 2, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 14: { # 'u' + 23: 3, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 3, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 2, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 3, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 2, # 'Z' + 1: 2, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 2, # 'e' + 18: 2, # 'f' + 27: 3, # 'g' + 25: 3, # 'h' + 3: 3, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 0, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 3, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 2, # 'v' + 57: 2, # 'w' + 58: 0, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 3, # 'ü' + 30: 1, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 32: { # 'v' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 1, # 'j' + 10: 1, # 'k' + 5: 3, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 1, # 'r' + 8: 2, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 1, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 1, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 57: { # 'w' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 1, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 1, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 1, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 1, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 1, # 's' + 9: 0, # 't' + 14: 1, # 'u' + 32: 0, # 'v' + 57: 2, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 0, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 0, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 58: { # 'x' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 1, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 1, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 2, # 'i' + 24: 2, # 'j' + 10: 1, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 2, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 1, # 'r' + 8: 2, # 's' + 9: 1, # 't' + 14: 0, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 11: { # 'y' + 23: 1, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 2, # 'g' + 25: 2, # 'h' + 3: 2, # 'i' + 24: 1, # 'j' + 10: 2, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 2, # 'r' + 8: 1, # 's' + 9: 2, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 3, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 2, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 22: { # 'z' + 23: 2, # 'A' + 37: 2, # 'B' + 47: 1, # 'C' + 39: 2, # 'D' + 29: 3, # 'E' + 52: 1, # 'F' + 36: 2, # 'G' + 45: 2, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 2, # 'N' + 42: 2, # 'O' + 48: 2, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 3, # 'T' + 51: 2, # 'U' + 38: 2, # 'V' + 62: 0, # 'W' + 43: 2, # 'Y' + 56: 1, # 'Z' + 1: 1, # 'a' + 21: 2, # 'b' + 28: 1, # 'c' + 12: 2, # 'd' + 2: 2, # 'e' + 18: 3, # 'f' + 27: 2, # 'g' + 25: 2, # 'h' + 3: 3, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 15: 2, # 'o' + 26: 2, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 0, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 3, # 'y' + 22: 2, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 2, # 'Ü' + 59: 1, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 2, # 'ö' + 17: 2, # 'ü' + 30: 2, # 'ğ' + 41: 1, # 'İ' + 6: 3, # 'ı' + 40: 1, # 'Ş' + 19: 2, # 'ş' + }, + 63: { # '·' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 0, # 'd' + 2: 1, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 0, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 0, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 54: { # 'Ç' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 1, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 1, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 1, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 2, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 1, # 'd' + 2: 0, # 'e' + 18: 0, # 'f' + 27: 1, # 'g' + 25: 0, # 'h' + 3: 3, # 'i' + 24: 0, # 'j' + 10: 1, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 2, # 'n' + 15: 1, # 'o' + 26: 0, # 'p' + 7: 2, # 'r' + 8: 0, # 's' + 9: 1, # 't' + 14: 0, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 2, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 50: { # 'Ö' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 1, # 'D' + 29: 2, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 2, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 1, # 'N' + 42: 2, # 'O' + 48: 2, # 'P' + 44: 1, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 2, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 2, # 'b' + 28: 1, # 'c' + 12: 2, # 'd' + 2: 0, # 'e' + 18: 1, # 'f' + 27: 1, # 'g' + 25: 1, # 'h' + 3: 2, # 'i' + 24: 0, # 'j' + 10: 2, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 3, # 'n' + 15: 2, # 'o' + 26: 2, # 'p' + 7: 3, # 'r' + 8: 1, # 's' + 9: 2, # 't' + 14: 0, # 'u' + 32: 1, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 2, # 'ö' + 17: 2, # 'ü' + 30: 1, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 55: { # 'Ü' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 1, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 2, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 1, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 1, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 1, # 'İ' + 6: 0, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 59: { # 'â' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 1, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 2, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 0, # 'n' + 15: 1, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 1, # 'ı' + 40: 1, # 'Ş' + 19: 0, # 'ş' + }, + 33: { # 'ç' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 3, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 0, # 'e' + 18: 2, # 'f' + 27: 1, # 'g' + 25: 3, # 'h' + 3: 3, # 'i' + 24: 0, # 'j' + 10: 3, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 3, # 'r' + 8: 2, # 's' + 9: 3, # 't' + 14: 0, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 61: { # 'î' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 1, # 'Z' + 1: 2, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 1, # 'j' + 10: 0, # 'k' + 5: 0, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 1, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 1, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 1, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 34: { # 'ö' + 23: 0, # 'A' + 37: 1, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 1, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 1, # 'L' + 20: 0, # 'M' + 46: 1, # 'N' + 42: 1, # 'O' + 48: 2, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 1, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 2, # 'c' + 12: 1, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 2, # 'g' + 25: 2, # 'h' + 3: 1, # 'i' + 24: 2, # 'j' + 10: 1, # 'k' + 5: 2, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 15: 2, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 3, # 's' + 9: 1, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 1, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 2, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 2, # 'ö' + 17: 0, # 'ü' + 30: 2, # 'ğ' + 41: 1, # 'İ' + 6: 1, # 'ı' + 40: 2, # 'Ş' + 19: 1, # 'ş' + }, + 17: { # 'ü' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 1, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 1, # 'd' + 2: 3, # 'e' + 18: 1, # 'f' + 27: 2, # 'g' + 25: 0, # 'h' + 3: 1, # 'i' + 24: 1, # 'j' + 10: 2, # 'k' + 5: 3, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 2, # 'p' + 7: 2, # 'r' + 8: 3, # 's' + 9: 2, # 't' + 14: 3, # 'u' + 32: 1, # 'v' + 57: 1, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 2, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 30: { # 'ğ' + 23: 0, # 'A' + 37: 2, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 1, # 'G' + 45: 0, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 2, # 'N' + 42: 2, # 'O' + 48: 1, # 'P' + 44: 1, # 'R' + 35: 0, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 2, # 'V' + 62: 0, # 'W' + 43: 2, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 3, # 'j' + 10: 1, # 'k' + 5: 2, # 'l' + 13: 3, # 'm' + 4: 0, # 'n' + 15: 1, # 'o' + 26: 0, # 'p' + 7: 1, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 2, # 'Ç' + 50: 2, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 2, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 2, # 'İ' + 6: 2, # 'ı' + 40: 2, # 'Ş' + 19: 1, # 'ş' + }, + 41: { # 'İ' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 1, # 'D' + 29: 1, # 'E' + 52: 0, # 'F' + 36: 2, # 'G' + 45: 2, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 1, # 'N' + 42: 1, # 'O' + 48: 2, # 'P' + 44: 0, # 'R' + 35: 1, # 'S' + 31: 1, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 2, # 'Y' + 56: 0, # 'Z' + 1: 1, # 'a' + 21: 2, # 'b' + 28: 1, # 'c' + 12: 2, # 'd' + 2: 1, # 'e' + 18: 0, # 'f' + 27: 3, # 'g' + 25: 2, # 'h' + 3: 2, # 'i' + 24: 2, # 'j' + 10: 2, # 'k' + 5: 0, # 'l' + 13: 1, # 'm' + 4: 3, # 'n' + 15: 1, # 'o' + 26: 1, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 2, # 't' + 14: 0, # 'u' + 32: 0, # 'v' + 57: 1, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 1, # 'Ü' + 59: 1, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 1, # 'ü' + 30: 2, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 6: { # 'ı' + 23: 2, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 2, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 1, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 2, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 1, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 3, # 'f' + 27: 3, # 'g' + 25: 2, # 'h' + 3: 3, # 'i' + 24: 3, # 'j' + 10: 3, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 3, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 3, # 'v' + 57: 1, # 'w' + 58: 1, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 3, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 40: { # 'Ş' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 1, # 'D' + 29: 1, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 2, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 1, # 'N' + 42: 1, # 'O' + 48: 2, # 'P' + 44: 2, # 'R' + 35: 1, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 2, # 'Y' + 56: 1, # 'Z' + 1: 0, # 'a' + 21: 2, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 0, # 'e' + 18: 3, # 'f' + 27: 0, # 'g' + 25: 2, # 'h' + 3: 3, # 'i' + 24: 2, # 'j' + 10: 1, # 'k' + 5: 0, # 'l' + 13: 1, # 'm' + 4: 3, # 'n' + 15: 2, # 'o' + 26: 0, # 'p' + 7: 3, # 'r' + 8: 2, # 's' + 9: 2, # 't' + 14: 1, # 'u' + 32: 3, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 1, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 2, # 'ö' + 17: 1, # 'ü' + 30: 2, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 1, # 'Ş' + 19: 2, # 'ş' + }, + 19: { # 'ş' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 1, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 2, # 'L' + 20: 0, # 'M' + 46: 1, # 'N' + 42: 1, # 'O' + 48: 1, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 2, # 'g' + 25: 1, # 'h' + 3: 1, # 'i' + 24: 0, # 'j' + 10: 2, # 'k' + 5: 2, # 'l' + 13: 3, # 'm' + 4: 0, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 3, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 2, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 1, # 'î' + 34: 2, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 1, # 'İ' + 6: 1, # 'ı' + 40: 1, # 'Ş' + 19: 1, # 'ş' + }, +} + +# 255: Undefined characters that did not exist in training text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 +# 251: Control characters + +# Character Mapping Table(s): +ISO_8859_9_TURKISH_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 255, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 255, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 255, # ' ' + 33: 255, # '!' + 34: 255, # '"' + 35: 255, # '#' + 36: 255, # '$' + 37: 255, # '%' + 38: 255, # '&' + 39: 255, # "'" + 40: 255, # '(' + 41: 255, # ')' + 42: 255, # '*' + 43: 255, # '+' + 44: 255, # ',' + 45: 255, # '-' + 46: 255, # '.' + 47: 255, # '/' + 48: 255, # '0' + 49: 255, # '1' + 50: 255, # '2' + 51: 255, # '3' + 52: 255, # '4' + 53: 255, # '5' + 54: 255, # '6' + 55: 255, # '7' + 56: 255, # '8' + 57: 255, # '9' + 58: 255, # ':' + 59: 255, # ';' + 60: 255, # '<' + 61: 255, # '=' + 62: 255, # '>' + 63: 255, # '?' + 64: 255, # '@' + 65: 23, # 'A' + 66: 37, # 'B' + 67: 47, # 'C' + 68: 39, # 'D' + 69: 29, # 'E' + 70: 52, # 'F' + 71: 36, # 'G' + 72: 45, # 'H' + 73: 53, # 'I' + 74: 60, # 'J' + 75: 16, # 'K' + 76: 49, # 'L' + 77: 20, # 'M' + 78: 46, # 'N' + 79: 42, # 'O' + 80: 48, # 'P' + 81: 69, # 'Q' + 82: 44, # 'R' + 83: 35, # 'S' + 84: 31, # 'T' + 85: 51, # 'U' + 86: 38, # 'V' + 87: 62, # 'W' + 88: 65, # 'X' + 89: 43, # 'Y' + 90: 56, # 'Z' + 91: 255, # '[' + 92: 255, # '\\' + 93: 255, # ']' + 94: 255, # '^' + 95: 255, # '_' + 96: 255, # '`' + 97: 1, # 'a' + 98: 21, # 'b' + 99: 28, # 'c' + 100: 12, # 'd' + 101: 2, # 'e' + 102: 18, # 'f' + 103: 27, # 'g' + 104: 25, # 'h' + 105: 3, # 'i' + 106: 24, # 'j' + 107: 10, # 'k' + 108: 5, # 'l' + 109: 13, # 'm' + 110: 4, # 'n' + 111: 15, # 'o' + 112: 26, # 'p' + 113: 64, # 'q' + 114: 7, # 'r' + 115: 8, # 's' + 116: 9, # 't' + 117: 14, # 'u' + 118: 32, # 'v' + 119: 57, # 'w' + 120: 58, # 'x' + 121: 11, # 'y' + 122: 22, # 'z' + 123: 255, # '{' + 124: 255, # '|' + 125: 255, # '}' + 126: 255, # '~' + 127: 255, # '\x7f' + 128: 180, # '\x80' + 129: 179, # '\x81' + 130: 178, # '\x82' + 131: 177, # '\x83' + 132: 176, # '\x84' + 133: 175, # '\x85' + 134: 174, # '\x86' + 135: 173, # '\x87' + 136: 172, # '\x88' + 137: 171, # '\x89' + 138: 170, # '\x8a' + 139: 169, # '\x8b' + 140: 168, # '\x8c' + 141: 167, # '\x8d' + 142: 166, # '\x8e' + 143: 165, # '\x8f' + 144: 164, # '\x90' + 145: 163, # '\x91' + 146: 162, # '\x92' + 147: 161, # '\x93' + 148: 160, # '\x94' + 149: 159, # '\x95' + 150: 101, # '\x96' + 151: 158, # '\x97' + 152: 157, # '\x98' + 153: 156, # '\x99' + 154: 155, # '\x9a' + 155: 154, # '\x9b' + 156: 153, # '\x9c' + 157: 152, # '\x9d' + 158: 151, # '\x9e' + 159: 106, # '\x9f' + 160: 150, # '\xa0' + 161: 149, # '¡' + 162: 148, # '¢' + 163: 147, # '£' + 164: 146, # '¤' + 165: 145, # '¥' + 166: 144, # '¦' + 167: 100, # '§' + 168: 143, # '¨' + 169: 142, # '©' + 170: 141, # 'ª' + 171: 140, # '«' + 172: 139, # '¬' + 173: 138, # '\xad' + 174: 137, # '®' + 175: 136, # '¯' + 176: 94, # '°' + 177: 80, # '±' + 178: 93, # '²' + 179: 135, # '³' + 180: 105, # '´' + 181: 134, # 'µ' + 182: 133, # '¶' + 183: 63, # '·' + 184: 132, # '¸' + 185: 131, # '¹' + 186: 130, # 'º' + 187: 129, # '»' + 188: 128, # '¼' + 189: 127, # '½' + 190: 126, # '¾' + 191: 125, # '¿' + 192: 124, # 'À' + 193: 104, # 'Á' + 194: 73, # 'Â' + 195: 99, # 'Ã' + 196: 79, # 'Ä' + 197: 85, # 'Å' + 198: 123, # 'Æ' + 199: 54, # 'Ç' + 200: 122, # 'È' + 201: 98, # 'É' + 202: 92, # 'Ê' + 203: 121, # 'Ë' + 204: 120, # 'Ì' + 205: 91, # 'Í' + 206: 103, # 'Î' + 207: 119, # 'Ï' + 208: 68, # 'Ğ' + 209: 118, # 'Ñ' + 210: 117, # 'Ò' + 211: 97, # 'Ó' + 212: 116, # 'Ô' + 213: 115, # 'Õ' + 214: 50, # 'Ö' + 215: 90, # '×' + 216: 114, # 'Ø' + 217: 113, # 'Ù' + 218: 112, # 'Ú' + 219: 111, # 'Û' + 220: 55, # 'Ü' + 221: 41, # 'İ' + 222: 40, # 'Ş' + 223: 86, # 'ß' + 224: 89, # 'à' + 225: 70, # 'á' + 226: 59, # 'â' + 227: 78, # 'ã' + 228: 71, # 'ä' + 229: 82, # 'å' + 230: 88, # 'æ' + 231: 33, # 'ç' + 232: 77, # 'è' + 233: 66, # 'é' + 234: 84, # 'ê' + 235: 83, # 'ë' + 236: 110, # 'ì' + 237: 75, # 'í' + 238: 61, # 'î' + 239: 96, # 'ï' + 240: 30, # 'ğ' + 241: 67, # 'ñ' + 242: 109, # 'ò' + 243: 74, # 'ó' + 244: 87, # 'ô' + 245: 102, # 'õ' + 246: 34, # 'ö' + 247: 95, # '÷' + 248: 81, # 'ø' + 249: 108, # 'ù' + 250: 76, # 'ú' + 251: 72, # 'û' + 252: 17, # 'ü' + 253: 6, # 'ı' + 254: 19, # 'ş' + 255: 107, # 'ÿ' +} + +ISO_8859_9_TURKISH_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-9', + language='Turkish', + char_to_order_map=ISO_8859_9_TURKISH_CHAR_TO_ORDER, + language_model=TURKISH_LANG_MODEL, + typical_positive_ratio=0.97029, + keep_ascii_letters=True, + alphabet='ABCDEFGHIJKLMNOPRSTUVYZabcdefghijklmnoprstuvyzÂÇÎÖÛÜâçîöûüĞğİıŞş') + diff --git a/openpype/vendor/python/python_2/chardet/latin1prober.py b/openpype/vendor/python/python_2/chardet/latin1prober.py new file mode 100644 index 0000000000..7d1e8c20fb --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/latin1prober.py @@ -0,0 +1,145 @@ +######################## 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 .enums import ProbingState + +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): + super(Latin1Prober, self).__init__() + self._last_char_class = None + self._freq_counter = None + self.reset() + + def reset(self): + self._last_char_class = OTH + self._freq_counter = [0] * FREQ_CAT_NUM + CharSetProber.reset(self) + + @property + def charset_name(self): + return "ISO-8859-1" + + @property + def language(self): + return "" + + def feed(self, byte_str): + byte_str = self.filter_with_english_letters(byte_str) + for c in byte_str: + char_class = Latin1_CharToClass[c] + freq = Latin1ClassModel[(self._last_char_class * CLASS_NUM) + + char_class] + if freq == 0: + self._state = ProbingState.NOT_ME + break + self._freq_counter[freq] += 1 + self._last_char_class = char_class + + return self.state + + def get_confidence(self): + if self.state == ProbingState.NOT_ME: + return 0.01 + + total = sum(self._freq_counter) + if total < 0.01: + confidence = 0.0 + else: + confidence = ((self._freq_counter[3] - self._freq_counter[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.73 + return confidence diff --git a/openpype/vendor/python/python_2/chardet/mbcharsetprober.py b/openpype/vendor/python/python_2/chardet/mbcharsetprober.py new file mode 100644 index 0000000000..6256ecfd1e --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/mbcharsetprober.py @@ -0,0 +1,91 @@ +######################## 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 .charsetprober import CharSetProber +from .enums import ProbingState, MachineState + + +class MultiByteCharSetProber(CharSetProber): + """ + MultiByteCharSetProber + """ + + def __init__(self, lang_filter=None): + super(MultiByteCharSetProber, self).__init__(lang_filter=lang_filter) + self.distribution_analyzer = None + self.coding_sm = None + self._last_char = [0, 0] + + def reset(self): + super(MultiByteCharSetProber, self).reset() + if self.coding_sm: + self.coding_sm.reset() + if self.distribution_analyzer: + self.distribution_analyzer.reset() + self._last_char = [0, 0] + + @property + def charset_name(self): + raise NotImplementedError + + @property + def language(self): + raise NotImplementedError + + def feed(self, byte_str): + for i in range(len(byte_str)): + coding_state = self.coding_sm.next_state(byte_str[i]) + if coding_state == MachineState.ERROR: + self.logger.debug('%s %s prober hit error at byte %s', + self.charset_name, self.language, i) + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + char_len = self.coding_sm.get_current_charlen() + if i == 0: + self._last_char[1] = byte_str[0] + self.distribution_analyzer.feed(self._last_char, char_len) + else: + self.distribution_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + + self._last_char[0] = byte_str[-1] + + if self.state == ProbingState.DETECTING: + if (self.distribution_analyzer.got_enough_data() and + (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + return self.distribution_analyzer.get_confidence() diff --git a/openpype/vendor/python/python_2/chardet/mbcsgroupprober.py b/openpype/vendor/python/python_2/chardet/mbcsgroupprober.py new file mode 100644 index 0000000000..530abe75e0 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/mbcsgroupprober.py @@ -0,0 +1,54 @@ +######################## 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 .cp949prober import CP949Prober +from .big5prober import Big5Prober +from .euctwprober import EUCTWProber + + +class MBCSGroupProber(CharSetGroupProber): + def __init__(self, lang_filter=None): + super(MBCSGroupProber, self).__init__(lang_filter=lang_filter) + self.probers = [ + UTF8Prober(), + SJISProber(), + EUCJPProber(), + GB2312Prober(), + EUCKRProber(), + CP949Prober(), + Big5Prober(), + EUCTWProber() + ] + self.reset() diff --git a/openpype/vendor/python/python_2/chardet/mbcssm.py b/openpype/vendor/python/python_2/chardet/mbcssm.py new file mode 100644 index 0000000000..8360d0f284 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/mbcssm.py @@ -0,0 +1,572 @@ +######################## 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 .enums import MachineState + +# 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 = ( + MachineState.ERROR,MachineState.START,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,#08-0f + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START#10-17 +) + +BIG5_CHAR_LEN_TABLE = (0, 1, 1, 2, 0) + +BIG5_SM_MODEL = {'class_table': BIG5_CLS, + 'class_factor': 5, + 'state_table': BIG5_ST, + 'char_len_table': BIG5_CHAR_LEN_TABLE, + 'name': 'Big5'} + +# CP949 + +CP949_CLS = ( + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,0,0, # 00 - 0f + 1,1,1,1,1,1,1,1, 1,1,1,0,1,1,1,1, # 10 - 1f + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 20 - 2f + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 30 - 3f + 1,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4, # 40 - 4f + 4,4,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 50 - 5f + 1,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, # 60 - 6f + 5,5,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 70 - 7f + 0,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 80 - 8f + 6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 90 - 9f + 6,7,7,7,7,7,7,7, 7,7,7,7,7,8,8,8, # a0 - af + 7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7, # b0 - bf + 7,7,7,7,7,7,9,2, 2,3,2,2,2,2,2,2, # c0 - cf + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # d0 - df + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # e0 - ef + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,0, # f0 - ff +) + +CP949_ST = ( +#cls= 0 1 2 3 4 5 6 7 8 9 # previous state = + MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START, 4, 5,MachineState.ERROR, 6, # MachineState.START + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, # MachineState.ERROR + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME, # MachineState.ITS_ME + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START, # 3 + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, # 4 + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, # 5 + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START, # 6 +) + +CP949_CHAR_LEN_TABLE = (0, 1, 2, 0, 1, 1, 2, 2, 0, 2) + +CP949_SM_MODEL = {'class_table': CP949_CLS, + 'class_factor': 10, + 'state_table': CP949_ST, + 'char_len_table': CP949_CHAR_LEN_TABLE, + 'name': 'CP949'} + +# 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,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.START,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#10-17 + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 3,MachineState.ERROR,#18-1f + 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START#20-27 +) + +EUCJP_CHAR_LEN_TABLE = (2, 2, 2, 3, 1, 0) + +EUCJP_SM_MODEL = {'class_table': EUCJP_CLS, + 'class_factor': 6, + 'state_table': EUCJP_ST, + 'char_len_table': EUCJP_CHAR_LEN_TABLE, + '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 = ( + MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #08-0f +) + +EUCKR_CHAR_LEN_TABLE = (0, 1, 2, 0) + +EUCKR_SM_MODEL = {'class_table': EUCKR_CLS, + 'class_factor': 4, + 'state_table': EUCKR_ST, + 'char_len_table': EUCKR_CHAR_LEN_TABLE, + '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 = ( + MachineState.ERROR,MachineState.ERROR,MachineState.START, 3, 3, 3, 4,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,MachineState.ERROR,#10-17 + MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f + 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,#20-27 + MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #28-2f +) + +EUCTW_CHAR_LEN_TABLE = (0, 0, 1, 2, 2, 2, 3) + +EUCTW_SM_MODEL = {'class_table': EUCTW_CLS, + 'class_factor': 7, + 'state_table': EUCTW_ST, + 'char_len_table': EUCTW_CHAR_LEN_TABLE, + '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 = ( + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, 3,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,#10-17 + 4,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f + MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,#20-27 + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #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 validating +# each code range there as well. So it is safe to set it to be +# 2 here. +GB2312_CHAR_LEN_TABLE = (0, 1, 1, 1, 1, 1, 2) + +GB2312_SM_MODEL = {'class_table': GB2312_CLS, + 'class_factor': 7, + 'state_table': GB2312_ST, + 'char_len_table': GB2312_CHAR_LEN_TABLE, + '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,2,2,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 + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,0,0,0) # f8 - ff + + +SJIS_ST = ( + MachineState.ERROR,MachineState.START,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START #10-17 +) + +SJIS_CHAR_LEN_TABLE = (0, 1, 1, 2, 0, 0) + +SJIS_SM_MODEL = {'class_table': SJIS_CLS, + 'class_factor': 6, + 'state_table': SJIS_ST, + 'char_len_table': SJIS_CHAR_LEN_TABLE, + '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,MachineState.ERROR, 4, 3,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME, 6, 6, 6, 6,MachineState.ERROR,MachineState.ERROR,#10-17 + 6, 6, 6, 6, 6,MachineState.ITS_ME, 6, 6,#18-1f + 6, 6, 6, 6, 5, 7, 7,MachineState.ERROR,#20-27 + 5, 8, 6, 6,MachineState.ERROR, 6, 6, 6,#28-2f + 6, 6, 6, 6,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #30-37 +) + +UCS2BE_CHAR_LEN_TABLE = (2, 2, 2, 0, 2, 2) + +UCS2BE_SM_MODEL = {'class_table': UCS2BE_CLS, + 'class_factor': 6, + 'state_table': UCS2BE_ST, + 'char_len_table': UCS2BE_CHAR_LEN_TABLE, + '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,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME, 5, 5, 5,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,#10-17 + 5, 5, 5,MachineState.ERROR, 5,MachineState.ERROR, 6, 6,#18-1f + 7, 6, 8, 8, 5, 5, 5,MachineState.ERROR,#20-27 + 5, 5, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5, 5,#28-2f + 5, 5, 5,MachineState.ERROR, 5,MachineState.ERROR,MachineState.START,MachineState.START #30-37 +) + +UCS2LE_CHAR_LEN_TABLE = (2, 2, 2, 2, 2, 2) + +UCS2LE_SM_MODEL = {'class_table': UCS2LE_CLS, + 'class_factor': 6, + 'state_table': UCS2LE_ST, + 'char_len_table': UCS2LE_CHAR_LEN_TABLE, + '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 = ( + MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 12, 10,#00-07 + 9, 11, 8, 7, 6, 5, 4, 3,#08-0f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#10-17 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#20-27 + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#28-2f + MachineState.ERROR,MachineState.ERROR, 5, 5, 5, 5,MachineState.ERROR,MachineState.ERROR,#30-37 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#38-3f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5, 5, 5,MachineState.ERROR,MachineState.ERROR,#40-47 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#48-4f + MachineState.ERROR,MachineState.ERROR, 7, 7, 7, 7,MachineState.ERROR,MachineState.ERROR,#50-57 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#58-5f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 7, 7,MachineState.ERROR,MachineState.ERROR,#60-67 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#68-6f + MachineState.ERROR,MachineState.ERROR, 9, 9, 9, 9,MachineState.ERROR,MachineState.ERROR,#70-77 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#78-7f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 9,MachineState.ERROR,MachineState.ERROR,#80-87 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#88-8f + MachineState.ERROR,MachineState.ERROR, 12, 12, 12, 12,MachineState.ERROR,MachineState.ERROR,#90-97 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#98-9f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 12,MachineState.ERROR,MachineState.ERROR,#a0-a7 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#a8-af + MachineState.ERROR,MachineState.ERROR, 12, 12, 12,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#b0-b7 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#b8-bf + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,#c0-c7 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR #c8-cf +) + +UTF8_CHAR_LEN_TABLE = (0, 1, 0, 0, 0, 0, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6) + +UTF8_SM_MODEL = {'class_table': UTF8_CLS, + 'class_factor': 16, + 'state_table': UTF8_ST, + 'char_len_table': UTF8_CHAR_LEN_TABLE, + 'name': 'UTF-8'} diff --git a/openpype/vendor/python/python_2/chardet/metadata/__init__.py b/openpype/vendor/python/python_2/chardet/metadata/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openpype/vendor/python/python_2/chardet/metadata/languages.py b/openpype/vendor/python/python_2/chardet/metadata/languages.py new file mode 100644 index 0000000000..3237d5abf6 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/metadata/languages.py @@ -0,0 +1,310 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +Metadata about languages used by our model training code for our +SingleByteCharSetProbers. Could be used for other things in the future. + +This code is based on the language metadata from the uchardet project. +""" +from __future__ import absolute_import, print_function + +from string import ascii_letters + + +# TODO: Add Ukranian (KOI8-U) + +class Language(object): + """Metadata about a language useful for training models + + :ivar name: The human name for the language, in English. + :type name: str + :ivar iso_code: 2-letter ISO 639-1 if possible, 3-letter ISO code otherwise, + or use another catalog as a last resort. + :type iso_code: str + :ivar use_ascii: Whether or not ASCII letters should be included in trained + models. + :type use_ascii: bool + :ivar charsets: The charsets we want to support and create data for. + :type charsets: list of str + :ivar alphabet: The characters in the language's alphabet. If `use_ascii` is + `True`, you only need to add those not in the ASCII set. + :type alphabet: str + :ivar wiki_start_pages: The Wikipedia pages to start from if we're crawling + Wikipedia for training data. + :type wiki_start_pages: list of str + """ + def __init__(self, name=None, iso_code=None, use_ascii=True, charsets=None, + alphabet=None, wiki_start_pages=None): + super(Language, self).__init__() + self.name = name + self.iso_code = iso_code + self.use_ascii = use_ascii + self.charsets = charsets + if self.use_ascii: + if alphabet: + alphabet += ascii_letters + else: + alphabet = ascii_letters + elif not alphabet: + raise ValueError('Must supply alphabet if use_ascii is False') + self.alphabet = ''.join(sorted(set(alphabet))) if alphabet else None + self.wiki_start_pages = wiki_start_pages + + def __repr__(self): + return '{}({})'.format(self.__class__.__name__, + ', '.join('{}={!r}'.format(k, v) + for k, v in self.__dict__.items() + if not k.startswith('_'))) + + +LANGUAGES = {'Arabic': Language(name='Arabic', + iso_code='ar', + use_ascii=False, + # We only support encodings that use isolated + # forms, because the current recommendation is + # that the rendering system handles presentation + # forms. This means we purposefully skip IBM864. + charsets=['ISO-8859-6', 'WINDOWS-1256', + 'CP720', 'CP864'], + alphabet=u'ءآأؤإئابةتثجحخدذرزسشصضطظعغػؼؽؾؿـفقكلمنهوىيًٌٍَُِّ', + wiki_start_pages=[u'الصفحة_الرئيسية']), + 'Belarusian': Language(name='Belarusian', + iso_code='be', + use_ascii=False, + charsets=['ISO-8859-5', 'WINDOWS-1251', + 'IBM866', 'MacCyrillic'], + alphabet=(u'АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШЫЬЭЮЯ' + u'абвгдеёжзійклмнопрстуўфхцчшыьэюяʼ'), + wiki_start_pages=[u'Галоўная_старонка']), + 'Bulgarian': Language(name='Bulgarian', + iso_code='bg', + use_ascii=False, + charsets=['ISO-8859-5', 'WINDOWS-1251', + 'IBM855'], + alphabet=(u'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯ' + u'абвгдежзийклмнопрстуфхцчшщъьюя'), + wiki_start_pages=[u'Начална_страница']), + 'Czech': Language(name='Czech', + iso_code='cz', + use_ascii=True, + charsets=['ISO-8859-2', 'WINDOWS-1250'], + alphabet=u'áčďéěíňóřšťúůýžÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ', + wiki_start_pages=[u'Hlavní_strana']), + 'Danish': Language(name='Danish', + iso_code='da', + use_ascii=True, + charsets=['ISO-8859-1', 'ISO-8859-15', + 'WINDOWS-1252'], + alphabet=u'æøåÆØÅ', + wiki_start_pages=[u'Forside']), + 'German': Language(name='German', + iso_code='de', + use_ascii=True, + charsets=['ISO-8859-1', 'WINDOWS-1252'], + alphabet=u'äöüßÄÖÜ', + wiki_start_pages=[u'Wikipedia:Hauptseite']), + 'Greek': Language(name='Greek', + iso_code='el', + use_ascii=False, + charsets=['ISO-8859-7', 'WINDOWS-1253'], + alphabet=(u'αβγδεζηθικλμνξοπρσςτυφχψωάέήίόύώ' + u'ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΣΤΥΦΧΨΩΆΈΉΊΌΎΏ'), + wiki_start_pages=[u'Πύλη:Κύρια']), + 'English': Language(name='English', + iso_code='en', + use_ascii=True, + charsets=['ISO-8859-1', 'WINDOWS-1252'], + wiki_start_pages=[u'Main_Page']), + 'Esperanto': Language(name='Esperanto', + iso_code='eo', + # Q, W, X, and Y not used at all + use_ascii=False, + charsets=['ISO-8859-3'], + alphabet=(u'abcĉdefgĝhĥijĵklmnoprsŝtuŭvz' + u'ABCĈDEFGĜHĤIJĴKLMNOPRSŜTUŬVZ'), + wiki_start_pages=[u'Vikipedio:Ĉefpaĝo']), + 'Spanish': Language(name='Spanish', + iso_code='es', + use_ascii=True, + charsets=['ISO-8859-1', 'ISO-8859-15', + 'WINDOWS-1252'], + alphabet=u'ñáéíóúüÑÁÉÍÓÚÜ', + wiki_start_pages=[u'Wikipedia:Portada']), + 'Estonian': Language(name='Estonian', + iso_code='et', + use_ascii=False, + charsets=['ISO-8859-4', 'ISO-8859-13', + 'WINDOWS-1257'], + # C, F, Š, Q, W, X, Y, Z, Ž are only for + # loanwords + alphabet=(u'ABDEGHIJKLMNOPRSTUVÕÄÖÜ' + u'abdeghijklmnoprstuvõäöü'), + wiki_start_pages=[u'Esileht']), + 'Finnish': Language(name='Finnish', + iso_code='fi', + use_ascii=True, + charsets=['ISO-8859-1', 'ISO-8859-15', + 'WINDOWS-1252'], + alphabet=u'ÅÄÖŠŽåäöšž', + wiki_start_pages=[u'Wikipedia:Etusivu']), + 'French': Language(name='French', + iso_code='fr', + use_ascii=True, + charsets=['ISO-8859-1', 'ISO-8859-15', + 'WINDOWS-1252'], + alphabet=u'œàâçèéîïùûêŒÀÂÇÈÉÎÏÙÛÊ', + wiki_start_pages=[u'Wikipédia:Accueil_principal', + u'Bœuf (animal)']), + 'Hebrew': Language(name='Hebrew', + iso_code='he', + use_ascii=False, + charsets=['ISO-8859-8', 'WINDOWS-1255'], + alphabet=u'אבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ', + wiki_start_pages=[u'עמוד_ראשי']), + 'Croatian': Language(name='Croatian', + iso_code='hr', + # Q, W, X, Y are only used for foreign words. + use_ascii=False, + charsets=['ISO-8859-2', 'WINDOWS-1250'], + alphabet=(u'abcčćdđefghijklmnoprsštuvzž' + u'ABCČĆDĐEFGHIJKLMNOPRSŠTUVZŽ'), + wiki_start_pages=[u'Glavna_stranica']), + 'Hungarian': Language(name='Hungarian', + iso_code='hu', + # Q, W, X, Y are only used for foreign words. + use_ascii=False, + charsets=['ISO-8859-2', 'WINDOWS-1250'], + alphabet=(u'abcdefghijklmnoprstuvzáéíóöőúüű' + u'ABCDEFGHIJKLMNOPRSTUVZÁÉÍÓÖŐÚÜŰ'), + wiki_start_pages=[u'Kezdőlap']), + 'Italian': Language(name='Italian', + iso_code='it', + use_ascii=True, + charsets=['ISO-8859-1', 'ISO-8859-15', + 'WINDOWS-1252'], + alphabet=u'ÀÈÉÌÒÓÙàèéìòóù', + wiki_start_pages=[u'Pagina_principale']), + 'Lithuanian': Language(name='Lithuanian', + iso_code='lt', + use_ascii=False, + charsets=['ISO-8859-13', 'WINDOWS-1257', + 'ISO-8859-4'], + # Q, W, and X not used at all + alphabet=(u'AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ' + u'aąbcčdeęėfghiįyjklmnoprsštuųūvzž'), + wiki_start_pages=[u'Pagrindinis_puslapis']), + 'Latvian': Language(name='Latvian', + iso_code='lv', + use_ascii=False, + charsets=['ISO-8859-13', 'WINDOWS-1257', + 'ISO-8859-4'], + # Q, W, X, Y are only for loanwords + alphabet=(u'AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ' + u'aābcčdeēfgģhiījkķlļmnņoprsštuūvzž'), + wiki_start_pages=[u'Sākumlapa']), + 'Macedonian': Language(name='Macedonian', + iso_code='mk', + use_ascii=False, + charsets=['ISO-8859-5', 'WINDOWS-1251', + 'MacCyrillic', 'IBM855'], + alphabet=(u'АБВГДЃЕЖЗЅИЈКЛЉМНЊОПРСТЌУФХЦЧЏШ' + u'абвгдѓежзѕијклљмнњопрстќуфхцчџш'), + wiki_start_pages=[u'Главна_страница']), + 'Dutch': Language(name='Dutch', + iso_code='nl', + use_ascii=True, + charsets=['ISO-8859-1', 'WINDOWS-1252'], + wiki_start_pages=[u'Hoofdpagina']), + 'Polish': Language(name='Polish', + iso_code='pl', + # Q and X are only used for foreign words. + use_ascii=False, + charsets=['ISO-8859-2', 'WINDOWS-1250'], + alphabet=(u'AĄBCĆDEĘFGHIJKLŁMNŃOÓPRSŚTUWYZŹŻ' + u'aąbcćdeęfghijklłmnńoóprsśtuwyzźż'), + wiki_start_pages=[u'Wikipedia:Strona_główna']), + 'Portuguese': Language(name='Portuguese', + iso_code='pt', + use_ascii=True, + charsets=['ISO-8859-1', 'ISO-8859-15', + 'WINDOWS-1252'], + alphabet=u'ÁÂÃÀÇÉÊÍÓÔÕÚáâãàçéêíóôõú', + wiki_start_pages=[u'Wikipédia:Página_principal']), + 'Romanian': Language(name='Romanian', + iso_code='ro', + use_ascii=True, + charsets=['ISO-8859-2', 'WINDOWS-1250'], + alphabet=u'ăâîșțĂÂÎȘȚ', + wiki_start_pages=[u'Pagina_principală']), + 'Russian': Language(name='Russian', + iso_code='ru', + use_ascii=False, + charsets=['ISO-8859-5', 'WINDOWS-1251', + 'KOI8-R', 'MacCyrillic', 'IBM866', + 'IBM855'], + alphabet=(u'абвгдеёжзийклмнопрстуфхцчшщъыьэюя' + u'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ'), + wiki_start_pages=[u'Заглавная_страница']), + 'Slovak': Language(name='Slovak', + iso_code='sk', + use_ascii=True, + charsets=['ISO-8859-2', 'WINDOWS-1250'], + alphabet=u'áäčďéíĺľňóôŕšťúýžÁÄČĎÉÍĹĽŇÓÔŔŠŤÚÝŽ', + wiki_start_pages=[u'Hlavná_stránka']), + 'Slovene': Language(name='Slovene', + iso_code='sl', + # Q, W, X, Y are only used for foreign words. + use_ascii=False, + charsets=['ISO-8859-2', 'WINDOWS-1250'], + alphabet=(u'abcčdefghijklmnoprsštuvzž' + u'ABCČDEFGHIJKLMNOPRSŠTUVZŽ'), + wiki_start_pages=[u'Glavna_stran']), + # Serbian can be written in both Latin and Cyrillic, but there's no + # simple way to get the Latin alphabet pages from Wikipedia through + # the API, so for now we just support Cyrillic. + 'Serbian': Language(name='Serbian', + iso_code='sr', + alphabet=(u'АБВГДЂЕЖЗИЈКЛЉМНЊОПРСТЋУФХЦЧЏШ' + u'абвгдђежзијклљмнњопрстћуфхцчџш'), + charsets=['ISO-8859-5', 'WINDOWS-1251', + 'MacCyrillic', 'IBM855'], + wiki_start_pages=[u'Главна_страна']), + 'Thai': Language(name='Thai', + iso_code='th', + use_ascii=False, + charsets=['ISO-8859-11', 'TIS-620', 'CP874'], + alphabet=u'กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛', + wiki_start_pages=[u'หน้าหลัก']), + 'Turkish': Language(name='Turkish', + iso_code='tr', + # Q, W, and X are not used by Turkish + use_ascii=False, + charsets=['ISO-8859-3', 'ISO-8859-9', + 'WINDOWS-1254'], + alphabet=(u'abcçdefgğhıijklmnoöprsştuüvyzâîû' + u'ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZÂÎÛ'), + wiki_start_pages=[u'Ana_Sayfa']), + 'Vietnamese': Language(name='Vietnamese', + iso_code='vi', + use_ascii=False, + # Windows-1258 is the only common 8-bit + # Vietnamese encoding supported by Python. + # From Wikipedia: + # For systems that lack support for Unicode, + # dozens of 8-bit Vietnamese code pages are + # available.[1] The most common are VISCII + # (TCVN 5712:1993), VPS, and Windows-1258.[3] + # Where ASCII is required, such as when + # ensuring readability in plain text e-mail, + # Vietnamese letters are often encoded + # according to Vietnamese Quoted-Readable + # (VIQR) or VSCII Mnemonic (VSCII-MNEM),[4] + # though usage of either variable-width + # scheme has declined dramatically following + # the adoption of Unicode on the World Wide + # Web. + charsets=['WINDOWS-1258'], + alphabet=(u'aăâbcdđeêghiklmnoôơpqrstuưvxy' + u'AĂÂBCDĐEÊGHIKLMNOÔƠPQRSTUƯVXY'), + wiki_start_pages=[u'Chữ_Quốc_ngữ']), + } diff --git a/openpype/vendor/python/python_2/chardet/sbcharsetprober.py b/openpype/vendor/python/python_2/chardet/sbcharsetprober.py new file mode 100644 index 0000000000..46ba835c66 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/sbcharsetprober.py @@ -0,0 +1,145 @@ +######################## 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 collections import namedtuple + +from .charsetprober import CharSetProber +from .enums import CharacterCategory, ProbingState, SequenceLikelihood + + +SingleByteCharSetModel = namedtuple('SingleByteCharSetModel', + ['charset_name', + 'language', + 'char_to_order_map', + 'language_model', + 'typical_positive_ratio', + 'keep_ascii_letters', + 'alphabet']) + + +class SingleByteCharSetProber(CharSetProber): + SAMPLE_SIZE = 64 + SB_ENOUGH_REL_THRESHOLD = 1024 # 0.25 * SAMPLE_SIZE^2 + POSITIVE_SHORTCUT_THRESHOLD = 0.95 + NEGATIVE_SHORTCUT_THRESHOLD = 0.05 + + def __init__(self, model, reversed=False, name_prober=None): + super(SingleByteCharSetProber, self).__init__() + self._model = model + # TRUE if we need to reverse every pair in the model lookup + self._reversed = reversed + # Optional auxiliary prober for name decision + self._name_prober = name_prober + self._last_order = None + self._seq_counters = None + self._total_seqs = None + self._total_char = None + self._freq_char = None + self.reset() + + def reset(self): + super(SingleByteCharSetProber, self).reset() + # char order of last character + self._last_order = 255 + self._seq_counters = [0] * SequenceLikelihood.get_num_categories() + self._total_seqs = 0 + self._total_char = 0 + # characters that fall in our sampling range + self._freq_char = 0 + + @property + def charset_name(self): + if self._name_prober: + return self._name_prober.charset_name + else: + return self._model.charset_name + + @property + def language(self): + if self._name_prober: + return self._name_prober.language + else: + return self._model.language + + def feed(self, byte_str): + # TODO: Make filter_international_words keep things in self.alphabet + if not self._model.keep_ascii_letters: + byte_str = self.filter_international_words(byte_str) + if not byte_str: + return self.state + char_to_order_map = self._model.char_to_order_map + language_model = self._model.language_model + for char in byte_str: + order = char_to_order_map.get(char, CharacterCategory.UNDEFINED) + # XXX: This was SYMBOL_CAT_ORDER before, with a value of 250, but + # CharacterCategory.SYMBOL is actually 253, so we use CONTROL + # to make it closer to the original intent. The only difference + # is whether or not we count digits and control characters for + # _total_char purposes. + if order < CharacterCategory.CONTROL: + self._total_char += 1 + # TODO: Follow uchardet's lead and discount confidence for frequent + # control characters. + # See https://github.com/BYVoid/uchardet/commit/55b4f23971db61 + if order < self.SAMPLE_SIZE: + self._freq_char += 1 + if self._last_order < self.SAMPLE_SIZE: + self._total_seqs += 1 + if not self._reversed: + lm_cat = language_model[self._last_order][order] + else: + lm_cat = language_model[order][self._last_order] + self._seq_counters[lm_cat] += 1 + self._last_order = order + + charset_name = self._model.charset_name + if self.state == ProbingState.DETECTING: + if self._total_seqs > self.SB_ENOUGH_REL_THRESHOLD: + confidence = self.get_confidence() + if confidence > self.POSITIVE_SHORTCUT_THRESHOLD: + self.logger.debug('%s confidence = %s, we have a winner', + charset_name, confidence) + self._state = ProbingState.FOUND_IT + elif confidence < self.NEGATIVE_SHORTCUT_THRESHOLD: + self.logger.debug('%s confidence = %s, below negative ' + 'shortcut threshhold %s', charset_name, + confidence, + self.NEGATIVE_SHORTCUT_THRESHOLD) + self._state = ProbingState.NOT_ME + + return self.state + + def get_confidence(self): + r = 0.01 + if self._total_seqs > 0: + r = ((1.0 * self._seq_counters[SequenceLikelihood.POSITIVE]) / + self._total_seqs / self._model.typical_positive_ratio) + r = r * self._freq_char / self._total_char + if r >= 1.0: + r = 0.99 + return r diff --git a/openpype/vendor/python/python_2/chardet/sbcsgroupprober.py b/openpype/vendor/python/python_2/chardet/sbcsgroupprober.py new file mode 100644 index 0000000000..bdeef4e15b --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/sbcsgroupprober.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 +# +# 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 .hebrewprober import HebrewProber +from .langbulgarianmodel import (ISO_8859_5_BULGARIAN_MODEL, + WINDOWS_1251_BULGARIAN_MODEL) +from .langgreekmodel import ISO_8859_7_GREEK_MODEL, WINDOWS_1253_GREEK_MODEL +from .langhebrewmodel import WINDOWS_1255_HEBREW_MODEL +# from .langhungarianmodel import (ISO_8859_2_HUNGARIAN_MODEL, +# WINDOWS_1250_HUNGARIAN_MODEL) +from .langrussianmodel import (IBM855_RUSSIAN_MODEL, IBM866_RUSSIAN_MODEL, + ISO_8859_5_RUSSIAN_MODEL, KOI8_R_RUSSIAN_MODEL, + MACCYRILLIC_RUSSIAN_MODEL, + WINDOWS_1251_RUSSIAN_MODEL) +from .langthaimodel import TIS_620_THAI_MODEL +from .langturkishmodel import ISO_8859_9_TURKISH_MODEL +from .sbcharsetprober import SingleByteCharSetProber + + +class SBCSGroupProber(CharSetGroupProber): + def __init__(self): + super(SBCSGroupProber, self).__init__() + hebrew_prober = HebrewProber() + logical_hebrew_prober = SingleByteCharSetProber(WINDOWS_1255_HEBREW_MODEL, + False, hebrew_prober) + # TODO: See if using ISO-8859-8 Hebrew model works better here, since + # it's actually the visual one + visual_hebrew_prober = SingleByteCharSetProber(WINDOWS_1255_HEBREW_MODEL, + True, hebrew_prober) + hebrew_prober.set_model_probers(logical_hebrew_prober, + visual_hebrew_prober) + # TODO: ORDER MATTERS HERE. I changed the order vs what was in master + # and several tests failed that did not before. Some thought + # should be put into the ordering, and we should consider making + # order not matter here, because that is very counter-intuitive. + self.probers = [ + SingleByteCharSetProber(WINDOWS_1251_RUSSIAN_MODEL), + SingleByteCharSetProber(KOI8_R_RUSSIAN_MODEL), + SingleByteCharSetProber(ISO_8859_5_RUSSIAN_MODEL), + SingleByteCharSetProber(MACCYRILLIC_RUSSIAN_MODEL), + SingleByteCharSetProber(IBM866_RUSSIAN_MODEL), + SingleByteCharSetProber(IBM855_RUSSIAN_MODEL), + SingleByteCharSetProber(ISO_8859_7_GREEK_MODEL), + SingleByteCharSetProber(WINDOWS_1253_GREEK_MODEL), + SingleByteCharSetProber(ISO_8859_5_BULGARIAN_MODEL), + SingleByteCharSetProber(WINDOWS_1251_BULGARIAN_MODEL), + # TODO: Restore Hungarian encodings (iso-8859-2 and windows-1250) + # after we retrain model. + # SingleByteCharSetProber(ISO_8859_2_HUNGARIAN_MODEL), + # SingleByteCharSetProber(WINDOWS_1250_HUNGARIAN_MODEL), + SingleByteCharSetProber(TIS_620_THAI_MODEL), + SingleByteCharSetProber(ISO_8859_9_TURKISH_MODEL), + hebrew_prober, + logical_hebrew_prober, + visual_hebrew_prober, + ] + self.reset() diff --git a/openpype/vendor/python/python_2/chardet/sjisprober.py b/openpype/vendor/python/python_2/chardet/sjisprober.py new file mode 100644 index 0000000000..9e29623bdc --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/sjisprober.py @@ -0,0 +1,92 @@ +######################## 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 SJIS_SM_MODEL +from .enums import ProbingState, MachineState + + +class SJISProber(MultiByteCharSetProber): + def __init__(self): + super(SJISProber, self).__init__() + self.coding_sm = CodingStateMachine(SJIS_SM_MODEL) + self.distribution_analyzer = SJISDistributionAnalysis() + self.context_analyzer = SJISContextAnalysis() + self.reset() + + def reset(self): + super(SJISProber, self).reset() + self.context_analyzer.reset() + + @property + def charset_name(self): + return self.context_analyzer.charset_name + + @property + def language(self): + return "Japanese" + + def feed(self, byte_str): + for i in range(len(byte_str)): + coding_state = self.coding_sm.next_state(byte_str[i]) + if coding_state == MachineState.ERROR: + self.logger.debug('%s %s prober hit error at byte %s', + self.charset_name, self.language, i) + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + char_len = self.coding_sm.get_current_charlen() + if i == 0: + self._last_char[1] = byte_str[0] + self.context_analyzer.feed(self._last_char[2 - char_len:], + char_len) + self.distribution_analyzer.feed(self._last_char, char_len) + else: + self.context_analyzer.feed(byte_str[i + 1 - char_len:i + 3 + - char_len], char_len) + self.distribution_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + + self._last_char[0] = byte_str[-1] + + if self.state == ProbingState.DETECTING: + if (self.context_analyzer.got_enough_data() and + (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + context_conf = self.context_analyzer.get_confidence() + distrib_conf = self.distribution_analyzer.get_confidence() + return max(context_conf, distrib_conf) diff --git a/openpype/vendor/python/python_2/chardet/universaldetector.py b/openpype/vendor/python/python_2/chardet/universaldetector.py new file mode 100644 index 0000000000..055a8ac1b1 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/universaldetector.py @@ -0,0 +1,286 @@ +######################## 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 ######################### +""" +Module containing the UniversalDetector detector class, which is the primary +class a user of ``chardet`` should use. + +:author: Mark Pilgrim (initial port to Python) +:author: Shy Shalom (original C code) +:author: Dan Blanchard (major refactoring for 3.0) +:author: Ian Cordasco +""" + + +import codecs +import logging +import re + +from .charsetgroupprober import CharSetGroupProber +from .enums import InputState, LanguageFilter, ProbingState +from .escprober import EscCharSetProber +from .latin1prober import Latin1Prober +from .mbcsgroupprober import MBCSGroupProber +from .sbcsgroupprober import SBCSGroupProber + + +class UniversalDetector(object): + """ + The ``UniversalDetector`` class underlies the ``chardet.detect`` function + and coordinates all of the different charset probers. + + To get a ``dict`` containing an encoding and its confidence, you can simply + run: + + .. code:: + + u = UniversalDetector() + u.feed(some_bytes) + u.close() + detected = u.result + + """ + + MINIMUM_THRESHOLD = 0.20 + HIGH_BYTE_DETECTOR = re.compile(b'[\x80-\xFF]') + ESC_DETECTOR = re.compile(b'(\033|~{)') + WIN_BYTE_DETECTOR = re.compile(b'[\x80-\x9F]') + ISO_WIN_MAP = {'iso-8859-1': 'Windows-1252', + 'iso-8859-2': 'Windows-1250', + 'iso-8859-5': 'Windows-1251', + 'iso-8859-6': 'Windows-1256', + 'iso-8859-7': 'Windows-1253', + 'iso-8859-8': 'Windows-1255', + 'iso-8859-9': 'Windows-1254', + 'iso-8859-13': 'Windows-1257'} + + def __init__(self, lang_filter=LanguageFilter.ALL): + self._esc_charset_prober = None + self._charset_probers = [] + self.result = None + self.done = None + self._got_data = None + self._input_state = None + self._last_char = None + self.lang_filter = lang_filter + self.logger = logging.getLogger(__name__) + self._has_win_bytes = None + self.reset() + + def reset(self): + """ + Reset the UniversalDetector and all of its probers back to their + initial states. This is called by ``__init__``, so you only need to + call this directly in between analyses of different documents. + """ + self.result = {'encoding': None, 'confidence': 0.0, 'language': None} + self.done = False + self._got_data = False + self._has_win_bytes = False + self._input_state = InputState.PURE_ASCII + self._last_char = b'' + if self._esc_charset_prober: + self._esc_charset_prober.reset() + for prober in self._charset_probers: + prober.reset() + + def feed(self, byte_str): + """ + Takes a chunk of a document and feeds it through all of the relevant + charset probers. + + After calling ``feed``, you can check the value of the ``done`` + attribute to see if you need to continue feeding the + ``UniversalDetector`` more data, or if it has made a prediction + (in the ``result`` attribute). + + .. note:: + You should always call ``close`` when you're done feeding in your + document if ``done`` is not already ``True``. + """ + if self.done: + return + + if not len(byte_str): + return + + if not isinstance(byte_str, bytearray): + byte_str = bytearray(byte_str) + + # First check for known BOMs, since these are guaranteed to be correct + if not self._got_data: + # If the data starts with BOM, we know it is UTF + if byte_str.startswith(codecs.BOM_UTF8): + # EF BB BF UTF-8 with BOM + self.result = {'encoding': "UTF-8-SIG", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith((codecs.BOM_UTF32_LE, + codecs.BOM_UTF32_BE)): + # FF FE 00 00 UTF-32, little-endian BOM + # 00 00 FE FF UTF-32, big-endian BOM + self.result = {'encoding': "UTF-32", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith(b'\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, + 'language': ''} + elif byte_str.startswith(b'\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, + 'language': ''} + elif byte_str.startswith((codecs.BOM_LE, codecs.BOM_BE)): + # FF FE UTF-16, little endian BOM + # FE FF UTF-16, big endian BOM + self.result = {'encoding': "UTF-16", + 'confidence': 1.0, + 'language': ''} + + self._got_data = True + if self.result['encoding'] is not None: + self.done = True + return + + # If none of those matched and we've only see ASCII so far, check + # for high bytes and escape sequences + if self._input_state == InputState.PURE_ASCII: + if self.HIGH_BYTE_DETECTOR.search(byte_str): + self._input_state = InputState.HIGH_BYTE + elif self._input_state == InputState.PURE_ASCII and \ + self.ESC_DETECTOR.search(self._last_char + byte_str): + self._input_state = InputState.ESC_ASCII + + self._last_char = byte_str[-1:] + + # If we've seen escape sequences, use the EscCharSetProber, which + # uses a simple state machine to check for known escape sequences in + # HZ and ISO-2022 encodings, since those are the only encodings that + # use such sequences. + if self._input_state == InputState.ESC_ASCII: + if not self._esc_charset_prober: + self._esc_charset_prober = EscCharSetProber(self.lang_filter) + if self._esc_charset_prober.feed(byte_str) == ProbingState.FOUND_IT: + self.result = {'encoding': + self._esc_charset_prober.charset_name, + 'confidence': + self._esc_charset_prober.get_confidence(), + 'language': + self._esc_charset_prober.language} + self.done = True + # If we've seen high bytes (i.e., those with values greater than 127), + # we need to do more complicated checks using all our multi-byte and + # single-byte probers that are left. The single-byte probers + # use character bigram distributions to determine the encoding, whereas + # the multi-byte probers use a combination of character unigram and + # bigram distributions. + elif self._input_state == InputState.HIGH_BYTE: + if not self._charset_probers: + self._charset_probers = [MBCSGroupProber(self.lang_filter)] + # If we're checking non-CJK encodings, use single-byte prober + if self.lang_filter & LanguageFilter.NON_CJK: + self._charset_probers.append(SBCSGroupProber()) + self._charset_probers.append(Latin1Prober()) + for prober in self._charset_probers: + if prober.feed(byte_str) == ProbingState.FOUND_IT: + self.result = {'encoding': prober.charset_name, + 'confidence': prober.get_confidence(), + 'language': prober.language} + self.done = True + break + if self.WIN_BYTE_DETECTOR.search(byte_str): + self._has_win_bytes = True + + def close(self): + """ + Stop analyzing the current document and come up with a final + prediction. + + :returns: The ``result`` attribute, a ``dict`` with the keys + `encoding`, `confidence`, and `language`. + """ + # Don't bother with checks if we're already done + if self.done: + return self.result + self.done = True + + if not self._got_data: + self.logger.debug('no data received!') + + # Default to ASCII if it is all we've seen so far + elif self._input_state == InputState.PURE_ASCII: + self.result = {'encoding': 'ascii', + 'confidence': 1.0, + 'language': ''} + + # If we have seen non-ASCII, return the best that met MINIMUM_THRESHOLD + elif self._input_state == InputState.HIGH_BYTE: + prober_confidence = None + max_prober_confidence = 0.0 + max_prober = None + for prober in self._charset_probers: + if not prober: + continue + prober_confidence = prober.get_confidence() + if prober_confidence > max_prober_confidence: + max_prober_confidence = prober_confidence + max_prober = prober + if max_prober and (max_prober_confidence > self.MINIMUM_THRESHOLD): + charset_name = max_prober.charset_name + lower_charset_name = max_prober.charset_name.lower() + confidence = max_prober.get_confidence() + # Use Windows encoding name instead of ISO-8859 if we saw any + # extra Windows-specific bytes + if lower_charset_name.startswith('iso-8859'): + if self._has_win_bytes: + charset_name = self.ISO_WIN_MAP.get(lower_charset_name, + charset_name) + self.result = {'encoding': charset_name, + 'confidence': confidence, + 'language': max_prober.language} + + # Log all prober confidences if none met MINIMUM_THRESHOLD + if self.logger.getEffectiveLevel() <= logging.DEBUG: + if self.result['encoding'] is None: + self.logger.debug('no probers hit minimum threshold') + for group_prober in self._charset_probers: + if not group_prober: + continue + if isinstance(group_prober, CharSetGroupProber): + for prober in group_prober.probers: + self.logger.debug('%s %s confidence = %s', + prober.charset_name, + prober.language, + prober.get_confidence()) + else: + self.logger.debug('%s %s confidence = %s', + group_prober.charset_name, + group_prober.language, + group_prober.get_confidence()) + return self.result diff --git a/openpype/vendor/python/python_2/chardet/utf8prober.py b/openpype/vendor/python/python_2/chardet/utf8prober.py new file mode 100644 index 0000000000..6c3196cc2d --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/utf8prober.py @@ -0,0 +1,82 @@ +######################## 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 .charsetprober import CharSetProber +from .enums import ProbingState, MachineState +from .codingstatemachine import CodingStateMachine +from .mbcssm import UTF8_SM_MODEL + + + +class UTF8Prober(CharSetProber): + ONE_CHAR_PROB = 0.5 + + def __init__(self): + super(UTF8Prober, self).__init__() + self.coding_sm = CodingStateMachine(UTF8_SM_MODEL) + self._num_mb_chars = None + self.reset() + + def reset(self): + super(UTF8Prober, self).reset() + self.coding_sm.reset() + self._num_mb_chars = 0 + + @property + def charset_name(self): + return "utf-8" + + @property + def language(self): + return "" + + def feed(self, byte_str): + for c in byte_str: + coding_state = self.coding_sm.next_state(c) + if coding_state == MachineState.ERROR: + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + if self.coding_sm.get_current_charlen() >= 2: + self._num_mb_chars += 1 + + if self.state == ProbingState.DETECTING: + if self.get_confidence() > self.SHORTCUT_THRESHOLD: + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + unlike = 0.99 + if self._num_mb_chars < 6: + unlike *= self.ONE_CHAR_PROB ** self._num_mb_chars + return 1.0 - unlike + else: + return unlike diff --git a/openpype/vendor/python/python_2/chardet/version.py b/openpype/vendor/python/python_2/chardet/version.py new file mode 100644 index 0000000000..70369b9d66 --- /dev/null +++ b/openpype/vendor/python/python_2/chardet/version.py @@ -0,0 +1,9 @@ +""" +This module exists only to simplify retrieving the version number of chardet +from within setup.py and from chardet subpackages. + +:author: Dan Blanchard (dan.blanchard@gmail.com) +""" + +__version__ = "4.0.0" +VERSION = __version__.split('.') diff --git a/openpype/vendor/python/python_2/idna/__init__.py b/openpype/vendor/python/python_2/idna/__init__.py new file mode 100644 index 0000000000..847bf93547 --- /dev/null +++ b/openpype/vendor/python/python_2/idna/__init__.py @@ -0,0 +1,2 @@ +from .package_data import __version__ +from .core import * diff --git a/openpype/vendor/python/python_2/idna/codec.py b/openpype/vendor/python/python_2/idna/codec.py new file mode 100644 index 0000000000..98c65ead14 --- /dev/null +++ b/openpype/vendor/python/python_2/idna/codec.py @@ -0,0 +1,118 @@ +from .core import encode, decode, alabel, ulabel, IDNAError +import codecs +import re + +_unicode_dots_re = re.compile(u'[\u002e\u3002\uff0e\uff61]') + +class Codec(codecs.Codec): + + def encode(self, data, errors='strict'): + + if errors != 'strict': + raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) + + if not data: + return "", 0 + + return encode(data), len(data) + + def decode(self, data, errors='strict'): + + if errors != 'strict': + raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) + + if not data: + return u"", 0 + + return decode(data), len(data) + +class IncrementalEncoder(codecs.BufferedIncrementalEncoder): + def _buffer_encode(self, data, errors, final): + if errors != 'strict': + raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) + + if not data: + return ("", 0) + + labels = _unicode_dots_re.split(data) + trailing_dot = u'' + if labels: + if not labels[-1]: + trailing_dot = '.' + del labels[-1] + elif not final: + # Keep potentially unfinished label until the next call + del labels[-1] + if labels: + trailing_dot = '.' + + result = [] + size = 0 + for label in labels: + result.append(alabel(label)) + if size: + size += 1 + size += len(label) + + # Join with U+002E + result = ".".join(result) + trailing_dot + size += len(trailing_dot) + return (result, size) + +class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + def _buffer_decode(self, data, errors, final): + if errors != 'strict': + raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) + + if not data: + return (u"", 0) + + # IDNA allows decoding to operate on Unicode strings, too. + if isinstance(data, unicode): + labels = _unicode_dots_re.split(data) + else: + # Must be ASCII string + data = str(data) + unicode(data, "ascii") + labels = data.split(".") + + trailing_dot = u'' + if labels: + if not labels[-1]: + trailing_dot = u'.' + del labels[-1] + elif not final: + # Keep potentially unfinished label until the next call + del labels[-1] + if labels: + trailing_dot = u'.' + + result = [] + size = 0 + for label in labels: + result.append(ulabel(label)) + if size: + size += 1 + size += len(label) + + result = u".".join(result) + trailing_dot + size += len(trailing_dot) + return (result, size) + + +class StreamWriter(Codec, codecs.StreamWriter): + pass + +class StreamReader(Codec, codecs.StreamReader): + pass + +def getregentry(): + return codecs.CodecInfo( + name='idna', + encode=Codec().encode, + decode=Codec().decode, + incrementalencoder=IncrementalEncoder, + incrementaldecoder=IncrementalDecoder, + streamwriter=StreamWriter, + streamreader=StreamReader, + ) diff --git a/openpype/vendor/python/python_2/idna/compat.py b/openpype/vendor/python/python_2/idna/compat.py new file mode 100644 index 0000000000..4d47f336db --- /dev/null +++ b/openpype/vendor/python/python_2/idna/compat.py @@ -0,0 +1,12 @@ +from .core import * +from .codec import * + +def ToASCII(label): + return encode(label) + +def ToUnicode(label): + return decode(label) + +def nameprep(s): + raise NotImplementedError("IDNA 2008 does not utilise nameprep protocol") + diff --git a/openpype/vendor/python/python_2/idna/core.py b/openpype/vendor/python/python_2/idna/core.py new file mode 100644 index 0000000000..41ec5c711d --- /dev/null +++ b/openpype/vendor/python/python_2/idna/core.py @@ -0,0 +1,400 @@ +from . import idnadata +import bisect +import unicodedata +import re +import sys +from .intranges import intranges_contain + +_virama_combining_class = 9 +_alabel_prefix = b'xn--' +_unicode_dots_re = re.compile(u'[\u002e\u3002\uff0e\uff61]') + +if sys.version_info[0] >= 3: + unicode = str + unichr = chr + +class IDNAError(UnicodeError): + """ Base exception for all IDNA-encoding related problems """ + pass + + +class IDNABidiError(IDNAError): + """ Exception when bidirectional requirements are not satisfied """ + pass + + +class InvalidCodepoint(IDNAError): + """ Exception when a disallowed or unallocated codepoint is used """ + pass + + +class InvalidCodepointContext(IDNAError): + """ Exception when the codepoint is not valid in the context it is used """ + pass + + +def _combining_class(cp): + v = unicodedata.combining(unichr(cp)) + if v == 0: + if not unicodedata.name(unichr(cp)): + raise ValueError("Unknown character in unicodedata") + return v + +def _is_script(cp, script): + return intranges_contain(ord(cp), idnadata.scripts[script]) + +def _punycode(s): + return s.encode('punycode') + +def _unot(s): + return 'U+{0:04X}'.format(s) + + +def valid_label_length(label): + + if len(label) > 63: + return False + return True + + +def valid_string_length(label, trailing_dot): + + if len(label) > (254 if trailing_dot else 253): + return False + return True + + +def check_bidi(label, check_ltr=False): + + # Bidi rules should only be applied if string contains RTL characters + bidi_label = False + for (idx, cp) in enumerate(label, 1): + direction = unicodedata.bidirectional(cp) + if direction == '': + # String likely comes from a newer version of Unicode + raise IDNABidiError('Unknown directionality in label {0} at position {1}'.format(repr(label), idx)) + if direction in ['R', 'AL', 'AN']: + bidi_label = True + if not bidi_label and not check_ltr: + return True + + # Bidi rule 1 + direction = unicodedata.bidirectional(label[0]) + if direction in ['R', 'AL']: + rtl = True + elif direction == 'L': + rtl = False + else: + raise IDNABidiError('First codepoint in label {0} must be directionality L, R or AL'.format(repr(label))) + + valid_ending = False + number_type = False + for (idx, cp) in enumerate(label, 1): + direction = unicodedata.bidirectional(cp) + + if rtl: + # Bidi rule 2 + if not direction in ['R', 'AL', 'AN', 'EN', 'ES', 'CS', 'ET', 'ON', 'BN', 'NSM']: + raise IDNABidiError('Invalid direction for codepoint at position {0} in a right-to-left label'.format(idx)) + # Bidi rule 3 + if direction in ['R', 'AL', 'EN', 'AN']: + valid_ending = True + elif direction != 'NSM': + valid_ending = False + # Bidi rule 4 + if direction in ['AN', 'EN']: + if not number_type: + number_type = direction + else: + if number_type != direction: + raise IDNABidiError('Can not mix numeral types in a right-to-left label') + else: + # Bidi rule 5 + if not direction in ['L', 'EN', 'ES', 'CS', 'ET', 'ON', 'BN', 'NSM']: + raise IDNABidiError('Invalid direction for codepoint at position {0} in a left-to-right label'.format(idx)) + # Bidi rule 6 + if direction in ['L', 'EN']: + valid_ending = True + elif direction != 'NSM': + valid_ending = False + + if not valid_ending: + raise IDNABidiError('Label ends with illegal codepoint directionality') + + return True + + +def check_initial_combiner(label): + + if unicodedata.category(label[0])[0] == 'M': + raise IDNAError('Label begins with an illegal combining character') + return True + + +def check_hyphen_ok(label): + + if label[2:4] == '--': + raise IDNAError('Label has disallowed hyphens in 3rd and 4th position') + if label[0] == '-' or label[-1] == '-': + raise IDNAError('Label must not start or end with a hyphen') + return True + + +def check_nfc(label): + + if unicodedata.normalize('NFC', label) != label: + raise IDNAError('Label must be in Normalization Form C') + + +def valid_contextj(label, pos): + + cp_value = ord(label[pos]) + + if cp_value == 0x200c: + + if pos > 0: + if _combining_class(ord(label[pos - 1])) == _virama_combining_class: + return True + + ok = False + for i in range(pos-1, -1, -1): + joining_type = idnadata.joining_types.get(ord(label[i])) + if joining_type == ord('T'): + continue + if joining_type in [ord('L'), ord('D')]: + ok = True + break + + if not ok: + return False + + ok = False + for i in range(pos+1, len(label)): + joining_type = idnadata.joining_types.get(ord(label[i])) + if joining_type == ord('T'): + continue + if joining_type in [ord('R'), ord('D')]: + ok = True + break + return ok + + if cp_value == 0x200d: + + if pos > 0: + if _combining_class(ord(label[pos - 1])) == _virama_combining_class: + return True + return False + + else: + + return False + + +def valid_contexto(label, pos, exception=False): + + cp_value = ord(label[pos]) + + if cp_value == 0x00b7: + if 0 < pos < len(label)-1: + if ord(label[pos - 1]) == 0x006c and ord(label[pos + 1]) == 0x006c: + return True + return False + + elif cp_value == 0x0375: + if pos < len(label)-1 and len(label) > 1: + return _is_script(label[pos + 1], 'Greek') + return False + + elif cp_value == 0x05f3 or cp_value == 0x05f4: + if pos > 0: + return _is_script(label[pos - 1], 'Hebrew') + return False + + elif cp_value == 0x30fb: + for cp in label: + if cp == u'\u30fb': + continue + if _is_script(cp, 'Hiragana') or _is_script(cp, 'Katakana') or _is_script(cp, 'Han'): + return True + return False + + elif 0x660 <= cp_value <= 0x669: + for cp in label: + if 0x6f0 <= ord(cp) <= 0x06f9: + return False + return True + + elif 0x6f0 <= cp_value <= 0x6f9: + for cp in label: + if 0x660 <= ord(cp) <= 0x0669: + return False + return True + + +def check_label(label): + + if isinstance(label, (bytes, bytearray)): + label = label.decode('utf-8') + if len(label) == 0: + raise IDNAError('Empty Label') + + check_nfc(label) + check_hyphen_ok(label) + check_initial_combiner(label) + + for (pos, cp) in enumerate(label): + cp_value = ord(cp) + if intranges_contain(cp_value, idnadata.codepoint_classes['PVALID']): + continue + elif intranges_contain(cp_value, idnadata.codepoint_classes['CONTEXTJ']): + try: + if not valid_contextj(label, pos): + raise InvalidCodepointContext('Joiner {0} not allowed at position {1} in {2}'.format( + _unot(cp_value), pos+1, repr(label))) + except ValueError: + raise IDNAError('Unknown codepoint adjacent to joiner {0} at position {1} in {2}'.format( + _unot(cp_value), pos+1, repr(label))) + elif intranges_contain(cp_value, idnadata.codepoint_classes['CONTEXTO']): + if not valid_contexto(label, pos): + raise InvalidCodepointContext('Codepoint {0} not allowed at position {1} in {2}'.format(_unot(cp_value), pos+1, repr(label))) + else: + raise InvalidCodepoint('Codepoint {0} at position {1} of {2} not allowed'.format(_unot(cp_value), pos+1, repr(label))) + + check_bidi(label) + + +def alabel(label): + + try: + label = label.encode('ascii') + ulabel(label) + if not valid_label_length(label): + raise IDNAError('Label too long') + return label + except UnicodeEncodeError: + pass + + if not label: + raise IDNAError('No Input') + + label = unicode(label) + check_label(label) + label = _punycode(label) + label = _alabel_prefix + label + + if not valid_label_length(label): + raise IDNAError('Label too long') + + return label + + +def ulabel(label): + + if not isinstance(label, (bytes, bytearray)): + try: + label = label.encode('ascii') + except UnicodeEncodeError: + check_label(label) + return label + + label = label.lower() + if label.startswith(_alabel_prefix): + label = label[len(_alabel_prefix):] + if not label: + raise IDNAError('Malformed A-label, no Punycode eligible content found') + if label.decode('ascii')[-1] == '-': + raise IDNAError('A-label must not end with a hyphen') + else: + check_label(label) + return label.decode('ascii') + + label = label.decode('punycode') + check_label(label) + return label + + +def uts46_remap(domain, std3_rules=True, transitional=False): + """Re-map the characters in the string according to UTS46 processing.""" + from .uts46data import uts46data + output = u"" + try: + for pos, char in enumerate(domain): + code_point = ord(char) + uts46row = uts46data[code_point if code_point < 256 else + bisect.bisect_left(uts46data, (code_point, "Z")) - 1] + status = uts46row[1] + replacement = uts46row[2] if len(uts46row) == 3 else None + if (status == "V" or + (status == "D" and not transitional) or + (status == "3" and not std3_rules and replacement is None)): + output += char + elif replacement is not None and (status == "M" or + (status == "3" and not std3_rules) or + (status == "D" and transitional)): + output += replacement + elif status != "I": + raise IndexError() + return unicodedata.normalize("NFC", output) + except IndexError: + raise InvalidCodepoint( + "Codepoint {0} not allowed at position {1} in {2}".format( + _unot(code_point), pos + 1, repr(domain))) + + +def encode(s, strict=False, uts46=False, std3_rules=False, transitional=False): + + if isinstance(s, (bytes, bytearray)): + s = s.decode("ascii") + if uts46: + s = uts46_remap(s, std3_rules, transitional) + trailing_dot = False + result = [] + if strict: + labels = s.split('.') + else: + labels = _unicode_dots_re.split(s) + if not labels or labels == ['']: + raise IDNAError('Empty domain') + if labels[-1] == '': + del labels[-1] + trailing_dot = True + for label in labels: + s = alabel(label) + if s: + result.append(s) + else: + raise IDNAError('Empty label') + if trailing_dot: + result.append(b'') + s = b'.'.join(result) + if not valid_string_length(s, trailing_dot): + raise IDNAError('Domain too long') + return s + + +def decode(s, strict=False, uts46=False, std3_rules=False): + + if isinstance(s, (bytes, bytearray)): + s = s.decode("ascii") + if uts46: + s = uts46_remap(s, std3_rules, False) + trailing_dot = False + result = [] + if not strict: + labels = _unicode_dots_re.split(s) + else: + labels = s.split(u'.') + if not labels or labels == ['']: + raise IDNAError('Empty domain') + if not labels[-1]: + del labels[-1] + trailing_dot = True + for label in labels: + s = ulabel(label) + if s: + result.append(s) + else: + raise IDNAError('Empty label') + if trailing_dot: + result.append(u'') + return u'.'.join(result) diff --git a/openpype/vendor/python/python_2/idna/idnadata.py b/openpype/vendor/python/python_2/idna/idnadata.py new file mode 100644 index 0000000000..a284e4c84a --- /dev/null +++ b/openpype/vendor/python/python_2/idna/idnadata.py @@ -0,0 +1,2050 @@ +# This file is automatically generated by tools/idna-data + +__version__ = "13.0.0" +scripts = { + 'Greek': ( + 0x37000000374, + 0x37500000378, + 0x37a0000037e, + 0x37f00000380, + 0x38400000385, + 0x38600000387, + 0x3880000038b, + 0x38c0000038d, + 0x38e000003a2, + 0x3a3000003e2, + 0x3f000000400, + 0x1d2600001d2b, + 0x1d5d00001d62, + 0x1d6600001d6b, + 0x1dbf00001dc0, + 0x1f0000001f16, + 0x1f1800001f1e, + 0x1f2000001f46, + 0x1f4800001f4e, + 0x1f5000001f58, + 0x1f5900001f5a, + 0x1f5b00001f5c, + 0x1f5d00001f5e, + 0x1f5f00001f7e, + 0x1f8000001fb5, + 0x1fb600001fc5, + 0x1fc600001fd4, + 0x1fd600001fdc, + 0x1fdd00001ff0, + 0x1ff200001ff5, + 0x1ff600001fff, + 0x212600002127, + 0xab650000ab66, + 0x101400001018f, + 0x101a0000101a1, + 0x1d2000001d246, + ), + 'Han': ( + 0x2e8000002e9a, + 0x2e9b00002ef4, + 0x2f0000002fd6, + 0x300500003006, + 0x300700003008, + 0x30210000302a, + 0x30380000303c, + 0x340000004dc0, + 0x4e0000009ffd, + 0xf9000000fa6e, + 0xfa700000fada, + 0x16ff000016ff2, + 0x200000002a6de, + 0x2a7000002b735, + 0x2b7400002b81e, + 0x2b8200002cea2, + 0x2ceb00002ebe1, + 0x2f8000002fa1e, + 0x300000003134b, + ), + 'Hebrew': ( + 0x591000005c8, + 0x5d0000005eb, + 0x5ef000005f5, + 0xfb1d0000fb37, + 0xfb380000fb3d, + 0xfb3e0000fb3f, + 0xfb400000fb42, + 0xfb430000fb45, + 0xfb460000fb50, + ), + 'Hiragana': ( + 0x304100003097, + 0x309d000030a0, + 0x1b0010001b11f, + 0x1b1500001b153, + 0x1f2000001f201, + ), + 'Katakana': ( + 0x30a1000030fb, + 0x30fd00003100, + 0x31f000003200, + 0x32d0000032ff, + 0x330000003358, + 0xff660000ff70, + 0xff710000ff9e, + 0x1b0000001b001, + 0x1b1640001b168, + ), +} +joining_types = { + 0x600: 85, + 0x601: 85, + 0x602: 85, + 0x603: 85, + 0x604: 85, + 0x605: 85, + 0x608: 85, + 0x60b: 85, + 0x620: 68, + 0x621: 85, + 0x622: 82, + 0x623: 82, + 0x624: 82, + 0x625: 82, + 0x626: 68, + 0x627: 82, + 0x628: 68, + 0x629: 82, + 0x62a: 68, + 0x62b: 68, + 0x62c: 68, + 0x62d: 68, + 0x62e: 68, + 0x62f: 82, + 0x630: 82, + 0x631: 82, + 0x632: 82, + 0x633: 68, + 0x634: 68, + 0x635: 68, + 0x636: 68, + 0x637: 68, + 0x638: 68, + 0x639: 68, + 0x63a: 68, + 0x63b: 68, + 0x63c: 68, + 0x63d: 68, + 0x63e: 68, + 0x63f: 68, + 0x640: 67, + 0x641: 68, + 0x642: 68, + 0x643: 68, + 0x644: 68, + 0x645: 68, + 0x646: 68, + 0x647: 68, + 0x648: 82, + 0x649: 68, + 0x64a: 68, + 0x66e: 68, + 0x66f: 68, + 0x671: 82, + 0x672: 82, + 0x673: 82, + 0x674: 85, + 0x675: 82, + 0x676: 82, + 0x677: 82, + 0x678: 68, + 0x679: 68, + 0x67a: 68, + 0x67b: 68, + 0x67c: 68, + 0x67d: 68, + 0x67e: 68, + 0x67f: 68, + 0x680: 68, + 0x681: 68, + 0x682: 68, + 0x683: 68, + 0x684: 68, + 0x685: 68, + 0x686: 68, + 0x687: 68, + 0x688: 82, + 0x689: 82, + 0x68a: 82, + 0x68b: 82, + 0x68c: 82, + 0x68d: 82, + 0x68e: 82, + 0x68f: 82, + 0x690: 82, + 0x691: 82, + 0x692: 82, + 0x693: 82, + 0x694: 82, + 0x695: 82, + 0x696: 82, + 0x697: 82, + 0x698: 82, + 0x699: 82, + 0x69a: 68, + 0x69b: 68, + 0x69c: 68, + 0x69d: 68, + 0x69e: 68, + 0x69f: 68, + 0x6a0: 68, + 0x6a1: 68, + 0x6a2: 68, + 0x6a3: 68, + 0x6a4: 68, + 0x6a5: 68, + 0x6a6: 68, + 0x6a7: 68, + 0x6a8: 68, + 0x6a9: 68, + 0x6aa: 68, + 0x6ab: 68, + 0x6ac: 68, + 0x6ad: 68, + 0x6ae: 68, + 0x6af: 68, + 0x6b0: 68, + 0x6b1: 68, + 0x6b2: 68, + 0x6b3: 68, + 0x6b4: 68, + 0x6b5: 68, + 0x6b6: 68, + 0x6b7: 68, + 0x6b8: 68, + 0x6b9: 68, + 0x6ba: 68, + 0x6bb: 68, + 0x6bc: 68, + 0x6bd: 68, + 0x6be: 68, + 0x6bf: 68, + 0x6c0: 82, + 0x6c1: 68, + 0x6c2: 68, + 0x6c3: 82, + 0x6c4: 82, + 0x6c5: 82, + 0x6c6: 82, + 0x6c7: 82, + 0x6c8: 82, + 0x6c9: 82, + 0x6ca: 82, + 0x6cb: 82, + 0x6cc: 68, + 0x6cd: 82, + 0x6ce: 68, + 0x6cf: 82, + 0x6d0: 68, + 0x6d1: 68, + 0x6d2: 82, + 0x6d3: 82, + 0x6d5: 82, + 0x6dd: 85, + 0x6ee: 82, + 0x6ef: 82, + 0x6fa: 68, + 0x6fb: 68, + 0x6fc: 68, + 0x6ff: 68, + 0x70f: 84, + 0x710: 82, + 0x712: 68, + 0x713: 68, + 0x714: 68, + 0x715: 82, + 0x716: 82, + 0x717: 82, + 0x718: 82, + 0x719: 82, + 0x71a: 68, + 0x71b: 68, + 0x71c: 68, + 0x71d: 68, + 0x71e: 82, + 0x71f: 68, + 0x720: 68, + 0x721: 68, + 0x722: 68, + 0x723: 68, + 0x724: 68, + 0x725: 68, + 0x726: 68, + 0x727: 68, + 0x728: 82, + 0x729: 68, + 0x72a: 82, + 0x72b: 68, + 0x72c: 82, + 0x72d: 68, + 0x72e: 68, + 0x72f: 82, + 0x74d: 82, + 0x74e: 68, + 0x74f: 68, + 0x750: 68, + 0x751: 68, + 0x752: 68, + 0x753: 68, + 0x754: 68, + 0x755: 68, + 0x756: 68, + 0x757: 68, + 0x758: 68, + 0x759: 82, + 0x75a: 82, + 0x75b: 82, + 0x75c: 68, + 0x75d: 68, + 0x75e: 68, + 0x75f: 68, + 0x760: 68, + 0x761: 68, + 0x762: 68, + 0x763: 68, + 0x764: 68, + 0x765: 68, + 0x766: 68, + 0x767: 68, + 0x768: 68, + 0x769: 68, + 0x76a: 68, + 0x76b: 82, + 0x76c: 82, + 0x76d: 68, + 0x76e: 68, + 0x76f: 68, + 0x770: 68, + 0x771: 82, + 0x772: 68, + 0x773: 82, + 0x774: 82, + 0x775: 68, + 0x776: 68, + 0x777: 68, + 0x778: 82, + 0x779: 82, + 0x77a: 68, + 0x77b: 68, + 0x77c: 68, + 0x77d: 68, + 0x77e: 68, + 0x77f: 68, + 0x7ca: 68, + 0x7cb: 68, + 0x7cc: 68, + 0x7cd: 68, + 0x7ce: 68, + 0x7cf: 68, + 0x7d0: 68, + 0x7d1: 68, + 0x7d2: 68, + 0x7d3: 68, + 0x7d4: 68, + 0x7d5: 68, + 0x7d6: 68, + 0x7d7: 68, + 0x7d8: 68, + 0x7d9: 68, + 0x7da: 68, + 0x7db: 68, + 0x7dc: 68, + 0x7dd: 68, + 0x7de: 68, + 0x7df: 68, + 0x7e0: 68, + 0x7e1: 68, + 0x7e2: 68, + 0x7e3: 68, + 0x7e4: 68, + 0x7e5: 68, + 0x7e6: 68, + 0x7e7: 68, + 0x7e8: 68, + 0x7e9: 68, + 0x7ea: 68, + 0x7fa: 67, + 0x840: 82, + 0x841: 68, + 0x842: 68, + 0x843: 68, + 0x844: 68, + 0x845: 68, + 0x846: 82, + 0x847: 82, + 0x848: 68, + 0x849: 82, + 0x84a: 68, + 0x84b: 68, + 0x84c: 68, + 0x84d: 68, + 0x84e: 68, + 0x84f: 68, + 0x850: 68, + 0x851: 68, + 0x852: 68, + 0x853: 68, + 0x854: 82, + 0x855: 68, + 0x856: 82, + 0x857: 82, + 0x858: 82, + 0x860: 68, + 0x861: 85, + 0x862: 68, + 0x863: 68, + 0x864: 68, + 0x865: 68, + 0x866: 85, + 0x867: 82, + 0x868: 68, + 0x869: 82, + 0x86a: 82, + 0x8a0: 68, + 0x8a1: 68, + 0x8a2: 68, + 0x8a3: 68, + 0x8a4: 68, + 0x8a5: 68, + 0x8a6: 68, + 0x8a7: 68, + 0x8a8: 68, + 0x8a9: 68, + 0x8aa: 82, + 0x8ab: 82, + 0x8ac: 82, + 0x8ad: 85, + 0x8ae: 82, + 0x8af: 68, + 0x8b0: 68, + 0x8b1: 82, + 0x8b2: 82, + 0x8b3: 68, + 0x8b4: 68, + 0x8b6: 68, + 0x8b7: 68, + 0x8b8: 68, + 0x8b9: 82, + 0x8ba: 68, + 0x8bb: 68, + 0x8bc: 68, + 0x8bd: 68, + 0x8be: 68, + 0x8bf: 68, + 0x8c0: 68, + 0x8c1: 68, + 0x8c2: 68, + 0x8c3: 68, + 0x8c4: 68, + 0x8c5: 68, + 0x8c6: 68, + 0x8c7: 68, + 0x8e2: 85, + 0x1806: 85, + 0x1807: 68, + 0x180a: 67, + 0x180e: 85, + 0x1820: 68, + 0x1821: 68, + 0x1822: 68, + 0x1823: 68, + 0x1824: 68, + 0x1825: 68, + 0x1826: 68, + 0x1827: 68, + 0x1828: 68, + 0x1829: 68, + 0x182a: 68, + 0x182b: 68, + 0x182c: 68, + 0x182d: 68, + 0x182e: 68, + 0x182f: 68, + 0x1830: 68, + 0x1831: 68, + 0x1832: 68, + 0x1833: 68, + 0x1834: 68, + 0x1835: 68, + 0x1836: 68, + 0x1837: 68, + 0x1838: 68, + 0x1839: 68, + 0x183a: 68, + 0x183b: 68, + 0x183c: 68, + 0x183d: 68, + 0x183e: 68, + 0x183f: 68, + 0x1840: 68, + 0x1841: 68, + 0x1842: 68, + 0x1843: 68, + 0x1844: 68, + 0x1845: 68, + 0x1846: 68, + 0x1847: 68, + 0x1848: 68, + 0x1849: 68, + 0x184a: 68, + 0x184b: 68, + 0x184c: 68, + 0x184d: 68, + 0x184e: 68, + 0x184f: 68, + 0x1850: 68, + 0x1851: 68, + 0x1852: 68, + 0x1853: 68, + 0x1854: 68, + 0x1855: 68, + 0x1856: 68, + 0x1857: 68, + 0x1858: 68, + 0x1859: 68, + 0x185a: 68, + 0x185b: 68, + 0x185c: 68, + 0x185d: 68, + 0x185e: 68, + 0x185f: 68, + 0x1860: 68, + 0x1861: 68, + 0x1862: 68, + 0x1863: 68, + 0x1864: 68, + 0x1865: 68, + 0x1866: 68, + 0x1867: 68, + 0x1868: 68, + 0x1869: 68, + 0x186a: 68, + 0x186b: 68, + 0x186c: 68, + 0x186d: 68, + 0x186e: 68, + 0x186f: 68, + 0x1870: 68, + 0x1871: 68, + 0x1872: 68, + 0x1873: 68, + 0x1874: 68, + 0x1875: 68, + 0x1876: 68, + 0x1877: 68, + 0x1878: 68, + 0x1880: 85, + 0x1881: 85, + 0x1882: 85, + 0x1883: 85, + 0x1884: 85, + 0x1885: 84, + 0x1886: 84, + 0x1887: 68, + 0x1888: 68, + 0x1889: 68, + 0x188a: 68, + 0x188b: 68, + 0x188c: 68, + 0x188d: 68, + 0x188e: 68, + 0x188f: 68, + 0x1890: 68, + 0x1891: 68, + 0x1892: 68, + 0x1893: 68, + 0x1894: 68, + 0x1895: 68, + 0x1896: 68, + 0x1897: 68, + 0x1898: 68, + 0x1899: 68, + 0x189a: 68, + 0x189b: 68, + 0x189c: 68, + 0x189d: 68, + 0x189e: 68, + 0x189f: 68, + 0x18a0: 68, + 0x18a1: 68, + 0x18a2: 68, + 0x18a3: 68, + 0x18a4: 68, + 0x18a5: 68, + 0x18a6: 68, + 0x18a7: 68, + 0x18a8: 68, + 0x18aa: 68, + 0x200c: 85, + 0x200d: 67, + 0x202f: 85, + 0x2066: 85, + 0x2067: 85, + 0x2068: 85, + 0x2069: 85, + 0xa840: 68, + 0xa841: 68, + 0xa842: 68, + 0xa843: 68, + 0xa844: 68, + 0xa845: 68, + 0xa846: 68, + 0xa847: 68, + 0xa848: 68, + 0xa849: 68, + 0xa84a: 68, + 0xa84b: 68, + 0xa84c: 68, + 0xa84d: 68, + 0xa84e: 68, + 0xa84f: 68, + 0xa850: 68, + 0xa851: 68, + 0xa852: 68, + 0xa853: 68, + 0xa854: 68, + 0xa855: 68, + 0xa856: 68, + 0xa857: 68, + 0xa858: 68, + 0xa859: 68, + 0xa85a: 68, + 0xa85b: 68, + 0xa85c: 68, + 0xa85d: 68, + 0xa85e: 68, + 0xa85f: 68, + 0xa860: 68, + 0xa861: 68, + 0xa862: 68, + 0xa863: 68, + 0xa864: 68, + 0xa865: 68, + 0xa866: 68, + 0xa867: 68, + 0xa868: 68, + 0xa869: 68, + 0xa86a: 68, + 0xa86b: 68, + 0xa86c: 68, + 0xa86d: 68, + 0xa86e: 68, + 0xa86f: 68, + 0xa870: 68, + 0xa871: 68, + 0xa872: 76, + 0xa873: 85, + 0x10ac0: 68, + 0x10ac1: 68, + 0x10ac2: 68, + 0x10ac3: 68, + 0x10ac4: 68, + 0x10ac5: 82, + 0x10ac6: 85, + 0x10ac7: 82, + 0x10ac8: 85, + 0x10ac9: 82, + 0x10aca: 82, + 0x10acb: 85, + 0x10acc: 85, + 0x10acd: 76, + 0x10ace: 82, + 0x10acf: 82, + 0x10ad0: 82, + 0x10ad1: 82, + 0x10ad2: 82, + 0x10ad3: 68, + 0x10ad4: 68, + 0x10ad5: 68, + 0x10ad6: 68, + 0x10ad7: 76, + 0x10ad8: 68, + 0x10ad9: 68, + 0x10ada: 68, + 0x10adb: 68, + 0x10adc: 68, + 0x10add: 82, + 0x10ade: 68, + 0x10adf: 68, + 0x10ae0: 68, + 0x10ae1: 82, + 0x10ae2: 85, + 0x10ae3: 85, + 0x10ae4: 82, + 0x10aeb: 68, + 0x10aec: 68, + 0x10aed: 68, + 0x10aee: 68, + 0x10aef: 82, + 0x10b80: 68, + 0x10b81: 82, + 0x10b82: 68, + 0x10b83: 82, + 0x10b84: 82, + 0x10b85: 82, + 0x10b86: 68, + 0x10b87: 68, + 0x10b88: 68, + 0x10b89: 82, + 0x10b8a: 68, + 0x10b8b: 68, + 0x10b8c: 82, + 0x10b8d: 68, + 0x10b8e: 82, + 0x10b8f: 82, + 0x10b90: 68, + 0x10b91: 82, + 0x10ba9: 82, + 0x10baa: 82, + 0x10bab: 82, + 0x10bac: 82, + 0x10bad: 68, + 0x10bae: 68, + 0x10baf: 85, + 0x10d00: 76, + 0x10d01: 68, + 0x10d02: 68, + 0x10d03: 68, + 0x10d04: 68, + 0x10d05: 68, + 0x10d06: 68, + 0x10d07: 68, + 0x10d08: 68, + 0x10d09: 68, + 0x10d0a: 68, + 0x10d0b: 68, + 0x10d0c: 68, + 0x10d0d: 68, + 0x10d0e: 68, + 0x10d0f: 68, + 0x10d10: 68, + 0x10d11: 68, + 0x10d12: 68, + 0x10d13: 68, + 0x10d14: 68, + 0x10d15: 68, + 0x10d16: 68, + 0x10d17: 68, + 0x10d18: 68, + 0x10d19: 68, + 0x10d1a: 68, + 0x10d1b: 68, + 0x10d1c: 68, + 0x10d1d: 68, + 0x10d1e: 68, + 0x10d1f: 68, + 0x10d20: 68, + 0x10d21: 68, + 0x10d22: 82, + 0x10d23: 68, + 0x10f30: 68, + 0x10f31: 68, + 0x10f32: 68, + 0x10f33: 82, + 0x10f34: 68, + 0x10f35: 68, + 0x10f36: 68, + 0x10f37: 68, + 0x10f38: 68, + 0x10f39: 68, + 0x10f3a: 68, + 0x10f3b: 68, + 0x10f3c: 68, + 0x10f3d: 68, + 0x10f3e: 68, + 0x10f3f: 68, + 0x10f40: 68, + 0x10f41: 68, + 0x10f42: 68, + 0x10f43: 68, + 0x10f44: 68, + 0x10f45: 85, + 0x10f51: 68, + 0x10f52: 68, + 0x10f53: 68, + 0x10f54: 82, + 0x10fb0: 68, + 0x10fb1: 85, + 0x10fb2: 68, + 0x10fb3: 68, + 0x10fb4: 82, + 0x10fb5: 82, + 0x10fb6: 82, + 0x10fb7: 85, + 0x10fb8: 68, + 0x10fb9: 82, + 0x10fba: 82, + 0x10fbb: 68, + 0x10fbc: 68, + 0x10fbd: 82, + 0x10fbe: 68, + 0x10fbf: 68, + 0x10fc0: 85, + 0x10fc1: 68, + 0x10fc2: 82, + 0x10fc3: 82, + 0x10fc4: 68, + 0x10fc5: 85, + 0x10fc6: 85, + 0x10fc7: 85, + 0x10fc8: 85, + 0x10fc9: 82, + 0x10fca: 68, + 0x10fcb: 76, + 0x110bd: 85, + 0x110cd: 85, + 0x1e900: 68, + 0x1e901: 68, + 0x1e902: 68, + 0x1e903: 68, + 0x1e904: 68, + 0x1e905: 68, + 0x1e906: 68, + 0x1e907: 68, + 0x1e908: 68, + 0x1e909: 68, + 0x1e90a: 68, + 0x1e90b: 68, + 0x1e90c: 68, + 0x1e90d: 68, + 0x1e90e: 68, + 0x1e90f: 68, + 0x1e910: 68, + 0x1e911: 68, + 0x1e912: 68, + 0x1e913: 68, + 0x1e914: 68, + 0x1e915: 68, + 0x1e916: 68, + 0x1e917: 68, + 0x1e918: 68, + 0x1e919: 68, + 0x1e91a: 68, + 0x1e91b: 68, + 0x1e91c: 68, + 0x1e91d: 68, + 0x1e91e: 68, + 0x1e91f: 68, + 0x1e920: 68, + 0x1e921: 68, + 0x1e922: 68, + 0x1e923: 68, + 0x1e924: 68, + 0x1e925: 68, + 0x1e926: 68, + 0x1e927: 68, + 0x1e928: 68, + 0x1e929: 68, + 0x1e92a: 68, + 0x1e92b: 68, + 0x1e92c: 68, + 0x1e92d: 68, + 0x1e92e: 68, + 0x1e92f: 68, + 0x1e930: 68, + 0x1e931: 68, + 0x1e932: 68, + 0x1e933: 68, + 0x1e934: 68, + 0x1e935: 68, + 0x1e936: 68, + 0x1e937: 68, + 0x1e938: 68, + 0x1e939: 68, + 0x1e93a: 68, + 0x1e93b: 68, + 0x1e93c: 68, + 0x1e93d: 68, + 0x1e93e: 68, + 0x1e93f: 68, + 0x1e940: 68, + 0x1e941: 68, + 0x1e942: 68, + 0x1e943: 68, + 0x1e94b: 84, +} +codepoint_classes = { + 'PVALID': ( + 0x2d0000002e, + 0x300000003a, + 0x610000007b, + 0xdf000000f7, + 0xf800000100, + 0x10100000102, + 0x10300000104, + 0x10500000106, + 0x10700000108, + 0x1090000010a, + 0x10b0000010c, + 0x10d0000010e, + 0x10f00000110, + 0x11100000112, + 0x11300000114, + 0x11500000116, + 0x11700000118, + 0x1190000011a, + 0x11b0000011c, + 0x11d0000011e, + 0x11f00000120, + 0x12100000122, + 0x12300000124, + 0x12500000126, + 0x12700000128, + 0x1290000012a, + 0x12b0000012c, + 0x12d0000012e, + 0x12f00000130, + 0x13100000132, + 0x13500000136, + 0x13700000139, + 0x13a0000013b, + 0x13c0000013d, + 0x13e0000013f, + 0x14200000143, + 0x14400000145, + 0x14600000147, + 0x14800000149, + 0x14b0000014c, + 0x14d0000014e, + 0x14f00000150, + 0x15100000152, + 0x15300000154, + 0x15500000156, + 0x15700000158, + 0x1590000015a, + 0x15b0000015c, + 0x15d0000015e, + 0x15f00000160, + 0x16100000162, + 0x16300000164, + 0x16500000166, + 0x16700000168, + 0x1690000016a, + 0x16b0000016c, + 0x16d0000016e, + 0x16f00000170, + 0x17100000172, + 0x17300000174, + 0x17500000176, + 0x17700000178, + 0x17a0000017b, + 0x17c0000017d, + 0x17e0000017f, + 0x18000000181, + 0x18300000184, + 0x18500000186, + 0x18800000189, + 0x18c0000018e, + 0x19200000193, + 0x19500000196, + 0x1990000019c, + 0x19e0000019f, + 0x1a1000001a2, + 0x1a3000001a4, + 0x1a5000001a6, + 0x1a8000001a9, + 0x1aa000001ac, + 0x1ad000001ae, + 0x1b0000001b1, + 0x1b4000001b5, + 0x1b6000001b7, + 0x1b9000001bc, + 0x1bd000001c4, + 0x1ce000001cf, + 0x1d0000001d1, + 0x1d2000001d3, + 0x1d4000001d5, + 0x1d6000001d7, + 0x1d8000001d9, + 0x1da000001db, + 0x1dc000001de, + 0x1df000001e0, + 0x1e1000001e2, + 0x1e3000001e4, + 0x1e5000001e6, + 0x1e7000001e8, + 0x1e9000001ea, + 0x1eb000001ec, + 0x1ed000001ee, + 0x1ef000001f1, + 0x1f5000001f6, + 0x1f9000001fa, + 0x1fb000001fc, + 0x1fd000001fe, + 0x1ff00000200, + 0x20100000202, + 0x20300000204, + 0x20500000206, + 0x20700000208, + 0x2090000020a, + 0x20b0000020c, + 0x20d0000020e, + 0x20f00000210, + 0x21100000212, + 0x21300000214, + 0x21500000216, + 0x21700000218, + 0x2190000021a, + 0x21b0000021c, + 0x21d0000021e, + 0x21f00000220, + 0x22100000222, + 0x22300000224, + 0x22500000226, + 0x22700000228, + 0x2290000022a, + 0x22b0000022c, + 0x22d0000022e, + 0x22f00000230, + 0x23100000232, + 0x2330000023a, + 0x23c0000023d, + 0x23f00000241, + 0x24200000243, + 0x24700000248, + 0x2490000024a, + 0x24b0000024c, + 0x24d0000024e, + 0x24f000002b0, + 0x2b9000002c2, + 0x2c6000002d2, + 0x2ec000002ed, + 0x2ee000002ef, + 0x30000000340, + 0x34200000343, + 0x3460000034f, + 0x35000000370, + 0x37100000372, + 0x37300000374, + 0x37700000378, + 0x37b0000037e, + 0x39000000391, + 0x3ac000003cf, + 0x3d7000003d8, + 0x3d9000003da, + 0x3db000003dc, + 0x3dd000003de, + 0x3df000003e0, + 0x3e1000003e2, + 0x3e3000003e4, + 0x3e5000003e6, + 0x3e7000003e8, + 0x3e9000003ea, + 0x3eb000003ec, + 0x3ed000003ee, + 0x3ef000003f0, + 0x3f3000003f4, + 0x3f8000003f9, + 0x3fb000003fd, + 0x43000000460, + 0x46100000462, + 0x46300000464, + 0x46500000466, + 0x46700000468, + 0x4690000046a, + 0x46b0000046c, + 0x46d0000046e, + 0x46f00000470, + 0x47100000472, + 0x47300000474, + 0x47500000476, + 0x47700000478, + 0x4790000047a, + 0x47b0000047c, + 0x47d0000047e, + 0x47f00000480, + 0x48100000482, + 0x48300000488, + 0x48b0000048c, + 0x48d0000048e, + 0x48f00000490, + 0x49100000492, + 0x49300000494, + 0x49500000496, + 0x49700000498, + 0x4990000049a, + 0x49b0000049c, + 0x49d0000049e, + 0x49f000004a0, + 0x4a1000004a2, + 0x4a3000004a4, + 0x4a5000004a6, + 0x4a7000004a8, + 0x4a9000004aa, + 0x4ab000004ac, + 0x4ad000004ae, + 0x4af000004b0, + 0x4b1000004b2, + 0x4b3000004b4, + 0x4b5000004b6, + 0x4b7000004b8, + 0x4b9000004ba, + 0x4bb000004bc, + 0x4bd000004be, + 0x4bf000004c0, + 0x4c2000004c3, + 0x4c4000004c5, + 0x4c6000004c7, + 0x4c8000004c9, + 0x4ca000004cb, + 0x4cc000004cd, + 0x4ce000004d0, + 0x4d1000004d2, + 0x4d3000004d4, + 0x4d5000004d6, + 0x4d7000004d8, + 0x4d9000004da, + 0x4db000004dc, + 0x4dd000004de, + 0x4df000004e0, + 0x4e1000004e2, + 0x4e3000004e4, + 0x4e5000004e6, + 0x4e7000004e8, + 0x4e9000004ea, + 0x4eb000004ec, + 0x4ed000004ee, + 0x4ef000004f0, + 0x4f1000004f2, + 0x4f3000004f4, + 0x4f5000004f6, + 0x4f7000004f8, + 0x4f9000004fa, + 0x4fb000004fc, + 0x4fd000004fe, + 0x4ff00000500, + 0x50100000502, + 0x50300000504, + 0x50500000506, + 0x50700000508, + 0x5090000050a, + 0x50b0000050c, + 0x50d0000050e, + 0x50f00000510, + 0x51100000512, + 0x51300000514, + 0x51500000516, + 0x51700000518, + 0x5190000051a, + 0x51b0000051c, + 0x51d0000051e, + 0x51f00000520, + 0x52100000522, + 0x52300000524, + 0x52500000526, + 0x52700000528, + 0x5290000052a, + 0x52b0000052c, + 0x52d0000052e, + 0x52f00000530, + 0x5590000055a, + 0x56000000587, + 0x58800000589, + 0x591000005be, + 0x5bf000005c0, + 0x5c1000005c3, + 0x5c4000005c6, + 0x5c7000005c8, + 0x5d0000005eb, + 0x5ef000005f3, + 0x6100000061b, + 0x62000000640, + 0x64100000660, + 0x66e00000675, + 0x679000006d4, + 0x6d5000006dd, + 0x6df000006e9, + 0x6ea000006f0, + 0x6fa00000700, + 0x7100000074b, + 0x74d000007b2, + 0x7c0000007f6, + 0x7fd000007fe, + 0x8000000082e, + 0x8400000085c, + 0x8600000086b, + 0x8a0000008b5, + 0x8b6000008c8, + 0x8d3000008e2, + 0x8e300000958, + 0x96000000964, + 0x96600000970, + 0x97100000984, + 0x9850000098d, + 0x98f00000991, + 0x993000009a9, + 0x9aa000009b1, + 0x9b2000009b3, + 0x9b6000009ba, + 0x9bc000009c5, + 0x9c7000009c9, + 0x9cb000009cf, + 0x9d7000009d8, + 0x9e0000009e4, + 0x9e6000009f2, + 0x9fc000009fd, + 0x9fe000009ff, + 0xa0100000a04, + 0xa0500000a0b, + 0xa0f00000a11, + 0xa1300000a29, + 0xa2a00000a31, + 0xa3200000a33, + 0xa3500000a36, + 0xa3800000a3a, + 0xa3c00000a3d, + 0xa3e00000a43, + 0xa4700000a49, + 0xa4b00000a4e, + 0xa5100000a52, + 0xa5c00000a5d, + 0xa6600000a76, + 0xa8100000a84, + 0xa8500000a8e, + 0xa8f00000a92, + 0xa9300000aa9, + 0xaaa00000ab1, + 0xab200000ab4, + 0xab500000aba, + 0xabc00000ac6, + 0xac700000aca, + 0xacb00000ace, + 0xad000000ad1, + 0xae000000ae4, + 0xae600000af0, + 0xaf900000b00, + 0xb0100000b04, + 0xb0500000b0d, + 0xb0f00000b11, + 0xb1300000b29, + 0xb2a00000b31, + 0xb3200000b34, + 0xb3500000b3a, + 0xb3c00000b45, + 0xb4700000b49, + 0xb4b00000b4e, + 0xb5500000b58, + 0xb5f00000b64, + 0xb6600000b70, + 0xb7100000b72, + 0xb8200000b84, + 0xb8500000b8b, + 0xb8e00000b91, + 0xb9200000b96, + 0xb9900000b9b, + 0xb9c00000b9d, + 0xb9e00000ba0, + 0xba300000ba5, + 0xba800000bab, + 0xbae00000bba, + 0xbbe00000bc3, + 0xbc600000bc9, + 0xbca00000bce, + 0xbd000000bd1, + 0xbd700000bd8, + 0xbe600000bf0, + 0xc0000000c0d, + 0xc0e00000c11, + 0xc1200000c29, + 0xc2a00000c3a, + 0xc3d00000c45, + 0xc4600000c49, + 0xc4a00000c4e, + 0xc5500000c57, + 0xc5800000c5b, + 0xc6000000c64, + 0xc6600000c70, + 0xc8000000c84, + 0xc8500000c8d, + 0xc8e00000c91, + 0xc9200000ca9, + 0xcaa00000cb4, + 0xcb500000cba, + 0xcbc00000cc5, + 0xcc600000cc9, + 0xcca00000cce, + 0xcd500000cd7, + 0xcde00000cdf, + 0xce000000ce4, + 0xce600000cf0, + 0xcf100000cf3, + 0xd0000000d0d, + 0xd0e00000d11, + 0xd1200000d45, + 0xd4600000d49, + 0xd4a00000d4f, + 0xd5400000d58, + 0xd5f00000d64, + 0xd6600000d70, + 0xd7a00000d80, + 0xd8100000d84, + 0xd8500000d97, + 0xd9a00000db2, + 0xdb300000dbc, + 0xdbd00000dbe, + 0xdc000000dc7, + 0xdca00000dcb, + 0xdcf00000dd5, + 0xdd600000dd7, + 0xdd800000de0, + 0xde600000df0, + 0xdf200000df4, + 0xe0100000e33, + 0xe3400000e3b, + 0xe4000000e4f, + 0xe5000000e5a, + 0xe8100000e83, + 0xe8400000e85, + 0xe8600000e8b, + 0xe8c00000ea4, + 0xea500000ea6, + 0xea700000eb3, + 0xeb400000ebe, + 0xec000000ec5, + 0xec600000ec7, + 0xec800000ece, + 0xed000000eda, + 0xede00000ee0, + 0xf0000000f01, + 0xf0b00000f0c, + 0xf1800000f1a, + 0xf2000000f2a, + 0xf3500000f36, + 0xf3700000f38, + 0xf3900000f3a, + 0xf3e00000f43, + 0xf4400000f48, + 0xf4900000f4d, + 0xf4e00000f52, + 0xf5300000f57, + 0xf5800000f5c, + 0xf5d00000f69, + 0xf6a00000f6d, + 0xf7100000f73, + 0xf7400000f75, + 0xf7a00000f81, + 0xf8200000f85, + 0xf8600000f93, + 0xf9400000f98, + 0xf9900000f9d, + 0xf9e00000fa2, + 0xfa300000fa7, + 0xfa800000fac, + 0xfad00000fb9, + 0xfba00000fbd, + 0xfc600000fc7, + 0x10000000104a, + 0x10500000109e, + 0x10d0000010fb, + 0x10fd00001100, + 0x120000001249, + 0x124a0000124e, + 0x125000001257, + 0x125800001259, + 0x125a0000125e, + 0x126000001289, + 0x128a0000128e, + 0x1290000012b1, + 0x12b2000012b6, + 0x12b8000012bf, + 0x12c0000012c1, + 0x12c2000012c6, + 0x12c8000012d7, + 0x12d800001311, + 0x131200001316, + 0x13180000135b, + 0x135d00001360, + 0x138000001390, + 0x13a0000013f6, + 0x14010000166d, + 0x166f00001680, + 0x16810000169b, + 0x16a0000016eb, + 0x16f1000016f9, + 0x17000000170d, + 0x170e00001715, + 0x172000001735, + 0x174000001754, + 0x17600000176d, + 0x176e00001771, + 0x177200001774, + 0x1780000017b4, + 0x17b6000017d4, + 0x17d7000017d8, + 0x17dc000017de, + 0x17e0000017ea, + 0x18100000181a, + 0x182000001879, + 0x1880000018ab, + 0x18b0000018f6, + 0x19000000191f, + 0x19200000192c, + 0x19300000193c, + 0x19460000196e, + 0x197000001975, + 0x1980000019ac, + 0x19b0000019ca, + 0x19d0000019da, + 0x1a0000001a1c, + 0x1a2000001a5f, + 0x1a6000001a7d, + 0x1a7f00001a8a, + 0x1a9000001a9a, + 0x1aa700001aa8, + 0x1ab000001abe, + 0x1abf00001ac1, + 0x1b0000001b4c, + 0x1b5000001b5a, + 0x1b6b00001b74, + 0x1b8000001bf4, + 0x1c0000001c38, + 0x1c4000001c4a, + 0x1c4d00001c7e, + 0x1cd000001cd3, + 0x1cd400001cfb, + 0x1d0000001d2c, + 0x1d2f00001d30, + 0x1d3b00001d3c, + 0x1d4e00001d4f, + 0x1d6b00001d78, + 0x1d7900001d9b, + 0x1dc000001dfa, + 0x1dfb00001e00, + 0x1e0100001e02, + 0x1e0300001e04, + 0x1e0500001e06, + 0x1e0700001e08, + 0x1e0900001e0a, + 0x1e0b00001e0c, + 0x1e0d00001e0e, + 0x1e0f00001e10, + 0x1e1100001e12, + 0x1e1300001e14, + 0x1e1500001e16, + 0x1e1700001e18, + 0x1e1900001e1a, + 0x1e1b00001e1c, + 0x1e1d00001e1e, + 0x1e1f00001e20, + 0x1e2100001e22, + 0x1e2300001e24, + 0x1e2500001e26, + 0x1e2700001e28, + 0x1e2900001e2a, + 0x1e2b00001e2c, + 0x1e2d00001e2e, + 0x1e2f00001e30, + 0x1e3100001e32, + 0x1e3300001e34, + 0x1e3500001e36, + 0x1e3700001e38, + 0x1e3900001e3a, + 0x1e3b00001e3c, + 0x1e3d00001e3e, + 0x1e3f00001e40, + 0x1e4100001e42, + 0x1e4300001e44, + 0x1e4500001e46, + 0x1e4700001e48, + 0x1e4900001e4a, + 0x1e4b00001e4c, + 0x1e4d00001e4e, + 0x1e4f00001e50, + 0x1e5100001e52, + 0x1e5300001e54, + 0x1e5500001e56, + 0x1e5700001e58, + 0x1e5900001e5a, + 0x1e5b00001e5c, + 0x1e5d00001e5e, + 0x1e5f00001e60, + 0x1e6100001e62, + 0x1e6300001e64, + 0x1e6500001e66, + 0x1e6700001e68, + 0x1e6900001e6a, + 0x1e6b00001e6c, + 0x1e6d00001e6e, + 0x1e6f00001e70, + 0x1e7100001e72, + 0x1e7300001e74, + 0x1e7500001e76, + 0x1e7700001e78, + 0x1e7900001e7a, + 0x1e7b00001e7c, + 0x1e7d00001e7e, + 0x1e7f00001e80, + 0x1e8100001e82, + 0x1e8300001e84, + 0x1e8500001e86, + 0x1e8700001e88, + 0x1e8900001e8a, + 0x1e8b00001e8c, + 0x1e8d00001e8e, + 0x1e8f00001e90, + 0x1e9100001e92, + 0x1e9300001e94, + 0x1e9500001e9a, + 0x1e9c00001e9e, + 0x1e9f00001ea0, + 0x1ea100001ea2, + 0x1ea300001ea4, + 0x1ea500001ea6, + 0x1ea700001ea8, + 0x1ea900001eaa, + 0x1eab00001eac, + 0x1ead00001eae, + 0x1eaf00001eb0, + 0x1eb100001eb2, + 0x1eb300001eb4, + 0x1eb500001eb6, + 0x1eb700001eb8, + 0x1eb900001eba, + 0x1ebb00001ebc, + 0x1ebd00001ebe, + 0x1ebf00001ec0, + 0x1ec100001ec2, + 0x1ec300001ec4, + 0x1ec500001ec6, + 0x1ec700001ec8, + 0x1ec900001eca, + 0x1ecb00001ecc, + 0x1ecd00001ece, + 0x1ecf00001ed0, + 0x1ed100001ed2, + 0x1ed300001ed4, + 0x1ed500001ed6, + 0x1ed700001ed8, + 0x1ed900001eda, + 0x1edb00001edc, + 0x1edd00001ede, + 0x1edf00001ee0, + 0x1ee100001ee2, + 0x1ee300001ee4, + 0x1ee500001ee6, + 0x1ee700001ee8, + 0x1ee900001eea, + 0x1eeb00001eec, + 0x1eed00001eee, + 0x1eef00001ef0, + 0x1ef100001ef2, + 0x1ef300001ef4, + 0x1ef500001ef6, + 0x1ef700001ef8, + 0x1ef900001efa, + 0x1efb00001efc, + 0x1efd00001efe, + 0x1eff00001f08, + 0x1f1000001f16, + 0x1f2000001f28, + 0x1f3000001f38, + 0x1f4000001f46, + 0x1f5000001f58, + 0x1f6000001f68, + 0x1f7000001f71, + 0x1f7200001f73, + 0x1f7400001f75, + 0x1f7600001f77, + 0x1f7800001f79, + 0x1f7a00001f7b, + 0x1f7c00001f7d, + 0x1fb000001fb2, + 0x1fb600001fb7, + 0x1fc600001fc7, + 0x1fd000001fd3, + 0x1fd600001fd8, + 0x1fe000001fe3, + 0x1fe400001fe8, + 0x1ff600001ff7, + 0x214e0000214f, + 0x218400002185, + 0x2c3000002c5f, + 0x2c6100002c62, + 0x2c6500002c67, + 0x2c6800002c69, + 0x2c6a00002c6b, + 0x2c6c00002c6d, + 0x2c7100002c72, + 0x2c7300002c75, + 0x2c7600002c7c, + 0x2c8100002c82, + 0x2c8300002c84, + 0x2c8500002c86, + 0x2c8700002c88, + 0x2c8900002c8a, + 0x2c8b00002c8c, + 0x2c8d00002c8e, + 0x2c8f00002c90, + 0x2c9100002c92, + 0x2c9300002c94, + 0x2c9500002c96, + 0x2c9700002c98, + 0x2c9900002c9a, + 0x2c9b00002c9c, + 0x2c9d00002c9e, + 0x2c9f00002ca0, + 0x2ca100002ca2, + 0x2ca300002ca4, + 0x2ca500002ca6, + 0x2ca700002ca8, + 0x2ca900002caa, + 0x2cab00002cac, + 0x2cad00002cae, + 0x2caf00002cb0, + 0x2cb100002cb2, + 0x2cb300002cb4, + 0x2cb500002cb6, + 0x2cb700002cb8, + 0x2cb900002cba, + 0x2cbb00002cbc, + 0x2cbd00002cbe, + 0x2cbf00002cc0, + 0x2cc100002cc2, + 0x2cc300002cc4, + 0x2cc500002cc6, + 0x2cc700002cc8, + 0x2cc900002cca, + 0x2ccb00002ccc, + 0x2ccd00002cce, + 0x2ccf00002cd0, + 0x2cd100002cd2, + 0x2cd300002cd4, + 0x2cd500002cd6, + 0x2cd700002cd8, + 0x2cd900002cda, + 0x2cdb00002cdc, + 0x2cdd00002cde, + 0x2cdf00002ce0, + 0x2ce100002ce2, + 0x2ce300002ce5, + 0x2cec00002ced, + 0x2cee00002cf2, + 0x2cf300002cf4, + 0x2d0000002d26, + 0x2d2700002d28, + 0x2d2d00002d2e, + 0x2d3000002d68, + 0x2d7f00002d97, + 0x2da000002da7, + 0x2da800002daf, + 0x2db000002db7, + 0x2db800002dbf, + 0x2dc000002dc7, + 0x2dc800002dcf, + 0x2dd000002dd7, + 0x2dd800002ddf, + 0x2de000002e00, + 0x2e2f00002e30, + 0x300500003008, + 0x302a0000302e, + 0x303c0000303d, + 0x304100003097, + 0x30990000309b, + 0x309d0000309f, + 0x30a1000030fb, + 0x30fc000030ff, + 0x310500003130, + 0x31a0000031c0, + 0x31f000003200, + 0x340000004dc0, + 0x4e0000009ffd, + 0xa0000000a48d, + 0xa4d00000a4fe, + 0xa5000000a60d, + 0xa6100000a62c, + 0xa6410000a642, + 0xa6430000a644, + 0xa6450000a646, + 0xa6470000a648, + 0xa6490000a64a, + 0xa64b0000a64c, + 0xa64d0000a64e, + 0xa64f0000a650, + 0xa6510000a652, + 0xa6530000a654, + 0xa6550000a656, + 0xa6570000a658, + 0xa6590000a65a, + 0xa65b0000a65c, + 0xa65d0000a65e, + 0xa65f0000a660, + 0xa6610000a662, + 0xa6630000a664, + 0xa6650000a666, + 0xa6670000a668, + 0xa6690000a66a, + 0xa66b0000a66c, + 0xa66d0000a670, + 0xa6740000a67e, + 0xa67f0000a680, + 0xa6810000a682, + 0xa6830000a684, + 0xa6850000a686, + 0xa6870000a688, + 0xa6890000a68a, + 0xa68b0000a68c, + 0xa68d0000a68e, + 0xa68f0000a690, + 0xa6910000a692, + 0xa6930000a694, + 0xa6950000a696, + 0xa6970000a698, + 0xa6990000a69a, + 0xa69b0000a69c, + 0xa69e0000a6e6, + 0xa6f00000a6f2, + 0xa7170000a720, + 0xa7230000a724, + 0xa7250000a726, + 0xa7270000a728, + 0xa7290000a72a, + 0xa72b0000a72c, + 0xa72d0000a72e, + 0xa72f0000a732, + 0xa7330000a734, + 0xa7350000a736, + 0xa7370000a738, + 0xa7390000a73a, + 0xa73b0000a73c, + 0xa73d0000a73e, + 0xa73f0000a740, + 0xa7410000a742, + 0xa7430000a744, + 0xa7450000a746, + 0xa7470000a748, + 0xa7490000a74a, + 0xa74b0000a74c, + 0xa74d0000a74e, + 0xa74f0000a750, + 0xa7510000a752, + 0xa7530000a754, + 0xa7550000a756, + 0xa7570000a758, + 0xa7590000a75a, + 0xa75b0000a75c, + 0xa75d0000a75e, + 0xa75f0000a760, + 0xa7610000a762, + 0xa7630000a764, + 0xa7650000a766, + 0xa7670000a768, + 0xa7690000a76a, + 0xa76b0000a76c, + 0xa76d0000a76e, + 0xa76f0000a770, + 0xa7710000a779, + 0xa77a0000a77b, + 0xa77c0000a77d, + 0xa77f0000a780, + 0xa7810000a782, + 0xa7830000a784, + 0xa7850000a786, + 0xa7870000a789, + 0xa78c0000a78d, + 0xa78e0000a790, + 0xa7910000a792, + 0xa7930000a796, + 0xa7970000a798, + 0xa7990000a79a, + 0xa79b0000a79c, + 0xa79d0000a79e, + 0xa79f0000a7a0, + 0xa7a10000a7a2, + 0xa7a30000a7a4, + 0xa7a50000a7a6, + 0xa7a70000a7a8, + 0xa7a90000a7aa, + 0xa7af0000a7b0, + 0xa7b50000a7b6, + 0xa7b70000a7b8, + 0xa7b90000a7ba, + 0xa7bb0000a7bc, + 0xa7bd0000a7be, + 0xa7bf0000a7c0, + 0xa7c30000a7c4, + 0xa7c80000a7c9, + 0xa7ca0000a7cb, + 0xa7f60000a7f8, + 0xa7fa0000a828, + 0xa82c0000a82d, + 0xa8400000a874, + 0xa8800000a8c6, + 0xa8d00000a8da, + 0xa8e00000a8f8, + 0xa8fb0000a8fc, + 0xa8fd0000a92e, + 0xa9300000a954, + 0xa9800000a9c1, + 0xa9cf0000a9da, + 0xa9e00000a9ff, + 0xaa000000aa37, + 0xaa400000aa4e, + 0xaa500000aa5a, + 0xaa600000aa77, + 0xaa7a0000aac3, + 0xaadb0000aade, + 0xaae00000aaf0, + 0xaaf20000aaf7, + 0xab010000ab07, + 0xab090000ab0f, + 0xab110000ab17, + 0xab200000ab27, + 0xab280000ab2f, + 0xab300000ab5b, + 0xab600000ab6a, + 0xabc00000abeb, + 0xabec0000abee, + 0xabf00000abfa, + 0xac000000d7a4, + 0xfa0e0000fa10, + 0xfa110000fa12, + 0xfa130000fa15, + 0xfa1f0000fa20, + 0xfa210000fa22, + 0xfa230000fa25, + 0xfa270000fa2a, + 0xfb1e0000fb1f, + 0xfe200000fe30, + 0xfe730000fe74, + 0x100000001000c, + 0x1000d00010027, + 0x100280001003b, + 0x1003c0001003e, + 0x1003f0001004e, + 0x100500001005e, + 0x10080000100fb, + 0x101fd000101fe, + 0x102800001029d, + 0x102a0000102d1, + 0x102e0000102e1, + 0x1030000010320, + 0x1032d00010341, + 0x103420001034a, + 0x103500001037b, + 0x103800001039e, + 0x103a0000103c4, + 0x103c8000103d0, + 0x104280001049e, + 0x104a0000104aa, + 0x104d8000104fc, + 0x1050000010528, + 0x1053000010564, + 0x1060000010737, + 0x1074000010756, + 0x1076000010768, + 0x1080000010806, + 0x1080800010809, + 0x1080a00010836, + 0x1083700010839, + 0x1083c0001083d, + 0x1083f00010856, + 0x1086000010877, + 0x108800001089f, + 0x108e0000108f3, + 0x108f4000108f6, + 0x1090000010916, + 0x109200001093a, + 0x10980000109b8, + 0x109be000109c0, + 0x10a0000010a04, + 0x10a0500010a07, + 0x10a0c00010a14, + 0x10a1500010a18, + 0x10a1900010a36, + 0x10a3800010a3b, + 0x10a3f00010a40, + 0x10a6000010a7d, + 0x10a8000010a9d, + 0x10ac000010ac8, + 0x10ac900010ae7, + 0x10b0000010b36, + 0x10b4000010b56, + 0x10b6000010b73, + 0x10b8000010b92, + 0x10c0000010c49, + 0x10cc000010cf3, + 0x10d0000010d28, + 0x10d3000010d3a, + 0x10e8000010eaa, + 0x10eab00010ead, + 0x10eb000010eb2, + 0x10f0000010f1d, + 0x10f2700010f28, + 0x10f3000010f51, + 0x10fb000010fc5, + 0x10fe000010ff7, + 0x1100000011047, + 0x1106600011070, + 0x1107f000110bb, + 0x110d0000110e9, + 0x110f0000110fa, + 0x1110000011135, + 0x1113600011140, + 0x1114400011148, + 0x1115000011174, + 0x1117600011177, + 0x11180000111c5, + 0x111c9000111cd, + 0x111ce000111db, + 0x111dc000111dd, + 0x1120000011212, + 0x1121300011238, + 0x1123e0001123f, + 0x1128000011287, + 0x1128800011289, + 0x1128a0001128e, + 0x1128f0001129e, + 0x1129f000112a9, + 0x112b0000112eb, + 0x112f0000112fa, + 0x1130000011304, + 0x113050001130d, + 0x1130f00011311, + 0x1131300011329, + 0x1132a00011331, + 0x1133200011334, + 0x113350001133a, + 0x1133b00011345, + 0x1134700011349, + 0x1134b0001134e, + 0x1135000011351, + 0x1135700011358, + 0x1135d00011364, + 0x113660001136d, + 0x1137000011375, + 0x114000001144b, + 0x114500001145a, + 0x1145e00011462, + 0x11480000114c6, + 0x114c7000114c8, + 0x114d0000114da, + 0x11580000115b6, + 0x115b8000115c1, + 0x115d8000115de, + 0x1160000011641, + 0x1164400011645, + 0x116500001165a, + 0x11680000116b9, + 0x116c0000116ca, + 0x117000001171b, + 0x1171d0001172c, + 0x117300001173a, + 0x118000001183b, + 0x118c0000118ea, + 0x118ff00011907, + 0x119090001190a, + 0x1190c00011914, + 0x1191500011917, + 0x1191800011936, + 0x1193700011939, + 0x1193b00011944, + 0x119500001195a, + 0x119a0000119a8, + 0x119aa000119d8, + 0x119da000119e2, + 0x119e3000119e5, + 0x11a0000011a3f, + 0x11a4700011a48, + 0x11a5000011a9a, + 0x11a9d00011a9e, + 0x11ac000011af9, + 0x11c0000011c09, + 0x11c0a00011c37, + 0x11c3800011c41, + 0x11c5000011c5a, + 0x11c7200011c90, + 0x11c9200011ca8, + 0x11ca900011cb7, + 0x11d0000011d07, + 0x11d0800011d0a, + 0x11d0b00011d37, + 0x11d3a00011d3b, + 0x11d3c00011d3e, + 0x11d3f00011d48, + 0x11d5000011d5a, + 0x11d6000011d66, + 0x11d6700011d69, + 0x11d6a00011d8f, + 0x11d9000011d92, + 0x11d9300011d99, + 0x11da000011daa, + 0x11ee000011ef7, + 0x11fb000011fb1, + 0x120000001239a, + 0x1248000012544, + 0x130000001342f, + 0x1440000014647, + 0x1680000016a39, + 0x16a4000016a5f, + 0x16a6000016a6a, + 0x16ad000016aee, + 0x16af000016af5, + 0x16b0000016b37, + 0x16b4000016b44, + 0x16b5000016b5a, + 0x16b6300016b78, + 0x16b7d00016b90, + 0x16e6000016e80, + 0x16f0000016f4b, + 0x16f4f00016f88, + 0x16f8f00016fa0, + 0x16fe000016fe2, + 0x16fe300016fe5, + 0x16ff000016ff2, + 0x17000000187f8, + 0x1880000018cd6, + 0x18d0000018d09, + 0x1b0000001b11f, + 0x1b1500001b153, + 0x1b1640001b168, + 0x1b1700001b2fc, + 0x1bc000001bc6b, + 0x1bc700001bc7d, + 0x1bc800001bc89, + 0x1bc900001bc9a, + 0x1bc9d0001bc9f, + 0x1da000001da37, + 0x1da3b0001da6d, + 0x1da750001da76, + 0x1da840001da85, + 0x1da9b0001daa0, + 0x1daa10001dab0, + 0x1e0000001e007, + 0x1e0080001e019, + 0x1e01b0001e022, + 0x1e0230001e025, + 0x1e0260001e02b, + 0x1e1000001e12d, + 0x1e1300001e13e, + 0x1e1400001e14a, + 0x1e14e0001e14f, + 0x1e2c00001e2fa, + 0x1e8000001e8c5, + 0x1e8d00001e8d7, + 0x1e9220001e94c, + 0x1e9500001e95a, + 0x1fbf00001fbfa, + 0x200000002a6de, + 0x2a7000002b735, + 0x2b7400002b81e, + 0x2b8200002cea2, + 0x2ceb00002ebe1, + 0x300000003134b, + ), + 'CONTEXTJ': ( + 0x200c0000200e, + ), + 'CONTEXTO': ( + 0xb7000000b8, + 0x37500000376, + 0x5f3000005f5, + 0x6600000066a, + 0x6f0000006fa, + 0x30fb000030fc, + ), +} diff --git a/openpype/vendor/python/python_2/idna/intranges.py b/openpype/vendor/python/python_2/idna/intranges.py new file mode 100644 index 0000000000..fa8a735662 --- /dev/null +++ b/openpype/vendor/python/python_2/idna/intranges.py @@ -0,0 +1,53 @@ +""" +Given a list of integers, made up of (hopefully) a small number of long runs +of consecutive integers, compute a representation of the form +((start1, end1), (start2, end2) ...). Then answer the question "was x present +in the original list?" in time O(log(# runs)). +""" + +import bisect + +def intranges_from_list(list_): + """Represent a list of integers as a sequence of ranges: + ((start_0, end_0), (start_1, end_1), ...), such that the original + integers are exactly those x such that start_i <= x < end_i for some i. + + Ranges are encoded as single integers (start << 32 | end), not as tuples. + """ + + sorted_list = sorted(list_) + ranges = [] + last_write = -1 + for i in range(len(sorted_list)): + if i+1 < len(sorted_list): + if sorted_list[i] == sorted_list[i+1]-1: + continue + current_range = sorted_list[last_write+1:i+1] + ranges.append(_encode_range(current_range[0], current_range[-1] + 1)) + last_write = i + + return tuple(ranges) + +def _encode_range(start, end): + return (start << 32) | end + +def _decode_range(r): + return (r >> 32), (r & ((1 << 32) - 1)) + + +def intranges_contain(int_, ranges): + """Determine if `int_` falls into one of the ranges in `ranges`.""" + tuple_ = _encode_range(int_, 0) + pos = bisect.bisect_left(ranges, tuple_) + # we could be immediately ahead of a tuple (start, end) + # with start < int_ <= end + if pos > 0: + left, right = _decode_range(ranges[pos-1]) + if left <= int_ < right: + return True + # or we could be immediately behind a tuple (int_, end) + if pos < len(ranges): + left, _ = _decode_range(ranges[pos]) + if left == int_: + return True + return False diff --git a/openpype/vendor/python/python_2/idna/package_data.py b/openpype/vendor/python/python_2/idna/package_data.py new file mode 100644 index 0000000000..ce1c521d23 --- /dev/null +++ b/openpype/vendor/python/python_2/idna/package_data.py @@ -0,0 +1,2 @@ +__version__ = '2.10' + diff --git a/openpype/vendor/python/python_2/idna/uts46data.py b/openpype/vendor/python/python_2/idna/uts46data.py new file mode 100644 index 0000000000..3766dd49f6 --- /dev/null +++ b/openpype/vendor/python/python_2/idna/uts46data.py @@ -0,0 +1,8357 @@ +# This file is automatically generated by tools/idna-data +# vim: set fileencoding=utf-8 : + +"""IDNA Mapping Table from UTS46.""" + + +__version__ = "13.0.0" +def _seg_0(): + return [ + (0x0, '3'), + (0x1, '3'), + (0x2, '3'), + (0x3, '3'), + (0x4, '3'), + (0x5, '3'), + (0x6, '3'), + (0x7, '3'), + (0x8, '3'), + (0x9, '3'), + (0xA, '3'), + (0xB, '3'), + (0xC, '3'), + (0xD, '3'), + (0xE, '3'), + (0xF, '3'), + (0x10, '3'), + (0x11, '3'), + (0x12, '3'), + (0x13, '3'), + (0x14, '3'), + (0x15, '3'), + (0x16, '3'), + (0x17, '3'), + (0x18, '3'), + (0x19, '3'), + (0x1A, '3'), + (0x1B, '3'), + (0x1C, '3'), + (0x1D, '3'), + (0x1E, '3'), + (0x1F, '3'), + (0x20, '3'), + (0x21, '3'), + (0x22, '3'), + (0x23, '3'), + (0x24, '3'), + (0x25, '3'), + (0x26, '3'), + (0x27, '3'), + (0x28, '3'), + (0x29, '3'), + (0x2A, '3'), + (0x2B, '3'), + (0x2C, '3'), + (0x2D, 'V'), + (0x2E, 'V'), + (0x2F, '3'), + (0x30, 'V'), + (0x31, 'V'), + (0x32, 'V'), + (0x33, 'V'), + (0x34, 'V'), + (0x35, 'V'), + (0x36, 'V'), + (0x37, 'V'), + (0x38, 'V'), + (0x39, 'V'), + (0x3A, '3'), + (0x3B, '3'), + (0x3C, '3'), + (0x3D, '3'), + (0x3E, '3'), + (0x3F, '3'), + (0x40, '3'), + (0x41, 'M', u'a'), + (0x42, 'M', u'b'), + (0x43, 'M', u'c'), + (0x44, 'M', u'd'), + (0x45, 'M', u'e'), + (0x46, 'M', u'f'), + (0x47, 'M', u'g'), + (0x48, 'M', u'h'), + (0x49, 'M', u'i'), + (0x4A, 'M', u'j'), + (0x4B, 'M', u'k'), + (0x4C, 'M', u'l'), + (0x4D, 'M', u'm'), + (0x4E, 'M', u'n'), + (0x4F, 'M', u'o'), + (0x50, 'M', u'p'), + (0x51, 'M', u'q'), + (0x52, 'M', u'r'), + (0x53, 'M', u's'), + (0x54, 'M', u't'), + (0x55, 'M', u'u'), + (0x56, 'M', u'v'), + (0x57, 'M', u'w'), + (0x58, 'M', u'x'), + (0x59, 'M', u'y'), + (0x5A, 'M', u'z'), + (0x5B, '3'), + (0x5C, '3'), + (0x5D, '3'), + (0x5E, '3'), + (0x5F, '3'), + (0x60, '3'), + (0x61, 'V'), + (0x62, 'V'), + (0x63, 'V'), + ] + +def _seg_1(): + return [ + (0x64, 'V'), + (0x65, 'V'), + (0x66, 'V'), + (0x67, 'V'), + (0x68, 'V'), + (0x69, 'V'), + (0x6A, 'V'), + (0x6B, 'V'), + (0x6C, 'V'), + (0x6D, 'V'), + (0x6E, 'V'), + (0x6F, 'V'), + (0x70, 'V'), + (0x71, 'V'), + (0x72, 'V'), + (0x73, 'V'), + (0x74, 'V'), + (0x75, 'V'), + (0x76, 'V'), + (0x77, 'V'), + (0x78, 'V'), + (0x79, 'V'), + (0x7A, 'V'), + (0x7B, '3'), + (0x7C, '3'), + (0x7D, '3'), + (0x7E, '3'), + (0x7F, '3'), + (0x80, 'X'), + (0x81, 'X'), + (0x82, 'X'), + (0x83, 'X'), + (0x84, 'X'), + (0x85, 'X'), + (0x86, 'X'), + (0x87, 'X'), + (0x88, 'X'), + (0x89, 'X'), + (0x8A, 'X'), + (0x8B, 'X'), + (0x8C, 'X'), + (0x8D, 'X'), + (0x8E, 'X'), + (0x8F, 'X'), + (0x90, 'X'), + (0x91, 'X'), + (0x92, 'X'), + (0x93, 'X'), + (0x94, 'X'), + (0x95, 'X'), + (0x96, 'X'), + (0x97, 'X'), + (0x98, 'X'), + (0x99, 'X'), + (0x9A, 'X'), + (0x9B, 'X'), + (0x9C, 'X'), + (0x9D, 'X'), + (0x9E, 'X'), + (0x9F, 'X'), + (0xA0, '3', u' '), + (0xA1, 'V'), + (0xA2, 'V'), + (0xA3, 'V'), + (0xA4, 'V'), + (0xA5, 'V'), + (0xA6, 'V'), + (0xA7, 'V'), + (0xA8, '3', u' ̈'), + (0xA9, 'V'), + (0xAA, 'M', u'a'), + (0xAB, 'V'), + (0xAC, 'V'), + (0xAD, 'I'), + (0xAE, 'V'), + (0xAF, '3', u' ̄'), + (0xB0, 'V'), + (0xB1, 'V'), + (0xB2, 'M', u'2'), + (0xB3, 'M', u'3'), + (0xB4, '3', u' ́'), + (0xB5, 'M', u'μ'), + (0xB6, 'V'), + (0xB7, 'V'), + (0xB8, '3', u' ̧'), + (0xB9, 'M', u'1'), + (0xBA, 'M', u'o'), + (0xBB, 'V'), + (0xBC, 'M', u'1⁄4'), + (0xBD, 'M', u'1⁄2'), + (0xBE, 'M', u'3⁄4'), + (0xBF, 'V'), + (0xC0, 'M', u'à'), + (0xC1, 'M', u'á'), + (0xC2, 'M', u'â'), + (0xC3, 'M', u'ã'), + (0xC4, 'M', u'ä'), + (0xC5, 'M', u'å'), + (0xC6, 'M', u'æ'), + (0xC7, 'M', u'ç'), + ] + +def _seg_2(): + return [ + (0xC8, 'M', u'è'), + (0xC9, 'M', u'é'), + (0xCA, 'M', u'ê'), + (0xCB, 'M', u'ë'), + (0xCC, 'M', u'ì'), + (0xCD, 'M', u'í'), + (0xCE, 'M', u'î'), + (0xCF, 'M', u'ï'), + (0xD0, 'M', u'ð'), + (0xD1, 'M', u'ñ'), + (0xD2, 'M', u'ò'), + (0xD3, 'M', u'ó'), + (0xD4, 'M', u'ô'), + (0xD5, 'M', u'õ'), + (0xD6, 'M', u'ö'), + (0xD7, 'V'), + (0xD8, 'M', u'ø'), + (0xD9, 'M', u'ù'), + (0xDA, 'M', u'ú'), + (0xDB, 'M', u'û'), + (0xDC, 'M', u'ü'), + (0xDD, 'M', u'ý'), + (0xDE, 'M', u'þ'), + (0xDF, 'D', u'ss'), + (0xE0, 'V'), + (0xE1, 'V'), + (0xE2, 'V'), + (0xE3, 'V'), + (0xE4, 'V'), + (0xE5, 'V'), + (0xE6, 'V'), + (0xE7, 'V'), + (0xE8, 'V'), + (0xE9, 'V'), + (0xEA, 'V'), + (0xEB, 'V'), + (0xEC, 'V'), + (0xED, 'V'), + (0xEE, 'V'), + (0xEF, 'V'), + (0xF0, 'V'), + (0xF1, 'V'), + (0xF2, 'V'), + (0xF3, 'V'), + (0xF4, 'V'), + (0xF5, 'V'), + (0xF6, 'V'), + (0xF7, 'V'), + (0xF8, 'V'), + (0xF9, 'V'), + (0xFA, 'V'), + (0xFB, 'V'), + (0xFC, 'V'), + (0xFD, 'V'), + (0xFE, 'V'), + (0xFF, 'V'), + (0x100, 'M', u'ā'), + (0x101, 'V'), + (0x102, 'M', u'ă'), + (0x103, 'V'), + (0x104, 'M', u'ą'), + (0x105, 'V'), + (0x106, 'M', u'ć'), + (0x107, 'V'), + (0x108, 'M', u'ĉ'), + (0x109, 'V'), + (0x10A, 'M', u'ċ'), + (0x10B, 'V'), + (0x10C, 'M', u'č'), + (0x10D, 'V'), + (0x10E, 'M', u'ď'), + (0x10F, 'V'), + (0x110, 'M', u'đ'), + (0x111, 'V'), + (0x112, 'M', u'ē'), + (0x113, 'V'), + (0x114, 'M', u'ĕ'), + (0x115, 'V'), + (0x116, 'M', u'ė'), + (0x117, 'V'), + (0x118, 'M', u'ę'), + (0x119, 'V'), + (0x11A, 'M', u'ě'), + (0x11B, 'V'), + (0x11C, 'M', u'ĝ'), + (0x11D, 'V'), + (0x11E, 'M', u'ğ'), + (0x11F, 'V'), + (0x120, 'M', u'ġ'), + (0x121, 'V'), + (0x122, 'M', u'ģ'), + (0x123, 'V'), + (0x124, 'M', u'ĥ'), + (0x125, 'V'), + (0x126, 'M', u'ħ'), + (0x127, 'V'), + (0x128, 'M', u'ĩ'), + (0x129, 'V'), + (0x12A, 'M', u'ī'), + (0x12B, 'V'), + ] + +def _seg_3(): + return [ + (0x12C, 'M', u'ĭ'), + (0x12D, 'V'), + (0x12E, 'M', u'į'), + (0x12F, 'V'), + (0x130, 'M', u'i̇'), + (0x131, 'V'), + (0x132, 'M', u'ij'), + (0x134, 'M', u'ĵ'), + (0x135, 'V'), + (0x136, 'M', u'ķ'), + (0x137, 'V'), + (0x139, 'M', u'ĺ'), + (0x13A, 'V'), + (0x13B, 'M', u'ļ'), + (0x13C, 'V'), + (0x13D, 'M', u'ľ'), + (0x13E, 'V'), + (0x13F, 'M', u'l·'), + (0x141, 'M', u'ł'), + (0x142, 'V'), + (0x143, 'M', u'ń'), + (0x144, 'V'), + (0x145, 'M', u'ņ'), + (0x146, 'V'), + (0x147, 'M', u'ň'), + (0x148, 'V'), + (0x149, 'M', u'ʼn'), + (0x14A, 'M', u'ŋ'), + (0x14B, 'V'), + (0x14C, 'M', u'ō'), + (0x14D, 'V'), + (0x14E, 'M', u'ŏ'), + (0x14F, 'V'), + (0x150, 'M', u'ő'), + (0x151, 'V'), + (0x152, 'M', u'œ'), + (0x153, 'V'), + (0x154, 'M', u'ŕ'), + (0x155, 'V'), + (0x156, 'M', u'ŗ'), + (0x157, 'V'), + (0x158, 'M', u'ř'), + (0x159, 'V'), + (0x15A, 'M', u'ś'), + (0x15B, 'V'), + (0x15C, 'M', u'ŝ'), + (0x15D, 'V'), + (0x15E, 'M', u'ş'), + (0x15F, 'V'), + (0x160, 'M', u'š'), + (0x161, 'V'), + (0x162, 'M', u'ţ'), + (0x163, 'V'), + (0x164, 'M', u'ť'), + (0x165, 'V'), + (0x166, 'M', u'ŧ'), + (0x167, 'V'), + (0x168, 'M', u'ũ'), + (0x169, 'V'), + (0x16A, 'M', u'ū'), + (0x16B, 'V'), + (0x16C, 'M', u'ŭ'), + (0x16D, 'V'), + (0x16E, 'M', u'ů'), + (0x16F, 'V'), + (0x170, 'M', u'ű'), + (0x171, 'V'), + (0x172, 'M', u'ų'), + (0x173, 'V'), + (0x174, 'M', u'ŵ'), + (0x175, 'V'), + (0x176, 'M', u'ŷ'), + (0x177, 'V'), + (0x178, 'M', u'ÿ'), + (0x179, 'M', u'ź'), + (0x17A, 'V'), + (0x17B, 'M', u'ż'), + (0x17C, 'V'), + (0x17D, 'M', u'ž'), + (0x17E, 'V'), + (0x17F, 'M', u's'), + (0x180, 'V'), + (0x181, 'M', u'ɓ'), + (0x182, 'M', u'ƃ'), + (0x183, 'V'), + (0x184, 'M', u'ƅ'), + (0x185, 'V'), + (0x186, 'M', u'ɔ'), + (0x187, 'M', u'ƈ'), + (0x188, 'V'), + (0x189, 'M', u'ɖ'), + (0x18A, 'M', u'ɗ'), + (0x18B, 'M', u'ƌ'), + (0x18C, 'V'), + (0x18E, 'M', u'ǝ'), + (0x18F, 'M', u'ə'), + (0x190, 'M', u'ɛ'), + (0x191, 'M', u'ƒ'), + (0x192, 'V'), + (0x193, 'M', u'ɠ'), + ] + +def _seg_4(): + return [ + (0x194, 'M', u'ɣ'), + (0x195, 'V'), + (0x196, 'M', u'ɩ'), + (0x197, 'M', u'ɨ'), + (0x198, 'M', u'ƙ'), + (0x199, 'V'), + (0x19C, 'M', u'ɯ'), + (0x19D, 'M', u'ɲ'), + (0x19E, 'V'), + (0x19F, 'M', u'ɵ'), + (0x1A0, 'M', u'ơ'), + (0x1A1, 'V'), + (0x1A2, 'M', u'ƣ'), + (0x1A3, 'V'), + (0x1A4, 'M', u'ƥ'), + (0x1A5, 'V'), + (0x1A6, 'M', u'ʀ'), + (0x1A7, 'M', u'ƨ'), + (0x1A8, 'V'), + (0x1A9, 'M', u'ʃ'), + (0x1AA, 'V'), + (0x1AC, 'M', u'ƭ'), + (0x1AD, 'V'), + (0x1AE, 'M', u'ʈ'), + (0x1AF, 'M', u'ư'), + (0x1B0, 'V'), + (0x1B1, 'M', u'ʊ'), + (0x1B2, 'M', u'ʋ'), + (0x1B3, 'M', u'ƴ'), + (0x1B4, 'V'), + (0x1B5, 'M', u'ƶ'), + (0x1B6, 'V'), + (0x1B7, 'M', u'ʒ'), + (0x1B8, 'M', u'ƹ'), + (0x1B9, 'V'), + (0x1BC, 'M', u'ƽ'), + (0x1BD, 'V'), + (0x1C4, 'M', u'dž'), + (0x1C7, 'M', u'lj'), + (0x1CA, 'M', u'nj'), + (0x1CD, 'M', u'ǎ'), + (0x1CE, 'V'), + (0x1CF, 'M', u'ǐ'), + (0x1D0, 'V'), + (0x1D1, 'M', u'ǒ'), + (0x1D2, 'V'), + (0x1D3, 'M', u'ǔ'), + (0x1D4, 'V'), + (0x1D5, 'M', u'ǖ'), + (0x1D6, 'V'), + (0x1D7, 'M', u'ǘ'), + (0x1D8, 'V'), + (0x1D9, 'M', u'ǚ'), + (0x1DA, 'V'), + (0x1DB, 'M', u'ǜ'), + (0x1DC, 'V'), + (0x1DE, 'M', u'ǟ'), + (0x1DF, 'V'), + (0x1E0, 'M', u'ǡ'), + (0x1E1, 'V'), + (0x1E2, 'M', u'ǣ'), + (0x1E3, 'V'), + (0x1E4, 'M', u'ǥ'), + (0x1E5, 'V'), + (0x1E6, 'M', u'ǧ'), + (0x1E7, 'V'), + (0x1E8, 'M', u'ǩ'), + (0x1E9, 'V'), + (0x1EA, 'M', u'ǫ'), + (0x1EB, 'V'), + (0x1EC, 'M', u'ǭ'), + (0x1ED, 'V'), + (0x1EE, 'M', u'ǯ'), + (0x1EF, 'V'), + (0x1F1, 'M', u'dz'), + (0x1F4, 'M', u'ǵ'), + (0x1F5, 'V'), + (0x1F6, 'M', u'ƕ'), + (0x1F7, 'M', u'ƿ'), + (0x1F8, 'M', u'ǹ'), + (0x1F9, 'V'), + (0x1FA, 'M', u'ǻ'), + (0x1FB, 'V'), + (0x1FC, 'M', u'ǽ'), + (0x1FD, 'V'), + (0x1FE, 'M', u'ǿ'), + (0x1FF, 'V'), + (0x200, 'M', u'ȁ'), + (0x201, 'V'), + (0x202, 'M', u'ȃ'), + (0x203, 'V'), + (0x204, 'M', u'ȅ'), + (0x205, 'V'), + (0x206, 'M', u'ȇ'), + (0x207, 'V'), + (0x208, 'M', u'ȉ'), + (0x209, 'V'), + (0x20A, 'M', u'ȋ'), + (0x20B, 'V'), + (0x20C, 'M', u'ȍ'), + ] + +def _seg_5(): + return [ + (0x20D, 'V'), + (0x20E, 'M', u'ȏ'), + (0x20F, 'V'), + (0x210, 'M', u'ȑ'), + (0x211, 'V'), + (0x212, 'M', u'ȓ'), + (0x213, 'V'), + (0x214, 'M', u'ȕ'), + (0x215, 'V'), + (0x216, 'M', u'ȗ'), + (0x217, 'V'), + (0x218, 'M', u'ș'), + (0x219, 'V'), + (0x21A, 'M', u'ț'), + (0x21B, 'V'), + (0x21C, 'M', u'ȝ'), + (0x21D, 'V'), + (0x21E, 'M', u'ȟ'), + (0x21F, 'V'), + (0x220, 'M', u'ƞ'), + (0x221, 'V'), + (0x222, 'M', u'ȣ'), + (0x223, 'V'), + (0x224, 'M', u'ȥ'), + (0x225, 'V'), + (0x226, 'M', u'ȧ'), + (0x227, 'V'), + (0x228, 'M', u'ȩ'), + (0x229, 'V'), + (0x22A, 'M', u'ȫ'), + (0x22B, 'V'), + (0x22C, 'M', u'ȭ'), + (0x22D, 'V'), + (0x22E, 'M', u'ȯ'), + (0x22F, 'V'), + (0x230, 'M', u'ȱ'), + (0x231, 'V'), + (0x232, 'M', u'ȳ'), + (0x233, 'V'), + (0x23A, 'M', u'ⱥ'), + (0x23B, 'M', u'ȼ'), + (0x23C, 'V'), + (0x23D, 'M', u'ƚ'), + (0x23E, 'M', u'ⱦ'), + (0x23F, 'V'), + (0x241, 'M', u'ɂ'), + (0x242, 'V'), + (0x243, 'M', u'ƀ'), + (0x244, 'M', u'ʉ'), + (0x245, 'M', u'ʌ'), + (0x246, 'M', u'ɇ'), + (0x247, 'V'), + (0x248, 'M', u'ɉ'), + (0x249, 'V'), + (0x24A, 'M', u'ɋ'), + (0x24B, 'V'), + (0x24C, 'M', u'ɍ'), + (0x24D, 'V'), + (0x24E, 'M', u'ɏ'), + (0x24F, 'V'), + (0x2B0, 'M', u'h'), + (0x2B1, 'M', u'ɦ'), + (0x2B2, 'M', u'j'), + (0x2B3, 'M', u'r'), + (0x2B4, 'M', u'ɹ'), + (0x2B5, 'M', u'ɻ'), + (0x2B6, 'M', u'ʁ'), + (0x2B7, 'M', u'w'), + (0x2B8, 'M', u'y'), + (0x2B9, 'V'), + (0x2D8, '3', u' ̆'), + (0x2D9, '3', u' ̇'), + (0x2DA, '3', u' ̊'), + (0x2DB, '3', u' ̨'), + (0x2DC, '3', u' ̃'), + (0x2DD, '3', u' ̋'), + (0x2DE, 'V'), + (0x2E0, 'M', u'ɣ'), + (0x2E1, 'M', u'l'), + (0x2E2, 'M', u's'), + (0x2E3, 'M', u'x'), + (0x2E4, 'M', u'ʕ'), + (0x2E5, 'V'), + (0x340, 'M', u'̀'), + (0x341, 'M', u'́'), + (0x342, 'V'), + (0x343, 'M', u'̓'), + (0x344, 'M', u'̈́'), + (0x345, 'M', u'ι'), + (0x346, 'V'), + (0x34F, 'I'), + (0x350, 'V'), + (0x370, 'M', u'ͱ'), + (0x371, 'V'), + (0x372, 'M', u'ͳ'), + (0x373, 'V'), + (0x374, 'M', u'ʹ'), + (0x375, 'V'), + (0x376, 'M', u'ͷ'), + (0x377, 'V'), + ] + +def _seg_6(): + return [ + (0x378, 'X'), + (0x37A, '3', u' ι'), + (0x37B, 'V'), + (0x37E, '3', u';'), + (0x37F, 'M', u'ϳ'), + (0x380, 'X'), + (0x384, '3', u' ́'), + (0x385, '3', u' ̈́'), + (0x386, 'M', u'ά'), + (0x387, 'M', u'·'), + (0x388, 'M', u'έ'), + (0x389, 'M', u'ή'), + (0x38A, 'M', u'ί'), + (0x38B, 'X'), + (0x38C, 'M', u'ό'), + (0x38D, 'X'), + (0x38E, 'M', u'ύ'), + (0x38F, 'M', u'ώ'), + (0x390, 'V'), + (0x391, 'M', u'α'), + (0x392, 'M', u'β'), + (0x393, 'M', u'γ'), + (0x394, 'M', u'δ'), + (0x395, 'M', u'ε'), + (0x396, 'M', u'ζ'), + (0x397, 'M', u'η'), + (0x398, 'M', u'θ'), + (0x399, 'M', u'ι'), + (0x39A, 'M', u'κ'), + (0x39B, 'M', u'λ'), + (0x39C, 'M', u'μ'), + (0x39D, 'M', u'ν'), + (0x39E, 'M', u'ξ'), + (0x39F, 'M', u'ο'), + (0x3A0, 'M', u'π'), + (0x3A1, 'M', u'ρ'), + (0x3A2, 'X'), + (0x3A3, 'M', u'σ'), + (0x3A4, 'M', u'τ'), + (0x3A5, 'M', u'υ'), + (0x3A6, 'M', u'φ'), + (0x3A7, 'M', u'χ'), + (0x3A8, 'M', u'ψ'), + (0x3A9, 'M', u'ω'), + (0x3AA, 'M', u'ϊ'), + (0x3AB, 'M', u'ϋ'), + (0x3AC, 'V'), + (0x3C2, 'D', u'σ'), + (0x3C3, 'V'), + (0x3CF, 'M', u'ϗ'), + (0x3D0, 'M', u'β'), + (0x3D1, 'M', u'θ'), + (0x3D2, 'M', u'υ'), + (0x3D3, 'M', u'ύ'), + (0x3D4, 'M', u'ϋ'), + (0x3D5, 'M', u'φ'), + (0x3D6, 'M', u'π'), + (0x3D7, 'V'), + (0x3D8, 'M', u'ϙ'), + (0x3D9, 'V'), + (0x3DA, 'M', u'ϛ'), + (0x3DB, 'V'), + (0x3DC, 'M', u'ϝ'), + (0x3DD, 'V'), + (0x3DE, 'M', u'ϟ'), + (0x3DF, 'V'), + (0x3E0, 'M', u'ϡ'), + (0x3E1, 'V'), + (0x3E2, 'M', u'ϣ'), + (0x3E3, 'V'), + (0x3E4, 'M', u'ϥ'), + (0x3E5, 'V'), + (0x3E6, 'M', u'ϧ'), + (0x3E7, 'V'), + (0x3E8, 'M', u'ϩ'), + (0x3E9, 'V'), + (0x3EA, 'M', u'ϫ'), + (0x3EB, 'V'), + (0x3EC, 'M', u'ϭ'), + (0x3ED, 'V'), + (0x3EE, 'M', u'ϯ'), + (0x3EF, 'V'), + (0x3F0, 'M', u'κ'), + (0x3F1, 'M', u'ρ'), + (0x3F2, 'M', u'σ'), + (0x3F3, 'V'), + (0x3F4, 'M', u'θ'), + (0x3F5, 'M', u'ε'), + (0x3F6, 'V'), + (0x3F7, 'M', u'ϸ'), + (0x3F8, 'V'), + (0x3F9, 'M', u'σ'), + (0x3FA, 'M', u'ϻ'), + (0x3FB, 'V'), + (0x3FD, 'M', u'ͻ'), + (0x3FE, 'M', u'ͼ'), + (0x3FF, 'M', u'ͽ'), + (0x400, 'M', u'ѐ'), + (0x401, 'M', u'ё'), + (0x402, 'M', u'ђ'), + ] + +def _seg_7(): + return [ + (0x403, 'M', u'ѓ'), + (0x404, 'M', u'є'), + (0x405, 'M', u'ѕ'), + (0x406, 'M', u'і'), + (0x407, 'M', u'ї'), + (0x408, 'M', u'ј'), + (0x409, 'M', u'љ'), + (0x40A, 'M', u'њ'), + (0x40B, 'M', u'ћ'), + (0x40C, 'M', u'ќ'), + (0x40D, 'M', u'ѝ'), + (0x40E, 'M', u'ў'), + (0x40F, 'M', u'џ'), + (0x410, 'M', u'а'), + (0x411, 'M', u'б'), + (0x412, 'M', u'в'), + (0x413, 'M', u'г'), + (0x414, 'M', u'д'), + (0x415, 'M', u'е'), + (0x416, 'M', u'ж'), + (0x417, 'M', u'з'), + (0x418, 'M', u'и'), + (0x419, 'M', u'й'), + (0x41A, 'M', u'к'), + (0x41B, 'M', u'л'), + (0x41C, 'M', u'м'), + (0x41D, 'M', u'н'), + (0x41E, 'M', u'о'), + (0x41F, 'M', u'п'), + (0x420, 'M', u'р'), + (0x421, 'M', u'с'), + (0x422, 'M', u'т'), + (0x423, 'M', u'у'), + (0x424, 'M', u'ф'), + (0x425, 'M', u'х'), + (0x426, 'M', u'ц'), + (0x427, 'M', u'ч'), + (0x428, 'M', u'ш'), + (0x429, 'M', u'щ'), + (0x42A, 'M', u'ъ'), + (0x42B, 'M', u'ы'), + (0x42C, 'M', u'ь'), + (0x42D, 'M', u'э'), + (0x42E, 'M', u'ю'), + (0x42F, 'M', u'я'), + (0x430, 'V'), + (0x460, 'M', u'ѡ'), + (0x461, 'V'), + (0x462, 'M', u'ѣ'), + (0x463, 'V'), + (0x464, 'M', u'ѥ'), + (0x465, 'V'), + (0x466, 'M', u'ѧ'), + (0x467, 'V'), + (0x468, 'M', u'ѩ'), + (0x469, 'V'), + (0x46A, 'M', u'ѫ'), + (0x46B, 'V'), + (0x46C, 'M', u'ѭ'), + (0x46D, 'V'), + (0x46E, 'M', u'ѯ'), + (0x46F, 'V'), + (0x470, 'M', u'ѱ'), + (0x471, 'V'), + (0x472, 'M', u'ѳ'), + (0x473, 'V'), + (0x474, 'M', u'ѵ'), + (0x475, 'V'), + (0x476, 'M', u'ѷ'), + (0x477, 'V'), + (0x478, 'M', u'ѹ'), + (0x479, 'V'), + (0x47A, 'M', u'ѻ'), + (0x47B, 'V'), + (0x47C, 'M', u'ѽ'), + (0x47D, 'V'), + (0x47E, 'M', u'ѿ'), + (0x47F, 'V'), + (0x480, 'M', u'ҁ'), + (0x481, 'V'), + (0x48A, 'M', u'ҋ'), + (0x48B, 'V'), + (0x48C, 'M', u'ҍ'), + (0x48D, 'V'), + (0x48E, 'M', u'ҏ'), + (0x48F, 'V'), + (0x490, 'M', u'ґ'), + (0x491, 'V'), + (0x492, 'M', u'ғ'), + (0x493, 'V'), + (0x494, 'M', u'ҕ'), + (0x495, 'V'), + (0x496, 'M', u'җ'), + (0x497, 'V'), + (0x498, 'M', u'ҙ'), + (0x499, 'V'), + (0x49A, 'M', u'қ'), + (0x49B, 'V'), + (0x49C, 'M', u'ҝ'), + (0x49D, 'V'), + ] + +def _seg_8(): + return [ + (0x49E, 'M', u'ҟ'), + (0x49F, 'V'), + (0x4A0, 'M', u'ҡ'), + (0x4A1, 'V'), + (0x4A2, 'M', u'ң'), + (0x4A3, 'V'), + (0x4A4, 'M', u'ҥ'), + (0x4A5, 'V'), + (0x4A6, 'M', u'ҧ'), + (0x4A7, 'V'), + (0x4A8, 'M', u'ҩ'), + (0x4A9, 'V'), + (0x4AA, 'M', u'ҫ'), + (0x4AB, 'V'), + (0x4AC, 'M', u'ҭ'), + (0x4AD, 'V'), + (0x4AE, 'M', u'ү'), + (0x4AF, 'V'), + (0x4B0, 'M', u'ұ'), + (0x4B1, 'V'), + (0x4B2, 'M', u'ҳ'), + (0x4B3, 'V'), + (0x4B4, 'M', u'ҵ'), + (0x4B5, 'V'), + (0x4B6, 'M', u'ҷ'), + (0x4B7, 'V'), + (0x4B8, 'M', u'ҹ'), + (0x4B9, 'V'), + (0x4BA, 'M', u'һ'), + (0x4BB, 'V'), + (0x4BC, 'M', u'ҽ'), + (0x4BD, 'V'), + (0x4BE, 'M', u'ҿ'), + (0x4BF, 'V'), + (0x4C0, 'X'), + (0x4C1, 'M', u'ӂ'), + (0x4C2, 'V'), + (0x4C3, 'M', u'ӄ'), + (0x4C4, 'V'), + (0x4C5, 'M', u'ӆ'), + (0x4C6, 'V'), + (0x4C7, 'M', u'ӈ'), + (0x4C8, 'V'), + (0x4C9, 'M', u'ӊ'), + (0x4CA, 'V'), + (0x4CB, 'M', u'ӌ'), + (0x4CC, 'V'), + (0x4CD, 'M', u'ӎ'), + (0x4CE, 'V'), + (0x4D0, 'M', u'ӑ'), + (0x4D1, 'V'), + (0x4D2, 'M', u'ӓ'), + (0x4D3, 'V'), + (0x4D4, 'M', u'ӕ'), + (0x4D5, 'V'), + (0x4D6, 'M', u'ӗ'), + (0x4D7, 'V'), + (0x4D8, 'M', u'ә'), + (0x4D9, 'V'), + (0x4DA, 'M', u'ӛ'), + (0x4DB, 'V'), + (0x4DC, 'M', u'ӝ'), + (0x4DD, 'V'), + (0x4DE, 'M', u'ӟ'), + (0x4DF, 'V'), + (0x4E0, 'M', u'ӡ'), + (0x4E1, 'V'), + (0x4E2, 'M', u'ӣ'), + (0x4E3, 'V'), + (0x4E4, 'M', u'ӥ'), + (0x4E5, 'V'), + (0x4E6, 'M', u'ӧ'), + (0x4E7, 'V'), + (0x4E8, 'M', u'ө'), + (0x4E9, 'V'), + (0x4EA, 'M', u'ӫ'), + (0x4EB, 'V'), + (0x4EC, 'M', u'ӭ'), + (0x4ED, 'V'), + (0x4EE, 'M', u'ӯ'), + (0x4EF, 'V'), + (0x4F0, 'M', u'ӱ'), + (0x4F1, 'V'), + (0x4F2, 'M', u'ӳ'), + (0x4F3, 'V'), + (0x4F4, 'M', u'ӵ'), + (0x4F5, 'V'), + (0x4F6, 'M', u'ӷ'), + (0x4F7, 'V'), + (0x4F8, 'M', u'ӹ'), + (0x4F9, 'V'), + (0x4FA, 'M', u'ӻ'), + (0x4FB, 'V'), + (0x4FC, 'M', u'ӽ'), + (0x4FD, 'V'), + (0x4FE, 'M', u'ӿ'), + (0x4FF, 'V'), + (0x500, 'M', u'ԁ'), + (0x501, 'V'), + (0x502, 'M', u'ԃ'), + ] + +def _seg_9(): + return [ + (0x503, 'V'), + (0x504, 'M', u'ԅ'), + (0x505, 'V'), + (0x506, 'M', u'ԇ'), + (0x507, 'V'), + (0x508, 'M', u'ԉ'), + (0x509, 'V'), + (0x50A, 'M', u'ԋ'), + (0x50B, 'V'), + (0x50C, 'M', u'ԍ'), + (0x50D, 'V'), + (0x50E, 'M', u'ԏ'), + (0x50F, 'V'), + (0x510, 'M', u'ԑ'), + (0x511, 'V'), + (0x512, 'M', u'ԓ'), + (0x513, 'V'), + (0x514, 'M', u'ԕ'), + (0x515, 'V'), + (0x516, 'M', u'ԗ'), + (0x517, 'V'), + (0x518, 'M', u'ԙ'), + (0x519, 'V'), + (0x51A, 'M', u'ԛ'), + (0x51B, 'V'), + (0x51C, 'M', u'ԝ'), + (0x51D, 'V'), + (0x51E, 'M', u'ԟ'), + (0x51F, 'V'), + (0x520, 'M', u'ԡ'), + (0x521, 'V'), + (0x522, 'M', u'ԣ'), + (0x523, 'V'), + (0x524, 'M', u'ԥ'), + (0x525, 'V'), + (0x526, 'M', u'ԧ'), + (0x527, 'V'), + (0x528, 'M', u'ԩ'), + (0x529, 'V'), + (0x52A, 'M', u'ԫ'), + (0x52B, 'V'), + (0x52C, 'M', u'ԭ'), + (0x52D, 'V'), + (0x52E, 'M', u'ԯ'), + (0x52F, 'V'), + (0x530, 'X'), + (0x531, 'M', u'ա'), + (0x532, 'M', u'բ'), + (0x533, 'M', u'գ'), + (0x534, 'M', u'դ'), + (0x535, 'M', u'ե'), + (0x536, 'M', u'զ'), + (0x537, 'M', u'է'), + (0x538, 'M', u'ը'), + (0x539, 'M', u'թ'), + (0x53A, 'M', u'ժ'), + (0x53B, 'M', u'ի'), + (0x53C, 'M', u'լ'), + (0x53D, 'M', u'խ'), + (0x53E, 'M', u'ծ'), + (0x53F, 'M', u'կ'), + (0x540, 'M', u'հ'), + (0x541, 'M', u'ձ'), + (0x542, 'M', u'ղ'), + (0x543, 'M', u'ճ'), + (0x544, 'M', u'մ'), + (0x545, 'M', u'յ'), + (0x546, 'M', u'ն'), + (0x547, 'M', u'շ'), + (0x548, 'M', u'ո'), + (0x549, 'M', u'չ'), + (0x54A, 'M', u'պ'), + (0x54B, 'M', u'ջ'), + (0x54C, 'M', u'ռ'), + (0x54D, 'M', u'ս'), + (0x54E, 'M', u'վ'), + (0x54F, 'M', u'տ'), + (0x550, 'M', u'ր'), + (0x551, 'M', u'ց'), + (0x552, 'M', u'ւ'), + (0x553, 'M', u'փ'), + (0x554, 'M', u'ք'), + (0x555, 'M', u'օ'), + (0x556, 'M', u'ֆ'), + (0x557, 'X'), + (0x559, 'V'), + (0x587, 'M', u'եւ'), + (0x588, 'V'), + (0x58B, 'X'), + (0x58D, 'V'), + (0x590, 'X'), + (0x591, 'V'), + (0x5C8, 'X'), + (0x5D0, 'V'), + (0x5EB, 'X'), + (0x5EF, 'V'), + (0x5F5, 'X'), + (0x606, 'V'), + (0x61C, 'X'), + (0x61E, 'V'), + ] + +def _seg_10(): + return [ + (0x675, 'M', u'اٴ'), + (0x676, 'M', u'وٴ'), + (0x677, 'M', u'ۇٴ'), + (0x678, 'M', u'يٴ'), + (0x679, 'V'), + (0x6DD, 'X'), + (0x6DE, 'V'), + (0x70E, 'X'), + (0x710, 'V'), + (0x74B, 'X'), + (0x74D, 'V'), + (0x7B2, 'X'), + (0x7C0, 'V'), + (0x7FB, 'X'), + (0x7FD, 'V'), + (0x82E, 'X'), + (0x830, 'V'), + (0x83F, 'X'), + (0x840, 'V'), + (0x85C, 'X'), + (0x85E, 'V'), + (0x85F, 'X'), + (0x860, 'V'), + (0x86B, 'X'), + (0x8A0, 'V'), + (0x8B5, 'X'), + (0x8B6, 'V'), + (0x8C8, 'X'), + (0x8D3, 'V'), + (0x8E2, 'X'), + (0x8E3, 'V'), + (0x958, 'M', u'क़'), + (0x959, 'M', u'ख़'), + (0x95A, 'M', u'ग़'), + (0x95B, 'M', u'ज़'), + (0x95C, 'M', u'ड़'), + (0x95D, 'M', u'ढ़'), + (0x95E, 'M', u'फ़'), + (0x95F, 'M', u'य़'), + (0x960, 'V'), + (0x984, 'X'), + (0x985, 'V'), + (0x98D, 'X'), + (0x98F, 'V'), + (0x991, 'X'), + (0x993, 'V'), + (0x9A9, 'X'), + (0x9AA, 'V'), + (0x9B1, 'X'), + (0x9B2, 'V'), + (0x9B3, 'X'), + (0x9B6, 'V'), + (0x9BA, 'X'), + (0x9BC, 'V'), + (0x9C5, 'X'), + (0x9C7, 'V'), + (0x9C9, 'X'), + (0x9CB, 'V'), + (0x9CF, 'X'), + (0x9D7, 'V'), + (0x9D8, 'X'), + (0x9DC, 'M', u'ড়'), + (0x9DD, 'M', u'ঢ়'), + (0x9DE, 'X'), + (0x9DF, 'M', u'য়'), + (0x9E0, 'V'), + (0x9E4, 'X'), + (0x9E6, 'V'), + (0x9FF, 'X'), + (0xA01, 'V'), + (0xA04, 'X'), + (0xA05, 'V'), + (0xA0B, 'X'), + (0xA0F, 'V'), + (0xA11, 'X'), + (0xA13, 'V'), + (0xA29, 'X'), + (0xA2A, 'V'), + (0xA31, 'X'), + (0xA32, 'V'), + (0xA33, 'M', u'ਲ਼'), + (0xA34, 'X'), + (0xA35, 'V'), + (0xA36, 'M', u'ਸ਼'), + (0xA37, 'X'), + (0xA38, 'V'), + (0xA3A, 'X'), + (0xA3C, 'V'), + (0xA3D, 'X'), + (0xA3E, 'V'), + (0xA43, 'X'), + (0xA47, 'V'), + (0xA49, 'X'), + (0xA4B, 'V'), + (0xA4E, 'X'), + (0xA51, 'V'), + (0xA52, 'X'), + (0xA59, 'M', u'ਖ਼'), + (0xA5A, 'M', u'ਗ਼'), + (0xA5B, 'M', u'ਜ਼'), + ] + +def _seg_11(): + return [ + (0xA5C, 'V'), + (0xA5D, 'X'), + (0xA5E, 'M', u'ਫ਼'), + (0xA5F, 'X'), + (0xA66, 'V'), + (0xA77, 'X'), + (0xA81, 'V'), + (0xA84, 'X'), + (0xA85, 'V'), + (0xA8E, 'X'), + (0xA8F, 'V'), + (0xA92, 'X'), + (0xA93, 'V'), + (0xAA9, 'X'), + (0xAAA, 'V'), + (0xAB1, 'X'), + (0xAB2, 'V'), + (0xAB4, 'X'), + (0xAB5, 'V'), + (0xABA, 'X'), + (0xABC, 'V'), + (0xAC6, 'X'), + (0xAC7, 'V'), + (0xACA, 'X'), + (0xACB, 'V'), + (0xACE, 'X'), + (0xAD0, 'V'), + (0xAD1, 'X'), + (0xAE0, 'V'), + (0xAE4, 'X'), + (0xAE6, 'V'), + (0xAF2, 'X'), + (0xAF9, 'V'), + (0xB00, 'X'), + (0xB01, 'V'), + (0xB04, 'X'), + (0xB05, 'V'), + (0xB0D, 'X'), + (0xB0F, 'V'), + (0xB11, 'X'), + (0xB13, 'V'), + (0xB29, 'X'), + (0xB2A, 'V'), + (0xB31, 'X'), + (0xB32, 'V'), + (0xB34, 'X'), + (0xB35, 'V'), + (0xB3A, 'X'), + (0xB3C, 'V'), + (0xB45, 'X'), + (0xB47, 'V'), + (0xB49, 'X'), + (0xB4B, 'V'), + (0xB4E, 'X'), + (0xB55, 'V'), + (0xB58, 'X'), + (0xB5C, 'M', u'ଡ଼'), + (0xB5D, 'M', u'ଢ଼'), + (0xB5E, 'X'), + (0xB5F, 'V'), + (0xB64, 'X'), + (0xB66, 'V'), + (0xB78, 'X'), + (0xB82, 'V'), + (0xB84, 'X'), + (0xB85, 'V'), + (0xB8B, 'X'), + (0xB8E, 'V'), + (0xB91, 'X'), + (0xB92, 'V'), + (0xB96, 'X'), + (0xB99, 'V'), + (0xB9B, 'X'), + (0xB9C, 'V'), + (0xB9D, 'X'), + (0xB9E, 'V'), + (0xBA0, 'X'), + (0xBA3, 'V'), + (0xBA5, 'X'), + (0xBA8, 'V'), + (0xBAB, 'X'), + (0xBAE, 'V'), + (0xBBA, 'X'), + (0xBBE, 'V'), + (0xBC3, 'X'), + (0xBC6, 'V'), + (0xBC9, 'X'), + (0xBCA, 'V'), + (0xBCE, 'X'), + (0xBD0, 'V'), + (0xBD1, 'X'), + (0xBD7, 'V'), + (0xBD8, 'X'), + (0xBE6, 'V'), + (0xBFB, 'X'), + (0xC00, 'V'), + (0xC0D, 'X'), + (0xC0E, 'V'), + (0xC11, 'X'), + (0xC12, 'V'), + ] + +def _seg_12(): + return [ + (0xC29, 'X'), + (0xC2A, 'V'), + (0xC3A, 'X'), + (0xC3D, 'V'), + (0xC45, 'X'), + (0xC46, 'V'), + (0xC49, 'X'), + (0xC4A, 'V'), + (0xC4E, 'X'), + (0xC55, 'V'), + (0xC57, 'X'), + (0xC58, 'V'), + (0xC5B, 'X'), + (0xC60, 'V'), + (0xC64, 'X'), + (0xC66, 'V'), + (0xC70, 'X'), + (0xC77, 'V'), + (0xC8D, 'X'), + (0xC8E, 'V'), + (0xC91, 'X'), + (0xC92, 'V'), + (0xCA9, 'X'), + (0xCAA, 'V'), + (0xCB4, 'X'), + (0xCB5, 'V'), + (0xCBA, 'X'), + (0xCBC, 'V'), + (0xCC5, 'X'), + (0xCC6, 'V'), + (0xCC9, 'X'), + (0xCCA, 'V'), + (0xCCE, 'X'), + (0xCD5, 'V'), + (0xCD7, 'X'), + (0xCDE, 'V'), + (0xCDF, 'X'), + (0xCE0, 'V'), + (0xCE4, 'X'), + (0xCE6, 'V'), + (0xCF0, 'X'), + (0xCF1, 'V'), + (0xCF3, 'X'), + (0xD00, 'V'), + (0xD0D, 'X'), + (0xD0E, 'V'), + (0xD11, 'X'), + (0xD12, 'V'), + (0xD45, 'X'), + (0xD46, 'V'), + (0xD49, 'X'), + (0xD4A, 'V'), + (0xD50, 'X'), + (0xD54, 'V'), + (0xD64, 'X'), + (0xD66, 'V'), + (0xD80, 'X'), + (0xD81, 'V'), + (0xD84, 'X'), + (0xD85, 'V'), + (0xD97, 'X'), + (0xD9A, 'V'), + (0xDB2, 'X'), + (0xDB3, 'V'), + (0xDBC, 'X'), + (0xDBD, 'V'), + (0xDBE, 'X'), + (0xDC0, 'V'), + (0xDC7, 'X'), + (0xDCA, 'V'), + (0xDCB, 'X'), + (0xDCF, 'V'), + (0xDD5, 'X'), + (0xDD6, 'V'), + (0xDD7, 'X'), + (0xDD8, 'V'), + (0xDE0, 'X'), + (0xDE6, 'V'), + (0xDF0, 'X'), + (0xDF2, 'V'), + (0xDF5, 'X'), + (0xE01, 'V'), + (0xE33, 'M', u'ํา'), + (0xE34, 'V'), + (0xE3B, 'X'), + (0xE3F, 'V'), + (0xE5C, 'X'), + (0xE81, 'V'), + (0xE83, 'X'), + (0xE84, 'V'), + (0xE85, 'X'), + (0xE86, 'V'), + (0xE8B, 'X'), + (0xE8C, 'V'), + (0xEA4, 'X'), + (0xEA5, 'V'), + (0xEA6, 'X'), + (0xEA7, 'V'), + (0xEB3, 'M', u'ໍາ'), + (0xEB4, 'V'), + ] + +def _seg_13(): + return [ + (0xEBE, 'X'), + (0xEC0, 'V'), + (0xEC5, 'X'), + (0xEC6, 'V'), + (0xEC7, 'X'), + (0xEC8, 'V'), + (0xECE, 'X'), + (0xED0, 'V'), + (0xEDA, 'X'), + (0xEDC, 'M', u'ຫນ'), + (0xEDD, 'M', u'ຫມ'), + (0xEDE, 'V'), + (0xEE0, 'X'), + (0xF00, 'V'), + (0xF0C, 'M', u'་'), + (0xF0D, 'V'), + (0xF43, 'M', u'གྷ'), + (0xF44, 'V'), + (0xF48, 'X'), + (0xF49, 'V'), + (0xF4D, 'M', u'ཌྷ'), + (0xF4E, 'V'), + (0xF52, 'M', u'དྷ'), + (0xF53, 'V'), + (0xF57, 'M', u'བྷ'), + (0xF58, 'V'), + (0xF5C, 'M', u'ཛྷ'), + (0xF5D, 'V'), + (0xF69, 'M', u'ཀྵ'), + (0xF6A, 'V'), + (0xF6D, 'X'), + (0xF71, 'V'), + (0xF73, 'M', u'ཱི'), + (0xF74, 'V'), + (0xF75, 'M', u'ཱུ'), + (0xF76, 'M', u'ྲྀ'), + (0xF77, 'M', u'ྲཱྀ'), + (0xF78, 'M', u'ླྀ'), + (0xF79, 'M', u'ླཱྀ'), + (0xF7A, 'V'), + (0xF81, 'M', u'ཱྀ'), + (0xF82, 'V'), + (0xF93, 'M', u'ྒྷ'), + (0xF94, 'V'), + (0xF98, 'X'), + (0xF99, 'V'), + (0xF9D, 'M', u'ྜྷ'), + (0xF9E, 'V'), + (0xFA2, 'M', u'ྡྷ'), + (0xFA3, 'V'), + (0xFA7, 'M', u'ྦྷ'), + (0xFA8, 'V'), + (0xFAC, 'M', u'ྫྷ'), + (0xFAD, 'V'), + (0xFB9, 'M', u'ྐྵ'), + (0xFBA, 'V'), + (0xFBD, 'X'), + (0xFBE, 'V'), + (0xFCD, 'X'), + (0xFCE, 'V'), + (0xFDB, 'X'), + (0x1000, 'V'), + (0x10A0, 'X'), + (0x10C7, 'M', u'ⴧ'), + (0x10C8, 'X'), + (0x10CD, 'M', u'ⴭ'), + (0x10CE, 'X'), + (0x10D0, 'V'), + (0x10FC, 'M', u'ნ'), + (0x10FD, 'V'), + (0x115F, 'X'), + (0x1161, 'V'), + (0x1249, 'X'), + (0x124A, 'V'), + (0x124E, 'X'), + (0x1250, 'V'), + (0x1257, 'X'), + (0x1258, 'V'), + (0x1259, 'X'), + (0x125A, 'V'), + (0x125E, 'X'), + (0x1260, 'V'), + (0x1289, 'X'), + (0x128A, 'V'), + (0x128E, 'X'), + (0x1290, 'V'), + (0x12B1, 'X'), + (0x12B2, 'V'), + (0x12B6, 'X'), + (0x12B8, 'V'), + (0x12BF, 'X'), + (0x12C0, 'V'), + (0x12C1, 'X'), + (0x12C2, 'V'), + (0x12C6, 'X'), + (0x12C8, 'V'), + (0x12D7, 'X'), + (0x12D8, 'V'), + (0x1311, 'X'), + (0x1312, 'V'), + ] + +def _seg_14(): + return [ + (0x1316, 'X'), + (0x1318, 'V'), + (0x135B, 'X'), + (0x135D, 'V'), + (0x137D, 'X'), + (0x1380, 'V'), + (0x139A, 'X'), + (0x13A0, 'V'), + (0x13F6, 'X'), + (0x13F8, 'M', u'Ᏸ'), + (0x13F9, 'M', u'Ᏹ'), + (0x13FA, 'M', u'Ᏺ'), + (0x13FB, 'M', u'Ᏻ'), + (0x13FC, 'M', u'Ᏼ'), + (0x13FD, 'M', u'Ᏽ'), + (0x13FE, 'X'), + (0x1400, 'V'), + (0x1680, 'X'), + (0x1681, 'V'), + (0x169D, 'X'), + (0x16A0, 'V'), + (0x16F9, 'X'), + (0x1700, 'V'), + (0x170D, 'X'), + (0x170E, 'V'), + (0x1715, 'X'), + (0x1720, 'V'), + (0x1737, 'X'), + (0x1740, 'V'), + (0x1754, 'X'), + (0x1760, 'V'), + (0x176D, 'X'), + (0x176E, 'V'), + (0x1771, 'X'), + (0x1772, 'V'), + (0x1774, 'X'), + (0x1780, 'V'), + (0x17B4, 'X'), + (0x17B6, 'V'), + (0x17DE, 'X'), + (0x17E0, 'V'), + (0x17EA, 'X'), + (0x17F0, 'V'), + (0x17FA, 'X'), + (0x1800, 'V'), + (0x1806, 'X'), + (0x1807, 'V'), + (0x180B, 'I'), + (0x180E, 'X'), + (0x1810, 'V'), + (0x181A, 'X'), + (0x1820, 'V'), + (0x1879, 'X'), + (0x1880, 'V'), + (0x18AB, 'X'), + (0x18B0, 'V'), + (0x18F6, 'X'), + (0x1900, 'V'), + (0x191F, 'X'), + (0x1920, 'V'), + (0x192C, 'X'), + (0x1930, 'V'), + (0x193C, 'X'), + (0x1940, 'V'), + (0x1941, 'X'), + (0x1944, 'V'), + (0x196E, 'X'), + (0x1970, 'V'), + (0x1975, 'X'), + (0x1980, 'V'), + (0x19AC, 'X'), + (0x19B0, 'V'), + (0x19CA, 'X'), + (0x19D0, 'V'), + (0x19DB, 'X'), + (0x19DE, 'V'), + (0x1A1C, 'X'), + (0x1A1E, 'V'), + (0x1A5F, 'X'), + (0x1A60, 'V'), + (0x1A7D, 'X'), + (0x1A7F, 'V'), + (0x1A8A, 'X'), + (0x1A90, 'V'), + (0x1A9A, 'X'), + (0x1AA0, 'V'), + (0x1AAE, 'X'), + (0x1AB0, 'V'), + (0x1AC1, 'X'), + (0x1B00, 'V'), + (0x1B4C, 'X'), + (0x1B50, 'V'), + (0x1B7D, 'X'), + (0x1B80, 'V'), + (0x1BF4, 'X'), + (0x1BFC, 'V'), + (0x1C38, 'X'), + (0x1C3B, 'V'), + (0x1C4A, 'X'), + (0x1C4D, 'V'), + ] + +def _seg_15(): + return [ + (0x1C80, 'M', u'в'), + (0x1C81, 'M', u'д'), + (0x1C82, 'M', u'о'), + (0x1C83, 'M', u'с'), + (0x1C84, 'M', u'т'), + (0x1C86, 'M', u'ъ'), + (0x1C87, 'M', u'ѣ'), + (0x1C88, 'M', u'ꙋ'), + (0x1C89, 'X'), + (0x1C90, 'M', u'ა'), + (0x1C91, 'M', u'ბ'), + (0x1C92, 'M', u'გ'), + (0x1C93, 'M', u'დ'), + (0x1C94, 'M', u'ე'), + (0x1C95, 'M', u'ვ'), + (0x1C96, 'M', u'ზ'), + (0x1C97, 'M', u'თ'), + (0x1C98, 'M', u'ი'), + (0x1C99, 'M', u'კ'), + (0x1C9A, 'M', u'ლ'), + (0x1C9B, 'M', u'მ'), + (0x1C9C, 'M', u'ნ'), + (0x1C9D, 'M', u'ო'), + (0x1C9E, 'M', u'პ'), + (0x1C9F, 'M', u'ჟ'), + (0x1CA0, 'M', u'რ'), + (0x1CA1, 'M', u'ს'), + (0x1CA2, 'M', u'ტ'), + (0x1CA3, 'M', u'უ'), + (0x1CA4, 'M', u'ფ'), + (0x1CA5, 'M', u'ქ'), + (0x1CA6, 'M', u'ღ'), + (0x1CA7, 'M', u'ყ'), + (0x1CA8, 'M', u'შ'), + (0x1CA9, 'M', u'ჩ'), + (0x1CAA, 'M', u'ც'), + (0x1CAB, 'M', u'ძ'), + (0x1CAC, 'M', u'წ'), + (0x1CAD, 'M', u'ჭ'), + (0x1CAE, 'M', u'ხ'), + (0x1CAF, 'M', u'ჯ'), + (0x1CB0, 'M', u'ჰ'), + (0x1CB1, 'M', u'ჱ'), + (0x1CB2, 'M', u'ჲ'), + (0x1CB3, 'M', u'ჳ'), + (0x1CB4, 'M', u'ჴ'), + (0x1CB5, 'M', u'ჵ'), + (0x1CB6, 'M', u'ჶ'), + (0x1CB7, 'M', u'ჷ'), + (0x1CB8, 'M', u'ჸ'), + (0x1CB9, 'M', u'ჹ'), + (0x1CBA, 'M', u'ჺ'), + (0x1CBB, 'X'), + (0x1CBD, 'M', u'ჽ'), + (0x1CBE, 'M', u'ჾ'), + (0x1CBF, 'M', u'ჿ'), + (0x1CC0, 'V'), + (0x1CC8, 'X'), + (0x1CD0, 'V'), + (0x1CFB, 'X'), + (0x1D00, 'V'), + (0x1D2C, 'M', u'a'), + (0x1D2D, 'M', u'æ'), + (0x1D2E, 'M', u'b'), + (0x1D2F, 'V'), + (0x1D30, 'M', u'd'), + (0x1D31, 'M', u'e'), + (0x1D32, 'M', u'ǝ'), + (0x1D33, 'M', u'g'), + (0x1D34, 'M', u'h'), + (0x1D35, 'M', u'i'), + (0x1D36, 'M', u'j'), + (0x1D37, 'M', u'k'), + (0x1D38, 'M', u'l'), + (0x1D39, 'M', u'm'), + (0x1D3A, 'M', u'n'), + (0x1D3B, 'V'), + (0x1D3C, 'M', u'o'), + (0x1D3D, 'M', u'ȣ'), + (0x1D3E, 'M', u'p'), + (0x1D3F, 'M', u'r'), + (0x1D40, 'M', u't'), + (0x1D41, 'M', u'u'), + (0x1D42, 'M', u'w'), + (0x1D43, 'M', u'a'), + (0x1D44, 'M', u'ɐ'), + (0x1D45, 'M', u'ɑ'), + (0x1D46, 'M', u'ᴂ'), + (0x1D47, 'M', u'b'), + (0x1D48, 'M', u'd'), + (0x1D49, 'M', u'e'), + (0x1D4A, 'M', u'ə'), + (0x1D4B, 'M', u'ɛ'), + (0x1D4C, 'M', u'ɜ'), + (0x1D4D, 'M', u'g'), + (0x1D4E, 'V'), + (0x1D4F, 'M', u'k'), + (0x1D50, 'M', u'm'), + (0x1D51, 'M', u'ŋ'), + (0x1D52, 'M', u'o'), + ] + +def _seg_16(): + return [ + (0x1D53, 'M', u'ɔ'), + (0x1D54, 'M', u'ᴖ'), + (0x1D55, 'M', u'ᴗ'), + (0x1D56, 'M', u'p'), + (0x1D57, 'M', u't'), + (0x1D58, 'M', u'u'), + (0x1D59, 'M', u'ᴝ'), + (0x1D5A, 'M', u'ɯ'), + (0x1D5B, 'M', u'v'), + (0x1D5C, 'M', u'ᴥ'), + (0x1D5D, 'M', u'β'), + (0x1D5E, 'M', u'γ'), + (0x1D5F, 'M', u'δ'), + (0x1D60, 'M', u'φ'), + (0x1D61, 'M', u'χ'), + (0x1D62, 'M', u'i'), + (0x1D63, 'M', u'r'), + (0x1D64, 'M', u'u'), + (0x1D65, 'M', u'v'), + (0x1D66, 'M', u'β'), + (0x1D67, 'M', u'γ'), + (0x1D68, 'M', u'ρ'), + (0x1D69, 'M', u'φ'), + (0x1D6A, 'M', u'χ'), + (0x1D6B, 'V'), + (0x1D78, 'M', u'н'), + (0x1D79, 'V'), + (0x1D9B, 'M', u'ɒ'), + (0x1D9C, 'M', u'c'), + (0x1D9D, 'M', u'ɕ'), + (0x1D9E, 'M', u'ð'), + (0x1D9F, 'M', u'ɜ'), + (0x1DA0, 'M', u'f'), + (0x1DA1, 'M', u'ɟ'), + (0x1DA2, 'M', u'ɡ'), + (0x1DA3, 'M', u'ɥ'), + (0x1DA4, 'M', u'ɨ'), + (0x1DA5, 'M', u'ɩ'), + (0x1DA6, 'M', u'ɪ'), + (0x1DA7, 'M', u'ᵻ'), + (0x1DA8, 'M', u'ʝ'), + (0x1DA9, 'M', u'ɭ'), + (0x1DAA, 'M', u'ᶅ'), + (0x1DAB, 'M', u'ʟ'), + (0x1DAC, 'M', u'ɱ'), + (0x1DAD, 'M', u'ɰ'), + (0x1DAE, 'M', u'ɲ'), + (0x1DAF, 'M', u'ɳ'), + (0x1DB0, 'M', u'ɴ'), + (0x1DB1, 'M', u'ɵ'), + (0x1DB2, 'M', u'ɸ'), + (0x1DB3, 'M', u'ʂ'), + (0x1DB4, 'M', u'ʃ'), + (0x1DB5, 'M', u'ƫ'), + (0x1DB6, 'M', u'ʉ'), + (0x1DB7, 'M', u'ʊ'), + (0x1DB8, 'M', u'ᴜ'), + (0x1DB9, 'M', u'ʋ'), + (0x1DBA, 'M', u'ʌ'), + (0x1DBB, 'M', u'z'), + (0x1DBC, 'M', u'ʐ'), + (0x1DBD, 'M', u'ʑ'), + (0x1DBE, 'M', u'ʒ'), + (0x1DBF, 'M', u'θ'), + (0x1DC0, 'V'), + (0x1DFA, 'X'), + (0x1DFB, 'V'), + (0x1E00, 'M', u'ḁ'), + (0x1E01, 'V'), + (0x1E02, 'M', u'ḃ'), + (0x1E03, 'V'), + (0x1E04, 'M', u'ḅ'), + (0x1E05, 'V'), + (0x1E06, 'M', u'ḇ'), + (0x1E07, 'V'), + (0x1E08, 'M', u'ḉ'), + (0x1E09, 'V'), + (0x1E0A, 'M', u'ḋ'), + (0x1E0B, 'V'), + (0x1E0C, 'M', u'ḍ'), + (0x1E0D, 'V'), + (0x1E0E, 'M', u'ḏ'), + (0x1E0F, 'V'), + (0x1E10, 'M', u'ḑ'), + (0x1E11, 'V'), + (0x1E12, 'M', u'ḓ'), + (0x1E13, 'V'), + (0x1E14, 'M', u'ḕ'), + (0x1E15, 'V'), + (0x1E16, 'M', u'ḗ'), + (0x1E17, 'V'), + (0x1E18, 'M', u'ḙ'), + (0x1E19, 'V'), + (0x1E1A, 'M', u'ḛ'), + (0x1E1B, 'V'), + (0x1E1C, 'M', u'ḝ'), + (0x1E1D, 'V'), + (0x1E1E, 'M', u'ḟ'), + (0x1E1F, 'V'), + (0x1E20, 'M', u'ḡ'), + ] + +def _seg_17(): + return [ + (0x1E21, 'V'), + (0x1E22, 'M', u'ḣ'), + (0x1E23, 'V'), + (0x1E24, 'M', u'ḥ'), + (0x1E25, 'V'), + (0x1E26, 'M', u'ḧ'), + (0x1E27, 'V'), + (0x1E28, 'M', u'ḩ'), + (0x1E29, 'V'), + (0x1E2A, 'M', u'ḫ'), + (0x1E2B, 'V'), + (0x1E2C, 'M', u'ḭ'), + (0x1E2D, 'V'), + (0x1E2E, 'M', u'ḯ'), + (0x1E2F, 'V'), + (0x1E30, 'M', u'ḱ'), + (0x1E31, 'V'), + (0x1E32, 'M', u'ḳ'), + (0x1E33, 'V'), + (0x1E34, 'M', u'ḵ'), + (0x1E35, 'V'), + (0x1E36, 'M', u'ḷ'), + (0x1E37, 'V'), + (0x1E38, 'M', u'ḹ'), + (0x1E39, 'V'), + (0x1E3A, 'M', u'ḻ'), + (0x1E3B, 'V'), + (0x1E3C, 'M', u'ḽ'), + (0x1E3D, 'V'), + (0x1E3E, 'M', u'ḿ'), + (0x1E3F, 'V'), + (0x1E40, 'M', u'ṁ'), + (0x1E41, 'V'), + (0x1E42, 'M', u'ṃ'), + (0x1E43, 'V'), + (0x1E44, 'M', u'ṅ'), + (0x1E45, 'V'), + (0x1E46, 'M', u'ṇ'), + (0x1E47, 'V'), + (0x1E48, 'M', u'ṉ'), + (0x1E49, 'V'), + (0x1E4A, 'M', u'ṋ'), + (0x1E4B, 'V'), + (0x1E4C, 'M', u'ṍ'), + (0x1E4D, 'V'), + (0x1E4E, 'M', u'ṏ'), + (0x1E4F, 'V'), + (0x1E50, 'M', u'ṑ'), + (0x1E51, 'V'), + (0x1E52, 'M', u'ṓ'), + (0x1E53, 'V'), + (0x1E54, 'M', u'ṕ'), + (0x1E55, 'V'), + (0x1E56, 'M', u'ṗ'), + (0x1E57, 'V'), + (0x1E58, 'M', u'ṙ'), + (0x1E59, 'V'), + (0x1E5A, 'M', u'ṛ'), + (0x1E5B, 'V'), + (0x1E5C, 'M', u'ṝ'), + (0x1E5D, 'V'), + (0x1E5E, 'M', u'ṟ'), + (0x1E5F, 'V'), + (0x1E60, 'M', u'ṡ'), + (0x1E61, 'V'), + (0x1E62, 'M', u'ṣ'), + (0x1E63, 'V'), + (0x1E64, 'M', u'ṥ'), + (0x1E65, 'V'), + (0x1E66, 'M', u'ṧ'), + (0x1E67, 'V'), + (0x1E68, 'M', u'ṩ'), + (0x1E69, 'V'), + (0x1E6A, 'M', u'ṫ'), + (0x1E6B, 'V'), + (0x1E6C, 'M', u'ṭ'), + (0x1E6D, 'V'), + (0x1E6E, 'M', u'ṯ'), + (0x1E6F, 'V'), + (0x1E70, 'M', u'ṱ'), + (0x1E71, 'V'), + (0x1E72, 'M', u'ṳ'), + (0x1E73, 'V'), + (0x1E74, 'M', u'ṵ'), + (0x1E75, 'V'), + (0x1E76, 'M', u'ṷ'), + (0x1E77, 'V'), + (0x1E78, 'M', u'ṹ'), + (0x1E79, 'V'), + (0x1E7A, 'M', u'ṻ'), + (0x1E7B, 'V'), + (0x1E7C, 'M', u'ṽ'), + (0x1E7D, 'V'), + (0x1E7E, 'M', u'ṿ'), + (0x1E7F, 'V'), + (0x1E80, 'M', u'ẁ'), + (0x1E81, 'V'), + (0x1E82, 'M', u'ẃ'), + (0x1E83, 'V'), + (0x1E84, 'M', u'ẅ'), + ] + +def _seg_18(): + return [ + (0x1E85, 'V'), + (0x1E86, 'M', u'ẇ'), + (0x1E87, 'V'), + (0x1E88, 'M', u'ẉ'), + (0x1E89, 'V'), + (0x1E8A, 'M', u'ẋ'), + (0x1E8B, 'V'), + (0x1E8C, 'M', u'ẍ'), + (0x1E8D, 'V'), + (0x1E8E, 'M', u'ẏ'), + (0x1E8F, 'V'), + (0x1E90, 'M', u'ẑ'), + (0x1E91, 'V'), + (0x1E92, 'M', u'ẓ'), + (0x1E93, 'V'), + (0x1E94, 'M', u'ẕ'), + (0x1E95, 'V'), + (0x1E9A, 'M', u'aʾ'), + (0x1E9B, 'M', u'ṡ'), + (0x1E9C, 'V'), + (0x1E9E, 'M', u'ss'), + (0x1E9F, 'V'), + (0x1EA0, 'M', u'ạ'), + (0x1EA1, 'V'), + (0x1EA2, 'M', u'ả'), + (0x1EA3, 'V'), + (0x1EA4, 'M', u'ấ'), + (0x1EA5, 'V'), + (0x1EA6, 'M', u'ầ'), + (0x1EA7, 'V'), + (0x1EA8, 'M', u'ẩ'), + (0x1EA9, 'V'), + (0x1EAA, 'M', u'ẫ'), + (0x1EAB, 'V'), + (0x1EAC, 'M', u'ậ'), + (0x1EAD, 'V'), + (0x1EAE, 'M', u'ắ'), + (0x1EAF, 'V'), + (0x1EB0, 'M', u'ằ'), + (0x1EB1, 'V'), + (0x1EB2, 'M', u'ẳ'), + (0x1EB3, 'V'), + (0x1EB4, 'M', u'ẵ'), + (0x1EB5, 'V'), + (0x1EB6, 'M', u'ặ'), + (0x1EB7, 'V'), + (0x1EB8, 'M', u'ẹ'), + (0x1EB9, 'V'), + (0x1EBA, 'M', u'ẻ'), + (0x1EBB, 'V'), + (0x1EBC, 'M', u'ẽ'), + (0x1EBD, 'V'), + (0x1EBE, 'M', u'ế'), + (0x1EBF, 'V'), + (0x1EC0, 'M', u'ề'), + (0x1EC1, 'V'), + (0x1EC2, 'M', u'ể'), + (0x1EC3, 'V'), + (0x1EC4, 'M', u'ễ'), + (0x1EC5, 'V'), + (0x1EC6, 'M', u'ệ'), + (0x1EC7, 'V'), + (0x1EC8, 'M', u'ỉ'), + (0x1EC9, 'V'), + (0x1ECA, 'M', u'ị'), + (0x1ECB, 'V'), + (0x1ECC, 'M', u'ọ'), + (0x1ECD, 'V'), + (0x1ECE, 'M', u'ỏ'), + (0x1ECF, 'V'), + (0x1ED0, 'M', u'ố'), + (0x1ED1, 'V'), + (0x1ED2, 'M', u'ồ'), + (0x1ED3, 'V'), + (0x1ED4, 'M', u'ổ'), + (0x1ED5, 'V'), + (0x1ED6, 'M', u'ỗ'), + (0x1ED7, 'V'), + (0x1ED8, 'M', u'ộ'), + (0x1ED9, 'V'), + (0x1EDA, 'M', u'ớ'), + (0x1EDB, 'V'), + (0x1EDC, 'M', u'ờ'), + (0x1EDD, 'V'), + (0x1EDE, 'M', u'ở'), + (0x1EDF, 'V'), + (0x1EE0, 'M', u'ỡ'), + (0x1EE1, 'V'), + (0x1EE2, 'M', u'ợ'), + (0x1EE3, 'V'), + (0x1EE4, 'M', u'ụ'), + (0x1EE5, 'V'), + (0x1EE6, 'M', u'ủ'), + (0x1EE7, 'V'), + (0x1EE8, 'M', u'ứ'), + (0x1EE9, 'V'), + (0x1EEA, 'M', u'ừ'), + (0x1EEB, 'V'), + (0x1EEC, 'M', u'ử'), + (0x1EED, 'V'), + ] + +def _seg_19(): + return [ + (0x1EEE, 'M', u'ữ'), + (0x1EEF, 'V'), + (0x1EF0, 'M', u'ự'), + (0x1EF1, 'V'), + (0x1EF2, 'M', u'ỳ'), + (0x1EF3, 'V'), + (0x1EF4, 'M', u'ỵ'), + (0x1EF5, 'V'), + (0x1EF6, 'M', u'ỷ'), + (0x1EF7, 'V'), + (0x1EF8, 'M', u'ỹ'), + (0x1EF9, 'V'), + (0x1EFA, 'M', u'ỻ'), + (0x1EFB, 'V'), + (0x1EFC, 'M', u'ỽ'), + (0x1EFD, 'V'), + (0x1EFE, 'M', u'ỿ'), + (0x1EFF, 'V'), + (0x1F08, 'M', u'ἀ'), + (0x1F09, 'M', u'ἁ'), + (0x1F0A, 'M', u'ἂ'), + (0x1F0B, 'M', u'ἃ'), + (0x1F0C, 'M', u'ἄ'), + (0x1F0D, 'M', u'ἅ'), + (0x1F0E, 'M', u'ἆ'), + (0x1F0F, 'M', u'ἇ'), + (0x1F10, 'V'), + (0x1F16, 'X'), + (0x1F18, 'M', u'ἐ'), + (0x1F19, 'M', u'ἑ'), + (0x1F1A, 'M', u'ἒ'), + (0x1F1B, 'M', u'ἓ'), + (0x1F1C, 'M', u'ἔ'), + (0x1F1D, 'M', u'ἕ'), + (0x1F1E, 'X'), + (0x1F20, 'V'), + (0x1F28, 'M', u'ἠ'), + (0x1F29, 'M', u'ἡ'), + (0x1F2A, 'M', u'ἢ'), + (0x1F2B, 'M', u'ἣ'), + (0x1F2C, 'M', u'ἤ'), + (0x1F2D, 'M', u'ἥ'), + (0x1F2E, 'M', u'ἦ'), + (0x1F2F, 'M', u'ἧ'), + (0x1F30, 'V'), + (0x1F38, 'M', u'ἰ'), + (0x1F39, 'M', u'ἱ'), + (0x1F3A, 'M', u'ἲ'), + (0x1F3B, 'M', u'ἳ'), + (0x1F3C, 'M', u'ἴ'), + (0x1F3D, 'M', u'ἵ'), + (0x1F3E, 'M', u'ἶ'), + (0x1F3F, 'M', u'ἷ'), + (0x1F40, 'V'), + (0x1F46, 'X'), + (0x1F48, 'M', u'ὀ'), + (0x1F49, 'M', u'ὁ'), + (0x1F4A, 'M', u'ὂ'), + (0x1F4B, 'M', u'ὃ'), + (0x1F4C, 'M', u'ὄ'), + (0x1F4D, 'M', u'ὅ'), + (0x1F4E, 'X'), + (0x1F50, 'V'), + (0x1F58, 'X'), + (0x1F59, 'M', u'ὑ'), + (0x1F5A, 'X'), + (0x1F5B, 'M', u'ὓ'), + (0x1F5C, 'X'), + (0x1F5D, 'M', u'ὕ'), + (0x1F5E, 'X'), + (0x1F5F, 'M', u'ὗ'), + (0x1F60, 'V'), + (0x1F68, 'M', u'ὠ'), + (0x1F69, 'M', u'ὡ'), + (0x1F6A, 'M', u'ὢ'), + (0x1F6B, 'M', u'ὣ'), + (0x1F6C, 'M', u'ὤ'), + (0x1F6D, 'M', u'ὥ'), + (0x1F6E, 'M', u'ὦ'), + (0x1F6F, 'M', u'ὧ'), + (0x1F70, 'V'), + (0x1F71, 'M', u'ά'), + (0x1F72, 'V'), + (0x1F73, 'M', u'έ'), + (0x1F74, 'V'), + (0x1F75, 'M', u'ή'), + (0x1F76, 'V'), + (0x1F77, 'M', u'ί'), + (0x1F78, 'V'), + (0x1F79, 'M', u'ό'), + (0x1F7A, 'V'), + (0x1F7B, 'M', u'ύ'), + (0x1F7C, 'V'), + (0x1F7D, 'M', u'ώ'), + (0x1F7E, 'X'), + (0x1F80, 'M', u'ἀι'), + (0x1F81, 'M', u'ἁι'), + (0x1F82, 'M', u'ἂι'), + (0x1F83, 'M', u'ἃι'), + (0x1F84, 'M', u'ἄι'), + ] + +def _seg_20(): + return [ + (0x1F85, 'M', u'ἅι'), + (0x1F86, 'M', u'ἆι'), + (0x1F87, 'M', u'ἇι'), + (0x1F88, 'M', u'ἀι'), + (0x1F89, 'M', u'ἁι'), + (0x1F8A, 'M', u'ἂι'), + (0x1F8B, 'M', u'ἃι'), + (0x1F8C, 'M', u'ἄι'), + (0x1F8D, 'M', u'ἅι'), + (0x1F8E, 'M', u'ἆι'), + (0x1F8F, 'M', u'ἇι'), + (0x1F90, 'M', u'ἠι'), + (0x1F91, 'M', u'ἡι'), + (0x1F92, 'M', u'ἢι'), + (0x1F93, 'M', u'ἣι'), + (0x1F94, 'M', u'ἤι'), + (0x1F95, 'M', u'ἥι'), + (0x1F96, 'M', u'ἦι'), + (0x1F97, 'M', u'ἧι'), + (0x1F98, 'M', u'ἠι'), + (0x1F99, 'M', u'ἡι'), + (0x1F9A, 'M', u'ἢι'), + (0x1F9B, 'M', u'ἣι'), + (0x1F9C, 'M', u'ἤι'), + (0x1F9D, 'M', u'ἥι'), + (0x1F9E, 'M', u'ἦι'), + (0x1F9F, 'M', u'ἧι'), + (0x1FA0, 'M', u'ὠι'), + (0x1FA1, 'M', u'ὡι'), + (0x1FA2, 'M', u'ὢι'), + (0x1FA3, 'M', u'ὣι'), + (0x1FA4, 'M', u'ὤι'), + (0x1FA5, 'M', u'ὥι'), + (0x1FA6, 'M', u'ὦι'), + (0x1FA7, 'M', u'ὧι'), + (0x1FA8, 'M', u'ὠι'), + (0x1FA9, 'M', u'ὡι'), + (0x1FAA, 'M', u'ὢι'), + (0x1FAB, 'M', u'ὣι'), + (0x1FAC, 'M', u'ὤι'), + (0x1FAD, 'M', u'ὥι'), + (0x1FAE, 'M', u'ὦι'), + (0x1FAF, 'M', u'ὧι'), + (0x1FB0, 'V'), + (0x1FB2, 'M', u'ὰι'), + (0x1FB3, 'M', u'αι'), + (0x1FB4, 'M', u'άι'), + (0x1FB5, 'X'), + (0x1FB6, 'V'), + (0x1FB7, 'M', u'ᾶι'), + (0x1FB8, 'M', u'ᾰ'), + (0x1FB9, 'M', u'ᾱ'), + (0x1FBA, 'M', u'ὰ'), + (0x1FBB, 'M', u'ά'), + (0x1FBC, 'M', u'αι'), + (0x1FBD, '3', u' ̓'), + (0x1FBE, 'M', u'ι'), + (0x1FBF, '3', u' ̓'), + (0x1FC0, '3', u' ͂'), + (0x1FC1, '3', u' ̈͂'), + (0x1FC2, 'M', u'ὴι'), + (0x1FC3, 'M', u'ηι'), + (0x1FC4, 'M', u'ήι'), + (0x1FC5, 'X'), + (0x1FC6, 'V'), + (0x1FC7, 'M', u'ῆι'), + (0x1FC8, 'M', u'ὲ'), + (0x1FC9, 'M', u'έ'), + (0x1FCA, 'M', u'ὴ'), + (0x1FCB, 'M', u'ή'), + (0x1FCC, 'M', u'ηι'), + (0x1FCD, '3', u' ̓̀'), + (0x1FCE, '3', u' ̓́'), + (0x1FCF, '3', u' ̓͂'), + (0x1FD0, 'V'), + (0x1FD3, 'M', u'ΐ'), + (0x1FD4, 'X'), + (0x1FD6, 'V'), + (0x1FD8, 'M', u'ῐ'), + (0x1FD9, 'M', u'ῑ'), + (0x1FDA, 'M', u'ὶ'), + (0x1FDB, 'M', u'ί'), + (0x1FDC, 'X'), + (0x1FDD, '3', u' ̔̀'), + (0x1FDE, '3', u' ̔́'), + (0x1FDF, '3', u' ̔͂'), + (0x1FE0, 'V'), + (0x1FE3, 'M', u'ΰ'), + (0x1FE4, 'V'), + (0x1FE8, 'M', u'ῠ'), + (0x1FE9, 'M', u'ῡ'), + (0x1FEA, 'M', u'ὺ'), + (0x1FEB, 'M', u'ύ'), + (0x1FEC, 'M', u'ῥ'), + (0x1FED, '3', u' ̈̀'), + (0x1FEE, '3', u' ̈́'), + (0x1FEF, '3', u'`'), + (0x1FF0, 'X'), + (0x1FF2, 'M', u'ὼι'), + (0x1FF3, 'M', u'ωι'), + ] + +def _seg_21(): + return [ + (0x1FF4, 'M', u'ώι'), + (0x1FF5, 'X'), + (0x1FF6, 'V'), + (0x1FF7, 'M', u'ῶι'), + (0x1FF8, 'M', u'ὸ'), + (0x1FF9, 'M', u'ό'), + (0x1FFA, 'M', u'ὼ'), + (0x1FFB, 'M', u'ώ'), + (0x1FFC, 'M', u'ωι'), + (0x1FFD, '3', u' ́'), + (0x1FFE, '3', u' ̔'), + (0x1FFF, 'X'), + (0x2000, '3', u' '), + (0x200B, 'I'), + (0x200C, 'D', u''), + (0x200E, 'X'), + (0x2010, 'V'), + (0x2011, 'M', u'‐'), + (0x2012, 'V'), + (0x2017, '3', u' ̳'), + (0x2018, 'V'), + (0x2024, 'X'), + (0x2027, 'V'), + (0x2028, 'X'), + (0x202F, '3', u' '), + (0x2030, 'V'), + (0x2033, 'M', u'′′'), + (0x2034, 'M', u'′′′'), + (0x2035, 'V'), + (0x2036, 'M', u'‵‵'), + (0x2037, 'M', u'‵‵‵'), + (0x2038, 'V'), + (0x203C, '3', u'!!'), + (0x203D, 'V'), + (0x203E, '3', u' ̅'), + (0x203F, 'V'), + (0x2047, '3', u'??'), + (0x2048, '3', u'?!'), + (0x2049, '3', u'!?'), + (0x204A, 'V'), + (0x2057, 'M', u'′′′′'), + (0x2058, 'V'), + (0x205F, '3', u' '), + (0x2060, 'I'), + (0x2061, 'X'), + (0x2064, 'I'), + (0x2065, 'X'), + (0x2070, 'M', u'0'), + (0x2071, 'M', u'i'), + (0x2072, 'X'), + (0x2074, 'M', u'4'), + (0x2075, 'M', u'5'), + (0x2076, 'M', u'6'), + (0x2077, 'M', u'7'), + (0x2078, 'M', u'8'), + (0x2079, 'M', u'9'), + (0x207A, '3', u'+'), + (0x207B, 'M', u'−'), + (0x207C, '3', u'='), + (0x207D, '3', u'('), + (0x207E, '3', u')'), + (0x207F, 'M', u'n'), + (0x2080, 'M', u'0'), + (0x2081, 'M', u'1'), + (0x2082, 'M', u'2'), + (0x2083, 'M', u'3'), + (0x2084, 'M', u'4'), + (0x2085, 'M', u'5'), + (0x2086, 'M', u'6'), + (0x2087, 'M', u'7'), + (0x2088, 'M', u'8'), + (0x2089, 'M', u'9'), + (0x208A, '3', u'+'), + (0x208B, 'M', u'−'), + (0x208C, '3', u'='), + (0x208D, '3', u'('), + (0x208E, '3', u')'), + (0x208F, 'X'), + (0x2090, 'M', u'a'), + (0x2091, 'M', u'e'), + (0x2092, 'M', u'o'), + (0x2093, 'M', u'x'), + (0x2094, 'M', u'ə'), + (0x2095, 'M', u'h'), + (0x2096, 'M', u'k'), + (0x2097, 'M', u'l'), + (0x2098, 'M', u'm'), + (0x2099, 'M', u'n'), + (0x209A, 'M', u'p'), + (0x209B, 'M', u's'), + (0x209C, 'M', u't'), + (0x209D, 'X'), + (0x20A0, 'V'), + (0x20A8, 'M', u'rs'), + (0x20A9, 'V'), + (0x20C0, 'X'), + (0x20D0, 'V'), + (0x20F1, 'X'), + (0x2100, '3', u'a/c'), + (0x2101, '3', u'a/s'), + ] + +def _seg_22(): + return [ + (0x2102, 'M', u'c'), + (0x2103, 'M', u'°c'), + (0x2104, 'V'), + (0x2105, '3', u'c/o'), + (0x2106, '3', u'c/u'), + (0x2107, 'M', u'ɛ'), + (0x2108, 'V'), + (0x2109, 'M', u'°f'), + (0x210A, 'M', u'g'), + (0x210B, 'M', u'h'), + (0x210F, 'M', u'ħ'), + (0x2110, 'M', u'i'), + (0x2112, 'M', u'l'), + (0x2114, 'V'), + (0x2115, 'M', u'n'), + (0x2116, 'M', u'no'), + (0x2117, 'V'), + (0x2119, 'M', u'p'), + (0x211A, 'M', u'q'), + (0x211B, 'M', u'r'), + (0x211E, 'V'), + (0x2120, 'M', u'sm'), + (0x2121, 'M', u'tel'), + (0x2122, 'M', u'tm'), + (0x2123, 'V'), + (0x2124, 'M', u'z'), + (0x2125, 'V'), + (0x2126, 'M', u'ω'), + (0x2127, 'V'), + (0x2128, 'M', u'z'), + (0x2129, 'V'), + (0x212A, 'M', u'k'), + (0x212B, 'M', u'å'), + (0x212C, 'M', u'b'), + (0x212D, 'M', u'c'), + (0x212E, 'V'), + (0x212F, 'M', u'e'), + (0x2131, 'M', u'f'), + (0x2132, 'X'), + (0x2133, 'M', u'm'), + (0x2134, 'M', u'o'), + (0x2135, 'M', u'א'), + (0x2136, 'M', u'ב'), + (0x2137, 'M', u'ג'), + (0x2138, 'M', u'ד'), + (0x2139, 'M', u'i'), + (0x213A, 'V'), + (0x213B, 'M', u'fax'), + (0x213C, 'M', u'π'), + (0x213D, 'M', u'γ'), + (0x213F, 'M', u'π'), + (0x2140, 'M', u'∑'), + (0x2141, 'V'), + (0x2145, 'M', u'd'), + (0x2147, 'M', u'e'), + (0x2148, 'M', u'i'), + (0x2149, 'M', u'j'), + (0x214A, 'V'), + (0x2150, 'M', u'1⁄7'), + (0x2151, 'M', u'1⁄9'), + (0x2152, 'M', u'1⁄10'), + (0x2153, 'M', u'1⁄3'), + (0x2154, 'M', u'2⁄3'), + (0x2155, 'M', u'1⁄5'), + (0x2156, 'M', u'2⁄5'), + (0x2157, 'M', u'3⁄5'), + (0x2158, 'M', u'4⁄5'), + (0x2159, 'M', u'1⁄6'), + (0x215A, 'M', u'5⁄6'), + (0x215B, 'M', u'1⁄8'), + (0x215C, 'M', u'3⁄8'), + (0x215D, 'M', u'5⁄8'), + (0x215E, 'M', u'7⁄8'), + (0x215F, 'M', u'1⁄'), + (0x2160, 'M', u'i'), + (0x2161, 'M', u'ii'), + (0x2162, 'M', u'iii'), + (0x2163, 'M', u'iv'), + (0x2164, 'M', u'v'), + (0x2165, 'M', u'vi'), + (0x2166, 'M', u'vii'), + (0x2167, 'M', u'viii'), + (0x2168, 'M', u'ix'), + (0x2169, 'M', u'x'), + (0x216A, 'M', u'xi'), + (0x216B, 'M', u'xii'), + (0x216C, 'M', u'l'), + (0x216D, 'M', u'c'), + (0x216E, 'M', u'd'), + (0x216F, 'M', u'm'), + (0x2170, 'M', u'i'), + (0x2171, 'M', u'ii'), + (0x2172, 'M', u'iii'), + (0x2173, 'M', u'iv'), + (0x2174, 'M', u'v'), + (0x2175, 'M', u'vi'), + (0x2176, 'M', u'vii'), + (0x2177, 'M', u'viii'), + (0x2178, 'M', u'ix'), + (0x2179, 'M', u'x'), + ] + +def _seg_23(): + return [ + (0x217A, 'M', u'xi'), + (0x217B, 'M', u'xii'), + (0x217C, 'M', u'l'), + (0x217D, 'M', u'c'), + (0x217E, 'M', u'd'), + (0x217F, 'M', u'm'), + (0x2180, 'V'), + (0x2183, 'X'), + (0x2184, 'V'), + (0x2189, 'M', u'0⁄3'), + (0x218A, 'V'), + (0x218C, 'X'), + (0x2190, 'V'), + (0x222C, 'M', u'∫∫'), + (0x222D, 'M', u'∫∫∫'), + (0x222E, 'V'), + (0x222F, 'M', u'∮∮'), + (0x2230, 'M', u'∮∮∮'), + (0x2231, 'V'), + (0x2260, '3'), + (0x2261, 'V'), + (0x226E, '3'), + (0x2270, 'V'), + (0x2329, 'M', u'〈'), + (0x232A, 'M', u'〉'), + (0x232B, 'V'), + (0x2427, 'X'), + (0x2440, 'V'), + (0x244B, 'X'), + (0x2460, 'M', u'1'), + (0x2461, 'M', u'2'), + (0x2462, 'M', u'3'), + (0x2463, 'M', u'4'), + (0x2464, 'M', u'5'), + (0x2465, 'M', u'6'), + (0x2466, 'M', u'7'), + (0x2467, 'M', u'8'), + (0x2468, 'M', u'9'), + (0x2469, 'M', u'10'), + (0x246A, 'M', u'11'), + (0x246B, 'M', u'12'), + (0x246C, 'M', u'13'), + (0x246D, 'M', u'14'), + (0x246E, 'M', u'15'), + (0x246F, 'M', u'16'), + (0x2470, 'M', u'17'), + (0x2471, 'M', u'18'), + (0x2472, 'M', u'19'), + (0x2473, 'M', u'20'), + (0x2474, '3', u'(1)'), + (0x2475, '3', u'(2)'), + (0x2476, '3', u'(3)'), + (0x2477, '3', u'(4)'), + (0x2478, '3', u'(5)'), + (0x2479, '3', u'(6)'), + (0x247A, '3', u'(7)'), + (0x247B, '3', u'(8)'), + (0x247C, '3', u'(9)'), + (0x247D, '3', u'(10)'), + (0x247E, '3', u'(11)'), + (0x247F, '3', u'(12)'), + (0x2480, '3', u'(13)'), + (0x2481, '3', u'(14)'), + (0x2482, '3', u'(15)'), + (0x2483, '3', u'(16)'), + (0x2484, '3', u'(17)'), + (0x2485, '3', u'(18)'), + (0x2486, '3', u'(19)'), + (0x2487, '3', u'(20)'), + (0x2488, 'X'), + (0x249C, '3', u'(a)'), + (0x249D, '3', u'(b)'), + (0x249E, '3', u'(c)'), + (0x249F, '3', u'(d)'), + (0x24A0, '3', u'(e)'), + (0x24A1, '3', u'(f)'), + (0x24A2, '3', u'(g)'), + (0x24A3, '3', u'(h)'), + (0x24A4, '3', u'(i)'), + (0x24A5, '3', u'(j)'), + (0x24A6, '3', u'(k)'), + (0x24A7, '3', u'(l)'), + (0x24A8, '3', u'(m)'), + (0x24A9, '3', u'(n)'), + (0x24AA, '3', u'(o)'), + (0x24AB, '3', u'(p)'), + (0x24AC, '3', u'(q)'), + (0x24AD, '3', u'(r)'), + (0x24AE, '3', u'(s)'), + (0x24AF, '3', u'(t)'), + (0x24B0, '3', u'(u)'), + (0x24B1, '3', u'(v)'), + (0x24B2, '3', u'(w)'), + (0x24B3, '3', u'(x)'), + (0x24B4, '3', u'(y)'), + (0x24B5, '3', u'(z)'), + (0x24B6, 'M', u'a'), + (0x24B7, 'M', u'b'), + (0x24B8, 'M', u'c'), + (0x24B9, 'M', u'd'), + ] + +def _seg_24(): + return [ + (0x24BA, 'M', u'e'), + (0x24BB, 'M', u'f'), + (0x24BC, 'M', u'g'), + (0x24BD, 'M', u'h'), + (0x24BE, 'M', u'i'), + (0x24BF, 'M', u'j'), + (0x24C0, 'M', u'k'), + (0x24C1, 'M', u'l'), + (0x24C2, 'M', u'm'), + (0x24C3, 'M', u'n'), + (0x24C4, 'M', u'o'), + (0x24C5, 'M', u'p'), + (0x24C6, 'M', u'q'), + (0x24C7, 'M', u'r'), + (0x24C8, 'M', u's'), + (0x24C9, 'M', u't'), + (0x24CA, 'M', u'u'), + (0x24CB, 'M', u'v'), + (0x24CC, 'M', u'w'), + (0x24CD, 'M', u'x'), + (0x24CE, 'M', u'y'), + (0x24CF, 'M', u'z'), + (0x24D0, 'M', u'a'), + (0x24D1, 'M', u'b'), + (0x24D2, 'M', u'c'), + (0x24D3, 'M', u'd'), + (0x24D4, 'M', u'e'), + (0x24D5, 'M', u'f'), + (0x24D6, 'M', u'g'), + (0x24D7, 'M', u'h'), + (0x24D8, 'M', u'i'), + (0x24D9, 'M', u'j'), + (0x24DA, 'M', u'k'), + (0x24DB, 'M', u'l'), + (0x24DC, 'M', u'm'), + (0x24DD, 'M', u'n'), + (0x24DE, 'M', u'o'), + (0x24DF, 'M', u'p'), + (0x24E0, 'M', u'q'), + (0x24E1, 'M', u'r'), + (0x24E2, 'M', u's'), + (0x24E3, 'M', u't'), + (0x24E4, 'M', u'u'), + (0x24E5, 'M', u'v'), + (0x24E6, 'M', u'w'), + (0x24E7, 'M', u'x'), + (0x24E8, 'M', u'y'), + (0x24E9, 'M', u'z'), + (0x24EA, 'M', u'0'), + (0x24EB, 'V'), + (0x2A0C, 'M', u'∫∫∫∫'), + (0x2A0D, 'V'), + (0x2A74, '3', u'::='), + (0x2A75, '3', u'=='), + (0x2A76, '3', u'==='), + (0x2A77, 'V'), + (0x2ADC, 'M', u'⫝̸'), + (0x2ADD, 'V'), + (0x2B74, 'X'), + (0x2B76, 'V'), + (0x2B96, 'X'), + (0x2B97, 'V'), + (0x2C00, 'M', u'ⰰ'), + (0x2C01, 'M', u'ⰱ'), + (0x2C02, 'M', u'ⰲ'), + (0x2C03, 'M', u'ⰳ'), + (0x2C04, 'M', u'ⰴ'), + (0x2C05, 'M', u'ⰵ'), + (0x2C06, 'M', u'ⰶ'), + (0x2C07, 'M', u'ⰷ'), + (0x2C08, 'M', u'ⰸ'), + (0x2C09, 'M', u'ⰹ'), + (0x2C0A, 'M', u'ⰺ'), + (0x2C0B, 'M', u'ⰻ'), + (0x2C0C, 'M', u'ⰼ'), + (0x2C0D, 'M', u'ⰽ'), + (0x2C0E, 'M', u'ⰾ'), + (0x2C0F, 'M', u'ⰿ'), + (0x2C10, 'M', u'ⱀ'), + (0x2C11, 'M', u'ⱁ'), + (0x2C12, 'M', u'ⱂ'), + (0x2C13, 'M', u'ⱃ'), + (0x2C14, 'M', u'ⱄ'), + (0x2C15, 'M', u'ⱅ'), + (0x2C16, 'M', u'ⱆ'), + (0x2C17, 'M', u'ⱇ'), + (0x2C18, 'M', u'ⱈ'), + (0x2C19, 'M', u'ⱉ'), + (0x2C1A, 'M', u'ⱊ'), + (0x2C1B, 'M', u'ⱋ'), + (0x2C1C, 'M', u'ⱌ'), + (0x2C1D, 'M', u'ⱍ'), + (0x2C1E, 'M', u'ⱎ'), + (0x2C1F, 'M', u'ⱏ'), + (0x2C20, 'M', u'ⱐ'), + (0x2C21, 'M', u'ⱑ'), + (0x2C22, 'M', u'ⱒ'), + (0x2C23, 'M', u'ⱓ'), + (0x2C24, 'M', u'ⱔ'), + (0x2C25, 'M', u'ⱕ'), + ] + +def _seg_25(): + return [ + (0x2C26, 'M', u'ⱖ'), + (0x2C27, 'M', u'ⱗ'), + (0x2C28, 'M', u'ⱘ'), + (0x2C29, 'M', u'ⱙ'), + (0x2C2A, 'M', u'ⱚ'), + (0x2C2B, 'M', u'ⱛ'), + (0x2C2C, 'M', u'ⱜ'), + (0x2C2D, 'M', u'ⱝ'), + (0x2C2E, 'M', u'ⱞ'), + (0x2C2F, 'X'), + (0x2C30, 'V'), + (0x2C5F, 'X'), + (0x2C60, 'M', u'ⱡ'), + (0x2C61, 'V'), + (0x2C62, 'M', u'ɫ'), + (0x2C63, 'M', u'ᵽ'), + (0x2C64, 'M', u'ɽ'), + (0x2C65, 'V'), + (0x2C67, 'M', u'ⱨ'), + (0x2C68, 'V'), + (0x2C69, 'M', u'ⱪ'), + (0x2C6A, 'V'), + (0x2C6B, 'M', u'ⱬ'), + (0x2C6C, 'V'), + (0x2C6D, 'M', u'ɑ'), + (0x2C6E, 'M', u'ɱ'), + (0x2C6F, 'M', u'ɐ'), + (0x2C70, 'M', u'ɒ'), + (0x2C71, 'V'), + (0x2C72, 'M', u'ⱳ'), + (0x2C73, 'V'), + (0x2C75, 'M', u'ⱶ'), + (0x2C76, 'V'), + (0x2C7C, 'M', u'j'), + (0x2C7D, 'M', u'v'), + (0x2C7E, 'M', u'ȿ'), + (0x2C7F, 'M', u'ɀ'), + (0x2C80, 'M', u'ⲁ'), + (0x2C81, 'V'), + (0x2C82, 'M', u'ⲃ'), + (0x2C83, 'V'), + (0x2C84, 'M', u'ⲅ'), + (0x2C85, 'V'), + (0x2C86, 'M', u'ⲇ'), + (0x2C87, 'V'), + (0x2C88, 'M', u'ⲉ'), + (0x2C89, 'V'), + (0x2C8A, 'M', u'ⲋ'), + (0x2C8B, 'V'), + (0x2C8C, 'M', u'ⲍ'), + (0x2C8D, 'V'), + (0x2C8E, 'M', u'ⲏ'), + (0x2C8F, 'V'), + (0x2C90, 'M', u'ⲑ'), + (0x2C91, 'V'), + (0x2C92, 'M', u'ⲓ'), + (0x2C93, 'V'), + (0x2C94, 'M', u'ⲕ'), + (0x2C95, 'V'), + (0x2C96, 'M', u'ⲗ'), + (0x2C97, 'V'), + (0x2C98, 'M', u'ⲙ'), + (0x2C99, 'V'), + (0x2C9A, 'M', u'ⲛ'), + (0x2C9B, 'V'), + (0x2C9C, 'M', u'ⲝ'), + (0x2C9D, 'V'), + (0x2C9E, 'M', u'ⲟ'), + (0x2C9F, 'V'), + (0x2CA0, 'M', u'ⲡ'), + (0x2CA1, 'V'), + (0x2CA2, 'M', u'ⲣ'), + (0x2CA3, 'V'), + (0x2CA4, 'M', u'ⲥ'), + (0x2CA5, 'V'), + (0x2CA6, 'M', u'ⲧ'), + (0x2CA7, 'V'), + (0x2CA8, 'M', u'ⲩ'), + (0x2CA9, 'V'), + (0x2CAA, 'M', u'ⲫ'), + (0x2CAB, 'V'), + (0x2CAC, 'M', u'ⲭ'), + (0x2CAD, 'V'), + (0x2CAE, 'M', u'ⲯ'), + (0x2CAF, 'V'), + (0x2CB0, 'M', u'ⲱ'), + (0x2CB1, 'V'), + (0x2CB2, 'M', u'ⲳ'), + (0x2CB3, 'V'), + (0x2CB4, 'M', u'ⲵ'), + (0x2CB5, 'V'), + (0x2CB6, 'M', u'ⲷ'), + (0x2CB7, 'V'), + (0x2CB8, 'M', u'ⲹ'), + (0x2CB9, 'V'), + (0x2CBA, 'M', u'ⲻ'), + (0x2CBB, 'V'), + (0x2CBC, 'M', u'ⲽ'), + (0x2CBD, 'V'), + (0x2CBE, 'M', u'ⲿ'), + ] + +def _seg_26(): + return [ + (0x2CBF, 'V'), + (0x2CC0, 'M', u'ⳁ'), + (0x2CC1, 'V'), + (0x2CC2, 'M', u'ⳃ'), + (0x2CC3, 'V'), + (0x2CC4, 'M', u'ⳅ'), + (0x2CC5, 'V'), + (0x2CC6, 'M', u'ⳇ'), + (0x2CC7, 'V'), + (0x2CC8, 'M', u'ⳉ'), + (0x2CC9, 'V'), + (0x2CCA, 'M', u'ⳋ'), + (0x2CCB, 'V'), + (0x2CCC, 'M', u'ⳍ'), + (0x2CCD, 'V'), + (0x2CCE, 'M', u'ⳏ'), + (0x2CCF, 'V'), + (0x2CD0, 'M', u'ⳑ'), + (0x2CD1, 'V'), + (0x2CD2, 'M', u'ⳓ'), + (0x2CD3, 'V'), + (0x2CD4, 'M', u'ⳕ'), + (0x2CD5, 'V'), + (0x2CD6, 'M', u'ⳗ'), + (0x2CD7, 'V'), + (0x2CD8, 'M', u'ⳙ'), + (0x2CD9, 'V'), + (0x2CDA, 'M', u'ⳛ'), + (0x2CDB, 'V'), + (0x2CDC, 'M', u'ⳝ'), + (0x2CDD, 'V'), + (0x2CDE, 'M', u'ⳟ'), + (0x2CDF, 'V'), + (0x2CE0, 'M', u'ⳡ'), + (0x2CE1, 'V'), + (0x2CE2, 'M', u'ⳣ'), + (0x2CE3, 'V'), + (0x2CEB, 'M', u'ⳬ'), + (0x2CEC, 'V'), + (0x2CED, 'M', u'ⳮ'), + (0x2CEE, 'V'), + (0x2CF2, 'M', u'ⳳ'), + (0x2CF3, 'V'), + (0x2CF4, 'X'), + (0x2CF9, 'V'), + (0x2D26, 'X'), + (0x2D27, 'V'), + (0x2D28, 'X'), + (0x2D2D, 'V'), + (0x2D2E, 'X'), + (0x2D30, 'V'), + (0x2D68, 'X'), + (0x2D6F, 'M', u'ⵡ'), + (0x2D70, 'V'), + (0x2D71, 'X'), + (0x2D7F, 'V'), + (0x2D97, 'X'), + (0x2DA0, 'V'), + (0x2DA7, 'X'), + (0x2DA8, 'V'), + (0x2DAF, 'X'), + (0x2DB0, 'V'), + (0x2DB7, 'X'), + (0x2DB8, 'V'), + (0x2DBF, 'X'), + (0x2DC0, 'V'), + (0x2DC7, 'X'), + (0x2DC8, 'V'), + (0x2DCF, 'X'), + (0x2DD0, 'V'), + (0x2DD7, 'X'), + (0x2DD8, 'V'), + (0x2DDF, 'X'), + (0x2DE0, 'V'), + (0x2E53, 'X'), + (0x2E80, 'V'), + (0x2E9A, 'X'), + (0x2E9B, 'V'), + (0x2E9F, 'M', u'母'), + (0x2EA0, 'V'), + (0x2EF3, 'M', u'龟'), + (0x2EF4, 'X'), + (0x2F00, 'M', u'一'), + (0x2F01, 'M', u'丨'), + (0x2F02, 'M', u'丶'), + (0x2F03, 'M', u'丿'), + (0x2F04, 'M', u'乙'), + (0x2F05, 'M', u'亅'), + (0x2F06, 'M', u'二'), + (0x2F07, 'M', u'亠'), + (0x2F08, 'M', u'人'), + (0x2F09, 'M', u'儿'), + (0x2F0A, 'M', u'入'), + (0x2F0B, 'M', u'八'), + (0x2F0C, 'M', u'冂'), + (0x2F0D, 'M', u'冖'), + (0x2F0E, 'M', u'冫'), + (0x2F0F, 'M', u'几'), + (0x2F10, 'M', u'凵'), + (0x2F11, 'M', u'刀'), + ] + +def _seg_27(): + return [ + (0x2F12, 'M', u'力'), + (0x2F13, 'M', u'勹'), + (0x2F14, 'M', u'匕'), + (0x2F15, 'M', u'匚'), + (0x2F16, 'M', u'匸'), + (0x2F17, 'M', u'十'), + (0x2F18, 'M', u'卜'), + (0x2F19, 'M', u'卩'), + (0x2F1A, 'M', u'厂'), + (0x2F1B, 'M', u'厶'), + (0x2F1C, 'M', u'又'), + (0x2F1D, 'M', u'口'), + (0x2F1E, 'M', u'囗'), + (0x2F1F, 'M', u'土'), + (0x2F20, 'M', u'士'), + (0x2F21, 'M', u'夂'), + (0x2F22, 'M', u'夊'), + (0x2F23, 'M', u'夕'), + (0x2F24, 'M', u'大'), + (0x2F25, 'M', u'女'), + (0x2F26, 'M', u'子'), + (0x2F27, 'M', u'宀'), + (0x2F28, 'M', u'寸'), + (0x2F29, 'M', u'小'), + (0x2F2A, 'M', u'尢'), + (0x2F2B, 'M', u'尸'), + (0x2F2C, 'M', u'屮'), + (0x2F2D, 'M', u'山'), + (0x2F2E, 'M', u'巛'), + (0x2F2F, 'M', u'工'), + (0x2F30, 'M', u'己'), + (0x2F31, 'M', u'巾'), + (0x2F32, 'M', u'干'), + (0x2F33, 'M', u'幺'), + (0x2F34, 'M', u'广'), + (0x2F35, 'M', u'廴'), + (0x2F36, 'M', u'廾'), + (0x2F37, 'M', u'弋'), + (0x2F38, 'M', u'弓'), + (0x2F39, 'M', u'彐'), + (0x2F3A, 'M', u'彡'), + (0x2F3B, 'M', u'彳'), + (0x2F3C, 'M', u'心'), + (0x2F3D, 'M', u'戈'), + (0x2F3E, 'M', u'戶'), + (0x2F3F, 'M', u'手'), + (0x2F40, 'M', u'支'), + (0x2F41, 'M', u'攴'), + (0x2F42, 'M', u'文'), + (0x2F43, 'M', u'斗'), + (0x2F44, 'M', u'斤'), + (0x2F45, 'M', u'方'), + (0x2F46, 'M', u'无'), + (0x2F47, 'M', u'日'), + (0x2F48, 'M', u'曰'), + (0x2F49, 'M', u'月'), + (0x2F4A, 'M', u'木'), + (0x2F4B, 'M', u'欠'), + (0x2F4C, 'M', u'止'), + (0x2F4D, 'M', u'歹'), + (0x2F4E, 'M', u'殳'), + (0x2F4F, 'M', u'毋'), + (0x2F50, 'M', u'比'), + (0x2F51, 'M', u'毛'), + (0x2F52, 'M', u'氏'), + (0x2F53, 'M', u'气'), + (0x2F54, 'M', u'水'), + (0x2F55, 'M', u'火'), + (0x2F56, 'M', u'爪'), + (0x2F57, 'M', u'父'), + (0x2F58, 'M', u'爻'), + (0x2F59, 'M', u'爿'), + (0x2F5A, 'M', u'片'), + (0x2F5B, 'M', u'牙'), + (0x2F5C, 'M', u'牛'), + (0x2F5D, 'M', u'犬'), + (0x2F5E, 'M', u'玄'), + (0x2F5F, 'M', u'玉'), + (0x2F60, 'M', u'瓜'), + (0x2F61, 'M', u'瓦'), + (0x2F62, 'M', u'甘'), + (0x2F63, 'M', u'生'), + (0x2F64, 'M', u'用'), + (0x2F65, 'M', u'田'), + (0x2F66, 'M', u'疋'), + (0x2F67, 'M', u'疒'), + (0x2F68, 'M', u'癶'), + (0x2F69, 'M', u'白'), + (0x2F6A, 'M', u'皮'), + (0x2F6B, 'M', u'皿'), + (0x2F6C, 'M', u'目'), + (0x2F6D, 'M', u'矛'), + (0x2F6E, 'M', u'矢'), + (0x2F6F, 'M', u'石'), + (0x2F70, 'M', u'示'), + (0x2F71, 'M', u'禸'), + (0x2F72, 'M', u'禾'), + (0x2F73, 'M', u'穴'), + (0x2F74, 'M', u'立'), + (0x2F75, 'M', u'竹'), + ] + +def _seg_28(): + return [ + (0x2F76, 'M', u'米'), + (0x2F77, 'M', u'糸'), + (0x2F78, 'M', u'缶'), + (0x2F79, 'M', u'网'), + (0x2F7A, 'M', u'羊'), + (0x2F7B, 'M', u'羽'), + (0x2F7C, 'M', u'老'), + (0x2F7D, 'M', u'而'), + (0x2F7E, 'M', u'耒'), + (0x2F7F, 'M', u'耳'), + (0x2F80, 'M', u'聿'), + (0x2F81, 'M', u'肉'), + (0x2F82, 'M', u'臣'), + (0x2F83, 'M', u'自'), + (0x2F84, 'M', u'至'), + (0x2F85, 'M', u'臼'), + (0x2F86, 'M', u'舌'), + (0x2F87, 'M', u'舛'), + (0x2F88, 'M', u'舟'), + (0x2F89, 'M', u'艮'), + (0x2F8A, 'M', u'色'), + (0x2F8B, 'M', u'艸'), + (0x2F8C, 'M', u'虍'), + (0x2F8D, 'M', u'虫'), + (0x2F8E, 'M', u'血'), + (0x2F8F, 'M', u'行'), + (0x2F90, 'M', u'衣'), + (0x2F91, 'M', u'襾'), + (0x2F92, 'M', u'見'), + (0x2F93, 'M', u'角'), + (0x2F94, 'M', u'言'), + (0x2F95, 'M', u'谷'), + (0x2F96, 'M', u'豆'), + (0x2F97, 'M', u'豕'), + (0x2F98, 'M', u'豸'), + (0x2F99, 'M', u'貝'), + (0x2F9A, 'M', u'赤'), + (0x2F9B, 'M', u'走'), + (0x2F9C, 'M', u'足'), + (0x2F9D, 'M', u'身'), + (0x2F9E, 'M', u'車'), + (0x2F9F, 'M', u'辛'), + (0x2FA0, 'M', u'辰'), + (0x2FA1, 'M', u'辵'), + (0x2FA2, 'M', u'邑'), + (0x2FA3, 'M', u'酉'), + (0x2FA4, 'M', u'釆'), + (0x2FA5, 'M', u'里'), + (0x2FA6, 'M', u'金'), + (0x2FA7, 'M', u'長'), + (0x2FA8, 'M', u'門'), + (0x2FA9, 'M', u'阜'), + (0x2FAA, 'M', u'隶'), + (0x2FAB, 'M', u'隹'), + (0x2FAC, 'M', u'雨'), + (0x2FAD, 'M', u'靑'), + (0x2FAE, 'M', u'非'), + (0x2FAF, 'M', u'面'), + (0x2FB0, 'M', u'革'), + (0x2FB1, 'M', u'韋'), + (0x2FB2, 'M', u'韭'), + (0x2FB3, 'M', u'音'), + (0x2FB4, 'M', u'頁'), + (0x2FB5, 'M', u'風'), + (0x2FB6, 'M', u'飛'), + (0x2FB7, 'M', u'食'), + (0x2FB8, 'M', u'首'), + (0x2FB9, 'M', u'香'), + (0x2FBA, 'M', u'馬'), + (0x2FBB, 'M', u'骨'), + (0x2FBC, 'M', u'高'), + (0x2FBD, 'M', u'髟'), + (0x2FBE, 'M', u'鬥'), + (0x2FBF, 'M', u'鬯'), + (0x2FC0, 'M', u'鬲'), + (0x2FC1, 'M', u'鬼'), + (0x2FC2, 'M', u'魚'), + (0x2FC3, 'M', u'鳥'), + (0x2FC4, 'M', u'鹵'), + (0x2FC5, 'M', u'鹿'), + (0x2FC6, 'M', u'麥'), + (0x2FC7, 'M', u'麻'), + (0x2FC8, 'M', u'黃'), + (0x2FC9, 'M', u'黍'), + (0x2FCA, 'M', u'黑'), + (0x2FCB, 'M', u'黹'), + (0x2FCC, 'M', u'黽'), + (0x2FCD, 'M', u'鼎'), + (0x2FCE, 'M', u'鼓'), + (0x2FCF, 'M', u'鼠'), + (0x2FD0, 'M', u'鼻'), + (0x2FD1, 'M', u'齊'), + (0x2FD2, 'M', u'齒'), + (0x2FD3, 'M', u'龍'), + (0x2FD4, 'M', u'龜'), + (0x2FD5, 'M', u'龠'), + (0x2FD6, 'X'), + (0x3000, '3', u' '), + (0x3001, 'V'), + (0x3002, 'M', u'.'), + ] + +def _seg_29(): + return [ + (0x3003, 'V'), + (0x3036, 'M', u'〒'), + (0x3037, 'V'), + (0x3038, 'M', u'十'), + (0x3039, 'M', u'卄'), + (0x303A, 'M', u'卅'), + (0x303B, 'V'), + (0x3040, 'X'), + (0x3041, 'V'), + (0x3097, 'X'), + (0x3099, 'V'), + (0x309B, '3', u' ゙'), + (0x309C, '3', u' ゚'), + (0x309D, 'V'), + (0x309F, 'M', u'より'), + (0x30A0, 'V'), + (0x30FF, 'M', u'コト'), + (0x3100, 'X'), + (0x3105, 'V'), + (0x3130, 'X'), + (0x3131, 'M', u'ᄀ'), + (0x3132, 'M', u'ᄁ'), + (0x3133, 'M', u'ᆪ'), + (0x3134, 'M', u'ᄂ'), + (0x3135, 'M', u'ᆬ'), + (0x3136, 'M', u'ᆭ'), + (0x3137, 'M', u'ᄃ'), + (0x3138, 'M', u'ᄄ'), + (0x3139, 'M', u'ᄅ'), + (0x313A, 'M', u'ᆰ'), + (0x313B, 'M', u'ᆱ'), + (0x313C, 'M', u'ᆲ'), + (0x313D, 'M', u'ᆳ'), + (0x313E, 'M', u'ᆴ'), + (0x313F, 'M', u'ᆵ'), + (0x3140, 'M', u'ᄚ'), + (0x3141, 'M', u'ᄆ'), + (0x3142, 'M', u'ᄇ'), + (0x3143, 'M', u'ᄈ'), + (0x3144, 'M', u'ᄡ'), + (0x3145, 'M', u'ᄉ'), + (0x3146, 'M', u'ᄊ'), + (0x3147, 'M', u'ᄋ'), + (0x3148, 'M', u'ᄌ'), + (0x3149, 'M', u'ᄍ'), + (0x314A, 'M', u'ᄎ'), + (0x314B, 'M', u'ᄏ'), + (0x314C, 'M', u'ᄐ'), + (0x314D, 'M', u'ᄑ'), + (0x314E, 'M', u'ᄒ'), + (0x314F, 'M', u'ᅡ'), + (0x3150, 'M', u'ᅢ'), + (0x3151, 'M', u'ᅣ'), + (0x3152, 'M', u'ᅤ'), + (0x3153, 'M', u'ᅥ'), + (0x3154, 'M', u'ᅦ'), + (0x3155, 'M', u'ᅧ'), + (0x3156, 'M', u'ᅨ'), + (0x3157, 'M', u'ᅩ'), + (0x3158, 'M', u'ᅪ'), + (0x3159, 'M', u'ᅫ'), + (0x315A, 'M', u'ᅬ'), + (0x315B, 'M', u'ᅭ'), + (0x315C, 'M', u'ᅮ'), + (0x315D, 'M', u'ᅯ'), + (0x315E, 'M', u'ᅰ'), + (0x315F, 'M', u'ᅱ'), + (0x3160, 'M', u'ᅲ'), + (0x3161, 'M', u'ᅳ'), + (0x3162, 'M', u'ᅴ'), + (0x3163, 'M', u'ᅵ'), + (0x3164, 'X'), + (0x3165, 'M', u'ᄔ'), + (0x3166, 'M', u'ᄕ'), + (0x3167, 'M', u'ᇇ'), + (0x3168, 'M', u'ᇈ'), + (0x3169, 'M', u'ᇌ'), + (0x316A, 'M', u'ᇎ'), + (0x316B, 'M', u'ᇓ'), + (0x316C, 'M', u'ᇗ'), + (0x316D, 'M', u'ᇙ'), + (0x316E, 'M', u'ᄜ'), + (0x316F, 'M', u'ᇝ'), + (0x3170, 'M', u'ᇟ'), + (0x3171, 'M', u'ᄝ'), + (0x3172, 'M', u'ᄞ'), + (0x3173, 'M', u'ᄠ'), + (0x3174, 'M', u'ᄢ'), + (0x3175, 'M', u'ᄣ'), + (0x3176, 'M', u'ᄧ'), + (0x3177, 'M', u'ᄩ'), + (0x3178, 'M', u'ᄫ'), + (0x3179, 'M', u'ᄬ'), + (0x317A, 'M', u'ᄭ'), + (0x317B, 'M', u'ᄮ'), + (0x317C, 'M', u'ᄯ'), + (0x317D, 'M', u'ᄲ'), + (0x317E, 'M', u'ᄶ'), + (0x317F, 'M', u'ᅀ'), + (0x3180, 'M', u'ᅇ'), + ] + +def _seg_30(): + return [ + (0x3181, 'M', u'ᅌ'), + (0x3182, 'M', u'ᇱ'), + (0x3183, 'M', u'ᇲ'), + (0x3184, 'M', u'ᅗ'), + (0x3185, 'M', u'ᅘ'), + (0x3186, 'M', u'ᅙ'), + (0x3187, 'M', u'ᆄ'), + (0x3188, 'M', u'ᆅ'), + (0x3189, 'M', u'ᆈ'), + (0x318A, 'M', u'ᆑ'), + (0x318B, 'M', u'ᆒ'), + (0x318C, 'M', u'ᆔ'), + (0x318D, 'M', u'ᆞ'), + (0x318E, 'M', u'ᆡ'), + (0x318F, 'X'), + (0x3190, 'V'), + (0x3192, 'M', u'一'), + (0x3193, 'M', u'二'), + (0x3194, 'M', u'三'), + (0x3195, 'M', u'四'), + (0x3196, 'M', u'上'), + (0x3197, 'M', u'中'), + (0x3198, 'M', u'下'), + (0x3199, 'M', u'甲'), + (0x319A, 'M', u'乙'), + (0x319B, 'M', u'丙'), + (0x319C, 'M', u'丁'), + (0x319D, 'M', u'天'), + (0x319E, 'M', u'地'), + (0x319F, 'M', u'人'), + (0x31A0, 'V'), + (0x31E4, 'X'), + (0x31F0, 'V'), + (0x3200, '3', u'(ᄀ)'), + (0x3201, '3', u'(ᄂ)'), + (0x3202, '3', u'(ᄃ)'), + (0x3203, '3', u'(ᄅ)'), + (0x3204, '3', u'(ᄆ)'), + (0x3205, '3', u'(ᄇ)'), + (0x3206, '3', u'(ᄉ)'), + (0x3207, '3', u'(ᄋ)'), + (0x3208, '3', u'(ᄌ)'), + (0x3209, '3', u'(ᄎ)'), + (0x320A, '3', u'(ᄏ)'), + (0x320B, '3', u'(ᄐ)'), + (0x320C, '3', u'(ᄑ)'), + (0x320D, '3', u'(ᄒ)'), + (0x320E, '3', u'(가)'), + (0x320F, '3', u'(나)'), + (0x3210, '3', u'(다)'), + (0x3211, '3', u'(라)'), + (0x3212, '3', u'(마)'), + (0x3213, '3', u'(바)'), + (0x3214, '3', u'(사)'), + (0x3215, '3', u'(아)'), + (0x3216, '3', u'(자)'), + (0x3217, '3', u'(차)'), + (0x3218, '3', u'(카)'), + (0x3219, '3', u'(타)'), + (0x321A, '3', u'(파)'), + (0x321B, '3', u'(하)'), + (0x321C, '3', u'(주)'), + (0x321D, '3', u'(오전)'), + (0x321E, '3', u'(오후)'), + (0x321F, 'X'), + (0x3220, '3', u'(一)'), + (0x3221, '3', u'(二)'), + (0x3222, '3', u'(三)'), + (0x3223, '3', u'(四)'), + (0x3224, '3', u'(五)'), + (0x3225, '3', u'(六)'), + (0x3226, '3', u'(七)'), + (0x3227, '3', u'(八)'), + (0x3228, '3', u'(九)'), + (0x3229, '3', u'(十)'), + (0x322A, '3', u'(月)'), + (0x322B, '3', u'(火)'), + (0x322C, '3', u'(水)'), + (0x322D, '3', u'(木)'), + (0x322E, '3', u'(金)'), + (0x322F, '3', u'(土)'), + (0x3230, '3', u'(日)'), + (0x3231, '3', u'(株)'), + (0x3232, '3', u'(有)'), + (0x3233, '3', u'(社)'), + (0x3234, '3', u'(名)'), + (0x3235, '3', u'(特)'), + (0x3236, '3', u'(財)'), + (0x3237, '3', u'(祝)'), + (0x3238, '3', u'(労)'), + (0x3239, '3', u'(代)'), + (0x323A, '3', u'(呼)'), + (0x323B, '3', u'(学)'), + (0x323C, '3', u'(監)'), + (0x323D, '3', u'(企)'), + (0x323E, '3', u'(資)'), + (0x323F, '3', u'(協)'), + (0x3240, '3', u'(祭)'), + (0x3241, '3', u'(休)'), + (0x3242, '3', u'(自)'), + ] + +def _seg_31(): + return [ + (0x3243, '3', u'(至)'), + (0x3244, 'M', u'問'), + (0x3245, 'M', u'幼'), + (0x3246, 'M', u'文'), + (0x3247, 'M', u'箏'), + (0x3248, 'V'), + (0x3250, 'M', u'pte'), + (0x3251, 'M', u'21'), + (0x3252, 'M', u'22'), + (0x3253, 'M', u'23'), + (0x3254, 'M', u'24'), + (0x3255, 'M', u'25'), + (0x3256, 'M', u'26'), + (0x3257, 'M', u'27'), + (0x3258, 'M', u'28'), + (0x3259, 'M', u'29'), + (0x325A, 'M', u'30'), + (0x325B, 'M', u'31'), + (0x325C, 'M', u'32'), + (0x325D, 'M', u'33'), + (0x325E, 'M', u'34'), + (0x325F, 'M', u'35'), + (0x3260, 'M', u'ᄀ'), + (0x3261, 'M', u'ᄂ'), + (0x3262, 'M', u'ᄃ'), + (0x3263, 'M', u'ᄅ'), + (0x3264, 'M', u'ᄆ'), + (0x3265, 'M', u'ᄇ'), + (0x3266, 'M', u'ᄉ'), + (0x3267, 'M', u'ᄋ'), + (0x3268, 'M', u'ᄌ'), + (0x3269, 'M', u'ᄎ'), + (0x326A, 'M', u'ᄏ'), + (0x326B, 'M', u'ᄐ'), + (0x326C, 'M', u'ᄑ'), + (0x326D, 'M', u'ᄒ'), + (0x326E, 'M', u'가'), + (0x326F, 'M', u'나'), + (0x3270, 'M', u'다'), + (0x3271, 'M', u'라'), + (0x3272, 'M', u'마'), + (0x3273, 'M', u'바'), + (0x3274, 'M', u'사'), + (0x3275, 'M', u'아'), + (0x3276, 'M', u'자'), + (0x3277, 'M', u'차'), + (0x3278, 'M', u'카'), + (0x3279, 'M', u'타'), + (0x327A, 'M', u'파'), + (0x327B, 'M', u'하'), + (0x327C, 'M', u'참고'), + (0x327D, 'M', u'주의'), + (0x327E, 'M', u'우'), + (0x327F, 'V'), + (0x3280, 'M', u'一'), + (0x3281, 'M', u'二'), + (0x3282, 'M', u'三'), + (0x3283, 'M', u'四'), + (0x3284, 'M', u'五'), + (0x3285, 'M', u'六'), + (0x3286, 'M', u'七'), + (0x3287, 'M', u'八'), + (0x3288, 'M', u'九'), + (0x3289, 'M', u'十'), + (0x328A, 'M', u'月'), + (0x328B, 'M', u'火'), + (0x328C, 'M', u'水'), + (0x328D, 'M', u'木'), + (0x328E, 'M', u'金'), + (0x328F, 'M', u'土'), + (0x3290, 'M', u'日'), + (0x3291, 'M', u'株'), + (0x3292, 'M', u'有'), + (0x3293, 'M', u'社'), + (0x3294, 'M', u'名'), + (0x3295, 'M', u'特'), + (0x3296, 'M', u'財'), + (0x3297, 'M', u'祝'), + (0x3298, 'M', u'労'), + (0x3299, 'M', u'秘'), + (0x329A, 'M', u'男'), + (0x329B, 'M', u'女'), + (0x329C, 'M', u'適'), + (0x329D, 'M', u'優'), + (0x329E, 'M', u'印'), + (0x329F, 'M', u'注'), + (0x32A0, 'M', u'項'), + (0x32A1, 'M', u'休'), + (0x32A2, 'M', u'写'), + (0x32A3, 'M', u'正'), + (0x32A4, 'M', u'上'), + (0x32A5, 'M', u'中'), + (0x32A6, 'M', u'下'), + (0x32A7, 'M', u'左'), + (0x32A8, 'M', u'右'), + (0x32A9, 'M', u'医'), + (0x32AA, 'M', u'宗'), + (0x32AB, 'M', u'学'), + (0x32AC, 'M', u'監'), + (0x32AD, 'M', u'企'), + ] + +def _seg_32(): + return [ + (0x32AE, 'M', u'資'), + (0x32AF, 'M', u'協'), + (0x32B0, 'M', u'夜'), + (0x32B1, 'M', u'36'), + (0x32B2, 'M', u'37'), + (0x32B3, 'M', u'38'), + (0x32B4, 'M', u'39'), + (0x32B5, 'M', u'40'), + (0x32B6, 'M', u'41'), + (0x32B7, 'M', u'42'), + (0x32B8, 'M', u'43'), + (0x32B9, 'M', u'44'), + (0x32BA, 'M', u'45'), + (0x32BB, 'M', u'46'), + (0x32BC, 'M', u'47'), + (0x32BD, 'M', u'48'), + (0x32BE, 'M', u'49'), + (0x32BF, 'M', u'50'), + (0x32C0, 'M', u'1月'), + (0x32C1, 'M', u'2月'), + (0x32C2, 'M', u'3月'), + (0x32C3, 'M', u'4月'), + (0x32C4, 'M', u'5月'), + (0x32C5, 'M', u'6月'), + (0x32C6, 'M', u'7月'), + (0x32C7, 'M', u'8月'), + (0x32C8, 'M', u'9月'), + (0x32C9, 'M', u'10月'), + (0x32CA, 'M', u'11月'), + (0x32CB, 'M', u'12月'), + (0x32CC, 'M', u'hg'), + (0x32CD, 'M', u'erg'), + (0x32CE, 'M', u'ev'), + (0x32CF, 'M', u'ltd'), + (0x32D0, 'M', u'ア'), + (0x32D1, 'M', u'イ'), + (0x32D2, 'M', u'ウ'), + (0x32D3, 'M', u'エ'), + (0x32D4, 'M', u'オ'), + (0x32D5, 'M', u'カ'), + (0x32D6, 'M', u'キ'), + (0x32D7, 'M', u'ク'), + (0x32D8, 'M', u'ケ'), + (0x32D9, 'M', u'コ'), + (0x32DA, 'M', u'サ'), + (0x32DB, 'M', u'シ'), + (0x32DC, 'M', u'ス'), + (0x32DD, 'M', u'セ'), + (0x32DE, 'M', u'ソ'), + (0x32DF, 'M', u'タ'), + (0x32E0, 'M', u'チ'), + (0x32E1, 'M', u'ツ'), + (0x32E2, 'M', u'テ'), + (0x32E3, 'M', u'ト'), + (0x32E4, 'M', u'ナ'), + (0x32E5, 'M', u'ニ'), + (0x32E6, 'M', u'ヌ'), + (0x32E7, 'M', u'ネ'), + (0x32E8, 'M', u'ノ'), + (0x32E9, 'M', u'ハ'), + (0x32EA, 'M', u'ヒ'), + (0x32EB, 'M', u'フ'), + (0x32EC, 'M', u'ヘ'), + (0x32ED, 'M', u'ホ'), + (0x32EE, 'M', u'マ'), + (0x32EF, 'M', u'ミ'), + (0x32F0, 'M', u'ム'), + (0x32F1, 'M', u'メ'), + (0x32F2, 'M', u'モ'), + (0x32F3, 'M', u'ヤ'), + (0x32F4, 'M', u'ユ'), + (0x32F5, 'M', u'ヨ'), + (0x32F6, 'M', u'ラ'), + (0x32F7, 'M', u'リ'), + (0x32F8, 'M', u'ル'), + (0x32F9, 'M', u'レ'), + (0x32FA, 'M', u'ロ'), + (0x32FB, 'M', u'ワ'), + (0x32FC, 'M', u'ヰ'), + (0x32FD, 'M', u'ヱ'), + (0x32FE, 'M', u'ヲ'), + (0x32FF, 'M', u'令和'), + (0x3300, 'M', u'アパート'), + (0x3301, 'M', u'アルファ'), + (0x3302, 'M', u'アンペア'), + (0x3303, 'M', u'アール'), + (0x3304, 'M', u'イニング'), + (0x3305, 'M', u'インチ'), + (0x3306, 'M', u'ウォン'), + (0x3307, 'M', u'エスクード'), + (0x3308, 'M', u'エーカー'), + (0x3309, 'M', u'オンス'), + (0x330A, 'M', u'オーム'), + (0x330B, 'M', u'カイリ'), + (0x330C, 'M', u'カラット'), + (0x330D, 'M', u'カロリー'), + (0x330E, 'M', u'ガロン'), + (0x330F, 'M', u'ガンマ'), + (0x3310, 'M', u'ギガ'), + (0x3311, 'M', u'ギニー'), + ] + +def _seg_33(): + return [ + (0x3312, 'M', u'キュリー'), + (0x3313, 'M', u'ギルダー'), + (0x3314, 'M', u'キロ'), + (0x3315, 'M', u'キログラム'), + (0x3316, 'M', u'キロメートル'), + (0x3317, 'M', u'キロワット'), + (0x3318, 'M', u'グラム'), + (0x3319, 'M', u'グラムトン'), + (0x331A, 'M', u'クルゼイロ'), + (0x331B, 'M', u'クローネ'), + (0x331C, 'M', u'ケース'), + (0x331D, 'M', u'コルナ'), + (0x331E, 'M', u'コーポ'), + (0x331F, 'M', u'サイクル'), + (0x3320, 'M', u'サンチーム'), + (0x3321, 'M', u'シリング'), + (0x3322, 'M', u'センチ'), + (0x3323, 'M', u'セント'), + (0x3324, 'M', u'ダース'), + (0x3325, 'M', u'デシ'), + (0x3326, 'M', u'ドル'), + (0x3327, 'M', u'トン'), + (0x3328, 'M', u'ナノ'), + (0x3329, 'M', u'ノット'), + (0x332A, 'M', u'ハイツ'), + (0x332B, 'M', u'パーセント'), + (0x332C, 'M', u'パーツ'), + (0x332D, 'M', u'バーレル'), + (0x332E, 'M', u'ピアストル'), + (0x332F, 'M', u'ピクル'), + (0x3330, 'M', u'ピコ'), + (0x3331, 'M', u'ビル'), + (0x3332, 'M', u'ファラッド'), + (0x3333, 'M', u'フィート'), + (0x3334, 'M', u'ブッシェル'), + (0x3335, 'M', u'フラン'), + (0x3336, 'M', u'ヘクタール'), + (0x3337, 'M', u'ペソ'), + (0x3338, 'M', u'ペニヒ'), + (0x3339, 'M', u'ヘルツ'), + (0x333A, 'M', u'ペンス'), + (0x333B, 'M', u'ページ'), + (0x333C, 'M', u'ベータ'), + (0x333D, 'M', u'ポイント'), + (0x333E, 'M', u'ボルト'), + (0x333F, 'M', u'ホン'), + (0x3340, 'M', u'ポンド'), + (0x3341, 'M', u'ホール'), + (0x3342, 'M', u'ホーン'), + (0x3343, 'M', u'マイクロ'), + (0x3344, 'M', u'マイル'), + (0x3345, 'M', u'マッハ'), + (0x3346, 'M', u'マルク'), + (0x3347, 'M', u'マンション'), + (0x3348, 'M', u'ミクロン'), + (0x3349, 'M', u'ミリ'), + (0x334A, 'M', u'ミリバール'), + (0x334B, 'M', u'メガ'), + (0x334C, 'M', u'メガトン'), + (0x334D, 'M', u'メートル'), + (0x334E, 'M', u'ヤード'), + (0x334F, 'M', u'ヤール'), + (0x3350, 'M', u'ユアン'), + (0x3351, 'M', u'リットル'), + (0x3352, 'M', u'リラ'), + (0x3353, 'M', u'ルピー'), + (0x3354, 'M', u'ルーブル'), + (0x3355, 'M', u'レム'), + (0x3356, 'M', u'レントゲン'), + (0x3357, 'M', u'ワット'), + (0x3358, 'M', u'0点'), + (0x3359, 'M', u'1点'), + (0x335A, 'M', u'2点'), + (0x335B, 'M', u'3点'), + (0x335C, 'M', u'4点'), + (0x335D, 'M', u'5点'), + (0x335E, 'M', u'6点'), + (0x335F, 'M', u'7点'), + (0x3360, 'M', u'8点'), + (0x3361, 'M', u'9点'), + (0x3362, 'M', u'10点'), + (0x3363, 'M', u'11点'), + (0x3364, 'M', u'12点'), + (0x3365, 'M', u'13点'), + (0x3366, 'M', u'14点'), + (0x3367, 'M', u'15点'), + (0x3368, 'M', u'16点'), + (0x3369, 'M', u'17点'), + (0x336A, 'M', u'18点'), + (0x336B, 'M', u'19点'), + (0x336C, 'M', u'20点'), + (0x336D, 'M', u'21点'), + (0x336E, 'M', u'22点'), + (0x336F, 'M', u'23点'), + (0x3370, 'M', u'24点'), + (0x3371, 'M', u'hpa'), + (0x3372, 'M', u'da'), + (0x3373, 'M', u'au'), + (0x3374, 'M', u'bar'), + (0x3375, 'M', u'ov'), + ] + +def _seg_34(): + return [ + (0x3376, 'M', u'pc'), + (0x3377, 'M', u'dm'), + (0x3378, 'M', u'dm2'), + (0x3379, 'M', u'dm3'), + (0x337A, 'M', u'iu'), + (0x337B, 'M', u'平成'), + (0x337C, 'M', u'昭和'), + (0x337D, 'M', u'大正'), + (0x337E, 'M', u'明治'), + (0x337F, 'M', u'株式会社'), + (0x3380, 'M', u'pa'), + (0x3381, 'M', u'na'), + (0x3382, 'M', u'μa'), + (0x3383, 'M', u'ma'), + (0x3384, 'M', u'ka'), + (0x3385, 'M', u'kb'), + (0x3386, 'M', u'mb'), + (0x3387, 'M', u'gb'), + (0x3388, 'M', u'cal'), + (0x3389, 'M', u'kcal'), + (0x338A, 'M', u'pf'), + (0x338B, 'M', u'nf'), + (0x338C, 'M', u'μf'), + (0x338D, 'M', u'μg'), + (0x338E, 'M', u'mg'), + (0x338F, 'M', u'kg'), + (0x3390, 'M', u'hz'), + (0x3391, 'M', u'khz'), + (0x3392, 'M', u'mhz'), + (0x3393, 'M', u'ghz'), + (0x3394, 'M', u'thz'), + (0x3395, 'M', u'μl'), + (0x3396, 'M', u'ml'), + (0x3397, 'M', u'dl'), + (0x3398, 'M', u'kl'), + (0x3399, 'M', u'fm'), + (0x339A, 'M', u'nm'), + (0x339B, 'M', u'μm'), + (0x339C, 'M', u'mm'), + (0x339D, 'M', u'cm'), + (0x339E, 'M', u'km'), + (0x339F, 'M', u'mm2'), + (0x33A0, 'M', u'cm2'), + (0x33A1, 'M', u'm2'), + (0x33A2, 'M', u'km2'), + (0x33A3, 'M', u'mm3'), + (0x33A4, 'M', u'cm3'), + (0x33A5, 'M', u'm3'), + (0x33A6, 'M', u'km3'), + (0x33A7, 'M', u'm∕s'), + (0x33A8, 'M', u'm∕s2'), + (0x33A9, 'M', u'pa'), + (0x33AA, 'M', u'kpa'), + (0x33AB, 'M', u'mpa'), + (0x33AC, 'M', u'gpa'), + (0x33AD, 'M', u'rad'), + (0x33AE, 'M', u'rad∕s'), + (0x33AF, 'M', u'rad∕s2'), + (0x33B0, 'M', u'ps'), + (0x33B1, 'M', u'ns'), + (0x33B2, 'M', u'μs'), + (0x33B3, 'M', u'ms'), + (0x33B4, 'M', u'pv'), + (0x33B5, 'M', u'nv'), + (0x33B6, 'M', u'μv'), + (0x33B7, 'M', u'mv'), + (0x33B8, 'M', u'kv'), + (0x33B9, 'M', u'mv'), + (0x33BA, 'M', u'pw'), + (0x33BB, 'M', u'nw'), + (0x33BC, 'M', u'μw'), + (0x33BD, 'M', u'mw'), + (0x33BE, 'M', u'kw'), + (0x33BF, 'M', u'mw'), + (0x33C0, 'M', u'kω'), + (0x33C1, 'M', u'mω'), + (0x33C2, 'X'), + (0x33C3, 'M', u'bq'), + (0x33C4, 'M', u'cc'), + (0x33C5, 'M', u'cd'), + (0x33C6, 'M', u'c∕kg'), + (0x33C7, 'X'), + (0x33C8, 'M', u'db'), + (0x33C9, 'M', u'gy'), + (0x33CA, 'M', u'ha'), + (0x33CB, 'M', u'hp'), + (0x33CC, 'M', u'in'), + (0x33CD, 'M', u'kk'), + (0x33CE, 'M', u'km'), + (0x33CF, 'M', u'kt'), + (0x33D0, 'M', u'lm'), + (0x33D1, 'M', u'ln'), + (0x33D2, 'M', u'log'), + (0x33D3, 'M', u'lx'), + (0x33D4, 'M', u'mb'), + (0x33D5, 'M', u'mil'), + (0x33D6, 'M', u'mol'), + (0x33D7, 'M', u'ph'), + (0x33D8, 'X'), + (0x33D9, 'M', u'ppm'), + ] + +def _seg_35(): + return [ + (0x33DA, 'M', u'pr'), + (0x33DB, 'M', u'sr'), + (0x33DC, 'M', u'sv'), + (0x33DD, 'M', u'wb'), + (0x33DE, 'M', u'v∕m'), + (0x33DF, 'M', u'a∕m'), + (0x33E0, 'M', u'1日'), + (0x33E1, 'M', u'2日'), + (0x33E2, 'M', u'3日'), + (0x33E3, 'M', u'4日'), + (0x33E4, 'M', u'5日'), + (0x33E5, 'M', u'6日'), + (0x33E6, 'M', u'7日'), + (0x33E7, 'M', u'8日'), + (0x33E8, 'M', u'9日'), + (0x33E9, 'M', u'10日'), + (0x33EA, 'M', u'11日'), + (0x33EB, 'M', u'12日'), + (0x33EC, 'M', u'13日'), + (0x33ED, 'M', u'14日'), + (0x33EE, 'M', u'15日'), + (0x33EF, 'M', u'16日'), + (0x33F0, 'M', u'17日'), + (0x33F1, 'M', u'18日'), + (0x33F2, 'M', u'19日'), + (0x33F3, 'M', u'20日'), + (0x33F4, 'M', u'21日'), + (0x33F5, 'M', u'22日'), + (0x33F6, 'M', u'23日'), + (0x33F7, 'M', u'24日'), + (0x33F8, 'M', u'25日'), + (0x33F9, 'M', u'26日'), + (0x33FA, 'M', u'27日'), + (0x33FB, 'M', u'28日'), + (0x33FC, 'M', u'29日'), + (0x33FD, 'M', u'30日'), + (0x33FE, 'M', u'31日'), + (0x33FF, 'M', u'gal'), + (0x3400, 'V'), + (0x9FFD, 'X'), + (0xA000, 'V'), + (0xA48D, 'X'), + (0xA490, 'V'), + (0xA4C7, 'X'), + (0xA4D0, 'V'), + (0xA62C, 'X'), + (0xA640, 'M', u'ꙁ'), + (0xA641, 'V'), + (0xA642, 'M', u'ꙃ'), + (0xA643, 'V'), + (0xA644, 'M', u'ꙅ'), + (0xA645, 'V'), + (0xA646, 'M', u'ꙇ'), + (0xA647, 'V'), + (0xA648, 'M', u'ꙉ'), + (0xA649, 'V'), + (0xA64A, 'M', u'ꙋ'), + (0xA64B, 'V'), + (0xA64C, 'M', u'ꙍ'), + (0xA64D, 'V'), + (0xA64E, 'M', u'ꙏ'), + (0xA64F, 'V'), + (0xA650, 'M', u'ꙑ'), + (0xA651, 'V'), + (0xA652, 'M', u'ꙓ'), + (0xA653, 'V'), + (0xA654, 'M', u'ꙕ'), + (0xA655, 'V'), + (0xA656, 'M', u'ꙗ'), + (0xA657, 'V'), + (0xA658, 'M', u'ꙙ'), + (0xA659, 'V'), + (0xA65A, 'M', u'ꙛ'), + (0xA65B, 'V'), + (0xA65C, 'M', u'ꙝ'), + (0xA65D, 'V'), + (0xA65E, 'M', u'ꙟ'), + (0xA65F, 'V'), + (0xA660, 'M', u'ꙡ'), + (0xA661, 'V'), + (0xA662, 'M', u'ꙣ'), + (0xA663, 'V'), + (0xA664, 'M', u'ꙥ'), + (0xA665, 'V'), + (0xA666, 'M', u'ꙧ'), + (0xA667, 'V'), + (0xA668, 'M', u'ꙩ'), + (0xA669, 'V'), + (0xA66A, 'M', u'ꙫ'), + (0xA66B, 'V'), + (0xA66C, 'M', u'ꙭ'), + (0xA66D, 'V'), + (0xA680, 'M', u'ꚁ'), + (0xA681, 'V'), + (0xA682, 'M', u'ꚃ'), + (0xA683, 'V'), + (0xA684, 'M', u'ꚅ'), + (0xA685, 'V'), + (0xA686, 'M', u'ꚇ'), + (0xA687, 'V'), + ] + +def _seg_36(): + return [ + (0xA688, 'M', u'ꚉ'), + (0xA689, 'V'), + (0xA68A, 'M', u'ꚋ'), + (0xA68B, 'V'), + (0xA68C, 'M', u'ꚍ'), + (0xA68D, 'V'), + (0xA68E, 'M', u'ꚏ'), + (0xA68F, 'V'), + (0xA690, 'M', u'ꚑ'), + (0xA691, 'V'), + (0xA692, 'M', u'ꚓ'), + (0xA693, 'V'), + (0xA694, 'M', u'ꚕ'), + (0xA695, 'V'), + (0xA696, 'M', u'ꚗ'), + (0xA697, 'V'), + (0xA698, 'M', u'ꚙ'), + (0xA699, 'V'), + (0xA69A, 'M', u'ꚛ'), + (0xA69B, 'V'), + (0xA69C, 'M', u'ъ'), + (0xA69D, 'M', u'ь'), + (0xA69E, 'V'), + (0xA6F8, 'X'), + (0xA700, 'V'), + (0xA722, 'M', u'ꜣ'), + (0xA723, 'V'), + (0xA724, 'M', u'ꜥ'), + (0xA725, 'V'), + (0xA726, 'M', u'ꜧ'), + (0xA727, 'V'), + (0xA728, 'M', u'ꜩ'), + (0xA729, 'V'), + (0xA72A, 'M', u'ꜫ'), + (0xA72B, 'V'), + (0xA72C, 'M', u'ꜭ'), + (0xA72D, 'V'), + (0xA72E, 'M', u'ꜯ'), + (0xA72F, 'V'), + (0xA732, 'M', u'ꜳ'), + (0xA733, 'V'), + (0xA734, 'M', u'ꜵ'), + (0xA735, 'V'), + (0xA736, 'M', u'ꜷ'), + (0xA737, 'V'), + (0xA738, 'M', u'ꜹ'), + (0xA739, 'V'), + (0xA73A, 'M', u'ꜻ'), + (0xA73B, 'V'), + (0xA73C, 'M', u'ꜽ'), + (0xA73D, 'V'), + (0xA73E, 'M', u'ꜿ'), + (0xA73F, 'V'), + (0xA740, 'M', u'ꝁ'), + (0xA741, 'V'), + (0xA742, 'M', u'ꝃ'), + (0xA743, 'V'), + (0xA744, 'M', u'ꝅ'), + (0xA745, 'V'), + (0xA746, 'M', u'ꝇ'), + (0xA747, 'V'), + (0xA748, 'M', u'ꝉ'), + (0xA749, 'V'), + (0xA74A, 'M', u'ꝋ'), + (0xA74B, 'V'), + (0xA74C, 'M', u'ꝍ'), + (0xA74D, 'V'), + (0xA74E, 'M', u'ꝏ'), + (0xA74F, 'V'), + (0xA750, 'M', u'ꝑ'), + (0xA751, 'V'), + (0xA752, 'M', u'ꝓ'), + (0xA753, 'V'), + (0xA754, 'M', u'ꝕ'), + (0xA755, 'V'), + (0xA756, 'M', u'ꝗ'), + (0xA757, 'V'), + (0xA758, 'M', u'ꝙ'), + (0xA759, 'V'), + (0xA75A, 'M', u'ꝛ'), + (0xA75B, 'V'), + (0xA75C, 'M', u'ꝝ'), + (0xA75D, 'V'), + (0xA75E, 'M', u'ꝟ'), + (0xA75F, 'V'), + (0xA760, 'M', u'ꝡ'), + (0xA761, 'V'), + (0xA762, 'M', u'ꝣ'), + (0xA763, 'V'), + (0xA764, 'M', u'ꝥ'), + (0xA765, 'V'), + (0xA766, 'M', u'ꝧ'), + (0xA767, 'V'), + (0xA768, 'M', u'ꝩ'), + (0xA769, 'V'), + (0xA76A, 'M', u'ꝫ'), + (0xA76B, 'V'), + (0xA76C, 'M', u'ꝭ'), + (0xA76D, 'V'), + (0xA76E, 'M', u'ꝯ'), + ] + +def _seg_37(): + return [ + (0xA76F, 'V'), + (0xA770, 'M', u'ꝯ'), + (0xA771, 'V'), + (0xA779, 'M', u'ꝺ'), + (0xA77A, 'V'), + (0xA77B, 'M', u'ꝼ'), + (0xA77C, 'V'), + (0xA77D, 'M', u'ᵹ'), + (0xA77E, 'M', u'ꝿ'), + (0xA77F, 'V'), + (0xA780, 'M', u'ꞁ'), + (0xA781, 'V'), + (0xA782, 'M', u'ꞃ'), + (0xA783, 'V'), + (0xA784, 'M', u'ꞅ'), + (0xA785, 'V'), + (0xA786, 'M', u'ꞇ'), + (0xA787, 'V'), + (0xA78B, 'M', u'ꞌ'), + (0xA78C, 'V'), + (0xA78D, 'M', u'ɥ'), + (0xA78E, 'V'), + (0xA790, 'M', u'ꞑ'), + (0xA791, 'V'), + (0xA792, 'M', u'ꞓ'), + (0xA793, 'V'), + (0xA796, 'M', u'ꞗ'), + (0xA797, 'V'), + (0xA798, 'M', u'ꞙ'), + (0xA799, 'V'), + (0xA79A, 'M', u'ꞛ'), + (0xA79B, 'V'), + (0xA79C, 'M', u'ꞝ'), + (0xA79D, 'V'), + (0xA79E, 'M', u'ꞟ'), + (0xA79F, 'V'), + (0xA7A0, 'M', u'ꞡ'), + (0xA7A1, 'V'), + (0xA7A2, 'M', u'ꞣ'), + (0xA7A3, 'V'), + (0xA7A4, 'M', u'ꞥ'), + (0xA7A5, 'V'), + (0xA7A6, 'M', u'ꞧ'), + (0xA7A7, 'V'), + (0xA7A8, 'M', u'ꞩ'), + (0xA7A9, 'V'), + (0xA7AA, 'M', u'ɦ'), + (0xA7AB, 'M', u'ɜ'), + (0xA7AC, 'M', u'ɡ'), + (0xA7AD, 'M', u'ɬ'), + (0xA7AE, 'M', u'ɪ'), + (0xA7AF, 'V'), + (0xA7B0, 'M', u'ʞ'), + (0xA7B1, 'M', u'ʇ'), + (0xA7B2, 'M', u'ʝ'), + (0xA7B3, 'M', u'ꭓ'), + (0xA7B4, 'M', u'ꞵ'), + (0xA7B5, 'V'), + (0xA7B6, 'M', u'ꞷ'), + (0xA7B7, 'V'), + (0xA7B8, 'M', u'ꞹ'), + (0xA7B9, 'V'), + (0xA7BA, 'M', u'ꞻ'), + (0xA7BB, 'V'), + (0xA7BC, 'M', u'ꞽ'), + (0xA7BD, 'V'), + (0xA7BE, 'M', u'ꞿ'), + (0xA7BF, 'V'), + (0xA7C0, 'X'), + (0xA7C2, 'M', u'ꟃ'), + (0xA7C3, 'V'), + (0xA7C4, 'M', u'ꞔ'), + (0xA7C5, 'M', u'ʂ'), + (0xA7C6, 'M', u'ᶎ'), + (0xA7C7, 'M', u'ꟈ'), + (0xA7C8, 'V'), + (0xA7C9, 'M', u'ꟊ'), + (0xA7CA, 'V'), + (0xA7CB, 'X'), + (0xA7F5, 'M', u'ꟶ'), + (0xA7F6, 'V'), + (0xA7F8, 'M', u'ħ'), + (0xA7F9, 'M', u'œ'), + (0xA7FA, 'V'), + (0xA82D, 'X'), + (0xA830, 'V'), + (0xA83A, 'X'), + (0xA840, 'V'), + (0xA878, 'X'), + (0xA880, 'V'), + (0xA8C6, 'X'), + (0xA8CE, 'V'), + (0xA8DA, 'X'), + (0xA8E0, 'V'), + (0xA954, 'X'), + (0xA95F, 'V'), + (0xA97D, 'X'), + (0xA980, 'V'), + (0xA9CE, 'X'), + (0xA9CF, 'V'), + ] + +def _seg_38(): + return [ + (0xA9DA, 'X'), + (0xA9DE, 'V'), + (0xA9FF, 'X'), + (0xAA00, 'V'), + (0xAA37, 'X'), + (0xAA40, 'V'), + (0xAA4E, 'X'), + (0xAA50, 'V'), + (0xAA5A, 'X'), + (0xAA5C, 'V'), + (0xAAC3, 'X'), + (0xAADB, 'V'), + (0xAAF7, 'X'), + (0xAB01, 'V'), + (0xAB07, 'X'), + (0xAB09, 'V'), + (0xAB0F, 'X'), + (0xAB11, 'V'), + (0xAB17, 'X'), + (0xAB20, 'V'), + (0xAB27, 'X'), + (0xAB28, 'V'), + (0xAB2F, 'X'), + (0xAB30, 'V'), + (0xAB5C, 'M', u'ꜧ'), + (0xAB5D, 'M', u'ꬷ'), + (0xAB5E, 'M', u'ɫ'), + (0xAB5F, 'M', u'ꭒ'), + (0xAB60, 'V'), + (0xAB69, 'M', u'ʍ'), + (0xAB6A, 'V'), + (0xAB6C, 'X'), + (0xAB70, 'M', u'Ꭰ'), + (0xAB71, 'M', u'Ꭱ'), + (0xAB72, 'M', u'Ꭲ'), + (0xAB73, 'M', u'Ꭳ'), + (0xAB74, 'M', u'Ꭴ'), + (0xAB75, 'M', u'Ꭵ'), + (0xAB76, 'M', u'Ꭶ'), + (0xAB77, 'M', u'Ꭷ'), + (0xAB78, 'M', u'Ꭸ'), + (0xAB79, 'M', u'Ꭹ'), + (0xAB7A, 'M', u'Ꭺ'), + (0xAB7B, 'M', u'Ꭻ'), + (0xAB7C, 'M', u'Ꭼ'), + (0xAB7D, 'M', u'Ꭽ'), + (0xAB7E, 'M', u'Ꭾ'), + (0xAB7F, 'M', u'Ꭿ'), + (0xAB80, 'M', u'Ꮀ'), + (0xAB81, 'M', u'Ꮁ'), + (0xAB82, 'M', u'Ꮂ'), + (0xAB83, 'M', u'Ꮃ'), + (0xAB84, 'M', u'Ꮄ'), + (0xAB85, 'M', u'Ꮅ'), + (0xAB86, 'M', u'Ꮆ'), + (0xAB87, 'M', u'Ꮇ'), + (0xAB88, 'M', u'Ꮈ'), + (0xAB89, 'M', u'Ꮉ'), + (0xAB8A, 'M', u'Ꮊ'), + (0xAB8B, 'M', u'Ꮋ'), + (0xAB8C, 'M', u'Ꮌ'), + (0xAB8D, 'M', u'Ꮍ'), + (0xAB8E, 'M', u'Ꮎ'), + (0xAB8F, 'M', u'Ꮏ'), + (0xAB90, 'M', u'Ꮐ'), + (0xAB91, 'M', u'Ꮑ'), + (0xAB92, 'M', u'Ꮒ'), + (0xAB93, 'M', u'Ꮓ'), + (0xAB94, 'M', u'Ꮔ'), + (0xAB95, 'M', u'Ꮕ'), + (0xAB96, 'M', u'Ꮖ'), + (0xAB97, 'M', u'Ꮗ'), + (0xAB98, 'M', u'Ꮘ'), + (0xAB99, 'M', u'Ꮙ'), + (0xAB9A, 'M', u'Ꮚ'), + (0xAB9B, 'M', u'Ꮛ'), + (0xAB9C, 'M', u'Ꮜ'), + (0xAB9D, 'M', u'Ꮝ'), + (0xAB9E, 'M', u'Ꮞ'), + (0xAB9F, 'M', u'Ꮟ'), + (0xABA0, 'M', u'Ꮠ'), + (0xABA1, 'M', u'Ꮡ'), + (0xABA2, 'M', u'Ꮢ'), + (0xABA3, 'M', u'Ꮣ'), + (0xABA4, 'M', u'Ꮤ'), + (0xABA5, 'M', u'Ꮥ'), + (0xABA6, 'M', u'Ꮦ'), + (0xABA7, 'M', u'Ꮧ'), + (0xABA8, 'M', u'Ꮨ'), + (0xABA9, 'M', u'Ꮩ'), + (0xABAA, 'M', u'Ꮪ'), + (0xABAB, 'M', u'Ꮫ'), + (0xABAC, 'M', u'Ꮬ'), + (0xABAD, 'M', u'Ꮭ'), + (0xABAE, 'M', u'Ꮮ'), + (0xABAF, 'M', u'Ꮯ'), + (0xABB0, 'M', u'Ꮰ'), + (0xABB1, 'M', u'Ꮱ'), + (0xABB2, 'M', u'Ꮲ'), + (0xABB3, 'M', u'Ꮳ'), + ] + +def _seg_39(): + return [ + (0xABB4, 'M', u'Ꮴ'), + (0xABB5, 'M', u'Ꮵ'), + (0xABB6, 'M', u'Ꮶ'), + (0xABB7, 'M', u'Ꮷ'), + (0xABB8, 'M', u'Ꮸ'), + (0xABB9, 'M', u'Ꮹ'), + (0xABBA, 'M', u'Ꮺ'), + (0xABBB, 'M', u'Ꮻ'), + (0xABBC, 'M', u'Ꮼ'), + (0xABBD, 'M', u'Ꮽ'), + (0xABBE, 'M', u'Ꮾ'), + (0xABBF, 'M', u'Ꮿ'), + (0xABC0, 'V'), + (0xABEE, 'X'), + (0xABF0, 'V'), + (0xABFA, 'X'), + (0xAC00, 'V'), + (0xD7A4, 'X'), + (0xD7B0, 'V'), + (0xD7C7, 'X'), + (0xD7CB, 'V'), + (0xD7FC, 'X'), + (0xF900, 'M', u'豈'), + (0xF901, 'M', u'更'), + (0xF902, 'M', u'車'), + (0xF903, 'M', u'賈'), + (0xF904, 'M', u'滑'), + (0xF905, 'M', u'串'), + (0xF906, 'M', u'句'), + (0xF907, 'M', u'龜'), + (0xF909, 'M', u'契'), + (0xF90A, 'M', u'金'), + (0xF90B, 'M', u'喇'), + (0xF90C, 'M', u'奈'), + (0xF90D, 'M', u'懶'), + (0xF90E, 'M', u'癩'), + (0xF90F, 'M', u'羅'), + (0xF910, 'M', u'蘿'), + (0xF911, 'M', u'螺'), + (0xF912, 'M', u'裸'), + (0xF913, 'M', u'邏'), + (0xF914, 'M', u'樂'), + (0xF915, 'M', u'洛'), + (0xF916, 'M', u'烙'), + (0xF917, 'M', u'珞'), + (0xF918, 'M', u'落'), + (0xF919, 'M', u'酪'), + (0xF91A, 'M', u'駱'), + (0xF91B, 'M', u'亂'), + (0xF91C, 'M', u'卵'), + (0xF91D, 'M', u'欄'), + (0xF91E, 'M', u'爛'), + (0xF91F, 'M', u'蘭'), + (0xF920, 'M', u'鸞'), + (0xF921, 'M', u'嵐'), + (0xF922, 'M', u'濫'), + (0xF923, 'M', u'藍'), + (0xF924, 'M', u'襤'), + (0xF925, 'M', u'拉'), + (0xF926, 'M', u'臘'), + (0xF927, 'M', u'蠟'), + (0xF928, 'M', u'廊'), + (0xF929, 'M', u'朗'), + (0xF92A, 'M', u'浪'), + (0xF92B, 'M', u'狼'), + (0xF92C, 'M', u'郎'), + (0xF92D, 'M', u'來'), + (0xF92E, 'M', u'冷'), + (0xF92F, 'M', u'勞'), + (0xF930, 'M', u'擄'), + (0xF931, 'M', u'櫓'), + (0xF932, 'M', u'爐'), + (0xF933, 'M', u'盧'), + (0xF934, 'M', u'老'), + (0xF935, 'M', u'蘆'), + (0xF936, 'M', u'虜'), + (0xF937, 'M', u'路'), + (0xF938, 'M', u'露'), + (0xF939, 'M', u'魯'), + (0xF93A, 'M', u'鷺'), + (0xF93B, 'M', u'碌'), + (0xF93C, 'M', u'祿'), + (0xF93D, 'M', u'綠'), + (0xF93E, 'M', u'菉'), + (0xF93F, 'M', u'錄'), + (0xF940, 'M', u'鹿'), + (0xF941, 'M', u'論'), + (0xF942, 'M', u'壟'), + (0xF943, 'M', u'弄'), + (0xF944, 'M', u'籠'), + (0xF945, 'M', u'聾'), + (0xF946, 'M', u'牢'), + (0xF947, 'M', u'磊'), + (0xF948, 'M', u'賂'), + (0xF949, 'M', u'雷'), + (0xF94A, 'M', u'壘'), + (0xF94B, 'M', u'屢'), + (0xF94C, 'M', u'樓'), + (0xF94D, 'M', u'淚'), + (0xF94E, 'M', u'漏'), + ] + +def _seg_40(): + return [ + (0xF94F, 'M', u'累'), + (0xF950, 'M', u'縷'), + (0xF951, 'M', u'陋'), + (0xF952, 'M', u'勒'), + (0xF953, 'M', u'肋'), + (0xF954, 'M', u'凜'), + (0xF955, 'M', u'凌'), + (0xF956, 'M', u'稜'), + (0xF957, 'M', u'綾'), + (0xF958, 'M', u'菱'), + (0xF959, 'M', u'陵'), + (0xF95A, 'M', u'讀'), + (0xF95B, 'M', u'拏'), + (0xF95C, 'M', u'樂'), + (0xF95D, 'M', u'諾'), + (0xF95E, 'M', u'丹'), + (0xF95F, 'M', u'寧'), + (0xF960, 'M', u'怒'), + (0xF961, 'M', u'率'), + (0xF962, 'M', u'異'), + (0xF963, 'M', u'北'), + (0xF964, 'M', u'磻'), + (0xF965, 'M', u'便'), + (0xF966, 'M', u'復'), + (0xF967, 'M', u'不'), + (0xF968, 'M', u'泌'), + (0xF969, 'M', u'數'), + (0xF96A, 'M', u'索'), + (0xF96B, 'M', u'參'), + (0xF96C, 'M', u'塞'), + (0xF96D, 'M', u'省'), + (0xF96E, 'M', u'葉'), + (0xF96F, 'M', u'說'), + (0xF970, 'M', u'殺'), + (0xF971, 'M', u'辰'), + (0xF972, 'M', u'沈'), + (0xF973, 'M', u'拾'), + (0xF974, 'M', u'若'), + (0xF975, 'M', u'掠'), + (0xF976, 'M', u'略'), + (0xF977, 'M', u'亮'), + (0xF978, 'M', u'兩'), + (0xF979, 'M', u'凉'), + (0xF97A, 'M', u'梁'), + (0xF97B, 'M', u'糧'), + (0xF97C, 'M', u'良'), + (0xF97D, 'M', u'諒'), + (0xF97E, 'M', u'量'), + (0xF97F, 'M', u'勵'), + (0xF980, 'M', u'呂'), + (0xF981, 'M', u'女'), + (0xF982, 'M', u'廬'), + (0xF983, 'M', u'旅'), + (0xF984, 'M', u'濾'), + (0xF985, 'M', u'礪'), + (0xF986, 'M', u'閭'), + (0xF987, 'M', u'驪'), + (0xF988, 'M', u'麗'), + (0xF989, 'M', u'黎'), + (0xF98A, 'M', u'力'), + (0xF98B, 'M', u'曆'), + (0xF98C, 'M', u'歷'), + (0xF98D, 'M', u'轢'), + (0xF98E, 'M', u'年'), + (0xF98F, 'M', u'憐'), + (0xF990, 'M', u'戀'), + (0xF991, 'M', u'撚'), + (0xF992, 'M', u'漣'), + (0xF993, 'M', u'煉'), + (0xF994, 'M', u'璉'), + (0xF995, 'M', u'秊'), + (0xF996, 'M', u'練'), + (0xF997, 'M', u'聯'), + (0xF998, 'M', u'輦'), + (0xF999, 'M', u'蓮'), + (0xF99A, 'M', u'連'), + (0xF99B, 'M', u'鍊'), + (0xF99C, 'M', u'列'), + (0xF99D, 'M', u'劣'), + (0xF99E, 'M', u'咽'), + (0xF99F, 'M', u'烈'), + (0xF9A0, 'M', u'裂'), + (0xF9A1, 'M', u'說'), + (0xF9A2, 'M', u'廉'), + (0xF9A3, 'M', u'念'), + (0xF9A4, 'M', u'捻'), + (0xF9A5, 'M', u'殮'), + (0xF9A6, 'M', u'簾'), + (0xF9A7, 'M', u'獵'), + (0xF9A8, 'M', u'令'), + (0xF9A9, 'M', u'囹'), + (0xF9AA, 'M', u'寧'), + (0xF9AB, 'M', u'嶺'), + (0xF9AC, 'M', u'怜'), + (0xF9AD, 'M', u'玲'), + (0xF9AE, 'M', u'瑩'), + (0xF9AF, 'M', u'羚'), + (0xF9B0, 'M', u'聆'), + (0xF9B1, 'M', u'鈴'), + (0xF9B2, 'M', u'零'), + ] + +def _seg_41(): + return [ + (0xF9B3, 'M', u'靈'), + (0xF9B4, 'M', u'領'), + (0xF9B5, 'M', u'例'), + (0xF9B6, 'M', u'禮'), + (0xF9B7, 'M', u'醴'), + (0xF9B8, 'M', u'隸'), + (0xF9B9, 'M', u'惡'), + (0xF9BA, 'M', u'了'), + (0xF9BB, 'M', u'僚'), + (0xF9BC, 'M', u'寮'), + (0xF9BD, 'M', u'尿'), + (0xF9BE, 'M', u'料'), + (0xF9BF, 'M', u'樂'), + (0xF9C0, 'M', u'燎'), + (0xF9C1, 'M', u'療'), + (0xF9C2, 'M', u'蓼'), + (0xF9C3, 'M', u'遼'), + (0xF9C4, 'M', u'龍'), + (0xF9C5, 'M', u'暈'), + (0xF9C6, 'M', u'阮'), + (0xF9C7, 'M', u'劉'), + (0xF9C8, 'M', u'杻'), + (0xF9C9, 'M', u'柳'), + (0xF9CA, 'M', u'流'), + (0xF9CB, 'M', u'溜'), + (0xF9CC, 'M', u'琉'), + (0xF9CD, 'M', u'留'), + (0xF9CE, 'M', u'硫'), + (0xF9CF, 'M', u'紐'), + (0xF9D0, 'M', u'類'), + (0xF9D1, 'M', u'六'), + (0xF9D2, 'M', u'戮'), + (0xF9D3, 'M', u'陸'), + (0xF9D4, 'M', u'倫'), + (0xF9D5, 'M', u'崙'), + (0xF9D6, 'M', u'淪'), + (0xF9D7, 'M', u'輪'), + (0xF9D8, 'M', u'律'), + (0xF9D9, 'M', u'慄'), + (0xF9DA, 'M', u'栗'), + (0xF9DB, 'M', u'率'), + (0xF9DC, 'M', u'隆'), + (0xF9DD, 'M', u'利'), + (0xF9DE, 'M', u'吏'), + (0xF9DF, 'M', u'履'), + (0xF9E0, 'M', u'易'), + (0xF9E1, 'M', u'李'), + (0xF9E2, 'M', u'梨'), + (0xF9E3, 'M', u'泥'), + (0xF9E4, 'M', u'理'), + (0xF9E5, 'M', u'痢'), + (0xF9E6, 'M', u'罹'), + (0xF9E7, 'M', u'裏'), + (0xF9E8, 'M', u'裡'), + (0xF9E9, 'M', u'里'), + (0xF9EA, 'M', u'離'), + (0xF9EB, 'M', u'匿'), + (0xF9EC, 'M', u'溺'), + (0xF9ED, 'M', u'吝'), + (0xF9EE, 'M', u'燐'), + (0xF9EF, 'M', u'璘'), + (0xF9F0, 'M', u'藺'), + (0xF9F1, 'M', u'隣'), + (0xF9F2, 'M', u'鱗'), + (0xF9F3, 'M', u'麟'), + (0xF9F4, 'M', u'林'), + (0xF9F5, 'M', u'淋'), + (0xF9F6, 'M', u'臨'), + (0xF9F7, 'M', u'立'), + (0xF9F8, 'M', u'笠'), + (0xF9F9, 'M', u'粒'), + (0xF9FA, 'M', u'狀'), + (0xF9FB, 'M', u'炙'), + (0xF9FC, 'M', u'識'), + (0xF9FD, 'M', u'什'), + (0xF9FE, 'M', u'茶'), + (0xF9FF, 'M', u'刺'), + (0xFA00, 'M', u'切'), + (0xFA01, 'M', u'度'), + (0xFA02, 'M', u'拓'), + (0xFA03, 'M', u'糖'), + (0xFA04, 'M', u'宅'), + (0xFA05, 'M', u'洞'), + (0xFA06, 'M', u'暴'), + (0xFA07, 'M', u'輻'), + (0xFA08, 'M', u'行'), + (0xFA09, 'M', u'降'), + (0xFA0A, 'M', u'見'), + (0xFA0B, 'M', u'廓'), + (0xFA0C, 'M', u'兀'), + (0xFA0D, 'M', u'嗀'), + (0xFA0E, 'V'), + (0xFA10, 'M', u'塚'), + (0xFA11, 'V'), + (0xFA12, 'M', u'晴'), + (0xFA13, 'V'), + (0xFA15, 'M', u'凞'), + (0xFA16, 'M', u'猪'), + (0xFA17, 'M', u'益'), + (0xFA18, 'M', u'礼'), + ] + +def _seg_42(): + return [ + (0xFA19, 'M', u'神'), + (0xFA1A, 'M', u'祥'), + (0xFA1B, 'M', u'福'), + (0xFA1C, 'M', u'靖'), + (0xFA1D, 'M', u'精'), + (0xFA1E, 'M', u'羽'), + (0xFA1F, 'V'), + (0xFA20, 'M', u'蘒'), + (0xFA21, 'V'), + (0xFA22, 'M', u'諸'), + (0xFA23, 'V'), + (0xFA25, 'M', u'逸'), + (0xFA26, 'M', u'都'), + (0xFA27, 'V'), + (0xFA2A, 'M', u'飯'), + (0xFA2B, 'M', u'飼'), + (0xFA2C, 'M', u'館'), + (0xFA2D, 'M', u'鶴'), + (0xFA2E, 'M', u'郞'), + (0xFA2F, 'M', u'隷'), + (0xFA30, 'M', u'侮'), + (0xFA31, 'M', u'僧'), + (0xFA32, 'M', u'免'), + (0xFA33, 'M', u'勉'), + (0xFA34, 'M', u'勤'), + (0xFA35, 'M', u'卑'), + (0xFA36, 'M', u'喝'), + (0xFA37, 'M', u'嘆'), + (0xFA38, 'M', u'器'), + (0xFA39, 'M', u'塀'), + (0xFA3A, 'M', u'墨'), + (0xFA3B, 'M', u'層'), + (0xFA3C, 'M', u'屮'), + (0xFA3D, 'M', u'悔'), + (0xFA3E, 'M', u'慨'), + (0xFA3F, 'M', u'憎'), + (0xFA40, 'M', u'懲'), + (0xFA41, 'M', u'敏'), + (0xFA42, 'M', u'既'), + (0xFA43, 'M', u'暑'), + (0xFA44, 'M', u'梅'), + (0xFA45, 'M', u'海'), + (0xFA46, 'M', u'渚'), + (0xFA47, 'M', u'漢'), + (0xFA48, 'M', u'煮'), + (0xFA49, 'M', u'爫'), + (0xFA4A, 'M', u'琢'), + (0xFA4B, 'M', u'碑'), + (0xFA4C, 'M', u'社'), + (0xFA4D, 'M', u'祉'), + (0xFA4E, 'M', u'祈'), + (0xFA4F, 'M', u'祐'), + (0xFA50, 'M', u'祖'), + (0xFA51, 'M', u'祝'), + (0xFA52, 'M', u'禍'), + (0xFA53, 'M', u'禎'), + (0xFA54, 'M', u'穀'), + (0xFA55, 'M', u'突'), + (0xFA56, 'M', u'節'), + (0xFA57, 'M', u'練'), + (0xFA58, 'M', u'縉'), + (0xFA59, 'M', u'繁'), + (0xFA5A, 'M', u'署'), + (0xFA5B, 'M', u'者'), + (0xFA5C, 'M', u'臭'), + (0xFA5D, 'M', u'艹'), + (0xFA5F, 'M', u'著'), + (0xFA60, 'M', u'褐'), + (0xFA61, 'M', u'視'), + (0xFA62, 'M', u'謁'), + (0xFA63, 'M', u'謹'), + (0xFA64, 'M', u'賓'), + (0xFA65, 'M', u'贈'), + (0xFA66, 'M', u'辶'), + (0xFA67, 'M', u'逸'), + (0xFA68, 'M', u'難'), + (0xFA69, 'M', u'響'), + (0xFA6A, 'M', u'頻'), + (0xFA6B, 'M', u'恵'), + (0xFA6C, 'M', u'𤋮'), + (0xFA6D, 'M', u'舘'), + (0xFA6E, 'X'), + (0xFA70, 'M', u'並'), + (0xFA71, 'M', u'况'), + (0xFA72, 'M', u'全'), + (0xFA73, 'M', u'侀'), + (0xFA74, 'M', u'充'), + (0xFA75, 'M', u'冀'), + (0xFA76, 'M', u'勇'), + (0xFA77, 'M', u'勺'), + (0xFA78, 'M', u'喝'), + (0xFA79, 'M', u'啕'), + (0xFA7A, 'M', u'喙'), + (0xFA7B, 'M', u'嗢'), + (0xFA7C, 'M', u'塚'), + (0xFA7D, 'M', u'墳'), + (0xFA7E, 'M', u'奄'), + (0xFA7F, 'M', u'奔'), + (0xFA80, 'M', u'婢'), + (0xFA81, 'M', u'嬨'), + ] + +def _seg_43(): + return [ + (0xFA82, 'M', u'廒'), + (0xFA83, 'M', u'廙'), + (0xFA84, 'M', u'彩'), + (0xFA85, 'M', u'徭'), + (0xFA86, 'M', u'惘'), + (0xFA87, 'M', u'慎'), + (0xFA88, 'M', u'愈'), + (0xFA89, 'M', u'憎'), + (0xFA8A, 'M', u'慠'), + (0xFA8B, 'M', u'懲'), + (0xFA8C, 'M', u'戴'), + (0xFA8D, 'M', u'揄'), + (0xFA8E, 'M', u'搜'), + (0xFA8F, 'M', u'摒'), + (0xFA90, 'M', u'敖'), + (0xFA91, 'M', u'晴'), + (0xFA92, 'M', u'朗'), + (0xFA93, 'M', u'望'), + (0xFA94, 'M', u'杖'), + (0xFA95, 'M', u'歹'), + (0xFA96, 'M', u'殺'), + (0xFA97, 'M', u'流'), + (0xFA98, 'M', u'滛'), + (0xFA99, 'M', u'滋'), + (0xFA9A, 'M', u'漢'), + (0xFA9B, 'M', u'瀞'), + (0xFA9C, 'M', u'煮'), + (0xFA9D, 'M', u'瞧'), + (0xFA9E, 'M', u'爵'), + (0xFA9F, 'M', u'犯'), + (0xFAA0, 'M', u'猪'), + (0xFAA1, 'M', u'瑱'), + (0xFAA2, 'M', u'甆'), + (0xFAA3, 'M', u'画'), + (0xFAA4, 'M', u'瘝'), + (0xFAA5, 'M', u'瘟'), + (0xFAA6, 'M', u'益'), + (0xFAA7, 'M', u'盛'), + (0xFAA8, 'M', u'直'), + (0xFAA9, 'M', u'睊'), + (0xFAAA, 'M', u'着'), + (0xFAAB, 'M', u'磌'), + (0xFAAC, 'M', u'窱'), + (0xFAAD, 'M', u'節'), + (0xFAAE, 'M', u'类'), + (0xFAAF, 'M', u'絛'), + (0xFAB0, 'M', u'練'), + (0xFAB1, 'M', u'缾'), + (0xFAB2, 'M', u'者'), + (0xFAB3, 'M', u'荒'), + (0xFAB4, 'M', u'華'), + (0xFAB5, 'M', u'蝹'), + (0xFAB6, 'M', u'襁'), + (0xFAB7, 'M', u'覆'), + (0xFAB8, 'M', u'視'), + (0xFAB9, 'M', u'調'), + (0xFABA, 'M', u'諸'), + (0xFABB, 'M', u'請'), + (0xFABC, 'M', u'謁'), + (0xFABD, 'M', u'諾'), + (0xFABE, 'M', u'諭'), + (0xFABF, 'M', u'謹'), + (0xFAC0, 'M', u'變'), + (0xFAC1, 'M', u'贈'), + (0xFAC2, 'M', u'輸'), + (0xFAC3, 'M', u'遲'), + (0xFAC4, 'M', u'醙'), + (0xFAC5, 'M', u'鉶'), + (0xFAC6, 'M', u'陼'), + (0xFAC7, 'M', u'難'), + (0xFAC8, 'M', u'靖'), + (0xFAC9, 'M', u'韛'), + (0xFACA, 'M', u'響'), + (0xFACB, 'M', u'頋'), + (0xFACC, 'M', u'頻'), + (0xFACD, 'M', u'鬒'), + (0xFACE, 'M', u'龜'), + (0xFACF, 'M', u'𢡊'), + (0xFAD0, 'M', u'𢡄'), + (0xFAD1, 'M', u'𣏕'), + (0xFAD2, 'M', u'㮝'), + (0xFAD3, 'M', u'䀘'), + (0xFAD4, 'M', u'䀹'), + (0xFAD5, 'M', u'𥉉'), + (0xFAD6, 'M', u'𥳐'), + (0xFAD7, 'M', u'𧻓'), + (0xFAD8, 'M', u'齃'), + (0xFAD9, 'M', u'龎'), + (0xFADA, 'X'), + (0xFB00, 'M', u'ff'), + (0xFB01, 'M', u'fi'), + (0xFB02, 'M', u'fl'), + (0xFB03, 'M', u'ffi'), + (0xFB04, 'M', u'ffl'), + (0xFB05, 'M', u'st'), + (0xFB07, 'X'), + (0xFB13, 'M', u'մն'), + (0xFB14, 'M', u'մե'), + (0xFB15, 'M', u'մի'), + (0xFB16, 'M', u'վն'), + ] + +def _seg_44(): + return [ + (0xFB17, 'M', u'մխ'), + (0xFB18, 'X'), + (0xFB1D, 'M', u'יִ'), + (0xFB1E, 'V'), + (0xFB1F, 'M', u'ײַ'), + (0xFB20, 'M', u'ע'), + (0xFB21, 'M', u'א'), + (0xFB22, 'M', u'ד'), + (0xFB23, 'M', u'ה'), + (0xFB24, 'M', u'כ'), + (0xFB25, 'M', u'ל'), + (0xFB26, 'M', u'ם'), + (0xFB27, 'M', u'ר'), + (0xFB28, 'M', u'ת'), + (0xFB29, '3', u'+'), + (0xFB2A, 'M', u'שׁ'), + (0xFB2B, 'M', u'שׂ'), + (0xFB2C, 'M', u'שּׁ'), + (0xFB2D, 'M', u'שּׂ'), + (0xFB2E, 'M', u'אַ'), + (0xFB2F, 'M', u'אָ'), + (0xFB30, 'M', u'אּ'), + (0xFB31, 'M', u'בּ'), + (0xFB32, 'M', u'גּ'), + (0xFB33, 'M', u'דּ'), + (0xFB34, 'M', u'הּ'), + (0xFB35, 'M', u'וּ'), + (0xFB36, 'M', u'זּ'), + (0xFB37, 'X'), + (0xFB38, 'M', u'טּ'), + (0xFB39, 'M', u'יּ'), + (0xFB3A, 'M', u'ךּ'), + (0xFB3B, 'M', u'כּ'), + (0xFB3C, 'M', u'לּ'), + (0xFB3D, 'X'), + (0xFB3E, 'M', u'מּ'), + (0xFB3F, 'X'), + (0xFB40, 'M', u'נּ'), + (0xFB41, 'M', u'סּ'), + (0xFB42, 'X'), + (0xFB43, 'M', u'ףּ'), + (0xFB44, 'M', u'פּ'), + (0xFB45, 'X'), + (0xFB46, 'M', u'צּ'), + (0xFB47, 'M', u'קּ'), + (0xFB48, 'M', u'רּ'), + (0xFB49, 'M', u'שּ'), + (0xFB4A, 'M', u'תּ'), + (0xFB4B, 'M', u'וֹ'), + (0xFB4C, 'M', u'בֿ'), + (0xFB4D, 'M', u'כֿ'), + (0xFB4E, 'M', u'פֿ'), + (0xFB4F, 'M', u'אל'), + (0xFB50, 'M', u'ٱ'), + (0xFB52, 'M', u'ٻ'), + (0xFB56, 'M', u'پ'), + (0xFB5A, 'M', u'ڀ'), + (0xFB5E, 'M', u'ٺ'), + (0xFB62, 'M', u'ٿ'), + (0xFB66, 'M', u'ٹ'), + (0xFB6A, 'M', u'ڤ'), + (0xFB6E, 'M', u'ڦ'), + (0xFB72, 'M', u'ڄ'), + (0xFB76, 'M', u'ڃ'), + (0xFB7A, 'M', u'چ'), + (0xFB7E, 'M', u'ڇ'), + (0xFB82, 'M', u'ڍ'), + (0xFB84, 'M', u'ڌ'), + (0xFB86, 'M', u'ڎ'), + (0xFB88, 'M', u'ڈ'), + (0xFB8A, 'M', u'ژ'), + (0xFB8C, 'M', u'ڑ'), + (0xFB8E, 'M', u'ک'), + (0xFB92, 'M', u'گ'), + (0xFB96, 'M', u'ڳ'), + (0xFB9A, 'M', u'ڱ'), + (0xFB9E, 'M', u'ں'), + (0xFBA0, 'M', u'ڻ'), + (0xFBA4, 'M', u'ۀ'), + (0xFBA6, 'M', u'ہ'), + (0xFBAA, 'M', u'ھ'), + (0xFBAE, 'M', u'ے'), + (0xFBB0, 'M', u'ۓ'), + (0xFBB2, 'V'), + (0xFBC2, 'X'), + (0xFBD3, 'M', u'ڭ'), + (0xFBD7, 'M', u'ۇ'), + (0xFBD9, 'M', u'ۆ'), + (0xFBDB, 'M', u'ۈ'), + (0xFBDD, 'M', u'ۇٴ'), + (0xFBDE, 'M', u'ۋ'), + (0xFBE0, 'M', u'ۅ'), + (0xFBE2, 'M', u'ۉ'), + (0xFBE4, 'M', u'ې'), + (0xFBE8, 'M', u'ى'), + (0xFBEA, 'M', u'ئا'), + (0xFBEC, 'M', u'ئە'), + (0xFBEE, 'M', u'ئو'), + (0xFBF0, 'M', u'ئۇ'), + (0xFBF2, 'M', u'ئۆ'), + ] + +def _seg_45(): + return [ + (0xFBF4, 'M', u'ئۈ'), + (0xFBF6, 'M', u'ئې'), + (0xFBF9, 'M', u'ئى'), + (0xFBFC, 'M', u'ی'), + (0xFC00, 'M', u'ئج'), + (0xFC01, 'M', u'ئح'), + (0xFC02, 'M', u'ئم'), + (0xFC03, 'M', u'ئى'), + (0xFC04, 'M', u'ئي'), + (0xFC05, 'M', u'بج'), + (0xFC06, 'M', u'بح'), + (0xFC07, 'M', u'بخ'), + (0xFC08, 'M', u'بم'), + (0xFC09, 'M', u'بى'), + (0xFC0A, 'M', u'بي'), + (0xFC0B, 'M', u'تج'), + (0xFC0C, 'M', u'تح'), + (0xFC0D, 'M', u'تخ'), + (0xFC0E, 'M', u'تم'), + (0xFC0F, 'M', u'تى'), + (0xFC10, 'M', u'تي'), + (0xFC11, 'M', u'ثج'), + (0xFC12, 'M', u'ثم'), + (0xFC13, 'M', u'ثى'), + (0xFC14, 'M', u'ثي'), + (0xFC15, 'M', u'جح'), + (0xFC16, 'M', u'جم'), + (0xFC17, 'M', u'حج'), + (0xFC18, 'M', u'حم'), + (0xFC19, 'M', u'خج'), + (0xFC1A, 'M', u'خح'), + (0xFC1B, 'M', u'خم'), + (0xFC1C, 'M', u'سج'), + (0xFC1D, 'M', u'سح'), + (0xFC1E, 'M', u'سخ'), + (0xFC1F, 'M', u'سم'), + (0xFC20, 'M', u'صح'), + (0xFC21, 'M', u'صم'), + (0xFC22, 'M', u'ضج'), + (0xFC23, 'M', u'ضح'), + (0xFC24, 'M', u'ضخ'), + (0xFC25, 'M', u'ضم'), + (0xFC26, 'M', u'طح'), + (0xFC27, 'M', u'طم'), + (0xFC28, 'M', u'ظم'), + (0xFC29, 'M', u'عج'), + (0xFC2A, 'M', u'عم'), + (0xFC2B, 'M', u'غج'), + (0xFC2C, 'M', u'غم'), + (0xFC2D, 'M', u'فج'), + (0xFC2E, 'M', u'فح'), + (0xFC2F, 'M', u'فخ'), + (0xFC30, 'M', u'فم'), + (0xFC31, 'M', u'فى'), + (0xFC32, 'M', u'في'), + (0xFC33, 'M', u'قح'), + (0xFC34, 'M', u'قم'), + (0xFC35, 'M', u'قى'), + (0xFC36, 'M', u'قي'), + (0xFC37, 'M', u'كا'), + (0xFC38, 'M', u'كج'), + (0xFC39, 'M', u'كح'), + (0xFC3A, 'M', u'كخ'), + (0xFC3B, 'M', u'كل'), + (0xFC3C, 'M', u'كم'), + (0xFC3D, 'M', u'كى'), + (0xFC3E, 'M', u'كي'), + (0xFC3F, 'M', u'لج'), + (0xFC40, 'M', u'لح'), + (0xFC41, 'M', u'لخ'), + (0xFC42, 'M', u'لم'), + (0xFC43, 'M', u'لى'), + (0xFC44, 'M', u'لي'), + (0xFC45, 'M', u'مج'), + (0xFC46, 'M', u'مح'), + (0xFC47, 'M', u'مخ'), + (0xFC48, 'M', u'مم'), + (0xFC49, 'M', u'مى'), + (0xFC4A, 'M', u'مي'), + (0xFC4B, 'M', u'نج'), + (0xFC4C, 'M', u'نح'), + (0xFC4D, 'M', u'نخ'), + (0xFC4E, 'M', u'نم'), + (0xFC4F, 'M', u'نى'), + (0xFC50, 'M', u'ني'), + (0xFC51, 'M', u'هج'), + (0xFC52, 'M', u'هم'), + (0xFC53, 'M', u'هى'), + (0xFC54, 'M', u'هي'), + (0xFC55, 'M', u'يج'), + (0xFC56, 'M', u'يح'), + (0xFC57, 'M', u'يخ'), + (0xFC58, 'M', u'يم'), + (0xFC59, 'M', u'يى'), + (0xFC5A, 'M', u'يي'), + (0xFC5B, 'M', u'ذٰ'), + (0xFC5C, 'M', u'رٰ'), + (0xFC5D, 'M', u'ىٰ'), + (0xFC5E, '3', u' ٌّ'), + (0xFC5F, '3', u' ٍّ'), + ] + +def _seg_46(): + return [ + (0xFC60, '3', u' َّ'), + (0xFC61, '3', u' ُّ'), + (0xFC62, '3', u' ِّ'), + (0xFC63, '3', u' ّٰ'), + (0xFC64, 'M', u'ئر'), + (0xFC65, 'M', u'ئز'), + (0xFC66, 'M', u'ئم'), + (0xFC67, 'M', u'ئن'), + (0xFC68, 'M', u'ئى'), + (0xFC69, 'M', u'ئي'), + (0xFC6A, 'M', u'بر'), + (0xFC6B, 'M', u'بز'), + (0xFC6C, 'M', u'بم'), + (0xFC6D, 'M', u'بن'), + (0xFC6E, 'M', u'بى'), + (0xFC6F, 'M', u'بي'), + (0xFC70, 'M', u'تر'), + (0xFC71, 'M', u'تز'), + (0xFC72, 'M', u'تم'), + (0xFC73, 'M', u'تن'), + (0xFC74, 'M', u'تى'), + (0xFC75, 'M', u'تي'), + (0xFC76, 'M', u'ثر'), + (0xFC77, 'M', u'ثز'), + (0xFC78, 'M', u'ثم'), + (0xFC79, 'M', u'ثن'), + (0xFC7A, 'M', u'ثى'), + (0xFC7B, 'M', u'ثي'), + (0xFC7C, 'M', u'فى'), + (0xFC7D, 'M', u'في'), + (0xFC7E, 'M', u'قى'), + (0xFC7F, 'M', u'قي'), + (0xFC80, 'M', u'كا'), + (0xFC81, 'M', u'كل'), + (0xFC82, 'M', u'كم'), + (0xFC83, 'M', u'كى'), + (0xFC84, 'M', u'كي'), + (0xFC85, 'M', u'لم'), + (0xFC86, 'M', u'لى'), + (0xFC87, 'M', u'لي'), + (0xFC88, 'M', u'ما'), + (0xFC89, 'M', u'مم'), + (0xFC8A, 'M', u'نر'), + (0xFC8B, 'M', u'نز'), + (0xFC8C, 'M', u'نم'), + (0xFC8D, 'M', u'نن'), + (0xFC8E, 'M', u'نى'), + (0xFC8F, 'M', u'ني'), + (0xFC90, 'M', u'ىٰ'), + (0xFC91, 'M', u'ير'), + (0xFC92, 'M', u'يز'), + (0xFC93, 'M', u'يم'), + (0xFC94, 'M', u'ين'), + (0xFC95, 'M', u'يى'), + (0xFC96, 'M', u'يي'), + (0xFC97, 'M', u'ئج'), + (0xFC98, 'M', u'ئح'), + (0xFC99, 'M', u'ئخ'), + (0xFC9A, 'M', u'ئم'), + (0xFC9B, 'M', u'ئه'), + (0xFC9C, 'M', u'بج'), + (0xFC9D, 'M', u'بح'), + (0xFC9E, 'M', u'بخ'), + (0xFC9F, 'M', u'بم'), + (0xFCA0, 'M', u'به'), + (0xFCA1, 'M', u'تج'), + (0xFCA2, 'M', u'تح'), + (0xFCA3, 'M', u'تخ'), + (0xFCA4, 'M', u'تم'), + (0xFCA5, 'M', u'ته'), + (0xFCA6, 'M', u'ثم'), + (0xFCA7, 'M', u'جح'), + (0xFCA8, 'M', u'جم'), + (0xFCA9, 'M', u'حج'), + (0xFCAA, 'M', u'حم'), + (0xFCAB, 'M', u'خج'), + (0xFCAC, 'M', u'خم'), + (0xFCAD, 'M', u'سج'), + (0xFCAE, 'M', u'سح'), + (0xFCAF, 'M', u'سخ'), + (0xFCB0, 'M', u'سم'), + (0xFCB1, 'M', u'صح'), + (0xFCB2, 'M', u'صخ'), + (0xFCB3, 'M', u'صم'), + (0xFCB4, 'M', u'ضج'), + (0xFCB5, 'M', u'ضح'), + (0xFCB6, 'M', u'ضخ'), + (0xFCB7, 'M', u'ضم'), + (0xFCB8, 'M', u'طح'), + (0xFCB9, 'M', u'ظم'), + (0xFCBA, 'M', u'عج'), + (0xFCBB, 'M', u'عم'), + (0xFCBC, 'M', u'غج'), + (0xFCBD, 'M', u'غم'), + (0xFCBE, 'M', u'فج'), + (0xFCBF, 'M', u'فح'), + (0xFCC0, 'M', u'فخ'), + (0xFCC1, 'M', u'فم'), + (0xFCC2, 'M', u'قح'), + (0xFCC3, 'M', u'قم'), + ] + +def _seg_47(): + return [ + (0xFCC4, 'M', u'كج'), + (0xFCC5, 'M', u'كح'), + (0xFCC6, 'M', u'كخ'), + (0xFCC7, 'M', u'كل'), + (0xFCC8, 'M', u'كم'), + (0xFCC9, 'M', u'لج'), + (0xFCCA, 'M', u'لح'), + (0xFCCB, 'M', u'لخ'), + (0xFCCC, 'M', u'لم'), + (0xFCCD, 'M', u'له'), + (0xFCCE, 'M', u'مج'), + (0xFCCF, 'M', u'مح'), + (0xFCD0, 'M', u'مخ'), + (0xFCD1, 'M', u'مم'), + (0xFCD2, 'M', u'نج'), + (0xFCD3, 'M', u'نح'), + (0xFCD4, 'M', u'نخ'), + (0xFCD5, 'M', u'نم'), + (0xFCD6, 'M', u'نه'), + (0xFCD7, 'M', u'هج'), + (0xFCD8, 'M', u'هم'), + (0xFCD9, 'M', u'هٰ'), + (0xFCDA, 'M', u'يج'), + (0xFCDB, 'M', u'يح'), + (0xFCDC, 'M', u'يخ'), + (0xFCDD, 'M', u'يم'), + (0xFCDE, 'M', u'يه'), + (0xFCDF, 'M', u'ئم'), + (0xFCE0, 'M', u'ئه'), + (0xFCE1, 'M', u'بم'), + (0xFCE2, 'M', u'به'), + (0xFCE3, 'M', u'تم'), + (0xFCE4, 'M', u'ته'), + (0xFCE5, 'M', u'ثم'), + (0xFCE6, 'M', u'ثه'), + (0xFCE7, 'M', u'سم'), + (0xFCE8, 'M', u'سه'), + (0xFCE9, 'M', u'شم'), + (0xFCEA, 'M', u'شه'), + (0xFCEB, 'M', u'كل'), + (0xFCEC, 'M', u'كم'), + (0xFCED, 'M', u'لم'), + (0xFCEE, 'M', u'نم'), + (0xFCEF, 'M', u'نه'), + (0xFCF0, 'M', u'يم'), + (0xFCF1, 'M', u'يه'), + (0xFCF2, 'M', u'ـَّ'), + (0xFCF3, 'M', u'ـُّ'), + (0xFCF4, 'M', u'ـِّ'), + (0xFCF5, 'M', u'طى'), + (0xFCF6, 'M', u'طي'), + (0xFCF7, 'M', u'عى'), + (0xFCF8, 'M', u'عي'), + (0xFCF9, 'M', u'غى'), + (0xFCFA, 'M', u'غي'), + (0xFCFB, 'M', u'سى'), + (0xFCFC, 'M', u'سي'), + (0xFCFD, 'M', u'شى'), + (0xFCFE, 'M', u'شي'), + (0xFCFF, 'M', u'حى'), + (0xFD00, 'M', u'حي'), + (0xFD01, 'M', u'جى'), + (0xFD02, 'M', u'جي'), + (0xFD03, 'M', u'خى'), + (0xFD04, 'M', u'خي'), + (0xFD05, 'M', u'صى'), + (0xFD06, 'M', u'صي'), + (0xFD07, 'M', u'ضى'), + (0xFD08, 'M', u'ضي'), + (0xFD09, 'M', u'شج'), + (0xFD0A, 'M', u'شح'), + (0xFD0B, 'M', u'شخ'), + (0xFD0C, 'M', u'شم'), + (0xFD0D, 'M', u'شر'), + (0xFD0E, 'M', u'سر'), + (0xFD0F, 'M', u'صر'), + (0xFD10, 'M', u'ضر'), + (0xFD11, 'M', u'طى'), + (0xFD12, 'M', u'طي'), + (0xFD13, 'M', u'عى'), + (0xFD14, 'M', u'عي'), + (0xFD15, 'M', u'غى'), + (0xFD16, 'M', u'غي'), + (0xFD17, 'M', u'سى'), + (0xFD18, 'M', u'سي'), + (0xFD19, 'M', u'شى'), + (0xFD1A, 'M', u'شي'), + (0xFD1B, 'M', u'حى'), + (0xFD1C, 'M', u'حي'), + (0xFD1D, 'M', u'جى'), + (0xFD1E, 'M', u'جي'), + (0xFD1F, 'M', u'خى'), + (0xFD20, 'M', u'خي'), + (0xFD21, 'M', u'صى'), + (0xFD22, 'M', u'صي'), + (0xFD23, 'M', u'ضى'), + (0xFD24, 'M', u'ضي'), + (0xFD25, 'M', u'شج'), + (0xFD26, 'M', u'شح'), + (0xFD27, 'M', u'شخ'), + ] + +def _seg_48(): + return [ + (0xFD28, 'M', u'شم'), + (0xFD29, 'M', u'شر'), + (0xFD2A, 'M', u'سر'), + (0xFD2B, 'M', u'صر'), + (0xFD2C, 'M', u'ضر'), + (0xFD2D, 'M', u'شج'), + (0xFD2E, 'M', u'شح'), + (0xFD2F, 'M', u'شخ'), + (0xFD30, 'M', u'شم'), + (0xFD31, 'M', u'سه'), + (0xFD32, 'M', u'شه'), + (0xFD33, 'M', u'طم'), + (0xFD34, 'M', u'سج'), + (0xFD35, 'M', u'سح'), + (0xFD36, 'M', u'سخ'), + (0xFD37, 'M', u'شج'), + (0xFD38, 'M', u'شح'), + (0xFD39, 'M', u'شخ'), + (0xFD3A, 'M', u'طم'), + (0xFD3B, 'M', u'ظم'), + (0xFD3C, 'M', u'اً'), + (0xFD3E, 'V'), + (0xFD40, 'X'), + (0xFD50, 'M', u'تجم'), + (0xFD51, 'M', u'تحج'), + (0xFD53, 'M', u'تحم'), + (0xFD54, 'M', u'تخم'), + (0xFD55, 'M', u'تمج'), + (0xFD56, 'M', u'تمح'), + (0xFD57, 'M', u'تمخ'), + (0xFD58, 'M', u'جمح'), + (0xFD5A, 'M', u'حمي'), + (0xFD5B, 'M', u'حمى'), + (0xFD5C, 'M', u'سحج'), + (0xFD5D, 'M', u'سجح'), + (0xFD5E, 'M', u'سجى'), + (0xFD5F, 'M', u'سمح'), + (0xFD61, 'M', u'سمج'), + (0xFD62, 'M', u'سمم'), + (0xFD64, 'M', u'صحح'), + (0xFD66, 'M', u'صمم'), + (0xFD67, 'M', u'شحم'), + (0xFD69, 'M', u'شجي'), + (0xFD6A, 'M', u'شمخ'), + (0xFD6C, 'M', u'شمم'), + (0xFD6E, 'M', u'ضحى'), + (0xFD6F, 'M', u'ضخم'), + (0xFD71, 'M', u'طمح'), + (0xFD73, 'M', u'طمم'), + (0xFD74, 'M', u'طمي'), + (0xFD75, 'M', u'عجم'), + (0xFD76, 'M', u'عمم'), + (0xFD78, 'M', u'عمى'), + (0xFD79, 'M', u'غمم'), + (0xFD7A, 'M', u'غمي'), + (0xFD7B, 'M', u'غمى'), + (0xFD7C, 'M', u'فخم'), + (0xFD7E, 'M', u'قمح'), + (0xFD7F, 'M', u'قمم'), + (0xFD80, 'M', u'لحم'), + (0xFD81, 'M', u'لحي'), + (0xFD82, 'M', u'لحى'), + (0xFD83, 'M', u'لجج'), + (0xFD85, 'M', u'لخم'), + (0xFD87, 'M', u'لمح'), + (0xFD89, 'M', u'محج'), + (0xFD8A, 'M', u'محم'), + (0xFD8B, 'M', u'محي'), + (0xFD8C, 'M', u'مجح'), + (0xFD8D, 'M', u'مجم'), + (0xFD8E, 'M', u'مخج'), + (0xFD8F, 'M', u'مخم'), + (0xFD90, 'X'), + (0xFD92, 'M', u'مجخ'), + (0xFD93, 'M', u'همج'), + (0xFD94, 'M', u'همم'), + (0xFD95, 'M', u'نحم'), + (0xFD96, 'M', u'نحى'), + (0xFD97, 'M', u'نجم'), + (0xFD99, 'M', u'نجى'), + (0xFD9A, 'M', u'نمي'), + (0xFD9B, 'M', u'نمى'), + (0xFD9C, 'M', u'يمم'), + (0xFD9E, 'M', u'بخي'), + (0xFD9F, 'M', u'تجي'), + (0xFDA0, 'M', u'تجى'), + (0xFDA1, 'M', u'تخي'), + (0xFDA2, 'M', u'تخى'), + (0xFDA3, 'M', u'تمي'), + (0xFDA4, 'M', u'تمى'), + (0xFDA5, 'M', u'جمي'), + (0xFDA6, 'M', u'جحى'), + (0xFDA7, 'M', u'جمى'), + (0xFDA8, 'M', u'سخى'), + (0xFDA9, 'M', u'صحي'), + (0xFDAA, 'M', u'شحي'), + (0xFDAB, 'M', u'ضحي'), + (0xFDAC, 'M', u'لجي'), + (0xFDAD, 'M', u'لمي'), + (0xFDAE, 'M', u'يحي'), + ] + +def _seg_49(): + return [ + (0xFDAF, 'M', u'يجي'), + (0xFDB0, 'M', u'يمي'), + (0xFDB1, 'M', u'ممي'), + (0xFDB2, 'M', u'قمي'), + (0xFDB3, 'M', u'نحي'), + (0xFDB4, 'M', u'قمح'), + (0xFDB5, 'M', u'لحم'), + (0xFDB6, 'M', u'عمي'), + (0xFDB7, 'M', u'كمي'), + (0xFDB8, 'M', u'نجح'), + (0xFDB9, 'M', u'مخي'), + (0xFDBA, 'M', u'لجم'), + (0xFDBB, 'M', u'كمم'), + (0xFDBC, 'M', u'لجم'), + (0xFDBD, 'M', u'نجح'), + (0xFDBE, 'M', u'جحي'), + (0xFDBF, 'M', u'حجي'), + (0xFDC0, 'M', u'مجي'), + (0xFDC1, 'M', u'فمي'), + (0xFDC2, 'M', u'بحي'), + (0xFDC3, 'M', u'كمم'), + (0xFDC4, 'M', u'عجم'), + (0xFDC5, 'M', u'صمم'), + (0xFDC6, 'M', u'سخي'), + (0xFDC7, 'M', u'نجي'), + (0xFDC8, 'X'), + (0xFDF0, 'M', u'صلے'), + (0xFDF1, 'M', u'قلے'), + (0xFDF2, 'M', u'الله'), + (0xFDF3, 'M', u'اكبر'), + (0xFDF4, 'M', u'محمد'), + (0xFDF5, 'M', u'صلعم'), + (0xFDF6, 'M', u'رسول'), + (0xFDF7, 'M', u'عليه'), + (0xFDF8, 'M', u'وسلم'), + (0xFDF9, 'M', u'صلى'), + (0xFDFA, '3', u'صلى الله عليه وسلم'), + (0xFDFB, '3', u'جل جلاله'), + (0xFDFC, 'M', u'ریال'), + (0xFDFD, 'V'), + (0xFDFE, 'X'), + (0xFE00, 'I'), + (0xFE10, '3', u','), + (0xFE11, 'M', u'、'), + (0xFE12, 'X'), + (0xFE13, '3', u':'), + (0xFE14, '3', u';'), + (0xFE15, '3', u'!'), + (0xFE16, '3', u'?'), + (0xFE17, 'M', u'〖'), + (0xFE18, 'M', u'〗'), + (0xFE19, 'X'), + (0xFE20, 'V'), + (0xFE30, 'X'), + (0xFE31, 'M', u'—'), + (0xFE32, 'M', u'–'), + (0xFE33, '3', u'_'), + (0xFE35, '3', u'('), + (0xFE36, '3', u')'), + (0xFE37, '3', u'{'), + (0xFE38, '3', u'}'), + (0xFE39, 'M', u'〔'), + (0xFE3A, 'M', u'〕'), + (0xFE3B, 'M', u'【'), + (0xFE3C, 'M', u'】'), + (0xFE3D, 'M', u'《'), + (0xFE3E, 'M', u'》'), + (0xFE3F, 'M', u'〈'), + (0xFE40, 'M', u'〉'), + (0xFE41, 'M', u'「'), + (0xFE42, 'M', u'」'), + (0xFE43, 'M', u'『'), + (0xFE44, 'M', u'』'), + (0xFE45, 'V'), + (0xFE47, '3', u'['), + (0xFE48, '3', u']'), + (0xFE49, '3', u' ̅'), + (0xFE4D, '3', u'_'), + (0xFE50, '3', u','), + (0xFE51, 'M', u'、'), + (0xFE52, 'X'), + (0xFE54, '3', u';'), + (0xFE55, '3', u':'), + (0xFE56, '3', u'?'), + (0xFE57, '3', u'!'), + (0xFE58, 'M', u'—'), + (0xFE59, '3', u'('), + (0xFE5A, '3', u')'), + (0xFE5B, '3', u'{'), + (0xFE5C, '3', u'}'), + (0xFE5D, 'M', u'〔'), + (0xFE5E, 'M', u'〕'), + (0xFE5F, '3', u'#'), + (0xFE60, '3', u'&'), + (0xFE61, '3', u'*'), + (0xFE62, '3', u'+'), + (0xFE63, 'M', u'-'), + (0xFE64, '3', u'<'), + (0xFE65, '3', u'>'), + (0xFE66, '3', u'='), + ] + +def _seg_50(): + return [ + (0xFE67, 'X'), + (0xFE68, '3', u'\\'), + (0xFE69, '3', u'$'), + (0xFE6A, '3', u'%'), + (0xFE6B, '3', u'@'), + (0xFE6C, 'X'), + (0xFE70, '3', u' ً'), + (0xFE71, 'M', u'ـً'), + (0xFE72, '3', u' ٌ'), + (0xFE73, 'V'), + (0xFE74, '3', u' ٍ'), + (0xFE75, 'X'), + (0xFE76, '3', u' َ'), + (0xFE77, 'M', u'ـَ'), + (0xFE78, '3', u' ُ'), + (0xFE79, 'M', u'ـُ'), + (0xFE7A, '3', u' ِ'), + (0xFE7B, 'M', u'ـِ'), + (0xFE7C, '3', u' ّ'), + (0xFE7D, 'M', u'ـّ'), + (0xFE7E, '3', u' ْ'), + (0xFE7F, 'M', u'ـْ'), + (0xFE80, 'M', u'ء'), + (0xFE81, 'M', u'آ'), + (0xFE83, 'M', u'أ'), + (0xFE85, 'M', u'ؤ'), + (0xFE87, 'M', u'إ'), + (0xFE89, 'M', u'ئ'), + (0xFE8D, 'M', u'ا'), + (0xFE8F, 'M', u'ب'), + (0xFE93, 'M', u'ة'), + (0xFE95, 'M', u'ت'), + (0xFE99, 'M', u'ث'), + (0xFE9D, 'M', u'ج'), + (0xFEA1, 'M', u'ح'), + (0xFEA5, 'M', u'خ'), + (0xFEA9, 'M', u'د'), + (0xFEAB, 'M', u'ذ'), + (0xFEAD, 'M', u'ر'), + (0xFEAF, 'M', u'ز'), + (0xFEB1, 'M', u'س'), + (0xFEB5, 'M', u'ش'), + (0xFEB9, 'M', u'ص'), + (0xFEBD, 'M', u'ض'), + (0xFEC1, 'M', u'ط'), + (0xFEC5, 'M', u'ظ'), + (0xFEC9, 'M', u'ع'), + (0xFECD, 'M', u'غ'), + (0xFED1, 'M', u'ف'), + (0xFED5, 'M', u'ق'), + (0xFED9, 'M', u'ك'), + (0xFEDD, 'M', u'ل'), + (0xFEE1, 'M', u'م'), + (0xFEE5, 'M', u'ن'), + (0xFEE9, 'M', u'ه'), + (0xFEED, 'M', u'و'), + (0xFEEF, 'M', u'ى'), + (0xFEF1, 'M', u'ي'), + (0xFEF5, 'M', u'لآ'), + (0xFEF7, 'M', u'لأ'), + (0xFEF9, 'M', u'لإ'), + (0xFEFB, 'M', u'لا'), + (0xFEFD, 'X'), + (0xFEFF, 'I'), + (0xFF00, 'X'), + (0xFF01, '3', u'!'), + (0xFF02, '3', u'"'), + (0xFF03, '3', u'#'), + (0xFF04, '3', u'$'), + (0xFF05, '3', u'%'), + (0xFF06, '3', u'&'), + (0xFF07, '3', u'\''), + (0xFF08, '3', u'('), + (0xFF09, '3', u')'), + (0xFF0A, '3', u'*'), + (0xFF0B, '3', u'+'), + (0xFF0C, '3', u','), + (0xFF0D, 'M', u'-'), + (0xFF0E, 'M', u'.'), + (0xFF0F, '3', u'/'), + (0xFF10, 'M', u'0'), + (0xFF11, 'M', u'1'), + (0xFF12, 'M', u'2'), + (0xFF13, 'M', u'3'), + (0xFF14, 'M', u'4'), + (0xFF15, 'M', u'5'), + (0xFF16, 'M', u'6'), + (0xFF17, 'M', u'7'), + (0xFF18, 'M', u'8'), + (0xFF19, 'M', u'9'), + (0xFF1A, '3', u':'), + (0xFF1B, '3', u';'), + (0xFF1C, '3', u'<'), + (0xFF1D, '3', u'='), + (0xFF1E, '3', u'>'), + (0xFF1F, '3', u'?'), + (0xFF20, '3', u'@'), + (0xFF21, 'M', u'a'), + (0xFF22, 'M', u'b'), + (0xFF23, 'M', u'c'), + ] + +def _seg_51(): + return [ + (0xFF24, 'M', u'd'), + (0xFF25, 'M', u'e'), + (0xFF26, 'M', u'f'), + (0xFF27, 'M', u'g'), + (0xFF28, 'M', u'h'), + (0xFF29, 'M', u'i'), + (0xFF2A, 'M', u'j'), + (0xFF2B, 'M', u'k'), + (0xFF2C, 'M', u'l'), + (0xFF2D, 'M', u'm'), + (0xFF2E, 'M', u'n'), + (0xFF2F, 'M', u'o'), + (0xFF30, 'M', u'p'), + (0xFF31, 'M', u'q'), + (0xFF32, 'M', u'r'), + (0xFF33, 'M', u's'), + (0xFF34, 'M', u't'), + (0xFF35, 'M', u'u'), + (0xFF36, 'M', u'v'), + (0xFF37, 'M', u'w'), + (0xFF38, 'M', u'x'), + (0xFF39, 'M', u'y'), + (0xFF3A, 'M', u'z'), + (0xFF3B, '3', u'['), + (0xFF3C, '3', u'\\'), + (0xFF3D, '3', u']'), + (0xFF3E, '3', u'^'), + (0xFF3F, '3', u'_'), + (0xFF40, '3', u'`'), + (0xFF41, 'M', u'a'), + (0xFF42, 'M', u'b'), + (0xFF43, 'M', u'c'), + (0xFF44, 'M', u'd'), + (0xFF45, 'M', u'e'), + (0xFF46, 'M', u'f'), + (0xFF47, 'M', u'g'), + (0xFF48, 'M', u'h'), + (0xFF49, 'M', u'i'), + (0xFF4A, 'M', u'j'), + (0xFF4B, 'M', u'k'), + (0xFF4C, 'M', u'l'), + (0xFF4D, 'M', u'm'), + (0xFF4E, 'M', u'n'), + (0xFF4F, 'M', u'o'), + (0xFF50, 'M', u'p'), + (0xFF51, 'M', u'q'), + (0xFF52, 'M', u'r'), + (0xFF53, 'M', u's'), + (0xFF54, 'M', u't'), + (0xFF55, 'M', u'u'), + (0xFF56, 'M', u'v'), + (0xFF57, 'M', u'w'), + (0xFF58, 'M', u'x'), + (0xFF59, 'M', u'y'), + (0xFF5A, 'M', u'z'), + (0xFF5B, '3', u'{'), + (0xFF5C, '3', u'|'), + (0xFF5D, '3', u'}'), + (0xFF5E, '3', u'~'), + (0xFF5F, 'M', u'⦅'), + (0xFF60, 'M', u'⦆'), + (0xFF61, 'M', u'.'), + (0xFF62, 'M', u'「'), + (0xFF63, 'M', u'」'), + (0xFF64, 'M', u'、'), + (0xFF65, 'M', u'・'), + (0xFF66, 'M', u'ヲ'), + (0xFF67, 'M', u'ァ'), + (0xFF68, 'M', u'ィ'), + (0xFF69, 'M', u'ゥ'), + (0xFF6A, 'M', u'ェ'), + (0xFF6B, 'M', u'ォ'), + (0xFF6C, 'M', u'ャ'), + (0xFF6D, 'M', u'ュ'), + (0xFF6E, 'M', u'ョ'), + (0xFF6F, 'M', u'ッ'), + (0xFF70, 'M', u'ー'), + (0xFF71, 'M', u'ア'), + (0xFF72, 'M', u'イ'), + (0xFF73, 'M', u'ウ'), + (0xFF74, 'M', u'エ'), + (0xFF75, 'M', u'オ'), + (0xFF76, 'M', u'カ'), + (0xFF77, 'M', u'キ'), + (0xFF78, 'M', u'ク'), + (0xFF79, 'M', u'ケ'), + (0xFF7A, 'M', u'コ'), + (0xFF7B, 'M', u'サ'), + (0xFF7C, 'M', u'シ'), + (0xFF7D, 'M', u'ス'), + (0xFF7E, 'M', u'セ'), + (0xFF7F, 'M', u'ソ'), + (0xFF80, 'M', u'タ'), + (0xFF81, 'M', u'チ'), + (0xFF82, 'M', u'ツ'), + (0xFF83, 'M', u'テ'), + (0xFF84, 'M', u'ト'), + (0xFF85, 'M', u'ナ'), + (0xFF86, 'M', u'ニ'), + (0xFF87, 'M', u'ヌ'), + ] + +def _seg_52(): + return [ + (0xFF88, 'M', u'ネ'), + (0xFF89, 'M', u'ノ'), + (0xFF8A, 'M', u'ハ'), + (0xFF8B, 'M', u'ヒ'), + (0xFF8C, 'M', u'フ'), + (0xFF8D, 'M', u'ヘ'), + (0xFF8E, 'M', u'ホ'), + (0xFF8F, 'M', u'マ'), + (0xFF90, 'M', u'ミ'), + (0xFF91, 'M', u'ム'), + (0xFF92, 'M', u'メ'), + (0xFF93, 'M', u'モ'), + (0xFF94, 'M', u'ヤ'), + (0xFF95, 'M', u'ユ'), + (0xFF96, 'M', u'ヨ'), + (0xFF97, 'M', u'ラ'), + (0xFF98, 'M', u'リ'), + (0xFF99, 'M', u'ル'), + (0xFF9A, 'M', u'レ'), + (0xFF9B, 'M', u'ロ'), + (0xFF9C, 'M', u'ワ'), + (0xFF9D, 'M', u'ン'), + (0xFF9E, 'M', u'゙'), + (0xFF9F, 'M', u'゚'), + (0xFFA0, 'X'), + (0xFFA1, 'M', u'ᄀ'), + (0xFFA2, 'M', u'ᄁ'), + (0xFFA3, 'M', u'ᆪ'), + (0xFFA4, 'M', u'ᄂ'), + (0xFFA5, 'M', u'ᆬ'), + (0xFFA6, 'M', u'ᆭ'), + (0xFFA7, 'M', u'ᄃ'), + (0xFFA8, 'M', u'ᄄ'), + (0xFFA9, 'M', u'ᄅ'), + (0xFFAA, 'M', u'ᆰ'), + (0xFFAB, 'M', u'ᆱ'), + (0xFFAC, 'M', u'ᆲ'), + (0xFFAD, 'M', u'ᆳ'), + (0xFFAE, 'M', u'ᆴ'), + (0xFFAF, 'M', u'ᆵ'), + (0xFFB0, 'M', u'ᄚ'), + (0xFFB1, 'M', u'ᄆ'), + (0xFFB2, 'M', u'ᄇ'), + (0xFFB3, 'M', u'ᄈ'), + (0xFFB4, 'M', u'ᄡ'), + (0xFFB5, 'M', u'ᄉ'), + (0xFFB6, 'M', u'ᄊ'), + (0xFFB7, 'M', u'ᄋ'), + (0xFFB8, 'M', u'ᄌ'), + (0xFFB9, 'M', u'ᄍ'), + (0xFFBA, 'M', u'ᄎ'), + (0xFFBB, 'M', u'ᄏ'), + (0xFFBC, 'M', u'ᄐ'), + (0xFFBD, 'M', u'ᄑ'), + (0xFFBE, 'M', u'ᄒ'), + (0xFFBF, 'X'), + (0xFFC2, 'M', u'ᅡ'), + (0xFFC3, 'M', u'ᅢ'), + (0xFFC4, 'M', u'ᅣ'), + (0xFFC5, 'M', u'ᅤ'), + (0xFFC6, 'M', u'ᅥ'), + (0xFFC7, 'M', u'ᅦ'), + (0xFFC8, 'X'), + (0xFFCA, 'M', u'ᅧ'), + (0xFFCB, 'M', u'ᅨ'), + (0xFFCC, 'M', u'ᅩ'), + (0xFFCD, 'M', u'ᅪ'), + (0xFFCE, 'M', u'ᅫ'), + (0xFFCF, 'M', u'ᅬ'), + (0xFFD0, 'X'), + (0xFFD2, 'M', u'ᅭ'), + (0xFFD3, 'M', u'ᅮ'), + (0xFFD4, 'M', u'ᅯ'), + (0xFFD5, 'M', u'ᅰ'), + (0xFFD6, 'M', u'ᅱ'), + (0xFFD7, 'M', u'ᅲ'), + (0xFFD8, 'X'), + (0xFFDA, 'M', u'ᅳ'), + (0xFFDB, 'M', u'ᅴ'), + (0xFFDC, 'M', u'ᅵ'), + (0xFFDD, 'X'), + (0xFFE0, 'M', u'¢'), + (0xFFE1, 'M', u'£'), + (0xFFE2, 'M', u'¬'), + (0xFFE3, '3', u' ̄'), + (0xFFE4, 'M', u'¦'), + (0xFFE5, 'M', u'¥'), + (0xFFE6, 'M', u'₩'), + (0xFFE7, 'X'), + (0xFFE8, 'M', u'│'), + (0xFFE9, 'M', u'←'), + (0xFFEA, 'M', u'↑'), + (0xFFEB, 'M', u'→'), + (0xFFEC, 'M', u'↓'), + (0xFFED, 'M', u'■'), + (0xFFEE, 'M', u'○'), + (0xFFEF, 'X'), + (0x10000, 'V'), + (0x1000C, 'X'), + (0x1000D, 'V'), + ] + +def _seg_53(): + return [ + (0x10027, 'X'), + (0x10028, 'V'), + (0x1003B, 'X'), + (0x1003C, 'V'), + (0x1003E, 'X'), + (0x1003F, 'V'), + (0x1004E, 'X'), + (0x10050, 'V'), + (0x1005E, 'X'), + (0x10080, 'V'), + (0x100FB, 'X'), + (0x10100, 'V'), + (0x10103, 'X'), + (0x10107, 'V'), + (0x10134, 'X'), + (0x10137, 'V'), + (0x1018F, 'X'), + (0x10190, 'V'), + (0x1019D, 'X'), + (0x101A0, 'V'), + (0x101A1, 'X'), + (0x101D0, 'V'), + (0x101FE, 'X'), + (0x10280, 'V'), + (0x1029D, 'X'), + (0x102A0, 'V'), + (0x102D1, 'X'), + (0x102E0, 'V'), + (0x102FC, 'X'), + (0x10300, 'V'), + (0x10324, 'X'), + (0x1032D, 'V'), + (0x1034B, 'X'), + (0x10350, 'V'), + (0x1037B, 'X'), + (0x10380, 'V'), + (0x1039E, 'X'), + (0x1039F, 'V'), + (0x103C4, 'X'), + (0x103C8, 'V'), + (0x103D6, 'X'), + (0x10400, 'M', u'𐐨'), + (0x10401, 'M', u'𐐩'), + (0x10402, 'M', u'𐐪'), + (0x10403, 'M', u'𐐫'), + (0x10404, 'M', u'𐐬'), + (0x10405, 'M', u'𐐭'), + (0x10406, 'M', u'𐐮'), + (0x10407, 'M', u'𐐯'), + (0x10408, 'M', u'𐐰'), + (0x10409, 'M', u'𐐱'), + (0x1040A, 'M', u'𐐲'), + (0x1040B, 'M', u'𐐳'), + (0x1040C, 'M', u'𐐴'), + (0x1040D, 'M', u'𐐵'), + (0x1040E, 'M', u'𐐶'), + (0x1040F, 'M', u'𐐷'), + (0x10410, 'M', u'𐐸'), + (0x10411, 'M', u'𐐹'), + (0x10412, 'M', u'𐐺'), + (0x10413, 'M', u'𐐻'), + (0x10414, 'M', u'𐐼'), + (0x10415, 'M', u'𐐽'), + (0x10416, 'M', u'𐐾'), + (0x10417, 'M', u'𐐿'), + (0x10418, 'M', u'𐑀'), + (0x10419, 'M', u'𐑁'), + (0x1041A, 'M', u'𐑂'), + (0x1041B, 'M', u'𐑃'), + (0x1041C, 'M', u'𐑄'), + (0x1041D, 'M', u'𐑅'), + (0x1041E, 'M', u'𐑆'), + (0x1041F, 'M', u'𐑇'), + (0x10420, 'M', u'𐑈'), + (0x10421, 'M', u'𐑉'), + (0x10422, 'M', u'𐑊'), + (0x10423, 'M', u'𐑋'), + (0x10424, 'M', u'𐑌'), + (0x10425, 'M', u'𐑍'), + (0x10426, 'M', u'𐑎'), + (0x10427, 'M', u'𐑏'), + (0x10428, 'V'), + (0x1049E, 'X'), + (0x104A0, 'V'), + (0x104AA, 'X'), + (0x104B0, 'M', u'𐓘'), + (0x104B1, 'M', u'𐓙'), + (0x104B2, 'M', u'𐓚'), + (0x104B3, 'M', u'𐓛'), + (0x104B4, 'M', u'𐓜'), + (0x104B5, 'M', u'𐓝'), + (0x104B6, 'M', u'𐓞'), + (0x104B7, 'M', u'𐓟'), + (0x104B8, 'M', u'𐓠'), + (0x104B9, 'M', u'𐓡'), + (0x104BA, 'M', u'𐓢'), + (0x104BB, 'M', u'𐓣'), + (0x104BC, 'M', u'𐓤'), + (0x104BD, 'M', u'𐓥'), + (0x104BE, 'M', u'𐓦'), + ] + +def _seg_54(): + return [ + (0x104BF, 'M', u'𐓧'), + (0x104C0, 'M', u'𐓨'), + (0x104C1, 'M', u'𐓩'), + (0x104C2, 'M', u'𐓪'), + (0x104C3, 'M', u'𐓫'), + (0x104C4, 'M', u'𐓬'), + (0x104C5, 'M', u'𐓭'), + (0x104C6, 'M', u'𐓮'), + (0x104C7, 'M', u'𐓯'), + (0x104C8, 'M', u'𐓰'), + (0x104C9, 'M', u'𐓱'), + (0x104CA, 'M', u'𐓲'), + (0x104CB, 'M', u'𐓳'), + (0x104CC, 'M', u'𐓴'), + (0x104CD, 'M', u'𐓵'), + (0x104CE, 'M', u'𐓶'), + (0x104CF, 'M', u'𐓷'), + (0x104D0, 'M', u'𐓸'), + (0x104D1, 'M', u'𐓹'), + (0x104D2, 'M', u'𐓺'), + (0x104D3, 'M', u'𐓻'), + (0x104D4, 'X'), + (0x104D8, 'V'), + (0x104FC, 'X'), + (0x10500, 'V'), + (0x10528, 'X'), + (0x10530, 'V'), + (0x10564, 'X'), + (0x1056F, 'V'), + (0x10570, 'X'), + (0x10600, 'V'), + (0x10737, 'X'), + (0x10740, 'V'), + (0x10756, 'X'), + (0x10760, 'V'), + (0x10768, 'X'), + (0x10800, 'V'), + (0x10806, 'X'), + (0x10808, 'V'), + (0x10809, 'X'), + (0x1080A, 'V'), + (0x10836, 'X'), + (0x10837, 'V'), + (0x10839, 'X'), + (0x1083C, 'V'), + (0x1083D, 'X'), + (0x1083F, 'V'), + (0x10856, 'X'), + (0x10857, 'V'), + (0x1089F, 'X'), + (0x108A7, 'V'), + (0x108B0, 'X'), + (0x108E0, 'V'), + (0x108F3, 'X'), + (0x108F4, 'V'), + (0x108F6, 'X'), + (0x108FB, 'V'), + (0x1091C, 'X'), + (0x1091F, 'V'), + (0x1093A, 'X'), + (0x1093F, 'V'), + (0x10940, 'X'), + (0x10980, 'V'), + (0x109B8, 'X'), + (0x109BC, 'V'), + (0x109D0, 'X'), + (0x109D2, 'V'), + (0x10A04, 'X'), + (0x10A05, 'V'), + (0x10A07, 'X'), + (0x10A0C, 'V'), + (0x10A14, 'X'), + (0x10A15, 'V'), + (0x10A18, 'X'), + (0x10A19, 'V'), + (0x10A36, 'X'), + (0x10A38, 'V'), + (0x10A3B, 'X'), + (0x10A3F, 'V'), + (0x10A49, 'X'), + (0x10A50, 'V'), + (0x10A59, 'X'), + (0x10A60, 'V'), + (0x10AA0, 'X'), + (0x10AC0, 'V'), + (0x10AE7, 'X'), + (0x10AEB, 'V'), + (0x10AF7, 'X'), + (0x10B00, 'V'), + (0x10B36, 'X'), + (0x10B39, 'V'), + (0x10B56, 'X'), + (0x10B58, 'V'), + (0x10B73, 'X'), + (0x10B78, 'V'), + (0x10B92, 'X'), + (0x10B99, 'V'), + (0x10B9D, 'X'), + (0x10BA9, 'V'), + (0x10BB0, 'X'), + ] + +def _seg_55(): + return [ + (0x10C00, 'V'), + (0x10C49, 'X'), + (0x10C80, 'M', u'𐳀'), + (0x10C81, 'M', u'𐳁'), + (0x10C82, 'M', u'𐳂'), + (0x10C83, 'M', u'𐳃'), + (0x10C84, 'M', u'𐳄'), + (0x10C85, 'M', u'𐳅'), + (0x10C86, 'M', u'𐳆'), + (0x10C87, 'M', u'𐳇'), + (0x10C88, 'M', u'𐳈'), + (0x10C89, 'M', u'𐳉'), + (0x10C8A, 'M', u'𐳊'), + (0x10C8B, 'M', u'𐳋'), + (0x10C8C, 'M', u'𐳌'), + (0x10C8D, 'M', u'𐳍'), + (0x10C8E, 'M', u'𐳎'), + (0x10C8F, 'M', u'𐳏'), + (0x10C90, 'M', u'𐳐'), + (0x10C91, 'M', u'𐳑'), + (0x10C92, 'M', u'𐳒'), + (0x10C93, 'M', u'𐳓'), + (0x10C94, 'M', u'𐳔'), + (0x10C95, 'M', u'𐳕'), + (0x10C96, 'M', u'𐳖'), + (0x10C97, 'M', u'𐳗'), + (0x10C98, 'M', u'𐳘'), + (0x10C99, 'M', u'𐳙'), + (0x10C9A, 'M', u'𐳚'), + (0x10C9B, 'M', u'𐳛'), + (0x10C9C, 'M', u'𐳜'), + (0x10C9D, 'M', u'𐳝'), + (0x10C9E, 'M', u'𐳞'), + (0x10C9F, 'M', u'𐳟'), + (0x10CA0, 'M', u'𐳠'), + (0x10CA1, 'M', u'𐳡'), + (0x10CA2, 'M', u'𐳢'), + (0x10CA3, 'M', u'𐳣'), + (0x10CA4, 'M', u'𐳤'), + (0x10CA5, 'M', u'𐳥'), + (0x10CA6, 'M', u'𐳦'), + (0x10CA7, 'M', u'𐳧'), + (0x10CA8, 'M', u'𐳨'), + (0x10CA9, 'M', u'𐳩'), + (0x10CAA, 'M', u'𐳪'), + (0x10CAB, 'M', u'𐳫'), + (0x10CAC, 'M', u'𐳬'), + (0x10CAD, 'M', u'𐳭'), + (0x10CAE, 'M', u'𐳮'), + (0x10CAF, 'M', u'𐳯'), + (0x10CB0, 'M', u'𐳰'), + (0x10CB1, 'M', u'𐳱'), + (0x10CB2, 'M', u'𐳲'), + (0x10CB3, 'X'), + (0x10CC0, 'V'), + (0x10CF3, 'X'), + (0x10CFA, 'V'), + (0x10D28, 'X'), + (0x10D30, 'V'), + (0x10D3A, 'X'), + (0x10E60, 'V'), + (0x10E7F, 'X'), + (0x10E80, 'V'), + (0x10EAA, 'X'), + (0x10EAB, 'V'), + (0x10EAE, 'X'), + (0x10EB0, 'V'), + (0x10EB2, 'X'), + (0x10F00, 'V'), + (0x10F28, 'X'), + (0x10F30, 'V'), + (0x10F5A, 'X'), + (0x10FB0, 'V'), + (0x10FCC, 'X'), + (0x10FE0, 'V'), + (0x10FF7, 'X'), + (0x11000, 'V'), + (0x1104E, 'X'), + (0x11052, 'V'), + (0x11070, 'X'), + (0x1107F, 'V'), + (0x110BD, 'X'), + (0x110BE, 'V'), + (0x110C2, 'X'), + (0x110D0, 'V'), + (0x110E9, 'X'), + (0x110F0, 'V'), + (0x110FA, 'X'), + (0x11100, 'V'), + (0x11135, 'X'), + (0x11136, 'V'), + (0x11148, 'X'), + (0x11150, 'V'), + (0x11177, 'X'), + (0x11180, 'V'), + (0x111E0, 'X'), + (0x111E1, 'V'), + (0x111F5, 'X'), + (0x11200, 'V'), + (0x11212, 'X'), + ] + +def _seg_56(): + return [ + (0x11213, 'V'), + (0x1123F, 'X'), + (0x11280, 'V'), + (0x11287, 'X'), + (0x11288, 'V'), + (0x11289, 'X'), + (0x1128A, 'V'), + (0x1128E, 'X'), + (0x1128F, 'V'), + (0x1129E, 'X'), + (0x1129F, 'V'), + (0x112AA, 'X'), + (0x112B0, 'V'), + (0x112EB, 'X'), + (0x112F0, 'V'), + (0x112FA, 'X'), + (0x11300, 'V'), + (0x11304, 'X'), + (0x11305, 'V'), + (0x1130D, 'X'), + (0x1130F, 'V'), + (0x11311, 'X'), + (0x11313, 'V'), + (0x11329, 'X'), + (0x1132A, 'V'), + (0x11331, 'X'), + (0x11332, 'V'), + (0x11334, 'X'), + (0x11335, 'V'), + (0x1133A, 'X'), + (0x1133B, 'V'), + (0x11345, 'X'), + (0x11347, 'V'), + (0x11349, 'X'), + (0x1134B, 'V'), + (0x1134E, 'X'), + (0x11350, 'V'), + (0x11351, 'X'), + (0x11357, 'V'), + (0x11358, 'X'), + (0x1135D, 'V'), + (0x11364, 'X'), + (0x11366, 'V'), + (0x1136D, 'X'), + (0x11370, 'V'), + (0x11375, 'X'), + (0x11400, 'V'), + (0x1145C, 'X'), + (0x1145D, 'V'), + (0x11462, 'X'), + (0x11480, 'V'), + (0x114C8, 'X'), + (0x114D0, 'V'), + (0x114DA, 'X'), + (0x11580, 'V'), + (0x115B6, 'X'), + (0x115B8, 'V'), + (0x115DE, 'X'), + (0x11600, 'V'), + (0x11645, 'X'), + (0x11650, 'V'), + (0x1165A, 'X'), + (0x11660, 'V'), + (0x1166D, 'X'), + (0x11680, 'V'), + (0x116B9, 'X'), + (0x116C0, 'V'), + (0x116CA, 'X'), + (0x11700, 'V'), + (0x1171B, 'X'), + (0x1171D, 'V'), + (0x1172C, 'X'), + (0x11730, 'V'), + (0x11740, 'X'), + (0x11800, 'V'), + (0x1183C, 'X'), + (0x118A0, 'M', u'𑣀'), + (0x118A1, 'M', u'𑣁'), + (0x118A2, 'M', u'𑣂'), + (0x118A3, 'M', u'𑣃'), + (0x118A4, 'M', u'𑣄'), + (0x118A5, 'M', u'𑣅'), + (0x118A6, 'M', u'𑣆'), + (0x118A7, 'M', u'𑣇'), + (0x118A8, 'M', u'𑣈'), + (0x118A9, 'M', u'𑣉'), + (0x118AA, 'M', u'𑣊'), + (0x118AB, 'M', u'𑣋'), + (0x118AC, 'M', u'𑣌'), + (0x118AD, 'M', u'𑣍'), + (0x118AE, 'M', u'𑣎'), + (0x118AF, 'M', u'𑣏'), + (0x118B0, 'M', u'𑣐'), + (0x118B1, 'M', u'𑣑'), + (0x118B2, 'M', u'𑣒'), + (0x118B3, 'M', u'𑣓'), + (0x118B4, 'M', u'𑣔'), + (0x118B5, 'M', u'𑣕'), + (0x118B6, 'M', u'𑣖'), + (0x118B7, 'M', u'𑣗'), + ] + +def _seg_57(): + return [ + (0x118B8, 'M', u'𑣘'), + (0x118B9, 'M', u'𑣙'), + (0x118BA, 'M', u'𑣚'), + (0x118BB, 'M', u'𑣛'), + (0x118BC, 'M', u'𑣜'), + (0x118BD, 'M', u'𑣝'), + (0x118BE, 'M', u'𑣞'), + (0x118BF, 'M', u'𑣟'), + (0x118C0, 'V'), + (0x118F3, 'X'), + (0x118FF, 'V'), + (0x11907, 'X'), + (0x11909, 'V'), + (0x1190A, 'X'), + (0x1190C, 'V'), + (0x11914, 'X'), + (0x11915, 'V'), + (0x11917, 'X'), + (0x11918, 'V'), + (0x11936, 'X'), + (0x11937, 'V'), + (0x11939, 'X'), + (0x1193B, 'V'), + (0x11947, 'X'), + (0x11950, 'V'), + (0x1195A, 'X'), + (0x119A0, 'V'), + (0x119A8, 'X'), + (0x119AA, 'V'), + (0x119D8, 'X'), + (0x119DA, 'V'), + (0x119E5, 'X'), + (0x11A00, 'V'), + (0x11A48, 'X'), + (0x11A50, 'V'), + (0x11AA3, 'X'), + (0x11AC0, 'V'), + (0x11AF9, 'X'), + (0x11C00, 'V'), + (0x11C09, 'X'), + (0x11C0A, 'V'), + (0x11C37, 'X'), + (0x11C38, 'V'), + (0x11C46, 'X'), + (0x11C50, 'V'), + (0x11C6D, 'X'), + (0x11C70, 'V'), + (0x11C90, 'X'), + (0x11C92, 'V'), + (0x11CA8, 'X'), + (0x11CA9, 'V'), + (0x11CB7, 'X'), + (0x11D00, 'V'), + (0x11D07, 'X'), + (0x11D08, 'V'), + (0x11D0A, 'X'), + (0x11D0B, 'V'), + (0x11D37, 'X'), + (0x11D3A, 'V'), + (0x11D3B, 'X'), + (0x11D3C, 'V'), + (0x11D3E, 'X'), + (0x11D3F, 'V'), + (0x11D48, 'X'), + (0x11D50, 'V'), + (0x11D5A, 'X'), + (0x11D60, 'V'), + (0x11D66, 'X'), + (0x11D67, 'V'), + (0x11D69, 'X'), + (0x11D6A, 'V'), + (0x11D8F, 'X'), + (0x11D90, 'V'), + (0x11D92, 'X'), + (0x11D93, 'V'), + (0x11D99, 'X'), + (0x11DA0, 'V'), + (0x11DAA, 'X'), + (0x11EE0, 'V'), + (0x11EF9, 'X'), + (0x11FB0, 'V'), + (0x11FB1, 'X'), + (0x11FC0, 'V'), + (0x11FF2, 'X'), + (0x11FFF, 'V'), + (0x1239A, 'X'), + (0x12400, 'V'), + (0x1246F, 'X'), + (0x12470, 'V'), + (0x12475, 'X'), + (0x12480, 'V'), + (0x12544, 'X'), + (0x13000, 'V'), + (0x1342F, 'X'), + (0x14400, 'V'), + (0x14647, 'X'), + (0x16800, 'V'), + (0x16A39, 'X'), + (0x16A40, 'V'), + (0x16A5F, 'X'), + ] + +def _seg_58(): + return [ + (0x16A60, 'V'), + (0x16A6A, 'X'), + (0x16A6E, 'V'), + (0x16A70, 'X'), + (0x16AD0, 'V'), + (0x16AEE, 'X'), + (0x16AF0, 'V'), + (0x16AF6, 'X'), + (0x16B00, 'V'), + (0x16B46, 'X'), + (0x16B50, 'V'), + (0x16B5A, 'X'), + (0x16B5B, 'V'), + (0x16B62, 'X'), + (0x16B63, 'V'), + (0x16B78, 'X'), + (0x16B7D, 'V'), + (0x16B90, 'X'), + (0x16E40, 'M', u'𖹠'), + (0x16E41, 'M', u'𖹡'), + (0x16E42, 'M', u'𖹢'), + (0x16E43, 'M', u'𖹣'), + (0x16E44, 'M', u'𖹤'), + (0x16E45, 'M', u'𖹥'), + (0x16E46, 'M', u'𖹦'), + (0x16E47, 'M', u'𖹧'), + (0x16E48, 'M', u'𖹨'), + (0x16E49, 'M', u'𖹩'), + (0x16E4A, 'M', u'𖹪'), + (0x16E4B, 'M', u'𖹫'), + (0x16E4C, 'M', u'𖹬'), + (0x16E4D, 'M', u'𖹭'), + (0x16E4E, 'M', u'𖹮'), + (0x16E4F, 'M', u'𖹯'), + (0x16E50, 'M', u'𖹰'), + (0x16E51, 'M', u'𖹱'), + (0x16E52, 'M', u'𖹲'), + (0x16E53, 'M', u'𖹳'), + (0x16E54, 'M', u'𖹴'), + (0x16E55, 'M', u'𖹵'), + (0x16E56, 'M', u'𖹶'), + (0x16E57, 'M', u'𖹷'), + (0x16E58, 'M', u'𖹸'), + (0x16E59, 'M', u'𖹹'), + (0x16E5A, 'M', u'𖹺'), + (0x16E5B, 'M', u'𖹻'), + (0x16E5C, 'M', u'𖹼'), + (0x16E5D, 'M', u'𖹽'), + (0x16E5E, 'M', u'𖹾'), + (0x16E5F, 'M', u'𖹿'), + (0x16E60, 'V'), + (0x16E9B, 'X'), + (0x16F00, 'V'), + (0x16F4B, 'X'), + (0x16F4F, 'V'), + (0x16F88, 'X'), + (0x16F8F, 'V'), + (0x16FA0, 'X'), + (0x16FE0, 'V'), + (0x16FE5, 'X'), + (0x16FF0, 'V'), + (0x16FF2, 'X'), + (0x17000, 'V'), + (0x187F8, 'X'), + (0x18800, 'V'), + (0x18CD6, 'X'), + (0x18D00, 'V'), + (0x18D09, 'X'), + (0x1B000, 'V'), + (0x1B11F, 'X'), + (0x1B150, 'V'), + (0x1B153, 'X'), + (0x1B164, 'V'), + (0x1B168, 'X'), + (0x1B170, 'V'), + (0x1B2FC, 'X'), + (0x1BC00, 'V'), + (0x1BC6B, 'X'), + (0x1BC70, 'V'), + (0x1BC7D, 'X'), + (0x1BC80, 'V'), + (0x1BC89, 'X'), + (0x1BC90, 'V'), + (0x1BC9A, 'X'), + (0x1BC9C, 'V'), + (0x1BCA0, 'I'), + (0x1BCA4, 'X'), + (0x1D000, 'V'), + (0x1D0F6, 'X'), + (0x1D100, 'V'), + (0x1D127, 'X'), + (0x1D129, 'V'), + (0x1D15E, 'M', u'𝅗𝅥'), + (0x1D15F, 'M', u'𝅘𝅥'), + (0x1D160, 'M', u'𝅘𝅥𝅮'), + (0x1D161, 'M', u'𝅘𝅥𝅯'), + (0x1D162, 'M', u'𝅘𝅥𝅰'), + (0x1D163, 'M', u'𝅘𝅥𝅱'), + (0x1D164, 'M', u'𝅘𝅥𝅲'), + (0x1D165, 'V'), + ] + +def _seg_59(): + return [ + (0x1D173, 'X'), + (0x1D17B, 'V'), + (0x1D1BB, 'M', u'𝆹𝅥'), + (0x1D1BC, 'M', u'𝆺𝅥'), + (0x1D1BD, 'M', u'𝆹𝅥𝅮'), + (0x1D1BE, 'M', u'𝆺𝅥𝅮'), + (0x1D1BF, 'M', u'𝆹𝅥𝅯'), + (0x1D1C0, 'M', u'𝆺𝅥𝅯'), + (0x1D1C1, 'V'), + (0x1D1E9, 'X'), + (0x1D200, 'V'), + (0x1D246, 'X'), + (0x1D2E0, 'V'), + (0x1D2F4, 'X'), + (0x1D300, 'V'), + (0x1D357, 'X'), + (0x1D360, 'V'), + (0x1D379, 'X'), + (0x1D400, 'M', u'a'), + (0x1D401, 'M', u'b'), + (0x1D402, 'M', u'c'), + (0x1D403, 'M', u'd'), + (0x1D404, 'M', u'e'), + (0x1D405, 'M', u'f'), + (0x1D406, 'M', u'g'), + (0x1D407, 'M', u'h'), + (0x1D408, 'M', u'i'), + (0x1D409, 'M', u'j'), + (0x1D40A, 'M', u'k'), + (0x1D40B, 'M', u'l'), + (0x1D40C, 'M', u'm'), + (0x1D40D, 'M', u'n'), + (0x1D40E, 'M', u'o'), + (0x1D40F, 'M', u'p'), + (0x1D410, 'M', u'q'), + (0x1D411, 'M', u'r'), + (0x1D412, 'M', u's'), + (0x1D413, 'M', u't'), + (0x1D414, 'M', u'u'), + (0x1D415, 'M', u'v'), + (0x1D416, 'M', u'w'), + (0x1D417, 'M', u'x'), + (0x1D418, 'M', u'y'), + (0x1D419, 'M', u'z'), + (0x1D41A, 'M', u'a'), + (0x1D41B, 'M', u'b'), + (0x1D41C, 'M', u'c'), + (0x1D41D, 'M', u'd'), + (0x1D41E, 'M', u'e'), + (0x1D41F, 'M', u'f'), + (0x1D420, 'M', u'g'), + (0x1D421, 'M', u'h'), + (0x1D422, 'M', u'i'), + (0x1D423, 'M', u'j'), + (0x1D424, 'M', u'k'), + (0x1D425, 'M', u'l'), + (0x1D426, 'M', u'm'), + (0x1D427, 'M', u'n'), + (0x1D428, 'M', u'o'), + (0x1D429, 'M', u'p'), + (0x1D42A, 'M', u'q'), + (0x1D42B, 'M', u'r'), + (0x1D42C, 'M', u's'), + (0x1D42D, 'M', u't'), + (0x1D42E, 'M', u'u'), + (0x1D42F, 'M', u'v'), + (0x1D430, 'M', u'w'), + (0x1D431, 'M', u'x'), + (0x1D432, 'M', u'y'), + (0x1D433, 'M', u'z'), + (0x1D434, 'M', u'a'), + (0x1D435, 'M', u'b'), + (0x1D436, 'M', u'c'), + (0x1D437, 'M', u'd'), + (0x1D438, 'M', u'e'), + (0x1D439, 'M', u'f'), + (0x1D43A, 'M', u'g'), + (0x1D43B, 'M', u'h'), + (0x1D43C, 'M', u'i'), + (0x1D43D, 'M', u'j'), + (0x1D43E, 'M', u'k'), + (0x1D43F, 'M', u'l'), + (0x1D440, 'M', u'm'), + (0x1D441, 'M', u'n'), + (0x1D442, 'M', u'o'), + (0x1D443, 'M', u'p'), + (0x1D444, 'M', u'q'), + (0x1D445, 'M', u'r'), + (0x1D446, 'M', u's'), + (0x1D447, 'M', u't'), + (0x1D448, 'M', u'u'), + (0x1D449, 'M', u'v'), + (0x1D44A, 'M', u'w'), + (0x1D44B, 'M', u'x'), + (0x1D44C, 'M', u'y'), + (0x1D44D, 'M', u'z'), + (0x1D44E, 'M', u'a'), + (0x1D44F, 'M', u'b'), + (0x1D450, 'M', u'c'), + (0x1D451, 'M', u'd'), + ] + +def _seg_60(): + return [ + (0x1D452, 'M', u'e'), + (0x1D453, 'M', u'f'), + (0x1D454, 'M', u'g'), + (0x1D455, 'X'), + (0x1D456, 'M', u'i'), + (0x1D457, 'M', u'j'), + (0x1D458, 'M', u'k'), + (0x1D459, 'M', u'l'), + (0x1D45A, 'M', u'm'), + (0x1D45B, 'M', u'n'), + (0x1D45C, 'M', u'o'), + (0x1D45D, 'M', u'p'), + (0x1D45E, 'M', u'q'), + (0x1D45F, 'M', u'r'), + (0x1D460, 'M', u's'), + (0x1D461, 'M', u't'), + (0x1D462, 'M', u'u'), + (0x1D463, 'M', u'v'), + (0x1D464, 'M', u'w'), + (0x1D465, 'M', u'x'), + (0x1D466, 'M', u'y'), + (0x1D467, 'M', u'z'), + (0x1D468, 'M', u'a'), + (0x1D469, 'M', u'b'), + (0x1D46A, 'M', u'c'), + (0x1D46B, 'M', u'd'), + (0x1D46C, 'M', u'e'), + (0x1D46D, 'M', u'f'), + (0x1D46E, 'M', u'g'), + (0x1D46F, 'M', u'h'), + (0x1D470, 'M', u'i'), + (0x1D471, 'M', u'j'), + (0x1D472, 'M', u'k'), + (0x1D473, 'M', u'l'), + (0x1D474, 'M', u'm'), + (0x1D475, 'M', u'n'), + (0x1D476, 'M', u'o'), + (0x1D477, 'M', u'p'), + (0x1D478, 'M', u'q'), + (0x1D479, 'M', u'r'), + (0x1D47A, 'M', u's'), + (0x1D47B, 'M', u't'), + (0x1D47C, 'M', u'u'), + (0x1D47D, 'M', u'v'), + (0x1D47E, 'M', u'w'), + (0x1D47F, 'M', u'x'), + (0x1D480, 'M', u'y'), + (0x1D481, 'M', u'z'), + (0x1D482, 'M', u'a'), + (0x1D483, 'M', u'b'), + (0x1D484, 'M', u'c'), + (0x1D485, 'M', u'd'), + (0x1D486, 'M', u'e'), + (0x1D487, 'M', u'f'), + (0x1D488, 'M', u'g'), + (0x1D489, 'M', u'h'), + (0x1D48A, 'M', u'i'), + (0x1D48B, 'M', u'j'), + (0x1D48C, 'M', u'k'), + (0x1D48D, 'M', u'l'), + (0x1D48E, 'M', u'm'), + (0x1D48F, 'M', u'n'), + (0x1D490, 'M', u'o'), + (0x1D491, 'M', u'p'), + (0x1D492, 'M', u'q'), + (0x1D493, 'M', u'r'), + (0x1D494, 'M', u's'), + (0x1D495, 'M', u't'), + (0x1D496, 'M', u'u'), + (0x1D497, 'M', u'v'), + (0x1D498, 'M', u'w'), + (0x1D499, 'M', u'x'), + (0x1D49A, 'M', u'y'), + (0x1D49B, 'M', u'z'), + (0x1D49C, 'M', u'a'), + (0x1D49D, 'X'), + (0x1D49E, 'M', u'c'), + (0x1D49F, 'M', u'd'), + (0x1D4A0, 'X'), + (0x1D4A2, 'M', u'g'), + (0x1D4A3, 'X'), + (0x1D4A5, 'M', u'j'), + (0x1D4A6, 'M', u'k'), + (0x1D4A7, 'X'), + (0x1D4A9, 'M', u'n'), + (0x1D4AA, 'M', u'o'), + (0x1D4AB, 'M', u'p'), + (0x1D4AC, 'M', u'q'), + (0x1D4AD, 'X'), + (0x1D4AE, 'M', u's'), + (0x1D4AF, 'M', u't'), + (0x1D4B0, 'M', u'u'), + (0x1D4B1, 'M', u'v'), + (0x1D4B2, 'M', u'w'), + (0x1D4B3, 'M', u'x'), + (0x1D4B4, 'M', u'y'), + (0x1D4B5, 'M', u'z'), + (0x1D4B6, 'M', u'a'), + (0x1D4B7, 'M', u'b'), + (0x1D4B8, 'M', u'c'), + ] + +def _seg_61(): + return [ + (0x1D4B9, 'M', u'd'), + (0x1D4BA, 'X'), + (0x1D4BB, 'M', u'f'), + (0x1D4BC, 'X'), + (0x1D4BD, 'M', u'h'), + (0x1D4BE, 'M', u'i'), + (0x1D4BF, 'M', u'j'), + (0x1D4C0, 'M', u'k'), + (0x1D4C1, 'M', u'l'), + (0x1D4C2, 'M', u'm'), + (0x1D4C3, 'M', u'n'), + (0x1D4C4, 'X'), + (0x1D4C5, 'M', u'p'), + (0x1D4C6, 'M', u'q'), + (0x1D4C7, 'M', u'r'), + (0x1D4C8, 'M', u's'), + (0x1D4C9, 'M', u't'), + (0x1D4CA, 'M', u'u'), + (0x1D4CB, 'M', u'v'), + (0x1D4CC, 'M', u'w'), + (0x1D4CD, 'M', u'x'), + (0x1D4CE, 'M', u'y'), + (0x1D4CF, 'M', u'z'), + (0x1D4D0, 'M', u'a'), + (0x1D4D1, 'M', u'b'), + (0x1D4D2, 'M', u'c'), + (0x1D4D3, 'M', u'd'), + (0x1D4D4, 'M', u'e'), + (0x1D4D5, 'M', u'f'), + (0x1D4D6, 'M', u'g'), + (0x1D4D7, 'M', u'h'), + (0x1D4D8, 'M', u'i'), + (0x1D4D9, 'M', u'j'), + (0x1D4DA, 'M', u'k'), + (0x1D4DB, 'M', u'l'), + (0x1D4DC, 'M', u'm'), + (0x1D4DD, 'M', u'n'), + (0x1D4DE, 'M', u'o'), + (0x1D4DF, 'M', u'p'), + (0x1D4E0, 'M', u'q'), + (0x1D4E1, 'M', u'r'), + (0x1D4E2, 'M', u's'), + (0x1D4E3, 'M', u't'), + (0x1D4E4, 'M', u'u'), + (0x1D4E5, 'M', u'v'), + (0x1D4E6, 'M', u'w'), + (0x1D4E7, 'M', u'x'), + (0x1D4E8, 'M', u'y'), + (0x1D4E9, 'M', u'z'), + (0x1D4EA, 'M', u'a'), + (0x1D4EB, 'M', u'b'), + (0x1D4EC, 'M', u'c'), + (0x1D4ED, 'M', u'd'), + (0x1D4EE, 'M', u'e'), + (0x1D4EF, 'M', u'f'), + (0x1D4F0, 'M', u'g'), + (0x1D4F1, 'M', u'h'), + (0x1D4F2, 'M', u'i'), + (0x1D4F3, 'M', u'j'), + (0x1D4F4, 'M', u'k'), + (0x1D4F5, 'M', u'l'), + (0x1D4F6, 'M', u'm'), + (0x1D4F7, 'M', u'n'), + (0x1D4F8, 'M', u'o'), + (0x1D4F9, 'M', u'p'), + (0x1D4FA, 'M', u'q'), + (0x1D4FB, 'M', u'r'), + (0x1D4FC, 'M', u's'), + (0x1D4FD, 'M', u't'), + (0x1D4FE, 'M', u'u'), + (0x1D4FF, 'M', u'v'), + (0x1D500, 'M', u'w'), + (0x1D501, 'M', u'x'), + (0x1D502, 'M', u'y'), + (0x1D503, 'M', u'z'), + (0x1D504, 'M', u'a'), + (0x1D505, 'M', u'b'), + (0x1D506, 'X'), + (0x1D507, 'M', u'd'), + (0x1D508, 'M', u'e'), + (0x1D509, 'M', u'f'), + (0x1D50A, 'M', u'g'), + (0x1D50B, 'X'), + (0x1D50D, 'M', u'j'), + (0x1D50E, 'M', u'k'), + (0x1D50F, 'M', u'l'), + (0x1D510, 'M', u'm'), + (0x1D511, 'M', u'n'), + (0x1D512, 'M', u'o'), + (0x1D513, 'M', u'p'), + (0x1D514, 'M', u'q'), + (0x1D515, 'X'), + (0x1D516, 'M', u's'), + (0x1D517, 'M', u't'), + (0x1D518, 'M', u'u'), + (0x1D519, 'M', u'v'), + (0x1D51A, 'M', u'w'), + (0x1D51B, 'M', u'x'), + (0x1D51C, 'M', u'y'), + (0x1D51D, 'X'), + ] + +def _seg_62(): + return [ + (0x1D51E, 'M', u'a'), + (0x1D51F, 'M', u'b'), + (0x1D520, 'M', u'c'), + (0x1D521, 'M', u'd'), + (0x1D522, 'M', u'e'), + (0x1D523, 'M', u'f'), + (0x1D524, 'M', u'g'), + (0x1D525, 'M', u'h'), + (0x1D526, 'M', u'i'), + (0x1D527, 'M', u'j'), + (0x1D528, 'M', u'k'), + (0x1D529, 'M', u'l'), + (0x1D52A, 'M', u'm'), + (0x1D52B, 'M', u'n'), + (0x1D52C, 'M', u'o'), + (0x1D52D, 'M', u'p'), + (0x1D52E, 'M', u'q'), + (0x1D52F, 'M', u'r'), + (0x1D530, 'M', u's'), + (0x1D531, 'M', u't'), + (0x1D532, 'M', u'u'), + (0x1D533, 'M', u'v'), + (0x1D534, 'M', u'w'), + (0x1D535, 'M', u'x'), + (0x1D536, 'M', u'y'), + (0x1D537, 'M', u'z'), + (0x1D538, 'M', u'a'), + (0x1D539, 'M', u'b'), + (0x1D53A, 'X'), + (0x1D53B, 'M', u'd'), + (0x1D53C, 'M', u'e'), + (0x1D53D, 'M', u'f'), + (0x1D53E, 'M', u'g'), + (0x1D53F, 'X'), + (0x1D540, 'M', u'i'), + (0x1D541, 'M', u'j'), + (0x1D542, 'M', u'k'), + (0x1D543, 'M', u'l'), + (0x1D544, 'M', u'm'), + (0x1D545, 'X'), + (0x1D546, 'M', u'o'), + (0x1D547, 'X'), + (0x1D54A, 'M', u's'), + (0x1D54B, 'M', u't'), + (0x1D54C, 'M', u'u'), + (0x1D54D, 'M', u'v'), + (0x1D54E, 'M', u'w'), + (0x1D54F, 'M', u'x'), + (0x1D550, 'M', u'y'), + (0x1D551, 'X'), + (0x1D552, 'M', u'a'), + (0x1D553, 'M', u'b'), + (0x1D554, 'M', u'c'), + (0x1D555, 'M', u'd'), + (0x1D556, 'M', u'e'), + (0x1D557, 'M', u'f'), + (0x1D558, 'M', u'g'), + (0x1D559, 'M', u'h'), + (0x1D55A, 'M', u'i'), + (0x1D55B, 'M', u'j'), + (0x1D55C, 'M', u'k'), + (0x1D55D, 'M', u'l'), + (0x1D55E, 'M', u'm'), + (0x1D55F, 'M', u'n'), + (0x1D560, 'M', u'o'), + (0x1D561, 'M', u'p'), + (0x1D562, 'M', u'q'), + (0x1D563, 'M', u'r'), + (0x1D564, 'M', u's'), + (0x1D565, 'M', u't'), + (0x1D566, 'M', u'u'), + (0x1D567, 'M', u'v'), + (0x1D568, 'M', u'w'), + (0x1D569, 'M', u'x'), + (0x1D56A, 'M', u'y'), + (0x1D56B, 'M', u'z'), + (0x1D56C, 'M', u'a'), + (0x1D56D, 'M', u'b'), + (0x1D56E, 'M', u'c'), + (0x1D56F, 'M', u'd'), + (0x1D570, 'M', u'e'), + (0x1D571, 'M', u'f'), + (0x1D572, 'M', u'g'), + (0x1D573, 'M', u'h'), + (0x1D574, 'M', u'i'), + (0x1D575, 'M', u'j'), + (0x1D576, 'M', u'k'), + (0x1D577, 'M', u'l'), + (0x1D578, 'M', u'm'), + (0x1D579, 'M', u'n'), + (0x1D57A, 'M', u'o'), + (0x1D57B, 'M', u'p'), + (0x1D57C, 'M', u'q'), + (0x1D57D, 'M', u'r'), + (0x1D57E, 'M', u's'), + (0x1D57F, 'M', u't'), + (0x1D580, 'M', u'u'), + (0x1D581, 'M', u'v'), + (0x1D582, 'M', u'w'), + (0x1D583, 'M', u'x'), + ] + +def _seg_63(): + return [ + (0x1D584, 'M', u'y'), + (0x1D585, 'M', u'z'), + (0x1D586, 'M', u'a'), + (0x1D587, 'M', u'b'), + (0x1D588, 'M', u'c'), + (0x1D589, 'M', u'd'), + (0x1D58A, 'M', u'e'), + (0x1D58B, 'M', u'f'), + (0x1D58C, 'M', u'g'), + (0x1D58D, 'M', u'h'), + (0x1D58E, 'M', u'i'), + (0x1D58F, 'M', u'j'), + (0x1D590, 'M', u'k'), + (0x1D591, 'M', u'l'), + (0x1D592, 'M', u'm'), + (0x1D593, 'M', u'n'), + (0x1D594, 'M', u'o'), + (0x1D595, 'M', u'p'), + (0x1D596, 'M', u'q'), + (0x1D597, 'M', u'r'), + (0x1D598, 'M', u's'), + (0x1D599, 'M', u't'), + (0x1D59A, 'M', u'u'), + (0x1D59B, 'M', u'v'), + (0x1D59C, 'M', u'w'), + (0x1D59D, 'M', u'x'), + (0x1D59E, 'M', u'y'), + (0x1D59F, 'M', u'z'), + (0x1D5A0, 'M', u'a'), + (0x1D5A1, 'M', u'b'), + (0x1D5A2, 'M', u'c'), + (0x1D5A3, 'M', u'd'), + (0x1D5A4, 'M', u'e'), + (0x1D5A5, 'M', u'f'), + (0x1D5A6, 'M', u'g'), + (0x1D5A7, 'M', u'h'), + (0x1D5A8, 'M', u'i'), + (0x1D5A9, 'M', u'j'), + (0x1D5AA, 'M', u'k'), + (0x1D5AB, 'M', u'l'), + (0x1D5AC, 'M', u'm'), + (0x1D5AD, 'M', u'n'), + (0x1D5AE, 'M', u'o'), + (0x1D5AF, 'M', u'p'), + (0x1D5B0, 'M', u'q'), + (0x1D5B1, 'M', u'r'), + (0x1D5B2, 'M', u's'), + (0x1D5B3, 'M', u't'), + (0x1D5B4, 'M', u'u'), + (0x1D5B5, 'M', u'v'), + (0x1D5B6, 'M', u'w'), + (0x1D5B7, 'M', u'x'), + (0x1D5B8, 'M', u'y'), + (0x1D5B9, 'M', u'z'), + (0x1D5BA, 'M', u'a'), + (0x1D5BB, 'M', u'b'), + (0x1D5BC, 'M', u'c'), + (0x1D5BD, 'M', u'd'), + (0x1D5BE, 'M', u'e'), + (0x1D5BF, 'M', u'f'), + (0x1D5C0, 'M', u'g'), + (0x1D5C1, 'M', u'h'), + (0x1D5C2, 'M', u'i'), + (0x1D5C3, 'M', u'j'), + (0x1D5C4, 'M', u'k'), + (0x1D5C5, 'M', u'l'), + (0x1D5C6, 'M', u'm'), + (0x1D5C7, 'M', u'n'), + (0x1D5C8, 'M', u'o'), + (0x1D5C9, 'M', u'p'), + (0x1D5CA, 'M', u'q'), + (0x1D5CB, 'M', u'r'), + (0x1D5CC, 'M', u's'), + (0x1D5CD, 'M', u't'), + (0x1D5CE, 'M', u'u'), + (0x1D5CF, 'M', u'v'), + (0x1D5D0, 'M', u'w'), + (0x1D5D1, 'M', u'x'), + (0x1D5D2, 'M', u'y'), + (0x1D5D3, 'M', u'z'), + (0x1D5D4, 'M', u'a'), + (0x1D5D5, 'M', u'b'), + (0x1D5D6, 'M', u'c'), + (0x1D5D7, 'M', u'd'), + (0x1D5D8, 'M', u'e'), + (0x1D5D9, 'M', u'f'), + (0x1D5DA, 'M', u'g'), + (0x1D5DB, 'M', u'h'), + (0x1D5DC, 'M', u'i'), + (0x1D5DD, 'M', u'j'), + (0x1D5DE, 'M', u'k'), + (0x1D5DF, 'M', u'l'), + (0x1D5E0, 'M', u'm'), + (0x1D5E1, 'M', u'n'), + (0x1D5E2, 'M', u'o'), + (0x1D5E3, 'M', u'p'), + (0x1D5E4, 'M', u'q'), + (0x1D5E5, 'M', u'r'), + (0x1D5E6, 'M', u's'), + (0x1D5E7, 'M', u't'), + ] + +def _seg_64(): + return [ + (0x1D5E8, 'M', u'u'), + (0x1D5E9, 'M', u'v'), + (0x1D5EA, 'M', u'w'), + (0x1D5EB, 'M', u'x'), + (0x1D5EC, 'M', u'y'), + (0x1D5ED, 'M', u'z'), + (0x1D5EE, 'M', u'a'), + (0x1D5EF, 'M', u'b'), + (0x1D5F0, 'M', u'c'), + (0x1D5F1, 'M', u'd'), + (0x1D5F2, 'M', u'e'), + (0x1D5F3, 'M', u'f'), + (0x1D5F4, 'M', u'g'), + (0x1D5F5, 'M', u'h'), + (0x1D5F6, 'M', u'i'), + (0x1D5F7, 'M', u'j'), + (0x1D5F8, 'M', u'k'), + (0x1D5F9, 'M', u'l'), + (0x1D5FA, 'M', u'm'), + (0x1D5FB, 'M', u'n'), + (0x1D5FC, 'M', u'o'), + (0x1D5FD, 'M', u'p'), + (0x1D5FE, 'M', u'q'), + (0x1D5FF, 'M', u'r'), + (0x1D600, 'M', u's'), + (0x1D601, 'M', u't'), + (0x1D602, 'M', u'u'), + (0x1D603, 'M', u'v'), + (0x1D604, 'M', u'w'), + (0x1D605, 'M', u'x'), + (0x1D606, 'M', u'y'), + (0x1D607, 'M', u'z'), + (0x1D608, 'M', u'a'), + (0x1D609, 'M', u'b'), + (0x1D60A, 'M', u'c'), + (0x1D60B, 'M', u'd'), + (0x1D60C, 'M', u'e'), + (0x1D60D, 'M', u'f'), + (0x1D60E, 'M', u'g'), + (0x1D60F, 'M', u'h'), + (0x1D610, 'M', u'i'), + (0x1D611, 'M', u'j'), + (0x1D612, 'M', u'k'), + (0x1D613, 'M', u'l'), + (0x1D614, 'M', u'm'), + (0x1D615, 'M', u'n'), + (0x1D616, 'M', u'o'), + (0x1D617, 'M', u'p'), + (0x1D618, 'M', u'q'), + (0x1D619, 'M', u'r'), + (0x1D61A, 'M', u's'), + (0x1D61B, 'M', u't'), + (0x1D61C, 'M', u'u'), + (0x1D61D, 'M', u'v'), + (0x1D61E, 'M', u'w'), + (0x1D61F, 'M', u'x'), + (0x1D620, 'M', u'y'), + (0x1D621, 'M', u'z'), + (0x1D622, 'M', u'a'), + (0x1D623, 'M', u'b'), + (0x1D624, 'M', u'c'), + (0x1D625, 'M', u'd'), + (0x1D626, 'M', u'e'), + (0x1D627, 'M', u'f'), + (0x1D628, 'M', u'g'), + (0x1D629, 'M', u'h'), + (0x1D62A, 'M', u'i'), + (0x1D62B, 'M', u'j'), + (0x1D62C, 'M', u'k'), + (0x1D62D, 'M', u'l'), + (0x1D62E, 'M', u'm'), + (0x1D62F, 'M', u'n'), + (0x1D630, 'M', u'o'), + (0x1D631, 'M', u'p'), + (0x1D632, 'M', u'q'), + (0x1D633, 'M', u'r'), + (0x1D634, 'M', u's'), + (0x1D635, 'M', u't'), + (0x1D636, 'M', u'u'), + (0x1D637, 'M', u'v'), + (0x1D638, 'M', u'w'), + (0x1D639, 'M', u'x'), + (0x1D63A, 'M', u'y'), + (0x1D63B, 'M', u'z'), + (0x1D63C, 'M', u'a'), + (0x1D63D, 'M', u'b'), + (0x1D63E, 'M', u'c'), + (0x1D63F, 'M', u'd'), + (0x1D640, 'M', u'e'), + (0x1D641, 'M', u'f'), + (0x1D642, 'M', u'g'), + (0x1D643, 'M', u'h'), + (0x1D644, 'M', u'i'), + (0x1D645, 'M', u'j'), + (0x1D646, 'M', u'k'), + (0x1D647, 'M', u'l'), + (0x1D648, 'M', u'm'), + (0x1D649, 'M', u'n'), + (0x1D64A, 'M', u'o'), + (0x1D64B, 'M', u'p'), + ] + +def _seg_65(): + return [ + (0x1D64C, 'M', u'q'), + (0x1D64D, 'M', u'r'), + (0x1D64E, 'M', u's'), + (0x1D64F, 'M', u't'), + (0x1D650, 'M', u'u'), + (0x1D651, 'M', u'v'), + (0x1D652, 'M', u'w'), + (0x1D653, 'M', u'x'), + (0x1D654, 'M', u'y'), + (0x1D655, 'M', u'z'), + (0x1D656, 'M', u'a'), + (0x1D657, 'M', u'b'), + (0x1D658, 'M', u'c'), + (0x1D659, 'M', u'd'), + (0x1D65A, 'M', u'e'), + (0x1D65B, 'M', u'f'), + (0x1D65C, 'M', u'g'), + (0x1D65D, 'M', u'h'), + (0x1D65E, 'M', u'i'), + (0x1D65F, 'M', u'j'), + (0x1D660, 'M', u'k'), + (0x1D661, 'M', u'l'), + (0x1D662, 'M', u'm'), + (0x1D663, 'M', u'n'), + (0x1D664, 'M', u'o'), + (0x1D665, 'M', u'p'), + (0x1D666, 'M', u'q'), + (0x1D667, 'M', u'r'), + (0x1D668, 'M', u's'), + (0x1D669, 'M', u't'), + (0x1D66A, 'M', u'u'), + (0x1D66B, 'M', u'v'), + (0x1D66C, 'M', u'w'), + (0x1D66D, 'M', u'x'), + (0x1D66E, 'M', u'y'), + (0x1D66F, 'M', u'z'), + (0x1D670, 'M', u'a'), + (0x1D671, 'M', u'b'), + (0x1D672, 'M', u'c'), + (0x1D673, 'M', u'd'), + (0x1D674, 'M', u'e'), + (0x1D675, 'M', u'f'), + (0x1D676, 'M', u'g'), + (0x1D677, 'M', u'h'), + (0x1D678, 'M', u'i'), + (0x1D679, 'M', u'j'), + (0x1D67A, 'M', u'k'), + (0x1D67B, 'M', u'l'), + (0x1D67C, 'M', u'm'), + (0x1D67D, 'M', u'n'), + (0x1D67E, 'M', u'o'), + (0x1D67F, 'M', u'p'), + (0x1D680, 'M', u'q'), + (0x1D681, 'M', u'r'), + (0x1D682, 'M', u's'), + (0x1D683, 'M', u't'), + (0x1D684, 'M', u'u'), + (0x1D685, 'M', u'v'), + (0x1D686, 'M', u'w'), + (0x1D687, 'M', u'x'), + (0x1D688, 'M', u'y'), + (0x1D689, 'M', u'z'), + (0x1D68A, 'M', u'a'), + (0x1D68B, 'M', u'b'), + (0x1D68C, 'M', u'c'), + (0x1D68D, 'M', u'd'), + (0x1D68E, 'M', u'e'), + (0x1D68F, 'M', u'f'), + (0x1D690, 'M', u'g'), + (0x1D691, 'M', u'h'), + (0x1D692, 'M', u'i'), + (0x1D693, 'M', u'j'), + (0x1D694, 'M', u'k'), + (0x1D695, 'M', u'l'), + (0x1D696, 'M', u'm'), + (0x1D697, 'M', u'n'), + (0x1D698, 'M', u'o'), + (0x1D699, 'M', u'p'), + (0x1D69A, 'M', u'q'), + (0x1D69B, 'M', u'r'), + (0x1D69C, 'M', u's'), + (0x1D69D, 'M', u't'), + (0x1D69E, 'M', u'u'), + (0x1D69F, 'M', u'v'), + (0x1D6A0, 'M', u'w'), + (0x1D6A1, 'M', u'x'), + (0x1D6A2, 'M', u'y'), + (0x1D6A3, 'M', u'z'), + (0x1D6A4, 'M', u'ı'), + (0x1D6A5, 'M', u'ȷ'), + (0x1D6A6, 'X'), + (0x1D6A8, 'M', u'α'), + (0x1D6A9, 'M', u'β'), + (0x1D6AA, 'M', u'γ'), + (0x1D6AB, 'M', u'δ'), + (0x1D6AC, 'M', u'ε'), + (0x1D6AD, 'M', u'ζ'), + (0x1D6AE, 'M', u'η'), + (0x1D6AF, 'M', u'θ'), + (0x1D6B0, 'M', u'ι'), + ] + +def _seg_66(): + return [ + (0x1D6B1, 'M', u'κ'), + (0x1D6B2, 'M', u'λ'), + (0x1D6B3, 'M', u'μ'), + (0x1D6B4, 'M', u'ν'), + (0x1D6B5, 'M', u'ξ'), + (0x1D6B6, 'M', u'ο'), + (0x1D6B7, 'M', u'π'), + (0x1D6B8, 'M', u'ρ'), + (0x1D6B9, 'M', u'θ'), + (0x1D6BA, 'M', u'σ'), + (0x1D6BB, 'M', u'τ'), + (0x1D6BC, 'M', u'υ'), + (0x1D6BD, 'M', u'φ'), + (0x1D6BE, 'M', u'χ'), + (0x1D6BF, 'M', u'ψ'), + (0x1D6C0, 'M', u'ω'), + (0x1D6C1, 'M', u'∇'), + (0x1D6C2, 'M', u'α'), + (0x1D6C3, 'M', u'β'), + (0x1D6C4, 'M', u'γ'), + (0x1D6C5, 'M', u'δ'), + (0x1D6C6, 'M', u'ε'), + (0x1D6C7, 'M', u'ζ'), + (0x1D6C8, 'M', u'η'), + (0x1D6C9, 'M', u'θ'), + (0x1D6CA, 'M', u'ι'), + (0x1D6CB, 'M', u'κ'), + (0x1D6CC, 'M', u'λ'), + (0x1D6CD, 'M', u'μ'), + (0x1D6CE, 'M', u'ν'), + (0x1D6CF, 'M', u'ξ'), + (0x1D6D0, 'M', u'ο'), + (0x1D6D1, 'M', u'π'), + (0x1D6D2, 'M', u'ρ'), + (0x1D6D3, 'M', u'σ'), + (0x1D6D5, 'M', u'τ'), + (0x1D6D6, 'M', u'υ'), + (0x1D6D7, 'M', u'φ'), + (0x1D6D8, 'M', u'χ'), + (0x1D6D9, 'M', u'ψ'), + (0x1D6DA, 'M', u'ω'), + (0x1D6DB, 'M', u'∂'), + (0x1D6DC, 'M', u'ε'), + (0x1D6DD, 'M', u'θ'), + (0x1D6DE, 'M', u'κ'), + (0x1D6DF, 'M', u'φ'), + (0x1D6E0, 'M', u'ρ'), + (0x1D6E1, 'M', u'π'), + (0x1D6E2, 'M', u'α'), + (0x1D6E3, 'M', u'β'), + (0x1D6E4, 'M', u'γ'), + (0x1D6E5, 'M', u'δ'), + (0x1D6E6, 'M', u'ε'), + (0x1D6E7, 'M', u'ζ'), + (0x1D6E8, 'M', u'η'), + (0x1D6E9, 'M', u'θ'), + (0x1D6EA, 'M', u'ι'), + (0x1D6EB, 'M', u'κ'), + (0x1D6EC, 'M', u'λ'), + (0x1D6ED, 'M', u'μ'), + (0x1D6EE, 'M', u'ν'), + (0x1D6EF, 'M', u'ξ'), + (0x1D6F0, 'M', u'ο'), + (0x1D6F1, 'M', u'π'), + (0x1D6F2, 'M', u'ρ'), + (0x1D6F3, 'M', u'θ'), + (0x1D6F4, 'M', u'σ'), + (0x1D6F5, 'M', u'τ'), + (0x1D6F6, 'M', u'υ'), + (0x1D6F7, 'M', u'φ'), + (0x1D6F8, 'M', u'χ'), + (0x1D6F9, 'M', u'ψ'), + (0x1D6FA, 'M', u'ω'), + (0x1D6FB, 'M', u'∇'), + (0x1D6FC, 'M', u'α'), + (0x1D6FD, 'M', u'β'), + (0x1D6FE, 'M', u'γ'), + (0x1D6FF, 'M', u'δ'), + (0x1D700, 'M', u'ε'), + (0x1D701, 'M', u'ζ'), + (0x1D702, 'M', u'η'), + (0x1D703, 'M', u'θ'), + (0x1D704, 'M', u'ι'), + (0x1D705, 'M', u'κ'), + (0x1D706, 'M', u'λ'), + (0x1D707, 'M', u'μ'), + (0x1D708, 'M', u'ν'), + (0x1D709, 'M', u'ξ'), + (0x1D70A, 'M', u'ο'), + (0x1D70B, 'M', u'π'), + (0x1D70C, 'M', u'ρ'), + (0x1D70D, 'M', u'σ'), + (0x1D70F, 'M', u'τ'), + (0x1D710, 'M', u'υ'), + (0x1D711, 'M', u'φ'), + (0x1D712, 'M', u'χ'), + (0x1D713, 'M', u'ψ'), + (0x1D714, 'M', u'ω'), + (0x1D715, 'M', u'∂'), + (0x1D716, 'M', u'ε'), + ] + +def _seg_67(): + return [ + (0x1D717, 'M', u'θ'), + (0x1D718, 'M', u'κ'), + (0x1D719, 'M', u'φ'), + (0x1D71A, 'M', u'ρ'), + (0x1D71B, 'M', u'π'), + (0x1D71C, 'M', u'α'), + (0x1D71D, 'M', u'β'), + (0x1D71E, 'M', u'γ'), + (0x1D71F, 'M', u'δ'), + (0x1D720, 'M', u'ε'), + (0x1D721, 'M', u'ζ'), + (0x1D722, 'M', u'η'), + (0x1D723, 'M', u'θ'), + (0x1D724, 'M', u'ι'), + (0x1D725, 'M', u'κ'), + (0x1D726, 'M', u'λ'), + (0x1D727, 'M', u'μ'), + (0x1D728, 'M', u'ν'), + (0x1D729, 'M', u'ξ'), + (0x1D72A, 'M', u'ο'), + (0x1D72B, 'M', u'π'), + (0x1D72C, 'M', u'ρ'), + (0x1D72D, 'M', u'θ'), + (0x1D72E, 'M', u'σ'), + (0x1D72F, 'M', u'τ'), + (0x1D730, 'M', u'υ'), + (0x1D731, 'M', u'φ'), + (0x1D732, 'M', u'χ'), + (0x1D733, 'M', u'ψ'), + (0x1D734, 'M', u'ω'), + (0x1D735, 'M', u'∇'), + (0x1D736, 'M', u'α'), + (0x1D737, 'M', u'β'), + (0x1D738, 'M', u'γ'), + (0x1D739, 'M', u'δ'), + (0x1D73A, 'M', u'ε'), + (0x1D73B, 'M', u'ζ'), + (0x1D73C, 'M', u'η'), + (0x1D73D, 'M', u'θ'), + (0x1D73E, 'M', u'ι'), + (0x1D73F, 'M', u'κ'), + (0x1D740, 'M', u'λ'), + (0x1D741, 'M', u'μ'), + (0x1D742, 'M', u'ν'), + (0x1D743, 'M', u'ξ'), + (0x1D744, 'M', u'ο'), + (0x1D745, 'M', u'π'), + (0x1D746, 'M', u'ρ'), + (0x1D747, 'M', u'σ'), + (0x1D749, 'M', u'τ'), + (0x1D74A, 'M', u'υ'), + (0x1D74B, 'M', u'φ'), + (0x1D74C, 'M', u'χ'), + (0x1D74D, 'M', u'ψ'), + (0x1D74E, 'M', u'ω'), + (0x1D74F, 'M', u'∂'), + (0x1D750, 'M', u'ε'), + (0x1D751, 'M', u'θ'), + (0x1D752, 'M', u'κ'), + (0x1D753, 'M', u'φ'), + (0x1D754, 'M', u'ρ'), + (0x1D755, 'M', u'π'), + (0x1D756, 'M', u'α'), + (0x1D757, 'M', u'β'), + (0x1D758, 'M', u'γ'), + (0x1D759, 'M', u'δ'), + (0x1D75A, 'M', u'ε'), + (0x1D75B, 'M', u'ζ'), + (0x1D75C, 'M', u'η'), + (0x1D75D, 'M', u'θ'), + (0x1D75E, 'M', u'ι'), + (0x1D75F, 'M', u'κ'), + (0x1D760, 'M', u'λ'), + (0x1D761, 'M', u'μ'), + (0x1D762, 'M', u'ν'), + (0x1D763, 'M', u'ξ'), + (0x1D764, 'M', u'ο'), + (0x1D765, 'M', u'π'), + (0x1D766, 'M', u'ρ'), + (0x1D767, 'M', u'θ'), + (0x1D768, 'M', u'σ'), + (0x1D769, 'M', u'τ'), + (0x1D76A, 'M', u'υ'), + (0x1D76B, 'M', u'φ'), + (0x1D76C, 'M', u'χ'), + (0x1D76D, 'M', u'ψ'), + (0x1D76E, 'M', u'ω'), + (0x1D76F, 'M', u'∇'), + (0x1D770, 'M', u'α'), + (0x1D771, 'M', u'β'), + (0x1D772, 'M', u'γ'), + (0x1D773, 'M', u'δ'), + (0x1D774, 'M', u'ε'), + (0x1D775, 'M', u'ζ'), + (0x1D776, 'M', u'η'), + (0x1D777, 'M', u'θ'), + (0x1D778, 'M', u'ι'), + (0x1D779, 'M', u'κ'), + (0x1D77A, 'M', u'λ'), + (0x1D77B, 'M', u'μ'), + ] + +def _seg_68(): + return [ + (0x1D77C, 'M', u'ν'), + (0x1D77D, 'M', u'ξ'), + (0x1D77E, 'M', u'ο'), + (0x1D77F, 'M', u'π'), + (0x1D780, 'M', u'ρ'), + (0x1D781, 'M', u'σ'), + (0x1D783, 'M', u'τ'), + (0x1D784, 'M', u'υ'), + (0x1D785, 'M', u'φ'), + (0x1D786, 'M', u'χ'), + (0x1D787, 'M', u'ψ'), + (0x1D788, 'M', u'ω'), + (0x1D789, 'M', u'∂'), + (0x1D78A, 'M', u'ε'), + (0x1D78B, 'M', u'θ'), + (0x1D78C, 'M', u'κ'), + (0x1D78D, 'M', u'φ'), + (0x1D78E, 'M', u'ρ'), + (0x1D78F, 'M', u'π'), + (0x1D790, 'M', u'α'), + (0x1D791, 'M', u'β'), + (0x1D792, 'M', u'γ'), + (0x1D793, 'M', u'δ'), + (0x1D794, 'M', u'ε'), + (0x1D795, 'M', u'ζ'), + (0x1D796, 'M', u'η'), + (0x1D797, 'M', u'θ'), + (0x1D798, 'M', u'ι'), + (0x1D799, 'M', u'κ'), + (0x1D79A, 'M', u'λ'), + (0x1D79B, 'M', u'μ'), + (0x1D79C, 'M', u'ν'), + (0x1D79D, 'M', u'ξ'), + (0x1D79E, 'M', u'ο'), + (0x1D79F, 'M', u'π'), + (0x1D7A0, 'M', u'ρ'), + (0x1D7A1, 'M', u'θ'), + (0x1D7A2, 'M', u'σ'), + (0x1D7A3, 'M', u'τ'), + (0x1D7A4, 'M', u'υ'), + (0x1D7A5, 'M', u'φ'), + (0x1D7A6, 'M', u'χ'), + (0x1D7A7, 'M', u'ψ'), + (0x1D7A8, 'M', u'ω'), + (0x1D7A9, 'M', u'∇'), + (0x1D7AA, 'M', u'α'), + (0x1D7AB, 'M', u'β'), + (0x1D7AC, 'M', u'γ'), + (0x1D7AD, 'M', u'δ'), + (0x1D7AE, 'M', u'ε'), + (0x1D7AF, 'M', u'ζ'), + (0x1D7B0, 'M', u'η'), + (0x1D7B1, 'M', u'θ'), + (0x1D7B2, 'M', u'ι'), + (0x1D7B3, 'M', u'κ'), + (0x1D7B4, 'M', u'λ'), + (0x1D7B5, 'M', u'μ'), + (0x1D7B6, 'M', u'ν'), + (0x1D7B7, 'M', u'ξ'), + (0x1D7B8, 'M', u'ο'), + (0x1D7B9, 'M', u'π'), + (0x1D7BA, 'M', u'ρ'), + (0x1D7BB, 'M', u'σ'), + (0x1D7BD, 'M', u'τ'), + (0x1D7BE, 'M', u'υ'), + (0x1D7BF, 'M', u'φ'), + (0x1D7C0, 'M', u'χ'), + (0x1D7C1, 'M', u'ψ'), + (0x1D7C2, 'M', u'ω'), + (0x1D7C3, 'M', u'∂'), + (0x1D7C4, 'M', u'ε'), + (0x1D7C5, 'M', u'θ'), + (0x1D7C6, 'M', u'κ'), + (0x1D7C7, 'M', u'φ'), + (0x1D7C8, 'M', u'ρ'), + (0x1D7C9, 'M', u'π'), + (0x1D7CA, 'M', u'ϝ'), + (0x1D7CC, 'X'), + (0x1D7CE, 'M', u'0'), + (0x1D7CF, 'M', u'1'), + (0x1D7D0, 'M', u'2'), + (0x1D7D1, 'M', u'3'), + (0x1D7D2, 'M', u'4'), + (0x1D7D3, 'M', u'5'), + (0x1D7D4, 'M', u'6'), + (0x1D7D5, 'M', u'7'), + (0x1D7D6, 'M', u'8'), + (0x1D7D7, 'M', u'9'), + (0x1D7D8, 'M', u'0'), + (0x1D7D9, 'M', u'1'), + (0x1D7DA, 'M', u'2'), + (0x1D7DB, 'M', u'3'), + (0x1D7DC, 'M', u'4'), + (0x1D7DD, 'M', u'5'), + (0x1D7DE, 'M', u'6'), + (0x1D7DF, 'M', u'7'), + (0x1D7E0, 'M', u'8'), + (0x1D7E1, 'M', u'9'), + (0x1D7E2, 'M', u'0'), + (0x1D7E3, 'M', u'1'), + ] + +def _seg_69(): + return [ + (0x1D7E4, 'M', u'2'), + (0x1D7E5, 'M', u'3'), + (0x1D7E6, 'M', u'4'), + (0x1D7E7, 'M', u'5'), + (0x1D7E8, 'M', u'6'), + (0x1D7E9, 'M', u'7'), + (0x1D7EA, 'M', u'8'), + (0x1D7EB, 'M', u'9'), + (0x1D7EC, 'M', u'0'), + (0x1D7ED, 'M', u'1'), + (0x1D7EE, 'M', u'2'), + (0x1D7EF, 'M', u'3'), + (0x1D7F0, 'M', u'4'), + (0x1D7F1, 'M', u'5'), + (0x1D7F2, 'M', u'6'), + (0x1D7F3, 'M', u'7'), + (0x1D7F4, 'M', u'8'), + (0x1D7F5, 'M', u'9'), + (0x1D7F6, 'M', u'0'), + (0x1D7F7, 'M', u'1'), + (0x1D7F8, 'M', u'2'), + (0x1D7F9, 'M', u'3'), + (0x1D7FA, 'M', u'4'), + (0x1D7FB, 'M', u'5'), + (0x1D7FC, 'M', u'6'), + (0x1D7FD, 'M', u'7'), + (0x1D7FE, 'M', u'8'), + (0x1D7FF, 'M', u'9'), + (0x1D800, 'V'), + (0x1DA8C, 'X'), + (0x1DA9B, 'V'), + (0x1DAA0, 'X'), + (0x1DAA1, 'V'), + (0x1DAB0, 'X'), + (0x1E000, 'V'), + (0x1E007, 'X'), + (0x1E008, 'V'), + (0x1E019, 'X'), + (0x1E01B, 'V'), + (0x1E022, 'X'), + (0x1E023, 'V'), + (0x1E025, 'X'), + (0x1E026, 'V'), + (0x1E02B, 'X'), + (0x1E100, 'V'), + (0x1E12D, 'X'), + (0x1E130, 'V'), + (0x1E13E, 'X'), + (0x1E140, 'V'), + (0x1E14A, 'X'), + (0x1E14E, 'V'), + (0x1E150, 'X'), + (0x1E2C0, 'V'), + (0x1E2FA, 'X'), + (0x1E2FF, 'V'), + (0x1E300, 'X'), + (0x1E800, 'V'), + (0x1E8C5, 'X'), + (0x1E8C7, 'V'), + (0x1E8D7, 'X'), + (0x1E900, 'M', u'𞤢'), + (0x1E901, 'M', u'𞤣'), + (0x1E902, 'M', u'𞤤'), + (0x1E903, 'M', u'𞤥'), + (0x1E904, 'M', u'𞤦'), + (0x1E905, 'M', u'𞤧'), + (0x1E906, 'M', u'𞤨'), + (0x1E907, 'M', u'𞤩'), + (0x1E908, 'M', u'𞤪'), + (0x1E909, 'M', u'𞤫'), + (0x1E90A, 'M', u'𞤬'), + (0x1E90B, 'M', u'𞤭'), + (0x1E90C, 'M', u'𞤮'), + (0x1E90D, 'M', u'𞤯'), + (0x1E90E, 'M', u'𞤰'), + (0x1E90F, 'M', u'𞤱'), + (0x1E910, 'M', u'𞤲'), + (0x1E911, 'M', u'𞤳'), + (0x1E912, 'M', u'𞤴'), + (0x1E913, 'M', u'𞤵'), + (0x1E914, 'M', u'𞤶'), + (0x1E915, 'M', u'𞤷'), + (0x1E916, 'M', u'𞤸'), + (0x1E917, 'M', u'𞤹'), + (0x1E918, 'M', u'𞤺'), + (0x1E919, 'M', u'𞤻'), + (0x1E91A, 'M', u'𞤼'), + (0x1E91B, 'M', u'𞤽'), + (0x1E91C, 'M', u'𞤾'), + (0x1E91D, 'M', u'𞤿'), + (0x1E91E, 'M', u'𞥀'), + (0x1E91F, 'M', u'𞥁'), + (0x1E920, 'M', u'𞥂'), + (0x1E921, 'M', u'𞥃'), + (0x1E922, 'V'), + (0x1E94C, 'X'), + (0x1E950, 'V'), + (0x1E95A, 'X'), + (0x1E95E, 'V'), + (0x1E960, 'X'), + ] + +def _seg_70(): + return [ + (0x1EC71, 'V'), + (0x1ECB5, 'X'), + (0x1ED01, 'V'), + (0x1ED3E, 'X'), + (0x1EE00, 'M', u'ا'), + (0x1EE01, 'M', u'ب'), + (0x1EE02, 'M', u'ج'), + (0x1EE03, 'M', u'د'), + (0x1EE04, 'X'), + (0x1EE05, 'M', u'و'), + (0x1EE06, 'M', u'ز'), + (0x1EE07, 'M', u'ح'), + (0x1EE08, 'M', u'ط'), + (0x1EE09, 'M', u'ي'), + (0x1EE0A, 'M', u'ك'), + (0x1EE0B, 'M', u'ل'), + (0x1EE0C, 'M', u'م'), + (0x1EE0D, 'M', u'ن'), + (0x1EE0E, 'M', u'س'), + (0x1EE0F, 'M', u'ع'), + (0x1EE10, 'M', u'ف'), + (0x1EE11, 'M', u'ص'), + (0x1EE12, 'M', u'ق'), + (0x1EE13, 'M', u'ر'), + (0x1EE14, 'M', u'ش'), + (0x1EE15, 'M', u'ت'), + (0x1EE16, 'M', u'ث'), + (0x1EE17, 'M', u'خ'), + (0x1EE18, 'M', u'ذ'), + (0x1EE19, 'M', u'ض'), + (0x1EE1A, 'M', u'ظ'), + (0x1EE1B, 'M', u'غ'), + (0x1EE1C, 'M', u'ٮ'), + (0x1EE1D, 'M', u'ں'), + (0x1EE1E, 'M', u'ڡ'), + (0x1EE1F, 'M', u'ٯ'), + (0x1EE20, 'X'), + (0x1EE21, 'M', u'ب'), + (0x1EE22, 'M', u'ج'), + (0x1EE23, 'X'), + (0x1EE24, 'M', u'ه'), + (0x1EE25, 'X'), + (0x1EE27, 'M', u'ح'), + (0x1EE28, 'X'), + (0x1EE29, 'M', u'ي'), + (0x1EE2A, 'M', u'ك'), + (0x1EE2B, 'M', u'ل'), + (0x1EE2C, 'M', u'م'), + (0x1EE2D, 'M', u'ن'), + (0x1EE2E, 'M', u'س'), + (0x1EE2F, 'M', u'ع'), + (0x1EE30, 'M', u'ف'), + (0x1EE31, 'M', u'ص'), + (0x1EE32, 'M', u'ق'), + (0x1EE33, 'X'), + (0x1EE34, 'M', u'ش'), + (0x1EE35, 'M', u'ت'), + (0x1EE36, 'M', u'ث'), + (0x1EE37, 'M', u'خ'), + (0x1EE38, 'X'), + (0x1EE39, 'M', u'ض'), + (0x1EE3A, 'X'), + (0x1EE3B, 'M', u'غ'), + (0x1EE3C, 'X'), + (0x1EE42, 'M', u'ج'), + (0x1EE43, 'X'), + (0x1EE47, 'M', u'ح'), + (0x1EE48, 'X'), + (0x1EE49, 'M', u'ي'), + (0x1EE4A, 'X'), + (0x1EE4B, 'M', u'ل'), + (0x1EE4C, 'X'), + (0x1EE4D, 'M', u'ن'), + (0x1EE4E, 'M', u'س'), + (0x1EE4F, 'M', u'ع'), + (0x1EE50, 'X'), + (0x1EE51, 'M', u'ص'), + (0x1EE52, 'M', u'ق'), + (0x1EE53, 'X'), + (0x1EE54, 'M', u'ش'), + (0x1EE55, 'X'), + (0x1EE57, 'M', u'خ'), + (0x1EE58, 'X'), + (0x1EE59, 'M', u'ض'), + (0x1EE5A, 'X'), + (0x1EE5B, 'M', u'غ'), + (0x1EE5C, 'X'), + (0x1EE5D, 'M', u'ں'), + (0x1EE5E, 'X'), + (0x1EE5F, 'M', u'ٯ'), + (0x1EE60, 'X'), + (0x1EE61, 'M', u'ب'), + (0x1EE62, 'M', u'ج'), + (0x1EE63, 'X'), + (0x1EE64, 'M', u'ه'), + (0x1EE65, 'X'), + (0x1EE67, 'M', u'ح'), + (0x1EE68, 'M', u'ط'), + (0x1EE69, 'M', u'ي'), + (0x1EE6A, 'M', u'ك'), + ] + +def _seg_71(): + return [ + (0x1EE6B, 'X'), + (0x1EE6C, 'M', u'م'), + (0x1EE6D, 'M', u'ن'), + (0x1EE6E, 'M', u'س'), + (0x1EE6F, 'M', u'ع'), + (0x1EE70, 'M', u'ف'), + (0x1EE71, 'M', u'ص'), + (0x1EE72, 'M', u'ق'), + (0x1EE73, 'X'), + (0x1EE74, 'M', u'ش'), + (0x1EE75, 'M', u'ت'), + (0x1EE76, 'M', u'ث'), + (0x1EE77, 'M', u'خ'), + (0x1EE78, 'X'), + (0x1EE79, 'M', u'ض'), + (0x1EE7A, 'M', u'ظ'), + (0x1EE7B, 'M', u'غ'), + (0x1EE7C, 'M', u'ٮ'), + (0x1EE7D, 'X'), + (0x1EE7E, 'M', u'ڡ'), + (0x1EE7F, 'X'), + (0x1EE80, 'M', u'ا'), + (0x1EE81, 'M', u'ب'), + (0x1EE82, 'M', u'ج'), + (0x1EE83, 'M', u'د'), + (0x1EE84, 'M', u'ه'), + (0x1EE85, 'M', u'و'), + (0x1EE86, 'M', u'ز'), + (0x1EE87, 'M', u'ح'), + (0x1EE88, 'M', u'ط'), + (0x1EE89, 'M', u'ي'), + (0x1EE8A, 'X'), + (0x1EE8B, 'M', u'ل'), + (0x1EE8C, 'M', u'م'), + (0x1EE8D, 'M', u'ن'), + (0x1EE8E, 'M', u'س'), + (0x1EE8F, 'M', u'ع'), + (0x1EE90, 'M', u'ف'), + (0x1EE91, 'M', u'ص'), + (0x1EE92, 'M', u'ق'), + (0x1EE93, 'M', u'ر'), + (0x1EE94, 'M', u'ش'), + (0x1EE95, 'M', u'ت'), + (0x1EE96, 'M', u'ث'), + (0x1EE97, 'M', u'خ'), + (0x1EE98, 'M', u'ذ'), + (0x1EE99, 'M', u'ض'), + (0x1EE9A, 'M', u'ظ'), + (0x1EE9B, 'M', u'غ'), + (0x1EE9C, 'X'), + (0x1EEA1, 'M', u'ب'), + (0x1EEA2, 'M', u'ج'), + (0x1EEA3, 'M', u'د'), + (0x1EEA4, 'X'), + (0x1EEA5, 'M', u'و'), + (0x1EEA6, 'M', u'ز'), + (0x1EEA7, 'M', u'ح'), + (0x1EEA8, 'M', u'ط'), + (0x1EEA9, 'M', u'ي'), + (0x1EEAA, 'X'), + (0x1EEAB, 'M', u'ل'), + (0x1EEAC, 'M', u'م'), + (0x1EEAD, 'M', u'ن'), + (0x1EEAE, 'M', u'س'), + (0x1EEAF, 'M', u'ع'), + (0x1EEB0, 'M', u'ف'), + (0x1EEB1, 'M', u'ص'), + (0x1EEB2, 'M', u'ق'), + (0x1EEB3, 'M', u'ر'), + (0x1EEB4, 'M', u'ش'), + (0x1EEB5, 'M', u'ت'), + (0x1EEB6, 'M', u'ث'), + (0x1EEB7, 'M', u'خ'), + (0x1EEB8, 'M', u'ذ'), + (0x1EEB9, 'M', u'ض'), + (0x1EEBA, 'M', u'ظ'), + (0x1EEBB, 'M', u'غ'), + (0x1EEBC, 'X'), + (0x1EEF0, 'V'), + (0x1EEF2, 'X'), + (0x1F000, 'V'), + (0x1F02C, 'X'), + (0x1F030, 'V'), + (0x1F094, 'X'), + (0x1F0A0, 'V'), + (0x1F0AF, 'X'), + (0x1F0B1, 'V'), + (0x1F0C0, 'X'), + (0x1F0C1, 'V'), + (0x1F0D0, 'X'), + (0x1F0D1, 'V'), + (0x1F0F6, 'X'), + (0x1F101, '3', u'0,'), + (0x1F102, '3', u'1,'), + (0x1F103, '3', u'2,'), + (0x1F104, '3', u'3,'), + (0x1F105, '3', u'4,'), + (0x1F106, '3', u'5,'), + (0x1F107, '3', u'6,'), + (0x1F108, '3', u'7,'), + ] + +def _seg_72(): + return [ + (0x1F109, '3', u'8,'), + (0x1F10A, '3', u'9,'), + (0x1F10B, 'V'), + (0x1F110, '3', u'(a)'), + (0x1F111, '3', u'(b)'), + (0x1F112, '3', u'(c)'), + (0x1F113, '3', u'(d)'), + (0x1F114, '3', u'(e)'), + (0x1F115, '3', u'(f)'), + (0x1F116, '3', u'(g)'), + (0x1F117, '3', u'(h)'), + (0x1F118, '3', u'(i)'), + (0x1F119, '3', u'(j)'), + (0x1F11A, '3', u'(k)'), + (0x1F11B, '3', u'(l)'), + (0x1F11C, '3', u'(m)'), + (0x1F11D, '3', u'(n)'), + (0x1F11E, '3', u'(o)'), + (0x1F11F, '3', u'(p)'), + (0x1F120, '3', u'(q)'), + (0x1F121, '3', u'(r)'), + (0x1F122, '3', u'(s)'), + (0x1F123, '3', u'(t)'), + (0x1F124, '3', u'(u)'), + (0x1F125, '3', u'(v)'), + (0x1F126, '3', u'(w)'), + (0x1F127, '3', u'(x)'), + (0x1F128, '3', u'(y)'), + (0x1F129, '3', u'(z)'), + (0x1F12A, 'M', u'〔s〕'), + (0x1F12B, 'M', u'c'), + (0x1F12C, 'M', u'r'), + (0x1F12D, 'M', u'cd'), + (0x1F12E, 'M', u'wz'), + (0x1F12F, 'V'), + (0x1F130, 'M', u'a'), + (0x1F131, 'M', u'b'), + (0x1F132, 'M', u'c'), + (0x1F133, 'M', u'd'), + (0x1F134, 'M', u'e'), + (0x1F135, 'M', u'f'), + (0x1F136, 'M', u'g'), + (0x1F137, 'M', u'h'), + (0x1F138, 'M', u'i'), + (0x1F139, 'M', u'j'), + (0x1F13A, 'M', u'k'), + (0x1F13B, 'M', u'l'), + (0x1F13C, 'M', u'm'), + (0x1F13D, 'M', u'n'), + (0x1F13E, 'M', u'o'), + (0x1F13F, 'M', u'p'), + (0x1F140, 'M', u'q'), + (0x1F141, 'M', u'r'), + (0x1F142, 'M', u's'), + (0x1F143, 'M', u't'), + (0x1F144, 'M', u'u'), + (0x1F145, 'M', u'v'), + (0x1F146, 'M', u'w'), + (0x1F147, 'M', u'x'), + (0x1F148, 'M', u'y'), + (0x1F149, 'M', u'z'), + (0x1F14A, 'M', u'hv'), + (0x1F14B, 'M', u'mv'), + (0x1F14C, 'M', u'sd'), + (0x1F14D, 'M', u'ss'), + (0x1F14E, 'M', u'ppv'), + (0x1F14F, 'M', u'wc'), + (0x1F150, 'V'), + (0x1F16A, 'M', u'mc'), + (0x1F16B, 'M', u'md'), + (0x1F16C, 'M', u'mr'), + (0x1F16D, 'V'), + (0x1F190, 'M', u'dj'), + (0x1F191, 'V'), + (0x1F1AE, 'X'), + (0x1F1E6, 'V'), + (0x1F200, 'M', u'ほか'), + (0x1F201, 'M', u'ココ'), + (0x1F202, 'M', u'サ'), + (0x1F203, 'X'), + (0x1F210, 'M', u'手'), + (0x1F211, 'M', u'字'), + (0x1F212, 'M', u'双'), + (0x1F213, 'M', u'デ'), + (0x1F214, 'M', u'二'), + (0x1F215, 'M', u'多'), + (0x1F216, 'M', u'解'), + (0x1F217, 'M', u'天'), + (0x1F218, 'M', u'交'), + (0x1F219, 'M', u'映'), + (0x1F21A, 'M', u'無'), + (0x1F21B, 'M', u'料'), + (0x1F21C, 'M', u'前'), + (0x1F21D, 'M', u'後'), + (0x1F21E, 'M', u'再'), + (0x1F21F, 'M', u'新'), + (0x1F220, 'M', u'初'), + (0x1F221, 'M', u'終'), + (0x1F222, 'M', u'生'), + (0x1F223, 'M', u'販'), + ] + +def _seg_73(): + return [ + (0x1F224, 'M', u'声'), + (0x1F225, 'M', u'吹'), + (0x1F226, 'M', u'演'), + (0x1F227, 'M', u'投'), + (0x1F228, 'M', u'捕'), + (0x1F229, 'M', u'一'), + (0x1F22A, 'M', u'三'), + (0x1F22B, 'M', u'遊'), + (0x1F22C, 'M', u'左'), + (0x1F22D, 'M', u'中'), + (0x1F22E, 'M', u'右'), + (0x1F22F, 'M', u'指'), + (0x1F230, 'M', u'走'), + (0x1F231, 'M', u'打'), + (0x1F232, 'M', u'禁'), + (0x1F233, 'M', u'空'), + (0x1F234, 'M', u'合'), + (0x1F235, 'M', u'満'), + (0x1F236, 'M', u'有'), + (0x1F237, 'M', u'月'), + (0x1F238, 'M', u'申'), + (0x1F239, 'M', u'割'), + (0x1F23A, 'M', u'営'), + (0x1F23B, 'M', u'配'), + (0x1F23C, 'X'), + (0x1F240, 'M', u'〔本〕'), + (0x1F241, 'M', u'〔三〕'), + (0x1F242, 'M', u'〔二〕'), + (0x1F243, 'M', u'〔安〕'), + (0x1F244, 'M', u'〔点〕'), + (0x1F245, 'M', u'〔打〕'), + (0x1F246, 'M', u'〔盗〕'), + (0x1F247, 'M', u'〔勝〕'), + (0x1F248, 'M', u'〔敗〕'), + (0x1F249, 'X'), + (0x1F250, 'M', u'得'), + (0x1F251, 'M', u'可'), + (0x1F252, 'X'), + (0x1F260, 'V'), + (0x1F266, 'X'), + (0x1F300, 'V'), + (0x1F6D8, 'X'), + (0x1F6E0, 'V'), + (0x1F6ED, 'X'), + (0x1F6F0, 'V'), + (0x1F6FD, 'X'), + (0x1F700, 'V'), + (0x1F774, 'X'), + (0x1F780, 'V'), + (0x1F7D9, 'X'), + (0x1F7E0, 'V'), + (0x1F7EC, 'X'), + (0x1F800, 'V'), + (0x1F80C, 'X'), + (0x1F810, 'V'), + (0x1F848, 'X'), + (0x1F850, 'V'), + (0x1F85A, 'X'), + (0x1F860, 'V'), + (0x1F888, 'X'), + (0x1F890, 'V'), + (0x1F8AE, 'X'), + (0x1F8B0, 'V'), + (0x1F8B2, 'X'), + (0x1F900, 'V'), + (0x1F979, 'X'), + (0x1F97A, 'V'), + (0x1F9CC, 'X'), + (0x1F9CD, 'V'), + (0x1FA54, 'X'), + (0x1FA60, 'V'), + (0x1FA6E, 'X'), + (0x1FA70, 'V'), + (0x1FA75, 'X'), + (0x1FA78, 'V'), + (0x1FA7B, 'X'), + (0x1FA80, 'V'), + (0x1FA87, 'X'), + (0x1FA90, 'V'), + (0x1FAA9, 'X'), + (0x1FAB0, 'V'), + (0x1FAB7, 'X'), + (0x1FAC0, 'V'), + (0x1FAC3, 'X'), + (0x1FAD0, 'V'), + (0x1FAD7, 'X'), + (0x1FB00, 'V'), + (0x1FB93, 'X'), + (0x1FB94, 'V'), + (0x1FBCB, 'X'), + (0x1FBF0, 'M', u'0'), + (0x1FBF1, 'M', u'1'), + (0x1FBF2, 'M', u'2'), + (0x1FBF3, 'M', u'3'), + (0x1FBF4, 'M', u'4'), + (0x1FBF5, 'M', u'5'), + (0x1FBF6, 'M', u'6'), + (0x1FBF7, 'M', u'7'), + (0x1FBF8, 'M', u'8'), + (0x1FBF9, 'M', u'9'), + ] + +def _seg_74(): + return [ + (0x1FBFA, 'X'), + (0x20000, 'V'), + (0x2A6DE, 'X'), + (0x2A700, 'V'), + (0x2B735, 'X'), + (0x2B740, 'V'), + (0x2B81E, 'X'), + (0x2B820, 'V'), + (0x2CEA2, 'X'), + (0x2CEB0, 'V'), + (0x2EBE1, 'X'), + (0x2F800, 'M', u'丽'), + (0x2F801, 'M', u'丸'), + (0x2F802, 'M', u'乁'), + (0x2F803, 'M', u'𠄢'), + (0x2F804, 'M', u'你'), + (0x2F805, 'M', u'侮'), + (0x2F806, 'M', u'侻'), + (0x2F807, 'M', u'倂'), + (0x2F808, 'M', u'偺'), + (0x2F809, 'M', u'備'), + (0x2F80A, 'M', u'僧'), + (0x2F80B, 'M', u'像'), + (0x2F80C, 'M', u'㒞'), + (0x2F80D, 'M', u'𠘺'), + (0x2F80E, 'M', u'免'), + (0x2F80F, 'M', u'兔'), + (0x2F810, 'M', u'兤'), + (0x2F811, 'M', u'具'), + (0x2F812, 'M', u'𠔜'), + (0x2F813, 'M', u'㒹'), + (0x2F814, 'M', u'內'), + (0x2F815, 'M', u'再'), + (0x2F816, 'M', u'𠕋'), + (0x2F817, 'M', u'冗'), + (0x2F818, 'M', u'冤'), + (0x2F819, 'M', u'仌'), + (0x2F81A, 'M', u'冬'), + (0x2F81B, 'M', u'况'), + (0x2F81C, 'M', u'𩇟'), + (0x2F81D, 'M', u'凵'), + (0x2F81E, 'M', u'刃'), + (0x2F81F, 'M', u'㓟'), + (0x2F820, 'M', u'刻'), + (0x2F821, 'M', u'剆'), + (0x2F822, 'M', u'割'), + (0x2F823, 'M', u'剷'), + (0x2F824, 'M', u'㔕'), + (0x2F825, 'M', u'勇'), + (0x2F826, 'M', u'勉'), + (0x2F827, 'M', u'勤'), + (0x2F828, 'M', u'勺'), + (0x2F829, 'M', u'包'), + (0x2F82A, 'M', u'匆'), + (0x2F82B, 'M', u'北'), + (0x2F82C, 'M', u'卉'), + (0x2F82D, 'M', u'卑'), + (0x2F82E, 'M', u'博'), + (0x2F82F, 'M', u'即'), + (0x2F830, 'M', u'卽'), + (0x2F831, 'M', u'卿'), + (0x2F834, 'M', u'𠨬'), + (0x2F835, 'M', u'灰'), + (0x2F836, 'M', u'及'), + (0x2F837, 'M', u'叟'), + (0x2F838, 'M', u'𠭣'), + (0x2F839, 'M', u'叫'), + (0x2F83A, 'M', u'叱'), + (0x2F83B, 'M', u'吆'), + (0x2F83C, 'M', u'咞'), + (0x2F83D, 'M', u'吸'), + (0x2F83E, 'M', u'呈'), + (0x2F83F, 'M', u'周'), + (0x2F840, 'M', u'咢'), + (0x2F841, 'M', u'哶'), + (0x2F842, 'M', u'唐'), + (0x2F843, 'M', u'啓'), + (0x2F844, 'M', u'啣'), + (0x2F845, 'M', u'善'), + (0x2F847, 'M', u'喙'), + (0x2F848, 'M', u'喫'), + (0x2F849, 'M', u'喳'), + (0x2F84A, 'M', u'嗂'), + (0x2F84B, 'M', u'圖'), + (0x2F84C, 'M', u'嘆'), + (0x2F84D, 'M', u'圗'), + (0x2F84E, 'M', u'噑'), + (0x2F84F, 'M', u'噴'), + (0x2F850, 'M', u'切'), + (0x2F851, 'M', u'壮'), + (0x2F852, 'M', u'城'), + (0x2F853, 'M', u'埴'), + (0x2F854, 'M', u'堍'), + (0x2F855, 'M', u'型'), + (0x2F856, 'M', u'堲'), + (0x2F857, 'M', u'報'), + (0x2F858, 'M', u'墬'), + (0x2F859, 'M', u'𡓤'), + (0x2F85A, 'M', u'売'), + (0x2F85B, 'M', u'壷'), + ] + +def _seg_75(): + return [ + (0x2F85C, 'M', u'夆'), + (0x2F85D, 'M', u'多'), + (0x2F85E, 'M', u'夢'), + (0x2F85F, 'M', u'奢'), + (0x2F860, 'M', u'𡚨'), + (0x2F861, 'M', u'𡛪'), + (0x2F862, 'M', u'姬'), + (0x2F863, 'M', u'娛'), + (0x2F864, 'M', u'娧'), + (0x2F865, 'M', u'姘'), + (0x2F866, 'M', u'婦'), + (0x2F867, 'M', u'㛮'), + (0x2F868, 'X'), + (0x2F869, 'M', u'嬈'), + (0x2F86A, 'M', u'嬾'), + (0x2F86C, 'M', u'𡧈'), + (0x2F86D, 'M', u'寃'), + (0x2F86E, 'M', u'寘'), + (0x2F86F, 'M', u'寧'), + (0x2F870, 'M', u'寳'), + (0x2F871, 'M', u'𡬘'), + (0x2F872, 'M', u'寿'), + (0x2F873, 'M', u'将'), + (0x2F874, 'X'), + (0x2F875, 'M', u'尢'), + (0x2F876, 'M', u'㞁'), + (0x2F877, 'M', u'屠'), + (0x2F878, 'M', u'屮'), + (0x2F879, 'M', u'峀'), + (0x2F87A, 'M', u'岍'), + (0x2F87B, 'M', u'𡷤'), + (0x2F87C, 'M', u'嵃'), + (0x2F87D, 'M', u'𡷦'), + (0x2F87E, 'M', u'嵮'), + (0x2F87F, 'M', u'嵫'), + (0x2F880, 'M', u'嵼'), + (0x2F881, 'M', u'巡'), + (0x2F882, 'M', u'巢'), + (0x2F883, 'M', u'㠯'), + (0x2F884, 'M', u'巽'), + (0x2F885, 'M', u'帨'), + (0x2F886, 'M', u'帽'), + (0x2F887, 'M', u'幩'), + (0x2F888, 'M', u'㡢'), + (0x2F889, 'M', u'𢆃'), + (0x2F88A, 'M', u'㡼'), + (0x2F88B, 'M', u'庰'), + (0x2F88C, 'M', u'庳'), + (0x2F88D, 'M', u'庶'), + (0x2F88E, 'M', u'廊'), + (0x2F88F, 'M', u'𪎒'), + (0x2F890, 'M', u'廾'), + (0x2F891, 'M', u'𢌱'), + (0x2F893, 'M', u'舁'), + (0x2F894, 'M', u'弢'), + (0x2F896, 'M', u'㣇'), + (0x2F897, 'M', u'𣊸'), + (0x2F898, 'M', u'𦇚'), + (0x2F899, 'M', u'形'), + (0x2F89A, 'M', u'彫'), + (0x2F89B, 'M', u'㣣'), + (0x2F89C, 'M', u'徚'), + (0x2F89D, 'M', u'忍'), + (0x2F89E, 'M', u'志'), + (0x2F89F, 'M', u'忹'), + (0x2F8A0, 'M', u'悁'), + (0x2F8A1, 'M', u'㤺'), + (0x2F8A2, 'M', u'㤜'), + (0x2F8A3, 'M', u'悔'), + (0x2F8A4, 'M', u'𢛔'), + (0x2F8A5, 'M', u'惇'), + (0x2F8A6, 'M', u'慈'), + (0x2F8A7, 'M', u'慌'), + (0x2F8A8, 'M', u'慎'), + (0x2F8A9, 'M', u'慌'), + (0x2F8AA, 'M', u'慺'), + (0x2F8AB, 'M', u'憎'), + (0x2F8AC, 'M', u'憲'), + (0x2F8AD, 'M', u'憤'), + (0x2F8AE, 'M', u'憯'), + (0x2F8AF, 'M', u'懞'), + (0x2F8B0, 'M', u'懲'), + (0x2F8B1, 'M', u'懶'), + (0x2F8B2, 'M', u'成'), + (0x2F8B3, 'M', u'戛'), + (0x2F8B4, 'M', u'扝'), + (0x2F8B5, 'M', u'抱'), + (0x2F8B6, 'M', u'拔'), + (0x2F8B7, 'M', u'捐'), + (0x2F8B8, 'M', u'𢬌'), + (0x2F8B9, 'M', u'挽'), + (0x2F8BA, 'M', u'拼'), + (0x2F8BB, 'M', u'捨'), + (0x2F8BC, 'M', u'掃'), + (0x2F8BD, 'M', u'揤'), + (0x2F8BE, 'M', u'𢯱'), + (0x2F8BF, 'M', u'搢'), + (0x2F8C0, 'M', u'揅'), + (0x2F8C1, 'M', u'掩'), + (0x2F8C2, 'M', u'㨮'), + ] + +def _seg_76(): + return [ + (0x2F8C3, 'M', u'摩'), + (0x2F8C4, 'M', u'摾'), + (0x2F8C5, 'M', u'撝'), + (0x2F8C6, 'M', u'摷'), + (0x2F8C7, 'M', u'㩬'), + (0x2F8C8, 'M', u'敏'), + (0x2F8C9, 'M', u'敬'), + (0x2F8CA, 'M', u'𣀊'), + (0x2F8CB, 'M', u'旣'), + (0x2F8CC, 'M', u'書'), + (0x2F8CD, 'M', u'晉'), + (0x2F8CE, 'M', u'㬙'), + (0x2F8CF, 'M', u'暑'), + (0x2F8D0, 'M', u'㬈'), + (0x2F8D1, 'M', u'㫤'), + (0x2F8D2, 'M', u'冒'), + (0x2F8D3, 'M', u'冕'), + (0x2F8D4, 'M', u'最'), + (0x2F8D5, 'M', u'暜'), + (0x2F8D6, 'M', u'肭'), + (0x2F8D7, 'M', u'䏙'), + (0x2F8D8, 'M', u'朗'), + (0x2F8D9, 'M', u'望'), + (0x2F8DA, 'M', u'朡'), + (0x2F8DB, 'M', u'杞'), + (0x2F8DC, 'M', u'杓'), + (0x2F8DD, 'M', u'𣏃'), + (0x2F8DE, 'M', u'㭉'), + (0x2F8DF, 'M', u'柺'), + (0x2F8E0, 'M', u'枅'), + (0x2F8E1, 'M', u'桒'), + (0x2F8E2, 'M', u'梅'), + (0x2F8E3, 'M', u'𣑭'), + (0x2F8E4, 'M', u'梎'), + (0x2F8E5, 'M', u'栟'), + (0x2F8E6, 'M', u'椔'), + (0x2F8E7, 'M', u'㮝'), + (0x2F8E8, 'M', u'楂'), + (0x2F8E9, 'M', u'榣'), + (0x2F8EA, 'M', u'槪'), + (0x2F8EB, 'M', u'檨'), + (0x2F8EC, 'M', u'𣚣'), + (0x2F8ED, 'M', u'櫛'), + (0x2F8EE, 'M', u'㰘'), + (0x2F8EF, 'M', u'次'), + (0x2F8F0, 'M', u'𣢧'), + (0x2F8F1, 'M', u'歔'), + (0x2F8F2, 'M', u'㱎'), + (0x2F8F3, 'M', u'歲'), + (0x2F8F4, 'M', u'殟'), + (0x2F8F5, 'M', u'殺'), + (0x2F8F6, 'M', u'殻'), + (0x2F8F7, 'M', u'𣪍'), + (0x2F8F8, 'M', u'𡴋'), + (0x2F8F9, 'M', u'𣫺'), + (0x2F8FA, 'M', u'汎'), + (0x2F8FB, 'M', u'𣲼'), + (0x2F8FC, 'M', u'沿'), + (0x2F8FD, 'M', u'泍'), + (0x2F8FE, 'M', u'汧'), + (0x2F8FF, 'M', u'洖'), + (0x2F900, 'M', u'派'), + (0x2F901, 'M', u'海'), + (0x2F902, 'M', u'流'), + (0x2F903, 'M', u'浩'), + (0x2F904, 'M', u'浸'), + (0x2F905, 'M', u'涅'), + (0x2F906, 'M', u'𣴞'), + (0x2F907, 'M', u'洴'), + (0x2F908, 'M', u'港'), + (0x2F909, 'M', u'湮'), + (0x2F90A, 'M', u'㴳'), + (0x2F90B, 'M', u'滋'), + (0x2F90C, 'M', u'滇'), + (0x2F90D, 'M', u'𣻑'), + (0x2F90E, 'M', u'淹'), + (0x2F90F, 'M', u'潮'), + (0x2F910, 'M', u'𣽞'), + (0x2F911, 'M', u'𣾎'), + (0x2F912, 'M', u'濆'), + (0x2F913, 'M', u'瀹'), + (0x2F914, 'M', u'瀞'), + (0x2F915, 'M', u'瀛'), + (0x2F916, 'M', u'㶖'), + (0x2F917, 'M', u'灊'), + (0x2F918, 'M', u'災'), + (0x2F919, 'M', u'灷'), + (0x2F91A, 'M', u'炭'), + (0x2F91B, 'M', u'𠔥'), + (0x2F91C, 'M', u'煅'), + (0x2F91D, 'M', u'𤉣'), + (0x2F91E, 'M', u'熜'), + (0x2F91F, 'X'), + (0x2F920, 'M', u'爨'), + (0x2F921, 'M', u'爵'), + (0x2F922, 'M', u'牐'), + (0x2F923, 'M', u'𤘈'), + (0x2F924, 'M', u'犀'), + (0x2F925, 'M', u'犕'), + (0x2F926, 'M', u'𤜵'), + ] + +def _seg_77(): + return [ + (0x2F927, 'M', u'𤠔'), + (0x2F928, 'M', u'獺'), + (0x2F929, 'M', u'王'), + (0x2F92A, 'M', u'㺬'), + (0x2F92B, 'M', u'玥'), + (0x2F92C, 'M', u'㺸'), + (0x2F92E, 'M', u'瑇'), + (0x2F92F, 'M', u'瑜'), + (0x2F930, 'M', u'瑱'), + (0x2F931, 'M', u'璅'), + (0x2F932, 'M', u'瓊'), + (0x2F933, 'M', u'㼛'), + (0x2F934, 'M', u'甤'), + (0x2F935, 'M', u'𤰶'), + (0x2F936, 'M', u'甾'), + (0x2F937, 'M', u'𤲒'), + (0x2F938, 'M', u'異'), + (0x2F939, 'M', u'𢆟'), + (0x2F93A, 'M', u'瘐'), + (0x2F93B, 'M', u'𤾡'), + (0x2F93C, 'M', u'𤾸'), + (0x2F93D, 'M', u'𥁄'), + (0x2F93E, 'M', u'㿼'), + (0x2F93F, 'M', u'䀈'), + (0x2F940, 'M', u'直'), + (0x2F941, 'M', u'𥃳'), + (0x2F942, 'M', u'𥃲'), + (0x2F943, 'M', u'𥄙'), + (0x2F944, 'M', u'𥄳'), + (0x2F945, 'M', u'眞'), + (0x2F946, 'M', u'真'), + (0x2F948, 'M', u'睊'), + (0x2F949, 'M', u'䀹'), + (0x2F94A, 'M', u'瞋'), + (0x2F94B, 'M', u'䁆'), + (0x2F94C, 'M', u'䂖'), + (0x2F94D, 'M', u'𥐝'), + (0x2F94E, 'M', u'硎'), + (0x2F94F, 'M', u'碌'), + (0x2F950, 'M', u'磌'), + (0x2F951, 'M', u'䃣'), + (0x2F952, 'M', u'𥘦'), + (0x2F953, 'M', u'祖'), + (0x2F954, 'M', u'𥚚'), + (0x2F955, 'M', u'𥛅'), + (0x2F956, 'M', u'福'), + (0x2F957, 'M', u'秫'), + (0x2F958, 'M', u'䄯'), + (0x2F959, 'M', u'穀'), + (0x2F95A, 'M', u'穊'), + (0x2F95B, 'M', u'穏'), + (0x2F95C, 'M', u'𥥼'), + (0x2F95D, 'M', u'𥪧'), + (0x2F95F, 'X'), + (0x2F960, 'M', u'䈂'), + (0x2F961, 'M', u'𥮫'), + (0x2F962, 'M', u'篆'), + (0x2F963, 'M', u'築'), + (0x2F964, 'M', u'䈧'), + (0x2F965, 'M', u'𥲀'), + (0x2F966, 'M', u'糒'), + (0x2F967, 'M', u'䊠'), + (0x2F968, 'M', u'糨'), + (0x2F969, 'M', u'糣'), + (0x2F96A, 'M', u'紀'), + (0x2F96B, 'M', u'𥾆'), + (0x2F96C, 'M', u'絣'), + (0x2F96D, 'M', u'䌁'), + (0x2F96E, 'M', u'緇'), + (0x2F96F, 'M', u'縂'), + (0x2F970, 'M', u'繅'), + (0x2F971, 'M', u'䌴'), + (0x2F972, 'M', u'𦈨'), + (0x2F973, 'M', u'𦉇'), + (0x2F974, 'M', u'䍙'), + (0x2F975, 'M', u'𦋙'), + (0x2F976, 'M', u'罺'), + (0x2F977, 'M', u'𦌾'), + (0x2F978, 'M', u'羕'), + (0x2F979, 'M', u'翺'), + (0x2F97A, 'M', u'者'), + (0x2F97B, 'M', u'𦓚'), + (0x2F97C, 'M', u'𦔣'), + (0x2F97D, 'M', u'聠'), + (0x2F97E, 'M', u'𦖨'), + (0x2F97F, 'M', u'聰'), + (0x2F980, 'M', u'𣍟'), + (0x2F981, 'M', u'䏕'), + (0x2F982, 'M', u'育'), + (0x2F983, 'M', u'脃'), + (0x2F984, 'M', u'䐋'), + (0x2F985, 'M', u'脾'), + (0x2F986, 'M', u'媵'), + (0x2F987, 'M', u'𦞧'), + (0x2F988, 'M', u'𦞵'), + (0x2F989, 'M', u'𣎓'), + (0x2F98A, 'M', u'𣎜'), + (0x2F98B, 'M', u'舁'), + (0x2F98C, 'M', u'舄'), + (0x2F98D, 'M', u'辞'), + ] + +def _seg_78(): + return [ + (0x2F98E, 'M', u'䑫'), + (0x2F98F, 'M', u'芑'), + (0x2F990, 'M', u'芋'), + (0x2F991, 'M', u'芝'), + (0x2F992, 'M', u'劳'), + (0x2F993, 'M', u'花'), + (0x2F994, 'M', u'芳'), + (0x2F995, 'M', u'芽'), + (0x2F996, 'M', u'苦'), + (0x2F997, 'M', u'𦬼'), + (0x2F998, 'M', u'若'), + (0x2F999, 'M', u'茝'), + (0x2F99A, 'M', u'荣'), + (0x2F99B, 'M', u'莭'), + (0x2F99C, 'M', u'茣'), + (0x2F99D, 'M', u'莽'), + (0x2F99E, 'M', u'菧'), + (0x2F99F, 'M', u'著'), + (0x2F9A0, 'M', u'荓'), + (0x2F9A1, 'M', u'菊'), + (0x2F9A2, 'M', u'菌'), + (0x2F9A3, 'M', u'菜'), + (0x2F9A4, 'M', u'𦰶'), + (0x2F9A5, 'M', u'𦵫'), + (0x2F9A6, 'M', u'𦳕'), + (0x2F9A7, 'M', u'䔫'), + (0x2F9A8, 'M', u'蓱'), + (0x2F9A9, 'M', u'蓳'), + (0x2F9AA, 'M', u'蔖'), + (0x2F9AB, 'M', u'𧏊'), + (0x2F9AC, 'M', u'蕤'), + (0x2F9AD, 'M', u'𦼬'), + (0x2F9AE, 'M', u'䕝'), + (0x2F9AF, 'M', u'䕡'), + (0x2F9B0, 'M', u'𦾱'), + (0x2F9B1, 'M', u'𧃒'), + (0x2F9B2, 'M', u'䕫'), + (0x2F9B3, 'M', u'虐'), + (0x2F9B4, 'M', u'虜'), + (0x2F9B5, 'M', u'虧'), + (0x2F9B6, 'M', u'虩'), + (0x2F9B7, 'M', u'蚩'), + (0x2F9B8, 'M', u'蚈'), + (0x2F9B9, 'M', u'蜎'), + (0x2F9BA, 'M', u'蛢'), + (0x2F9BB, 'M', u'蝹'), + (0x2F9BC, 'M', u'蜨'), + (0x2F9BD, 'M', u'蝫'), + (0x2F9BE, 'M', u'螆'), + (0x2F9BF, 'X'), + (0x2F9C0, 'M', u'蟡'), + (0x2F9C1, 'M', u'蠁'), + (0x2F9C2, 'M', u'䗹'), + (0x2F9C3, 'M', u'衠'), + (0x2F9C4, 'M', u'衣'), + (0x2F9C5, 'M', u'𧙧'), + (0x2F9C6, 'M', u'裗'), + (0x2F9C7, 'M', u'裞'), + (0x2F9C8, 'M', u'䘵'), + (0x2F9C9, 'M', u'裺'), + (0x2F9CA, 'M', u'㒻'), + (0x2F9CB, 'M', u'𧢮'), + (0x2F9CC, 'M', u'𧥦'), + (0x2F9CD, 'M', u'䚾'), + (0x2F9CE, 'M', u'䛇'), + (0x2F9CF, 'M', u'誠'), + (0x2F9D0, 'M', u'諭'), + (0x2F9D1, 'M', u'變'), + (0x2F9D2, 'M', u'豕'), + (0x2F9D3, 'M', u'𧲨'), + (0x2F9D4, 'M', u'貫'), + (0x2F9D5, 'M', u'賁'), + (0x2F9D6, 'M', u'贛'), + (0x2F9D7, 'M', u'起'), + (0x2F9D8, 'M', u'𧼯'), + (0x2F9D9, 'M', u'𠠄'), + (0x2F9DA, 'M', u'跋'), + (0x2F9DB, 'M', u'趼'), + (0x2F9DC, 'M', u'跰'), + (0x2F9DD, 'M', u'𠣞'), + (0x2F9DE, 'M', u'軔'), + (0x2F9DF, 'M', u'輸'), + (0x2F9E0, 'M', u'𨗒'), + (0x2F9E1, 'M', u'𨗭'), + (0x2F9E2, 'M', u'邔'), + (0x2F9E3, 'M', u'郱'), + (0x2F9E4, 'M', u'鄑'), + (0x2F9E5, 'M', u'𨜮'), + (0x2F9E6, 'M', u'鄛'), + (0x2F9E7, 'M', u'鈸'), + (0x2F9E8, 'M', u'鋗'), + (0x2F9E9, 'M', u'鋘'), + (0x2F9EA, 'M', u'鉼'), + (0x2F9EB, 'M', u'鏹'), + (0x2F9EC, 'M', u'鐕'), + (0x2F9ED, 'M', u'𨯺'), + (0x2F9EE, 'M', u'開'), + (0x2F9EF, 'M', u'䦕'), + (0x2F9F0, 'M', u'閷'), + (0x2F9F1, 'M', u'𨵷'), + ] + +def _seg_79(): + return [ + (0x2F9F2, 'M', u'䧦'), + (0x2F9F3, 'M', u'雃'), + (0x2F9F4, 'M', u'嶲'), + (0x2F9F5, 'M', u'霣'), + (0x2F9F6, 'M', u'𩅅'), + (0x2F9F7, 'M', u'𩈚'), + (0x2F9F8, 'M', u'䩮'), + (0x2F9F9, 'M', u'䩶'), + (0x2F9FA, 'M', u'韠'), + (0x2F9FB, 'M', u'𩐊'), + (0x2F9FC, 'M', u'䪲'), + (0x2F9FD, 'M', u'𩒖'), + (0x2F9FE, 'M', u'頋'), + (0x2FA00, 'M', u'頩'), + (0x2FA01, 'M', u'𩖶'), + (0x2FA02, 'M', u'飢'), + (0x2FA03, 'M', u'䬳'), + (0x2FA04, 'M', u'餩'), + (0x2FA05, 'M', u'馧'), + (0x2FA06, 'M', u'駂'), + (0x2FA07, 'M', u'駾'), + (0x2FA08, 'M', u'䯎'), + (0x2FA09, 'M', u'𩬰'), + (0x2FA0A, 'M', u'鬒'), + (0x2FA0B, 'M', u'鱀'), + (0x2FA0C, 'M', u'鳽'), + (0x2FA0D, 'M', u'䳎'), + (0x2FA0E, 'M', u'䳭'), + (0x2FA0F, 'M', u'鵧'), + (0x2FA10, 'M', u'𪃎'), + (0x2FA11, 'M', u'䳸'), + (0x2FA12, 'M', u'𪄅'), + (0x2FA13, 'M', u'𪈎'), + (0x2FA14, 'M', u'𪊑'), + (0x2FA15, 'M', u'麻'), + (0x2FA16, 'M', u'䵖'), + (0x2FA17, 'M', u'黹'), + (0x2FA18, 'M', u'黾'), + (0x2FA19, 'M', u'鼅'), + (0x2FA1A, 'M', u'鼏'), + (0x2FA1B, 'M', u'鼖'), + (0x2FA1C, 'M', u'鼻'), + (0x2FA1D, 'M', u'𪘀'), + (0x2FA1E, 'X'), + (0x30000, 'V'), + (0x3134B, 'X'), + (0xE0100, 'I'), + (0xE01F0, 'X'), + ] + +uts46data = tuple( + _seg_0() + + _seg_1() + + _seg_2() + + _seg_3() + + _seg_4() + + _seg_5() + + _seg_6() + + _seg_7() + + _seg_8() + + _seg_9() + + _seg_10() + + _seg_11() + + _seg_12() + + _seg_13() + + _seg_14() + + _seg_15() + + _seg_16() + + _seg_17() + + _seg_18() + + _seg_19() + + _seg_20() + + _seg_21() + + _seg_22() + + _seg_23() + + _seg_24() + + _seg_25() + + _seg_26() + + _seg_27() + + _seg_28() + + _seg_29() + + _seg_30() + + _seg_31() + + _seg_32() + + _seg_33() + + _seg_34() + + _seg_35() + + _seg_36() + + _seg_37() + + _seg_38() + + _seg_39() + + _seg_40() + + _seg_41() + + _seg_42() + + _seg_43() + + _seg_44() + + _seg_45() + + _seg_46() + + _seg_47() + + _seg_48() + + _seg_49() + + _seg_50() + + _seg_51() + + _seg_52() + + _seg_53() + + _seg_54() + + _seg_55() + + _seg_56() + + _seg_57() + + _seg_58() + + _seg_59() + + _seg_60() + + _seg_61() + + _seg_62() + + _seg_63() + + _seg_64() + + _seg_65() + + _seg_66() + + _seg_67() + + _seg_68() + + _seg_69() + + _seg_70() + + _seg_71() + + _seg_72() + + _seg_73() + + _seg_74() + + _seg_75() + + _seg_76() + + _seg_77() + + _seg_78() + + _seg_79() +) diff --git a/openpype/vendor/python/python_2/requests/__init__.py b/openpype/vendor/python/python_2/requests/__init__.py new file mode 100644 index 0000000000..53a5b42af6 --- /dev/null +++ b/openpype/vendor/python/python_2/requests/__init__.py @@ -0,0 +1,152 @@ +# -*- coding: utf-8 -*- + +# __ +# /__) _ _ _ _ _/ _ +# / ( (- (/ (/ (- _) / _) +# / + +""" +Requests HTTP Library +~~~~~~~~~~~~~~~~~~~~~ + +Requests is an HTTP library, written in Python, for human beings. +Basic GET usage: + + >>> import requests + >>> r = requests.get('https://www.python.org') + >>> r.status_code + 200 + >>> b'Python is a programming language' in r.content + True + +... or POST: + + >>> payload = dict(key1='value1', key2='value2') + >>> r = requests.post('https://httpbin.org/post', data=payload) + >>> print(r.text) + { + ... + "form": { + "key1": "value1", + "key2": "value2" + }, + ... + } + +The other HTTP methods are supported - see `requests.api`. Full documentation +is at . + +:copyright: (c) 2017 by Kenneth Reitz. +:license: Apache 2.0, see LICENSE for more details. +""" + +import urllib3 +import warnings +from .exceptions import RequestsDependencyWarning + +try: + from charset_normalizer import __version__ as charset_normalizer_version +except ImportError: + charset_normalizer_version = None + +try: + from chardet import __version__ as chardet_version +except ImportError: + chardet_version = None + +def check_compatibility(urllib3_version, chardet_version, charset_normalizer_version): + urllib3_version = urllib3_version.split('.') + assert urllib3_version != ['dev'] # Verify urllib3 isn't installed from git. + + # Sometimes, urllib3 only reports its version as 16.1. + if len(urllib3_version) == 2: + urllib3_version.append('0') + + # Check urllib3 for compatibility. + major, minor, patch = urllib3_version # noqa: F811 + major, minor, patch = int(major), int(minor), int(patch) + # urllib3 >= 1.21.1, <= 1.26 + assert major == 1 + assert minor >= 21 + assert minor <= 26 + + # Check charset_normalizer for compatibility. + if chardet_version: + major, minor, patch = chardet_version.split('.')[:3] + major, minor, patch = int(major), int(minor), int(patch) + # chardet_version >= 3.0.2, < 5.0.0 + assert (3, 0, 2) <= (major, minor, patch) < (5, 0, 0) + elif charset_normalizer_version: + major, minor, patch = charset_normalizer_version.split('.')[:3] + major, minor, patch = int(major), int(minor), int(patch) + # charset_normalizer >= 2.0.0 < 3.0.0 + assert (2, 0, 0) <= (major, minor, patch) < (3, 0, 0) + else: + raise Exception("You need either charset_normalizer or chardet installed") + +def _check_cryptography(cryptography_version): + # cryptography < 1.3.4 + try: + cryptography_version = list(map(int, cryptography_version.split('.'))) + except ValueError: + return + + if cryptography_version < [1, 3, 4]: + warning = 'Old version of cryptography ({}) may cause slowdown.'.format(cryptography_version) + warnings.warn(warning, RequestsDependencyWarning) + +# Check imported dependencies for compatibility. +try: + check_compatibility(urllib3.__version__, chardet_version, charset_normalizer_version) +except (AssertionError, ValueError): + warnings.warn("urllib3 ({}) or chardet ({})/charset_normalizer ({}) doesn't match a supported " + "version!".format(urllib3.__version__, chardet_version, charset_normalizer_version), + RequestsDependencyWarning) + +# Attempt to enable urllib3's fallback for SNI support +# if the standard library doesn't support SNI or the +# 'ssl' library isn't available. +try: + try: + import ssl + except ImportError: + ssl = None + + if not getattr(ssl, "HAS_SNI", False): + from urllib3.contrib import pyopenssl + pyopenssl.inject_into_urllib3() + + # Check cryptography version + from cryptography import __version__ as cryptography_version + _check_cryptography(cryptography_version) +except ImportError: + pass + +# urllib3's DependencyWarnings should be silenced. +from urllib3.exceptions import DependencyWarning +warnings.simplefilter('ignore', DependencyWarning) + +from .__version__ import __title__, __description__, __url__, __version__ +from .__version__ import __build__, __author__, __author_email__, __license__ +from .__version__ import __copyright__, __cake__ + +from . import utils +from . import packages +from .models import Request, Response, PreparedRequest +from .api import request, get, head, post, patch, put, delete, options +from .sessions import session, Session +from .status_codes import codes +from .exceptions import ( + RequestException, Timeout, URLRequired, + TooManyRedirects, HTTPError, ConnectionError, + FileModeWarning, ConnectTimeout, ReadTimeout, JSONDecodeError +) + +# Set default logging handler to avoid "No handler found" warnings. +import logging +from logging import NullHandler + +logging.getLogger(__name__).addHandler(NullHandler()) + +# FileModeWarnings go off per the default. +warnings.simplefilter('default', FileModeWarning, append=True) diff --git a/openpype/vendor/python/python_2/requests/__version__.py b/openpype/vendor/python/python_2/requests/__version__.py new file mode 100644 index 0000000000..e973b03b5f --- /dev/null +++ b/openpype/vendor/python/python_2/requests/__version__.py @@ -0,0 +1,14 @@ +# .-. .-. .-. . . .-. .-. .-. .-. +# |( |- |.| | | |- `-. | `-. +# ' ' `-' `-`.`-' `-' `-' ' `-' + +__title__ = 'requests' +__description__ = 'Python HTTP for Humans.' +__url__ = 'https://requests.readthedocs.io' +__version__ = '2.27.1' +__build__ = 0x022701 +__author__ = 'Kenneth Reitz' +__author_email__ = 'me@kennethreitz.org' +__license__ = 'Apache 2.0' +__copyright__ = 'Copyright 2022 Kenneth Reitz' +__cake__ = u'\u2728 \U0001f370 \u2728' diff --git a/openpype/vendor/python/python_2/requests/_internal_utils.py b/openpype/vendor/python/python_2/requests/_internal_utils.py new file mode 100644 index 0000000000..759d9a56ba --- /dev/null +++ b/openpype/vendor/python/python_2/requests/_internal_utils.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- + +""" +requests._internal_utils +~~~~~~~~~~~~~~ + +Provides utility functions that are consumed internally by Requests +which depend on extremely few external helpers (such as compat) +""" + +from .compat import is_py2, builtin_str, str + + +def to_native_string(string, encoding='ascii'): + """Given a string object, regardless of type, returns a representation of + that string in the native string type, encoding and decoding where + necessary. This assumes ASCII unless told otherwise. + """ + if isinstance(string, builtin_str): + out = string + else: + if is_py2: + out = string.encode(encoding) + else: + out = string.decode(encoding) + + return out + + +def unicode_is_ascii(u_string): + """Determine if unicode string only contains ASCII characters. + + :param str u_string: unicode string to check. Must be unicode + and not Python 2 `str`. + :rtype: bool + """ + assert isinstance(u_string, str) + try: + u_string.encode('ascii') + return True + except UnicodeEncodeError: + return False diff --git a/openpype/vendor/python/python_2/requests/adapters.py b/openpype/vendor/python/python_2/requests/adapters.py new file mode 100644 index 0000000000..fe22ff450e --- /dev/null +++ b/openpype/vendor/python/python_2/requests/adapters.py @@ -0,0 +1,538 @@ +# -*- coding: utf-8 -*- + +""" +requests.adapters +~~~~~~~~~~~~~~~~~ + +This module contains the transport adapters that Requests uses to define +and maintain connections. +""" + +import os.path +import socket + +from urllib3.poolmanager import PoolManager, proxy_from_url +from urllib3.response import HTTPResponse +from urllib3.util import parse_url +from urllib3.util import Timeout as TimeoutSauce +from urllib3.util.retry import Retry +from urllib3.exceptions import ClosedPoolError +from urllib3.exceptions import ConnectTimeoutError +from urllib3.exceptions import HTTPError as _HTTPError +from urllib3.exceptions import InvalidHeader as _InvalidHeader +from urllib3.exceptions import MaxRetryError +from urllib3.exceptions import NewConnectionError +from urllib3.exceptions import ProxyError as _ProxyError +from urllib3.exceptions import ProtocolError +from urllib3.exceptions import ReadTimeoutError +from urllib3.exceptions import SSLError as _SSLError +from urllib3.exceptions import ResponseError +from urllib3.exceptions import LocationValueError + +from .models import Response +from .compat import urlparse, basestring +from .utils import (DEFAULT_CA_BUNDLE_PATH, extract_zipped_paths, + get_encoding_from_headers, prepend_scheme_if_needed, + get_auth_from_url, urldefragauth, select_proxy) +from .structures import CaseInsensitiveDict +from .cookies import extract_cookies_to_jar +from .exceptions import (ConnectionError, ConnectTimeout, ReadTimeout, SSLError, + ProxyError, RetryError, InvalidSchema, InvalidProxyURL, + InvalidURL, InvalidHeader) +from .auth import _basic_auth_str + +try: + from urllib3.contrib.socks import SOCKSProxyManager +except ImportError: + def SOCKSProxyManager(*args, **kwargs): + raise InvalidSchema("Missing dependencies for SOCKS support.") + +DEFAULT_POOLBLOCK = False +DEFAULT_POOLSIZE = 10 +DEFAULT_RETRIES = 0 +DEFAULT_POOL_TIMEOUT = None + + +class BaseAdapter(object): + """The Base Transport Adapter""" + + def __init__(self): + super(BaseAdapter, self).__init__() + + def send(self, request, stream=False, timeout=None, verify=True, + cert=None, proxies=None): + """Sends PreparedRequest object. Returns Response object. + + :param request: The :class:`PreparedRequest ` being sent. + :param stream: (optional) Whether to stream the request content. + :param timeout: (optional) How long to wait for the server to send + data before giving up, as a float, or a :ref:`(connect timeout, + read timeout) ` tuple. + :type timeout: float or tuple + :param verify: (optional) Either a boolean, in which case it controls whether we verify + the server's TLS certificate, or a string, in which case it must be a path + to a CA bundle to use + :param cert: (optional) Any user-provided SSL certificate to be trusted. + :param proxies: (optional) The proxies dictionary to apply to the request. + """ + raise NotImplementedError + + def close(self): + """Cleans up adapter specific items.""" + raise NotImplementedError + + +class HTTPAdapter(BaseAdapter): + """The built-in HTTP Adapter for urllib3. + + Provides a general-case interface for Requests sessions to contact HTTP and + HTTPS urls by implementing the Transport Adapter interface. This class will + usually be created by the :class:`Session ` class under the + covers. + + :param pool_connections: The number of urllib3 connection pools to cache. + :param pool_maxsize: The maximum number of connections to save in the pool. + :param max_retries: The maximum number of retries each connection + should attempt. Note, this applies only to failed DNS lookups, socket + connections and connection timeouts, never to requests where data has + made it to the server. By default, Requests does not retry failed + connections. If you need granular control over the conditions under + which we retry a request, import urllib3's ``Retry`` class and pass + that instead. + :param pool_block: Whether the connection pool should block for connections. + + Usage:: + + >>> import requests + >>> s = requests.Session() + >>> a = requests.adapters.HTTPAdapter(max_retries=3) + >>> s.mount('http://', a) + """ + __attrs__ = ['max_retries', 'config', '_pool_connections', '_pool_maxsize', + '_pool_block'] + + def __init__(self, pool_connections=DEFAULT_POOLSIZE, + pool_maxsize=DEFAULT_POOLSIZE, max_retries=DEFAULT_RETRIES, + pool_block=DEFAULT_POOLBLOCK): + if max_retries == DEFAULT_RETRIES: + self.max_retries = Retry(0, read=False) + else: + self.max_retries = Retry.from_int(max_retries) + self.config = {} + self.proxy_manager = {} + + super(HTTPAdapter, self).__init__() + + self._pool_connections = pool_connections + self._pool_maxsize = pool_maxsize + self._pool_block = pool_block + + self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block) + + def __getstate__(self): + return {attr: getattr(self, attr, None) for attr in self.__attrs__} + + def __setstate__(self, state): + # Can't handle by adding 'proxy_manager' to self.__attrs__ because + # self.poolmanager uses a lambda function, which isn't pickleable. + self.proxy_manager = {} + self.config = {} + + for attr, value in state.items(): + setattr(self, attr, value) + + self.init_poolmanager(self._pool_connections, self._pool_maxsize, + block=self._pool_block) + + def init_poolmanager(self, connections, maxsize, block=DEFAULT_POOLBLOCK, **pool_kwargs): + """Initializes a urllib3 PoolManager. + + This method should not be called from user code, and is only + exposed for use when subclassing the + :class:`HTTPAdapter `. + + :param connections: The number of urllib3 connection pools to cache. + :param maxsize: The maximum number of connections to save in the pool. + :param block: Block when no free connections are available. + :param pool_kwargs: Extra keyword arguments used to initialize the Pool Manager. + """ + # save these values for pickling + self._pool_connections = connections + self._pool_maxsize = maxsize + self._pool_block = block + + self.poolmanager = PoolManager(num_pools=connections, maxsize=maxsize, + block=block, strict=True, **pool_kwargs) + + def proxy_manager_for(self, proxy, **proxy_kwargs): + """Return urllib3 ProxyManager for the given proxy. + + This method should not be called from user code, and is only + exposed for use when subclassing the + :class:`HTTPAdapter `. + + :param proxy: The proxy to return a urllib3 ProxyManager for. + :param proxy_kwargs: Extra keyword arguments used to configure the Proxy Manager. + :returns: ProxyManager + :rtype: urllib3.ProxyManager + """ + if proxy in self.proxy_manager: + manager = self.proxy_manager[proxy] + elif proxy.lower().startswith('socks'): + username, password = get_auth_from_url(proxy) + manager = self.proxy_manager[proxy] = SOCKSProxyManager( + proxy, + username=username, + password=password, + num_pools=self._pool_connections, + maxsize=self._pool_maxsize, + block=self._pool_block, + **proxy_kwargs + ) + else: + proxy_headers = self.proxy_headers(proxy) + manager = self.proxy_manager[proxy] = proxy_from_url( + proxy, + proxy_headers=proxy_headers, + num_pools=self._pool_connections, + maxsize=self._pool_maxsize, + block=self._pool_block, + **proxy_kwargs) + + return manager + + def cert_verify(self, conn, url, verify, cert): + """Verify a SSL certificate. This method should not be called from user + code, and is only exposed for use when subclassing the + :class:`HTTPAdapter `. + + :param conn: The urllib3 connection object associated with the cert. + :param url: The requested URL. + :param verify: Either a boolean, in which case it controls whether we verify + the server's TLS certificate, or a string, in which case it must be a path + to a CA bundle to use + :param cert: The SSL certificate to verify. + """ + if url.lower().startswith('https') and verify: + + cert_loc = None + + # Allow self-specified cert location. + if verify is not True: + cert_loc = verify + + if not cert_loc: + cert_loc = extract_zipped_paths(DEFAULT_CA_BUNDLE_PATH) + + if not cert_loc or not os.path.exists(cert_loc): + raise IOError("Could not find a suitable TLS CA certificate bundle, " + "invalid path: {}".format(cert_loc)) + + conn.cert_reqs = 'CERT_REQUIRED' + + if not os.path.isdir(cert_loc): + conn.ca_certs = cert_loc + else: + conn.ca_cert_dir = cert_loc + else: + conn.cert_reqs = 'CERT_NONE' + conn.ca_certs = None + conn.ca_cert_dir = None + + if cert: + if not isinstance(cert, basestring): + conn.cert_file = cert[0] + conn.key_file = cert[1] + else: + conn.cert_file = cert + conn.key_file = None + if conn.cert_file and not os.path.exists(conn.cert_file): + raise IOError("Could not find the TLS certificate file, " + "invalid path: {}".format(conn.cert_file)) + if conn.key_file and not os.path.exists(conn.key_file): + raise IOError("Could not find the TLS key file, " + "invalid path: {}".format(conn.key_file)) + + def build_response(self, req, resp): + """Builds a :class:`Response ` object from a urllib3 + response. This should not be called from user code, and is only exposed + for use when subclassing the + :class:`HTTPAdapter ` + + :param req: The :class:`PreparedRequest ` used to generate the response. + :param resp: The urllib3 response object. + :rtype: requests.Response + """ + response = Response() + + # Fallback to None if there's no status_code, for whatever reason. + response.status_code = getattr(resp, 'status', None) + + # Make headers case-insensitive. + response.headers = CaseInsensitiveDict(getattr(resp, 'headers', {})) + + # Set encoding. + response.encoding = get_encoding_from_headers(response.headers) + response.raw = resp + response.reason = response.raw.reason + + if isinstance(req.url, bytes): + response.url = req.url.decode('utf-8') + else: + response.url = req.url + + # Add new cookies from the server. + extract_cookies_to_jar(response.cookies, req, resp) + + # Give the Response some context. + response.request = req + response.connection = self + + return response + + def get_connection(self, url, proxies=None): + """Returns a urllib3 connection for the given URL. This should not be + called from user code, and is only exposed for use when subclassing the + :class:`HTTPAdapter `. + + :param url: The URL to connect to. + :param proxies: (optional) A Requests-style dictionary of proxies used on this request. + :rtype: urllib3.ConnectionPool + """ + proxy = select_proxy(url, proxies) + + if proxy: + proxy = prepend_scheme_if_needed(proxy, 'http') + proxy_url = parse_url(proxy) + if not proxy_url.host: + raise InvalidProxyURL("Please check proxy URL. It is malformed" + " and could be missing the host.") + proxy_manager = self.proxy_manager_for(proxy) + conn = proxy_manager.connection_from_url(url) + else: + # Only scheme should be lower case + parsed = urlparse(url) + url = parsed.geturl() + conn = self.poolmanager.connection_from_url(url) + + return conn + + def close(self): + """Disposes of any internal state. + + Currently, this closes the PoolManager and any active ProxyManager, + which closes any pooled connections. + """ + self.poolmanager.clear() + for proxy in self.proxy_manager.values(): + proxy.clear() + + def request_url(self, request, proxies): + """Obtain the url to use when making the final request. + + If the message is being sent through a HTTP proxy, the full URL has to + be used. Otherwise, we should only use the path portion of the URL. + + This should not be called from user code, and is only exposed for use + when subclassing the + :class:`HTTPAdapter `. + + :param request: The :class:`PreparedRequest ` being sent. + :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs. + :rtype: str + """ + proxy = select_proxy(request.url, proxies) + scheme = urlparse(request.url).scheme + + is_proxied_http_request = (proxy and scheme != 'https') + using_socks_proxy = False + if proxy: + proxy_scheme = urlparse(proxy).scheme.lower() + using_socks_proxy = proxy_scheme.startswith('socks') + + url = request.path_url + if is_proxied_http_request and not using_socks_proxy: + url = urldefragauth(request.url) + + return url + + def add_headers(self, request, **kwargs): + """Add any headers needed by the connection. As of v2.0 this does + nothing by default, but is left for overriding by users that subclass + the :class:`HTTPAdapter `. + + This should not be called from user code, and is only exposed for use + when subclassing the + :class:`HTTPAdapter `. + + :param request: The :class:`PreparedRequest ` to add headers to. + :param kwargs: The keyword arguments from the call to send(). + """ + pass + + def proxy_headers(self, proxy): + """Returns a dictionary of the headers to add to any request sent + through a proxy. This works with urllib3 magic to ensure that they are + correctly sent to the proxy, rather than in a tunnelled request if + CONNECT is being used. + + This should not be called from user code, and is only exposed for use + when subclassing the + :class:`HTTPAdapter `. + + :param proxy: The url of the proxy being used for this request. + :rtype: dict + """ + headers = {} + username, password = get_auth_from_url(proxy) + + if username: + headers['Proxy-Authorization'] = _basic_auth_str(username, + password) + + return headers + + def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None): + """Sends PreparedRequest object. Returns Response object. + + :param request: The :class:`PreparedRequest ` being sent. + :param stream: (optional) Whether to stream the request content. + :param timeout: (optional) How long to wait for the server to send + data before giving up, as a float, or a :ref:`(connect timeout, + read timeout) ` tuple. + :type timeout: float or tuple or urllib3 Timeout object + :param verify: (optional) Either a boolean, in which case it controls whether + we verify the server's TLS certificate, or a string, in which case it + must be a path to a CA bundle to use + :param cert: (optional) Any user-provided SSL certificate to be trusted. + :param proxies: (optional) The proxies dictionary to apply to the request. + :rtype: requests.Response + """ + + try: + conn = self.get_connection(request.url, proxies) + except LocationValueError as e: + raise InvalidURL(e, request=request) + + self.cert_verify(conn, request.url, verify, cert) + url = self.request_url(request, proxies) + self.add_headers(request, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies) + + chunked = not (request.body is None or 'Content-Length' in request.headers) + + if isinstance(timeout, tuple): + try: + connect, read = timeout + timeout = TimeoutSauce(connect=connect, read=read) + except ValueError as e: + # this may raise a string formatting error. + err = ("Invalid timeout {}. Pass a (connect, read) " + "timeout tuple, or a single float to set " + "both timeouts to the same value".format(timeout)) + raise ValueError(err) + elif isinstance(timeout, TimeoutSauce): + pass + else: + timeout = TimeoutSauce(connect=timeout, read=timeout) + + try: + if not chunked: + resp = conn.urlopen( + method=request.method, + url=url, + body=request.body, + headers=request.headers, + redirect=False, + assert_same_host=False, + preload_content=False, + decode_content=False, + retries=self.max_retries, + timeout=timeout + ) + + # Send the request. + else: + if hasattr(conn, 'proxy_pool'): + conn = conn.proxy_pool + + low_conn = conn._get_conn(timeout=DEFAULT_POOL_TIMEOUT) + + try: + skip_host = 'Host' in request.headers + low_conn.putrequest(request.method, + url, + skip_accept_encoding=True, + skip_host=skip_host) + + for header, value in request.headers.items(): + low_conn.putheader(header, value) + + low_conn.endheaders() + + for i in request.body: + low_conn.send(hex(len(i))[2:].encode('utf-8')) + low_conn.send(b'\r\n') + low_conn.send(i) + low_conn.send(b'\r\n') + low_conn.send(b'0\r\n\r\n') + + # Receive the response from the server + try: + # For Python 2.7, use buffering of HTTP responses + r = low_conn.getresponse(buffering=True) + except TypeError: + # For compatibility with Python 3.3+ + r = low_conn.getresponse() + + resp = HTTPResponse.from_httplib( + r, + pool=conn, + connection=low_conn, + preload_content=False, + decode_content=False + ) + except: + # If we hit any problems here, clean up the connection. + # Then, reraise so that we can handle the actual exception. + low_conn.close() + raise + + except (ProtocolError, socket.error) as err: + raise ConnectionError(err, request=request) + + except MaxRetryError as e: + if isinstance(e.reason, ConnectTimeoutError): + # TODO: Remove this in 3.0.0: see #2811 + if not isinstance(e.reason, NewConnectionError): + raise ConnectTimeout(e, request=request) + + if isinstance(e.reason, ResponseError): + raise RetryError(e, request=request) + + if isinstance(e.reason, _ProxyError): + raise ProxyError(e, request=request) + + if isinstance(e.reason, _SSLError): + # This branch is for urllib3 v1.22 and later. + raise SSLError(e, request=request) + + raise ConnectionError(e, request=request) + + except ClosedPoolError as e: + raise ConnectionError(e, request=request) + + except _ProxyError as e: + raise ProxyError(e) + + except (_SSLError, _HTTPError) as e: + if isinstance(e, _SSLError): + # This branch is for urllib3 versions earlier than v1.22 + raise SSLError(e, request=request) + elif isinstance(e, ReadTimeoutError): + raise ReadTimeout(e, request=request) + elif isinstance(e, _InvalidHeader): + raise InvalidHeader(e, request=request) + else: + raise + + return self.build_response(request, resp) diff --git a/openpype/vendor/python/python_2/requests/api.py b/openpype/vendor/python/python_2/requests/api.py new file mode 100644 index 0000000000..4cba90eefe --- /dev/null +++ b/openpype/vendor/python/python_2/requests/api.py @@ -0,0 +1,159 @@ +# -*- coding: utf-8 -*- + +""" +requests.api +~~~~~~~~~~~~ + +This module implements the Requests API. + +:copyright: (c) 2012 by Kenneth Reitz. +:license: Apache2, see LICENSE for more details. +""" + +from . import sessions + + +def request(method, url, **kwargs): + """Constructs and sends a :class:`Request `. + + :param method: method for the new :class:`Request` object: ``GET``, ``OPTIONS``, ``HEAD``, ``POST``, ``PUT``, ``PATCH``, or ``DELETE``. + :param url: URL for the new :class:`Request` object. + :param params: (optional) Dictionary, list of tuples or bytes to send + in the query string for the :class:`Request`. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`. + :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`. + :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. + :param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': file-tuple}``) for multipart encoding upload. + ``file-tuple`` can be a 2-tuple ``('filename', fileobj)``, 3-tuple ``('filename', fileobj, 'content_type')`` + or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``, where ``'content-type'`` is a string + defining the content type of the given file and ``custom_headers`` a dict-like object containing additional headers + to add for the file. + :param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth. + :param timeout: (optional) How many seconds to wait for the server to send data + before giving up, as a float, or a :ref:`(connect timeout, read + timeout) ` tuple. + :type timeout: float or tuple + :param allow_redirects: (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to ``True``. + :type allow_redirects: bool + :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. + :param verify: (optional) Either a boolean, in which case it controls whether we verify + the server's TLS certificate, or a string, in which case it must be a path + to a CA bundle to use. Defaults to ``True``. + :param stream: (optional) if ``False``, the response content will be immediately downloaded. + :param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair. + :return: :class:`Response ` object + :rtype: requests.Response + + Usage:: + + >>> import requests + >>> req = requests.request('GET', 'https://httpbin.org/get') + >>> req + + """ + + # By using the 'with' statement we are sure the session is closed, thus we + # avoid leaving sockets open which can trigger a ResourceWarning in some + # cases, and look like a memory leak in others. + with sessions.Session() as session: + return session.request(method=method, url=url, **kwargs) + + +def get(url, params=None, **kwargs): + r"""Sends a GET request. + + :param url: URL for the new :class:`Request` object. + :param params: (optional) Dictionary, list of tuples or bytes to send + in the query string for the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + return request('get', url, params=params, **kwargs) + + +def options(url, **kwargs): + r"""Sends an OPTIONS request. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + return request('options', url, **kwargs) + + +def head(url, **kwargs): + r"""Sends a HEAD request. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. If + `allow_redirects` is not provided, it will be set to `False` (as + opposed to the default :meth:`request` behavior). + :return: :class:`Response ` object + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', False) + return request('head', url, **kwargs) + + +def post(url, data=None, json=None, **kwargs): + r"""Sends a POST request. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) json data to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + return request('post', url, data=data, json=json, **kwargs) + + +def put(url, data=None, **kwargs): + r"""Sends a PUT request. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) json data to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + return request('put', url, data=data, **kwargs) + + +def patch(url, data=None, **kwargs): + r"""Sends a PATCH request. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) json data to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + return request('patch', url, data=data, **kwargs) + + +def delete(url, **kwargs): + r"""Sends a DELETE request. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + return request('delete', url, **kwargs) diff --git a/openpype/vendor/python/python_2/requests/auth.py b/openpype/vendor/python/python_2/requests/auth.py new file mode 100644 index 0000000000..eeface39ae --- /dev/null +++ b/openpype/vendor/python/python_2/requests/auth.py @@ -0,0 +1,305 @@ +# -*- coding: utf-8 -*- + +""" +requests.auth +~~~~~~~~~~~~~ + +This module contains the authentication handlers for Requests. +""" + +import os +import re +import time +import hashlib +import threading +import warnings + +from base64 import b64encode + +from .compat import urlparse, str, basestring +from .cookies import extract_cookies_to_jar +from ._internal_utils import to_native_string +from .utils import parse_dict_header + +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.""" + + # "I want us to put a big-ol' comment on top of it that + # says that this behaviour is dumb but we need to preserve + # it because people are relying on it." + # - Lukasa + # + # These are here solely to maintain backwards compatibility + # for things like ints. This will be removed in 3.0.0. + if not isinstance(username, basestring): + warnings.warn( + "Non-string usernames will no longer be supported in Requests " + "3.0.0. Please convert the object you've passed in ({!r}) to " + "a string or bytes object in the near future to avoid " + "problems.".format(username), + category=DeprecationWarning, + ) + username = str(username) + + if not isinstance(password, basestring): + warnings.warn( + "Non-string passwords will no longer be supported in Requests " + "3.0.0. Please convert the object you've passed in ({!r}) to " + "a string or bytes object in the near future to avoid " + "problems.".format(type(password)), + category=DeprecationWarning, + ) + password = str(password) + # -- End Removal -- + + if isinstance(username, str): + username = username.encode('latin1') + + if isinstance(password, str): + password = password.encode('latin1') + + authstr = 'Basic ' + to_native_string( + b64encode(b':'.join((username, password))).strip() + ) + + return authstr + + +class AuthBase(object): + """Base class that all auth implementations derive from""" + + def __call__(self, r): + raise NotImplementedError('Auth hooks must be callable.') + + +class HTTPBasicAuth(AuthBase): + """Attaches HTTP Basic Authentication to the given Request object.""" + + def __init__(self, username, password): + self.username = username + self.password = password + + def __eq__(self, other): + return all([ + self.username == getattr(other, 'username', None), + self.password == getattr(other, 'password', None) + ]) + + def __ne__(self, other): + return not self == other + + def __call__(self, r): + r.headers['Authorization'] = _basic_auth_str(self.username, self.password) + return r + + +class HTTPProxyAuth(HTTPBasicAuth): + """Attaches HTTP Proxy Authentication to a given Request object.""" + + def __call__(self, r): + r.headers['Proxy-Authorization'] = _basic_auth_str(self.username, self.password) + return r + + +class HTTPDigestAuth(AuthBase): + """Attaches HTTP Digest Authentication to the given Request object.""" + + def __init__(self, username, password): + self.username = username + self.password = password + # Keep state in per-thread local storage + self._thread_local = threading.local() + + def init_per_thread_state(self): + # Ensure state is initialized just once per-thread + if not hasattr(self._thread_local, 'init'): + self._thread_local.init = True + self._thread_local.last_nonce = '' + self._thread_local.nonce_count = 0 + self._thread_local.chal = {} + self._thread_local.pos = None + self._thread_local.num_401_calls = None + + def build_digest_header(self, method, url): + """ + :rtype: str + """ + + realm = self._thread_local.chal['realm'] + nonce = self._thread_local.chal['nonce'] + qop = self._thread_local.chal.get('qop') + algorithm = self._thread_local.chal.get('algorithm') + opaque = self._thread_local.chal.get('opaque') + hash_utf8 = None + + if algorithm is None: + _algorithm = 'MD5' + else: + _algorithm = algorithm.upper() + # lambdas assume digest modules are imported at the top level + if _algorithm == 'MD5' or _algorithm == 'MD5-SESS': + 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 + elif _algorithm == 'SHA-256': + def sha256_utf8(x): + if isinstance(x, str): + x = x.encode('utf-8') + return hashlib.sha256(x).hexdigest() + hash_utf8 = sha256_utf8 + elif _algorithm == 'SHA-512': + def sha512_utf8(x): + if isinstance(x, str): + x = x.encode('utf-8') + return hashlib.sha512(x).hexdigest() + hash_utf8 = sha512_utf8 + + 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 is request-uri defined in RFC 2616 which should not be empty + path = p_parsed.path or "/" + if p_parsed.query: + path += '?' + p_parsed.query + + A1 = '%s:%s:%s' % (self.username, realm, self.password) + A2 = '%s:%s' % (method, path) + + HA1 = hash_utf8(A1) + HA2 = hash_utf8(A2) + + if nonce == self._thread_local.last_nonce: + self._thread_local.nonce_count += 1 + else: + self._thread_local.nonce_count = 1 + ncvalue = '%08x' % self._thread_local.nonce_count + s = str(self._thread_local.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]) + if _algorithm == 'MD5-SESS': + HA1 = hash_utf8('%s:%s:%s' % (HA1, nonce, cnonce)) + + if not qop: + respdig = KD(HA1, "%s:%s" % (nonce, HA2)) + elif qop == 'auth' or 'auth' in qop.split(','): + noncebit = "%s:%s:%s:%s:%s" % ( + nonce, ncvalue, cnonce, 'auth', HA2 + ) + respdig = KD(HA1, noncebit) + else: + # XXX handle auth-int. + return None + + self._thread_local.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 algorithm: + base += ', algorithm="%s"' % algorithm + if entdig: + base += ', digest="%s"' % entdig + if qop: + base += ', qop="auth", nc=%s, cnonce="%s"' % (ncvalue, cnonce) + + return 'Digest %s' % (base) + + def handle_redirect(self, r, **kwargs): + """Reset num_401_calls counter on redirects.""" + if r.is_redirect: + self._thread_local.num_401_calls = 1 + + def handle_401(self, r, **kwargs): + """ + Takes the given response and tries digest-auth, if needed. + + :rtype: requests.Response + """ + + # If response is not 4xx, do not auth + # See https://github.com/psf/requests/issues/3772 + if not 400 <= r.status_code < 500: + self._thread_local.num_401_calls = 1 + return r + + if self._thread_local.pos is not None: + # Rewind the file position indicator of the body to where + # it was to resend the request. + r.request.body.seek(self._thread_local.pos) + s_auth = r.headers.get('www-authenticate', '') + + if 'digest' in s_auth.lower() and self._thread_local.num_401_calls < 2: + + self._thread_local.num_401_calls += 1 + pat = re.compile(r'digest ', flags=re.IGNORECASE) + self._thread_local.chal = parse_dict_header(pat.sub('', s_auth, count=1)) + + # Consume content and release the original connection + # to allow our new request to reuse the same one. + r.content + r.close() + prep = r.request.copy() + extract_cookies_to_jar(prep._cookies, r.request, r.raw) + prep.prepare_cookies(prep._cookies) + + prep.headers['Authorization'] = self.build_digest_header( + prep.method, prep.url) + _r = r.connection.send(prep, **kwargs) + _r.history.append(r) + _r.request = prep + + return _r + + self._thread_local.num_401_calls = 1 + return r + + def __call__(self, r): + # Initialize per-thread state, if needed + self.init_per_thread_state() + # If we have a saved nonce, skip the 401 + if self._thread_local.last_nonce: + r.headers['Authorization'] = self.build_digest_header(r.method, r.url) + try: + self._thread_local.pos = r.body.tell() + except AttributeError: + # In the case of HTTPDigestAuth being reused and the body of + # the previous request was a file-like object, pos has the + # file position of the previous body. Ensure it's set to + # None. + self._thread_local.pos = None + r.register_hook('response', self.handle_401) + r.register_hook('response', self.handle_redirect) + self._thread_local.num_401_calls = 1 + + return r + + def __eq__(self, other): + return all([ + self.username == getattr(other, 'username', None), + self.password == getattr(other, 'password', None) + ]) + + def __ne__(self, other): + return not self == other diff --git a/openpype/vendor/python/python_2/requests/certs.py b/openpype/vendor/python/python_2/requests/certs.py new file mode 100644 index 0000000000..d1a378d787 --- /dev/null +++ b/openpype/vendor/python/python_2/requests/certs.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +requests.certs +~~~~~~~~~~~~~~ + +This module returns the preferred default CA certificate bundle. There is +only one — the one from the certifi package. + +If you are packaging Requests, e.g., for a Linux distribution or a managed +environment, you can change the definition of where() to return a separately +packaged CA bundle. +""" +from certifi import where + +if __name__ == '__main__': + print(where()) diff --git a/openpype/vendor/python/python_2/requests/compat.py b/openpype/vendor/python/python_2/requests/compat.py new file mode 100644 index 0000000000..029ae62ac3 --- /dev/null +++ b/openpype/vendor/python/python_2/requests/compat.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- + +""" +requests.compat +~~~~~~~~~~~~~~~ + +This module handles import compatibility issues between Python 2 and +Python 3. +""" + +try: + import chardet +except ImportError: + import charset_normalizer as chardet + +import sys + +# ------- +# Pythons +# ------- + +# Syntax sugar. +_ver = sys.version_info + +#: Python 2.x? +is_py2 = (_ver[0] == 2) + +#: Python 3.x? +is_py3 = (_ver[0] == 3) + +has_simplejson = False +try: + import simplejson as json + has_simplejson = True +except ImportError: + import json + +# --------- +# Specifics +# --------- + +if is_py2: + from urllib import ( + quote, unquote, quote_plus, unquote_plus, urlencode, getproxies, + proxy_bypass, proxy_bypass_environment, getproxies_environment) + from urlparse import urlparse, urlunparse, urljoin, urlsplit, urldefrag + from urllib2 import parse_http_list + import cookielib + from Cookie import Morsel + from StringIO import StringIO + # Keep OrderedDict for backwards compatibility. + from collections import Callable, Mapping, MutableMapping, OrderedDict + + builtin_str = str + bytes = str + str = unicode + basestring = basestring + numeric_types = (int, long, float) + integer_types = (int, long) + JSONDecodeError = ValueError + +elif is_py3: + from urllib.parse import urlparse, urlunparse, urljoin, urlsplit, urlencode, quote, unquote, quote_plus, unquote_plus, urldefrag + from urllib.request import parse_http_list, getproxies, proxy_bypass, proxy_bypass_environment, getproxies_environment + from http import cookiejar as cookielib + from http.cookies import Morsel + from io import StringIO + # Keep OrderedDict for backwards compatibility. + from collections import OrderedDict + from collections.abc import Callable, Mapping, MutableMapping + if has_simplejson: + from simplejson import JSONDecodeError + else: + from json import JSONDecodeError + + builtin_str = str + str = str + bytes = bytes + basestring = (str, bytes) + numeric_types = (int, float) + integer_types = (int,) diff --git a/openpype/vendor/python/python_2/requests/cookies.py b/openpype/vendor/python/python_2/requests/cookies.py new file mode 100644 index 0000000000..56fccd9c25 --- /dev/null +++ b/openpype/vendor/python/python_2/requests/cookies.py @@ -0,0 +1,549 @@ +# -*- coding: utf-8 -*- + +""" +requests.cookies +~~~~~~~~~~~~~~~~ + +Compatibility code to be able to use `cookielib.CookieJar` with requests. + +requests.utils imports from here, so be careful with imports. +""" + +import copy +import time +import calendar + +from ._internal_utils import to_native_string +from .compat import cookielib, urlparse, urlunparse, Morsel, MutableMapping + +try: + import threading +except ImportError: + import dummy_threading as threading + + +class MockRequest(object): + """Wraps a `requests.Request` to mimic a `urllib2.Request`. + + The code in `cookielib.CookieJar` expects this interface in order to correctly + manage cookie policies, i.e., determine whether a cookie can be set, given the + domains of the request and the cookie. + + The original request object is read-only. The client is responsible for collecting + the new headers via `get_new_headers()` and interpreting them appropriately. You + probably want `get_cookie_header`, defined below. + """ + + def __init__(self, request): + self._r = request + self._new_headers = {} + self.type = urlparse(self._r.url).scheme + + def get_type(self): + return self.type + + def get_host(self): + return urlparse(self._r.url).netloc + + def get_origin_req_host(self): + return self.get_host() + + def get_full_url(self): + # Only return the response's URL if the user hadn't set the Host + # header + if not self._r.headers.get('Host'): + return self._r.url + # If they did set it, retrieve it and reconstruct the expected domain + host = to_native_string(self._r.headers['Host'], encoding='utf-8') + parsed = urlparse(self._r.url) + # Reconstruct the URL as we expect it + return urlunparse([ + parsed.scheme, host, parsed.path, parsed.params, parsed.query, + parsed.fragment + ]) + + def is_unverifiable(self): + return True + + def has_header(self, name): + return name in self._r.headers or name in self._new_headers + + def get_header(self, name, default=None): + return self._r.headers.get(name, self._new_headers.get(name, default)) + + def add_header(self, key, val): + """cookielib has no legitimate use for this method; add it back if you find one.""" + raise NotImplementedError("Cookie headers should be added with add_unredirected_header()") + + def add_unredirected_header(self, name, value): + self._new_headers[name] = value + + def get_new_headers(self): + return self._new_headers + + @property + def unverifiable(self): + return self.is_unverifiable() + + @property + def origin_req_host(self): + return self.get_origin_req_host() + + @property + def host(self): + return self.get_host() + + +class MockResponse(object): + """Wraps a `httplib.HTTPMessage` to mimic a `urllib.addinfourl`. + + ...what? Basically, expose the parsed HTTP headers from the server response + the way `cookielib` expects to see them. + """ + + def __init__(self, headers): + """Make a MockResponse for `cookielib` to read. + + :param headers: a httplib.HTTPMessage or analogous carrying the headers + """ + self._headers = headers + + def info(self): + return self._headers + + 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. + + :param jar: cookielib.CookieJar (not necessarily a RequestsCookieJar) + :param request: our own requests.Request object + :param response: urllib3.HTTPResponse object + """ + if not (hasattr(response, '_original_response') and + response._original_response): + return + # the _original_response field is the wrapped httplib.HTTPResponse object, + req = MockRequest(request) + # pull out the HTTPMessage with the headers and put it in the mock: + 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. + + :rtype: str + """ + 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. + + Wraps CookieJar.clear(), is O(n). + """ + clearables = [] + for cookie in cookiejar: + if cookie.name != name: + continue + if domain is not None and domain != cookie.domain: + continue + if path is not None and path != cookie.path: + continue + clearables.append((cookie.domain, cookie.path, cookie.name)) + + 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. + Use .get and .set and include domain and path args in order to be more specific. + """ + + +class RequestsCookieJar(cookielib.CookieJar, MutableMapping): + """Compatibility class; is a cookielib.CookieJar, but exposes a dict + interface. + + This is the CookieJar we create by default for requests and sessions that + don't specify one, since some clients may expect response.cookies and + session.cookies to support dict operations. + + Requests does not use the dict interface internally; it's just for + compatibility with external client code. All requests code should work + out of the box with externally provided instances of ``CookieJar``, e.g. + ``LWPCookieJar`` and ``FileCookieJar``. + + Unlike a regular CookieJar, this class is pickleable. + + .. warning:: dictionary operations that are normally O(1) may be O(n). + """ + + def get(self, name, default=None, domain=None, path=None): + """Dict-like get() that also supports optional domain and path args in + order to resolve naming collisions from using one cookie jar over + multiple domains. + + .. warning:: operation is O(n), not O(1). + """ + try: + return self._find_no_duplicates(name, domain, path) + except KeyError: + return default + + def set(self, name, value, **kwargs): + """Dict-like set() that also supports optional domain and path args in + order to resolve naming collisions from using one cookie jar over + multiple domains. + """ + # support client code that unsets cookies by assignment of a None value: + if value is None: + remove_cookie_by_name(self, name, domain=kwargs.get('domain'), path=kwargs.get('path')) + return + + if isinstance(value, Morsel): + c = morsel_to_cookie(value) + else: + c = create_cookie(name, value, **kwargs) + self.set_cookie(c) + return c + + def iterkeys(self): + """Dict-like iterkeys() that returns an iterator of names of cookies + from the jar. + + .. seealso:: itervalues() and iteritems(). + """ + for cookie in iter(self): + yield cookie.name + + def keys(self): + """Dict-like keys() that returns a list of names of cookies from the + jar. + + .. seealso:: values() and items(). + """ + return list(self.iterkeys()) + + def itervalues(self): + """Dict-like itervalues() that returns an iterator of values of cookies + from the jar. + + .. seealso:: iterkeys() and iteritems(). + """ + for cookie in iter(self): + yield cookie.value + + def values(self): + """Dict-like values() that returns a list of values of cookies from the + jar. + + .. seealso:: keys() and items(). + """ + return list(self.itervalues()) + + def iteritems(self): + """Dict-like iteritems() that returns an iterator of name-value tuples + from the jar. + + .. seealso:: iterkeys() and itervalues(). + """ + for cookie in iter(self): + yield cookie.name, cookie.value + + def items(self): + """Dict-like items() that returns a list of name-value tuples from the + jar. Allows client-code to call ``dict(RequestsCookieJar)`` and get a + vanilla python dict of key value pairs. + + .. seealso:: keys() and values(). + """ + return list(self.iteritems()) + + def list_domains(self): + """Utility method to list all the domains in the jar.""" + domains = [] + for cookie in iter(self): + if cookie.domain not in domains: + domains.append(cookie.domain) + return domains + + def list_paths(self): + """Utility method to list all the paths in the jar.""" + paths = [] + for cookie in iter(self): + if cookie.path not in paths: + paths.append(cookie.path) + return paths + + def multiple_domains(self): + """Returns True if there are multiple domains in the jar. + Returns False otherwise. + + :rtype: bool + """ + domains = [] + for cookie in iter(self): + 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 + + 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. + + :rtype: dict + """ + dictionary = {} + for cookie in iter(self): + if ( + (domain is None or cookie.domain == domain) and + (path is None or cookie.path == path) + ): + dictionary[cookie.name] = cookie.value + return dictionary + + def __contains__(self, name): + try: + return super(RequestsCookieJar, self).__contains__(name) + except CookieConflictError: + return True + + def __getitem__(self, name): + """Dict-like __getitem__() for compatibility with client code. Throws + exception if there are more than one cookie with name. In that case, + use the more explicit get() method instead. + + .. warning:: operation is O(n), not O(1). + """ + return self._find_no_duplicates(name) + + def __setitem__(self, name, value): + """Dict-like __setitem__ for compatibility with client code. Throws + exception if there is already a cookie of that name in the jar. In that + case, use the more explicit set() method instead. + """ + self.set(name, value) + + def __delitem__(self, name): + """Deletes a cookie given a name. Wraps ``cookielib.CookieJar``'s + ``remove_cookie_by_name()``. + """ + remove_cookie_by_name(self, name) + + def set_cookie(self, cookie, *args, **kwargs): + if hasattr(cookie.value, 'startswith') and cookie.value.startswith('"') and cookie.value.endswith('"'): + cookie.value = cookie.value.replace('\\"', '') + return super(RequestsCookieJar, self).set_cookie(cookie, *args, **kwargs) + + def update(self, other): + """Updates this jar with cookies from another CookieJar or dict-like""" + if isinstance(other, cookielib.CookieJar): + for cookie in other: + self.set_cookie(copy.copy(cookie)) + else: + super(RequestsCookieJar, self).update(other) + + def _find(self, name, domain=None, path=None): + """Requests uses this method internally to get cookie values. + + If there are conflicting cookies, _find arbitrarily chooses one. + See _find_no_duplicates if you want an exception thrown if there are + conflicting cookies. + + :param name: a string containing name of cookie + :param domain: (optional) string containing domain of cookie + :param path: (optional) string containing path of cookie + :return: cookie.value + """ + 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: + return cookie.value + + raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path)) + + def _find_no_duplicates(self, name, domain=None, path=None): + """Both ``__get_item__`` and ``get`` call this function: it's never + used elsewhere in Requests. + + :param name: a string containing name of cookie + :param domain: (optional) string containing domain of cookie + :param path: (optional) string containing path of cookie + :raises KeyError: if cookie is not found + :raises CookieConflictError: if there are multiple cookies + that match name and optionally domain and path + :return: cookie.value + """ + 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 is not 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 + + if toReturn: + return toReturn + raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path)) + + def __getstate__(self): + """Unlike a normal CookieJar, this class is pickleable.""" + state = self.__dict__.copy() + # remove the unpickleable RLock object + state.pop('_cookies_lock') + return state + + def __setstate__(self, state): + """Unlike a normal CookieJar, this class is pickleable.""" + self.__dict__.update(state) + if '_cookies_lock' not in self.__dict__: + self._cookies_lock = threading.RLock() + + def copy(self): + """Return a copy of this RequestsCookieJar.""" + new_cj = RequestsCookieJar() + new_cj.set_policy(self.get_policy()) + new_cj.update(self) + return new_cj + + def get_policy(self): + """Return the CookiePolicy instance used.""" + return self._policy + + +def _copy_cookie_jar(jar): + if jar is None: + return None + + if hasattr(jar, 'copy'): + # We're dealing with an instance of RequestsCookieJar + return jar.copy() + # We're dealing with a generic CookieJar instance + new_jar = copy.copy(jar) + new_jar.clear() + for cookie in jar: + new_jar.set_cookie(copy.copy(cookie)) + return new_jar + + +def create_cookie(name, value, **kwargs): + """Make a cookie from underspecified parameters. + + By default, the pair of `name` and `value` will be set for the domain '' + and sent on every request (this is sometimes called a "supercookie"). + """ + result = { + 'version': 0, + 'name': name, + 'value': value, + 'port': None, + 'domain': '', + 'path': '/', + 'secure': False, + 'expires': None, + 'discard': True, + 'comment': None, + 'comment_url': None, + 'rest': {'HttpOnly': None}, + 'rfc2109': False, + } + + badargs = set(kwargs) - set(result) + if badargs: + err = 'create_cookie() got unexpected keyword arguments: %s' + raise TypeError(err % list(badargs)) + + result.update(kwargs) + result['port_specified'] = bool(result['port']) + result['domain_specified'] = bool(result['domain']) + result['domain_initial_dot'] = result['domain'].startswith('.') + result['path_specified'] = bool(result['path']) + + return cookielib.Cookie(**result) + + +def morsel_to_cookie(morsel): + """Convert a Morsel object into a Cookie containing the one k/v pair.""" + + expires = None + if morsel['max-age']: + try: + expires = int(time.time() + int(morsel['max-age'])) + except ValueError: + raise TypeError('max-age: %s must be integer' % morsel['max-age']) + elif morsel['expires']: + time_template = '%a, %d-%b-%Y %H:%M:%S GMT' + expires = calendar.timegm( + time.strptime(morsel['expires'], time_template) + ) + return create_cookie( + comment=morsel['comment'], + comment_url=bool(morsel['comment']), + discard=False, + domain=morsel['domain'], + expires=expires, + name=morsel.key, + path=morsel['path'], + port=None, + rest={'HttpOnly': morsel['httponly']}, + rfc2109=False, + secure=bool(morsel['secure']), + value=morsel.value, + version=morsel['version'] or 0, + ) + + +def cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True): + """Returns a CookieJar from a key/value dictionary. + + :param cookie_dict: Dict of key/values to insert into CookieJar. + :param cookiejar: (optional) A cookiejar to add the cookies to. + :param overwrite: (optional) If False, will not replace cookies + already in the jar with new ones. + :rtype: CookieJar + """ + if cookiejar is None: + cookiejar = RequestsCookieJar() + + if cookie_dict is not None: + names_from_jar = [cookie.name for cookie in cookiejar] + for name in cookie_dict: + if overwrite or (name not in names_from_jar): + cookiejar.set_cookie(create_cookie(name, cookie_dict[name])) + + return cookiejar + + +def merge_cookies(cookiejar, cookies): + """Add cookies to cookiejar and returns a merged CookieJar. + + :param cookiejar: CookieJar object to add the cookies to. + :param cookies: Dictionary or CookieJar object to be added. + :rtype: CookieJar + """ + if not isinstance(cookiejar, cookielib.CookieJar): + raise ValueError('You can only merge into CookieJar') + + if isinstance(cookies, dict): + cookiejar = cookiejar_from_dict( + cookies, cookiejar=cookiejar, overwrite=False) + elif isinstance(cookies, cookielib.CookieJar): + try: + cookiejar.update(cookies) + except AttributeError: + for cookie_in_jar in cookies: + cookiejar.set_cookie(cookie_in_jar) + + return cookiejar diff --git a/openpype/vendor/python/python_2/requests/exceptions.py b/openpype/vendor/python/python_2/requests/exceptions.py new file mode 100644 index 0000000000..79697635a5 --- /dev/null +++ b/openpype/vendor/python/python_2/requests/exceptions.py @@ -0,0 +1,133 @@ +# -*- coding: utf-8 -*- + +""" +requests.exceptions +~~~~~~~~~~~~~~~~~~~ + +This module contains the set of Requests' exceptions. +""" +from urllib3.exceptions import HTTPError as BaseHTTPError + +from .compat import JSONDecodeError as CompatJSONDecodeError + + +class RequestException(IOError): + """There was an ambiguous exception that occurred while handling your + request. + """ + + def __init__(self, *args, **kwargs): + """Initialize RequestException with `request` and `response` objects.""" + response = kwargs.pop('response', None) + self.response = response + self.request = kwargs.pop('request', None) + if (response is not None and not self.request and + hasattr(response, 'request')): + self.request = self.response.request + super(RequestException, self).__init__(*args, **kwargs) + + +class InvalidJSONError(RequestException): + """A JSON error occurred.""" + + +class JSONDecodeError(InvalidJSONError, CompatJSONDecodeError): + """Couldn't decode the text into json""" + + +class HTTPError(RequestException): + """An HTTP error occurred.""" + + +class ConnectionError(RequestException): + """A Connection error occurred.""" + + +class ProxyError(ConnectionError): + """A proxy error occurred.""" + + +class SSLError(ConnectionError): + """An SSL error occurred.""" + + +class Timeout(RequestException): + """The request timed out. + + Catching this error will catch both + :exc:`~requests.exceptions.ConnectTimeout` and + :exc:`~requests.exceptions.ReadTimeout` errors. + """ + + +class ConnectTimeout(ConnectionError, Timeout): + """The request timed out while trying to connect to the remote server. + + Requests that produced this error are safe to retry. + """ + + +class ReadTimeout(Timeout): + """The server did not send any data in the allotted amount of time.""" + + +class URLRequired(RequestException): + """A valid URL is required to make a request.""" + + +class TooManyRedirects(RequestException): + """Too many redirects.""" + + +class MissingSchema(RequestException, ValueError): + """The URL scheme (e.g. http or https) is missing.""" + + +class InvalidSchema(RequestException, ValueError): + """The URL scheme provided is either invalid or unsupported.""" + + +class InvalidURL(RequestException, ValueError): + """The URL provided was somehow invalid.""" + + +class InvalidHeader(RequestException, ValueError): + """The header value provided was somehow invalid.""" + + +class InvalidProxyURL(InvalidURL): + """The proxy URL provided is invalid.""" + + +class ChunkedEncodingError(RequestException): + """The server declared chunked encoding but sent an invalid chunk.""" + + +class ContentDecodingError(RequestException, BaseHTTPError): + """Failed to decode response content.""" + + +class StreamConsumedError(RequestException, TypeError): + """The content for this response was already consumed.""" + + +class RetryError(RequestException): + """Custom retries logic failed""" + + +class UnrewindableBodyError(RequestException): + """Requests encountered an error when trying to rewind a body.""" + +# Warnings + + +class RequestsWarning(Warning): + """Base warning for Requests.""" + + +class FileModeWarning(RequestsWarning, DeprecationWarning): + """A file was opened in text mode, but Requests determined its binary length.""" + + +class RequestsDependencyWarning(RequestsWarning): + """An imported dependency doesn't match the expected version range.""" diff --git a/openpype/vendor/python/python_2/requests/help.py b/openpype/vendor/python/python_2/requests/help.py new file mode 100644 index 0000000000..4cd6389f55 --- /dev/null +++ b/openpype/vendor/python/python_2/requests/help.py @@ -0,0 +1,135 @@ +"""Module containing bug report helper(s).""" +from __future__ import print_function + +import json +import platform +import sys +import ssl + +import idna +import urllib3 + +from . import __version__ as requests_version + +try: + import charset_normalizer +except ImportError: + charset_normalizer = None + +try: + import chardet +except ImportError: + chardet = None + +try: + from urllib3.contrib import pyopenssl +except ImportError: + pyopenssl = None + OpenSSL = None + cryptography = None +else: + import OpenSSL + import cryptography + + +def _implementation(): + """Return a dict with the Python implementation and version. + + Provide both the name and the version of the Python implementation + currently running. For example, on CPython 2.7.5 it will return + {'name': 'CPython', 'version': '2.7.5'}. + + This function works best on CPython and PyPy: in particular, it probably + doesn't work for Jython or IronPython. Future investigation should be done + to work out the correct shape of the code for those platforms. + """ + 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 {'name': implementation, 'version': implementation_version} + + +def info(): + """Generate information for a bug report.""" + try: + platform_info = { + 'system': platform.system(), + 'release': platform.release(), + } + except IOError: + platform_info = { + 'system': 'Unknown', + 'release': 'Unknown', + } + + implementation_info = _implementation() + urllib3_info = {'version': urllib3.__version__} + charset_normalizer_info = {'version': None} + chardet_info = {'version': None} + if charset_normalizer: + charset_normalizer_info = {'version': charset_normalizer.__version__} + if chardet: + chardet_info = {'version': chardet.__version__} + + pyopenssl_info = { + 'version': None, + 'openssl_version': '', + } + if OpenSSL: + pyopenssl_info = { + 'version': OpenSSL.__version__, + 'openssl_version': '%x' % OpenSSL.SSL.OPENSSL_VERSION_NUMBER, + } + cryptography_info = { + 'version': getattr(cryptography, '__version__', ''), + } + idna_info = { + 'version': getattr(idna, '__version__', ''), + } + + system_ssl = ssl.OPENSSL_VERSION_NUMBER + system_ssl_info = { + 'version': '%x' % system_ssl if system_ssl is not None else '' + } + + return { + 'platform': platform_info, + 'implementation': implementation_info, + 'system_ssl': system_ssl_info, + 'using_pyopenssl': pyopenssl is not None, + 'using_charset_normalizer': chardet is None, + 'pyOpenSSL': pyopenssl_info, + 'urllib3': urllib3_info, + 'chardet': chardet_info, + 'charset_normalizer': charset_normalizer_info, + 'cryptography': cryptography_info, + 'idna': idna_info, + 'requests': { + 'version': requests_version, + }, + } + + +def main(): + """Pretty-print the bug information as JSON.""" + print(json.dumps(info(), sort_keys=True, indent=2)) + + +if __name__ == '__main__': + main() diff --git a/openpype/vendor/python/python_2/requests/hooks.py b/openpype/vendor/python/python_2/requests/hooks.py new file mode 100644 index 0000000000..7a51f212c8 --- /dev/null +++ b/openpype/vendor/python/python_2/requests/hooks.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +""" +requests.hooks +~~~~~~~~~~~~~~ + +This module provides the capabilities for the Requests hooks system. + +Available hooks: + +``response``: + The response generated from a Request. +""" +HOOKS = ['response'] + + +def default_hooks(): + return {event: [] for event in HOOKS} + +# TODO: response is the only one + + +def dispatch_hook(key, hooks, hook_data, **kwargs): + """Dispatches a hook dictionary on a given piece of data.""" + hooks = hooks or {} + hooks = hooks.get(key) + if hooks: + if hasattr(hooks, '__call__'): + hooks = [hooks] + for hook in hooks: + _hook_data = hook(hook_data, **kwargs) + if _hook_data is not None: + hook_data = _hook_data + return hook_data diff --git a/openpype/vendor/python/python_2/requests/models.py b/openpype/vendor/python/python_2/requests/models.py new file mode 100644 index 0000000000..dfbea854f9 --- /dev/null +++ b/openpype/vendor/python/python_2/requests/models.py @@ -0,0 +1,973 @@ +# -*- coding: utf-8 -*- + +""" +requests.models +~~~~~~~~~~~~~~~ + +This module contains the primary objects that power Requests. +""" + +import datetime +import sys + +# Import encoding now, to avoid implicit import later. +# Implicit import within threads may cause LookupError when standard library is in a ZIP, +# such as in Embedded Python. See https://github.com/psf/requests/issues/3578. +import encodings.idna + +from urllib3.fields import RequestField +from urllib3.filepost import encode_multipart_formdata +from urllib3.util import parse_url +from urllib3.exceptions import ( + DecodeError, ReadTimeoutError, ProtocolError, LocationParseError) + +from io import UnsupportedOperation +from .hooks import default_hooks +from .structures import CaseInsensitiveDict + +from .auth import HTTPBasicAuth +from .cookies import cookiejar_from_dict, get_cookie_header, _copy_cookie_jar +from .exceptions import ( + HTTPError, MissingSchema, InvalidURL, ChunkedEncodingError, + ContentDecodingError, ConnectionError, StreamConsumedError, + InvalidJSONError) +from .exceptions import JSONDecodeError as RequestsJSONDecodeError +from ._internal_utils import to_native_string, unicode_is_ascii +from .utils import ( + guess_filename, get_auth_from_url, requote_uri, + stream_decode_response_unicode, to_key_val_list, parse_header_links, + iter_slices, guess_json_utf, super_len, check_header_validity) +from .compat import ( + Callable, Mapping, + cookielib, urlunparse, urlsplit, urlencode, str, bytes, + is_py2, chardet, builtin_str, basestring, JSONDecodeError) +from .compat import json as complexjson +from .status_codes import codes + +#: The set of HTTP status codes that indicate an automatically +#: processable redirect. +REDIRECT_STATI = ( + codes.moved, # 301 + codes.found, # 302 + codes.other, # 303 + codes.temporary_redirect, # 307 + codes.permanent_redirect, # 308 +) + +DEFAULT_REDIRECT_LIMIT = 30 +CONTENT_CHUNK_SIZE = 10 * 1024 +ITER_CHUNK_SIZE = 512 + + +class RequestEncodingMixin(object): + @property + def path_url(self): + """Build the path URL to use.""" + + url = [] + + p = urlsplit(self.url) + + path = p.path + if not path: + path = '/' + + url.append(path) + + query = p.query + if query: + url.append('?') + url.append(query) + + return ''.join(url) + + @staticmethod + def _encode_params(data): + """Encode parameters in a piece of data. + + Will successfully encode parameters when passed as a dict or a list of + 2-tuples. Order is retained if data is a list of 2-tuples but arbitrary + if parameters are supplied as a dict. + """ + + if isinstance(data, (str, bytes)): + return data + elif hasattr(data, 'read'): + return data + elif hasattr(data, '__iter__'): + result = [] + for k, vs in to_key_val_list(data): + if isinstance(vs, basestring) or not hasattr(vs, '__iter__'): + vs = [vs] + for v in vs: + 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 + + @staticmethod + def _encode_files(files, data): + """Build the body for a multipart/form-data request. + + Will successfully encode files when passed as a dict or a list of + tuples. Order is retained if data is a list of tuples but arbitrary + if parameters are supplied as a dict. + The tuples may be 2-tuples (filename, fileobj), 3-tuples (filename, fileobj, contentype) + or 4-tuples (filename, fileobj, contentype, custom_headers). + """ + if (not files): + raise ValueError("Files must be provided.") + elif isinstance(data, basestring): + raise ValueError("Data must not be a string.") + + new_fields = [] + fields = to_key_val_list(data or {}) + files = to_key_val_list(files or {}) + + for field, val in fields: + if isinstance(val, basestring) or not hasattr(val, '__iter__'): + val = [val] + for v in val: + if v is not None: + # Don't call str() on bytestrings: in Py3 it all goes wrong. + if not isinstance(v, bytes): + v = str(v) + + new_fields.append( + (field.decode('utf-8') if isinstance(field, bytes) else field, + v.encode('utf-8') if isinstance(v, str) else v)) + + for (k, v) in files: + # support for explicit filename + ft = None + fh = None + if isinstance(v, (tuple, list)): + if len(v) == 2: + fn, fp = v + elif len(v) == 3: + fn, fp, ft = v + else: + fn, fp, ft, fh = v + else: + fn = guess_filename(v) or k + fp = v + + if isinstance(fp, (str, bytes, bytearray)): + fdata = fp + elif hasattr(fp, 'read'): + fdata = fp.read() + elif fp is None: + continue + else: + fdata = fp + + rf = RequestField(name=k, data=fdata, filename=fn, headers=fh) + rf.make_multipart(content_type=ft) + new_fields.append(rf) + + body, content_type = encode_multipart_formdata(new_fields) + + return body, content_type + + +class RequestHooksMixin(object): + def register_hook(self, event, hook): + """Properly register a hook.""" + + if event not in self.hooks: + raise ValueError('Unsupported event specified, with event name "%s"' % (event)) + + if isinstance(hook, Callable): + self.hooks[event].append(hook) + elif hasattr(hook, '__iter__'): + self.hooks[event].extend(h for h in hook if isinstance(h, Callable)) + + def deregister_hook(self, event, hook): + """Deregister a previously registered hook. + Returns True if the hook existed, False if not. + """ + + try: + self.hooks[event].remove(hook) + return True + except ValueError: + return False + + +class Request(RequestHooksMixin): + """A user-created :class:`Request ` object. + + Used to prepare a :class:`PreparedRequest `, which is sent to the server. + + :param method: HTTP method to use. + :param url: URL to send. + :param headers: dictionary of headers to send. + :param files: dictionary of {filename: fileobject} files to multipart upload. + :param data: the body to attach to the request. If a dictionary or + list of tuples ``[(key, value)]`` is provided, form-encoding will + take place. + :param json: json for the body to attach to the request (if files or data is not specified). + :param params: URL parameters to append to the URL. If a dictionary or + list of tuples ``[(key, value)]`` is provided, form-encoding will + take place. + :param auth: Auth handler or (user, pass) tuple. + :param cookies: dictionary or CookieJar of cookies to attach to this request. + :param hooks: dictionary of callback hooks, for internal usage. + + Usage:: + + >>> import requests + >>> req = requests.Request('GET', 'https://httpbin.org/get') + >>> req.prepare() + + """ + + def __init__(self, + method=None, url=None, headers=None, files=None, data=None, + params=None, auth=None, cookies=None, hooks=None, json=None): + + # Default empty dicts for dict params. + 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 + + self.hooks = default_hooks() + for (k, v) in list(hooks.items()): + self.register_hook(event=k, hook=v) + + self.method = method + self.url = url + self.headers = headers + self.files = files + self.data = data + self.json = json + self.params = params + self.auth = auth + self.cookies = cookies + + def __repr__(self): + return '' % (self.method) + + def prepare(self): + """Constructs a :class:`PreparedRequest ` for transmission and returns it.""" + p = PreparedRequest() + p.prepare( + method=self.method, + url=self.url, + headers=self.headers, + files=self.files, + data=self.data, + json=self.json, + params=self.params, + auth=self.auth, + cookies=self.cookies, + hooks=self.hooks, + ) + return p + + +class PreparedRequest(RequestEncodingMixin, RequestHooksMixin): + """The fully mutable :class:`PreparedRequest ` object, + containing the exact bytes that will be sent to the server. + + Instances are generated from a :class:`Request ` object, and + should not be instantiated manually; doing so may produce undesirable + effects. + + Usage:: + + >>> import requests + >>> req = requests.Request('GET', 'https://httpbin.org/get') + >>> r = req.prepare() + >>> r + + + >>> s = requests.Session() + >>> s.send(r) + + """ + + def __init__(self): + #: HTTP verb to send to the server. + self.method = None + #: HTTP URL to send the request to. + self.url = None + #: dictionary of HTTP headers. + self.headers = None + # The `CookieJar` used to create the Cookie header will be stored here + # after prepare_cookies is called + self._cookies = None + #: request body to send to the server. + self.body = None + #: dictionary of callback hooks, for internal usage. + self.hooks = default_hooks() + #: integer denoting starting position of a readable file-like body. + self._body_position = None + + def prepare(self, + method=None, url=None, headers=None, files=None, data=None, + params=None, auth=None, cookies=None, hooks=None, json=None): + """Prepares the entire request with the given parameters.""" + + self.prepare_method(method) + self.prepare_url(url, params) + self.prepare_headers(headers) + self.prepare_cookies(cookies) + self.prepare_body(data, files, json) + self.prepare_auth(auth, url) + + # Note that prepare_auth must be last to enable authentication schemes + # such as OAuth to work on a fully prepared request. + + # This MUST go after prepare_auth. Authenticators could add a hook + self.prepare_hooks(hooks) + + def __repr__(self): + return '' % (self.method) + + def copy(self): + p = PreparedRequest() + p.method = self.method + p.url = self.url + p.headers = self.headers.copy() if self.headers is not None else None + p._cookies = _copy_cookie_jar(self._cookies) + p.body = self.body + p.hooks = self.hooks + p._body_position = self._body_position + return p + + def prepare_method(self, method): + """Prepares the given HTTP method.""" + self.method = method + if self.method is not None: + self.method = to_native_string(self.method.upper()) + + @staticmethod + def _get_idna_encoded_host(host): + import idna + + try: + host = idna.encode(host, uts46=True).decode('utf-8') + except idna.IDNAError: + raise UnicodeError + return host + + def prepare_url(self, url, params): + """Prepares the given HTTP URL.""" + #: Accept objects that have string representations. + #: We're unable to blindly call unicode/str functions + #: as this will include the bytestring indicator (b'') + #: on python 3.x. + #: https://github.com/psf/requests/pull/2238 + if isinstance(url, bytes): + url = url.decode('utf8') + else: + url = unicode(url) if is_py2 else str(url) + + # Remove leading whitespaces from url + url = url.lstrip() + + # Don't do any URL preparation for non-HTTP schemes like `mailto`, + # `data` etc to work around exceptions from `url_parse`, which + # handles RFC 3986 only. + if ':' in url and not url.lower().startswith('http'): + self.url = url + return + + # Support for unicode domain names and paths. + try: + scheme, auth, host, port, path, query, fragment = parse_url(url) + except LocationParseError as e: + raise InvalidURL(*e.args) + + if not scheme: + error = ("Invalid URL {0!r}: No scheme supplied. Perhaps you meant http://{0}?") + error = error.format(to_native_string(url, 'utf8')) + + raise MissingSchema(error) + + if not host: + raise InvalidURL("Invalid URL %r: No host supplied" % url) + + # In general, we want to try IDNA encoding the hostname if the string contains + # non-ASCII characters. This allows users to automatically get the correct IDNA + # behaviour. For strings containing only ASCII characters, we need to also verify + # it doesn't start with a wildcard (*), before allowing the unencoded hostname. + if not unicode_is_ascii(host): + try: + host = self._get_idna_encoded_host(host) + except UnicodeError: + raise InvalidURL('URL has an invalid label.') + elif host.startswith((u'*', u'.')): + raise InvalidURL('URL has an invalid label.') + + # Carefully reconstruct the network location + netloc = auth or '' + if netloc: + netloc += '@' + netloc += host + if port: + netloc += ':' + str(port) + + # Bare domains aren't valid URLs. + if not path: + path = '/' + + if is_py2: + if isinstance(scheme, str): + scheme = scheme.encode('utf-8') + if isinstance(netloc, str): + netloc = netloc.encode('utf-8') + if isinstance(path, str): + path = path.encode('utf-8') + if isinstance(query, str): + query = query.encode('utf-8') + if isinstance(fragment, str): + fragment = fragment.encode('utf-8') + + if isinstance(params, (str, bytes)): + params = to_native_string(params) + + enc_params = self._encode_params(params) + if enc_params: + if query: + query = '%s&%s' % (query, enc_params) + else: + query = enc_params + + url = requote_uri(urlunparse([scheme, netloc, path, None, query, fragment])) + self.url = url + + def prepare_headers(self, headers): + """Prepares the given HTTP headers.""" + + self.headers = CaseInsensitiveDict() + if headers: + for header in headers.items(): + # Raise exception on invalid header value. + check_header_validity(header) + name, value = header + self.headers[to_native_string(name)] = value + + def prepare_body(self, data, files, json=None): + """Prepares the given HTTP body data.""" + + # Check if file, fo, generator, iterator. + # If not, run through normal process. + + # Nottin' on you. + body = None + content_type = None + + if not data and json is not None: + # urllib3 requires a bytes-like body. Python 2's json.dumps + # provides this natively, but Python 3 gives a Unicode string. + content_type = 'application/json' + + try: + body = complexjson.dumps(json, allow_nan=False) + except ValueError as ve: + raise InvalidJSONError(ve, request=self) + + if not isinstance(body, bytes): + body = body.encode('utf-8') + + is_stream = all([ + hasattr(data, '__iter__'), + not isinstance(data, (basestring, list, tuple, Mapping)) + ]) + + if is_stream: + try: + length = super_len(data) + except (TypeError, AttributeError, UnsupportedOperation): + length = None + + body = data + + if getattr(body, 'tell', None) is not None: + # Record the current file position before reading. + # This will allow us to rewind a file in the event + # of a redirect. + try: + self._body_position = body.tell() + except (IOError, OSError): + # This differentiates from None, allowing us to catch + # a failed `tell()` later when trying to rewind the body + self._body_position = object() + + if files: + raise NotImplementedError('Streamed bodies and files are mutually exclusive.') + + if length: + self.headers['Content-Length'] = builtin_str(length) + else: + self.headers['Transfer-Encoding'] = 'chunked' + else: + # Multi-part file uploads. + if files: + (body, content_type) = self._encode_files(files, data) + else: + if data: + body = self._encode_params(data) + if isinstance(data, basestring) or hasattr(data, 'read'): + content_type = None + else: + content_type = 'application/x-www-form-urlencoded' + + self.prepare_content_length(body) + + # Add content-type if it wasn't explicitly provided. + if content_type and ('content-type' not in self.headers): + self.headers['Content-Type'] = content_type + + self.body = body + + def prepare_content_length(self, body): + """Prepare Content-Length header based on request method and body""" + if body is not None: + length = super_len(body) + if length: + # If length exists, set it. Otherwise, we fallback + # to Transfer-Encoding: chunked. + self.headers['Content-Length'] = builtin_str(length) + elif self.method not in ('GET', 'HEAD') and self.headers.get('Content-Length') is None: + # Set Content-Length to 0 for methods that can have a body + # but don't provide one. (i.e. not GET or HEAD) + self.headers['Content-Length'] = '0' + + def prepare_auth(self, auth, url=''): + """Prepares the given HTTP auth data.""" + + # If no Auth is explicitly provided, extract it from the URL first. + if auth is None: + url_auth = get_auth_from_url(self.url) + auth = url_auth if any(url_auth) else None + + if auth: + if isinstance(auth, tuple) and len(auth) == 2: + # special-case basic HTTP auth + auth = HTTPBasicAuth(*auth) + + # Allow auth to make its changes. + r = auth(self) + + # Update self to reflect the auth changes. + self.__dict__.update(r.__dict__) + + # Recompute Content-Length + self.prepare_content_length(self.body) + + def prepare_cookies(self, cookies): + """Prepares the given HTTP cookie data. + + This function eventually generates a ``Cookie`` header from the + given cookies using cookielib. Due to cookielib's design, the header + will not be regenerated if it already exists, meaning this function + can only be called once for the life of the + :class:`PreparedRequest ` object. Any subsequent calls + to ``prepare_cookies`` will have no actual effect, unless the "Cookie" + header is removed beforehand. + """ + if isinstance(cookies, cookielib.CookieJar): + self._cookies = cookies + else: + self._cookies = cookiejar_from_dict(cookies) + + cookie_header = get_cookie_header(self._cookies, self) + if cookie_header is not None: + self.headers['Cookie'] = cookie_header + + def prepare_hooks(self, hooks): + """Prepares the given hooks.""" + # hooks can be passed as None to the prepare method and to this + # method. To prevent iterating over None, simply use an empty list + # if hooks is False-y + hooks = hooks or [] + for event in hooks: + self.register_hook(event, hooks[event]) + + +class Response(object): + """The :class:`Response ` object, which contains a + server's response to an HTTP request. + """ + + __attrs__ = [ + '_content', 'status_code', 'headers', 'url', 'history', + 'encoding', 'reason', 'cookies', 'elapsed', 'request' + ] + + def __init__(self): + self._content = False + self._content_consumed = False + self._next = None + + #: Integer Code of responded HTTP Status, e.g. 404 or 200. + self.status_code = None + + #: Case-insensitive Dictionary of Response Headers. + #: For example, ``headers['content-encoding']`` will return the + #: value of a ``'Content-Encoding'`` response header. + self.headers = CaseInsensitiveDict() + + #: File-like object representation of response (for advanced usage). + #: Use of ``raw`` requires that ``stream=True`` be set on the request. + #: This requirement does not apply for use internally to Requests. + self.raw = None + + #: Final URL location of Response. + self.url = None + + #: Encoding to decode with when accessing r.text. + self.encoding = None + + #: A list of :class:`Response ` objects from + #: the history of the Request. Any redirect responses will end + #: up here. The list is sorted from the oldest to the most recent request. + self.history = [] + + #: Textual reason of responded HTTP Status, e.g. "Not Found" or "OK". + self.reason = None + + #: A CookieJar of Cookies the server sent back. + self.cookies = cookiejar_from_dict({}) + + #: The amount of time elapsed between sending the request + #: and the arrival of the response (as a timedelta). + #: This property specifically measures the time taken between sending + #: the first byte of the request and finishing parsing the headers. It + #: is therefore unaffected by consuming the response content or the + #: value of the ``stream`` keyword argument. + self.elapsed = datetime.timedelta(0) + + #: The :class:`PreparedRequest ` object to which this + #: is a response. + self.request = None + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + def __getstate__(self): + # Consume everything; accessing the content attribute makes + # sure the content has been fully read. + if not self._content_consumed: + self.content + + return {attr: getattr(self, attr, None) for attr in self.__attrs__} + + def __setstate__(self, state): + for name, value in state.items(): + setattr(self, name, value) + + # pickled objects do not have .raw + setattr(self, '_content_consumed', True) + setattr(self, 'raw', None) + + def __repr__(self): + return '' % (self.status_code) + + def __bool__(self): + """Returns True if :attr:`status_code` is less than 400. + + This attribute checks if the status code of the response is between + 400 and 600 to see if there was a client error or a server error. If + the status code, is between 200 and 400, this will return True. This + is **not** a check to see if the response code is ``200 OK``. + """ + return self.ok + + def __nonzero__(self): + """Returns True if :attr:`status_code` is less than 400. + + This attribute checks if the status code of the response is between + 400 and 600 to see if there was a client error or a server error. If + the status code, is between 200 and 400, this will return True. This + is **not** a check to see if the response code is ``200 OK``. + """ + return self.ok + + def __iter__(self): + """Allows you to use a response as an iterator.""" + return self.iter_content(128) + + @property + def ok(self): + """Returns True if :attr:`status_code` is less than 400, False if not. + + This attribute checks if the status code of the response is between + 400 and 600 to see if there was a client error or a server error. If + the status code is between 200 and 400, this will return True. This + is **not** a check to see if the response code is ``200 OK``. + """ + try: + self.raise_for_status() + except HTTPError: + return False + return True + + @property + def is_redirect(self): + """True if this Response is a well-formed HTTP redirect that could have + been processed automatically (by :meth:`Session.resolve_redirects`). + """ + return ('location' in self.headers and self.status_code in REDIRECT_STATI) + + @property + def is_permanent_redirect(self): + """True if this Response one of the permanent versions of redirect.""" + return ('location' in self.headers and self.status_code in (codes.moved_permanently, codes.permanent_redirect)) + + @property + def next(self): + """Returns a PreparedRequest for the next request in a redirect chain, if there is one.""" + return self._next + + @property + def apparent_encoding(self): + """The apparent encoding, provided by the charset_normalizer or chardet libraries.""" + return chardet.detect(self.content)['encoding'] + + def iter_content(self, chunk_size=1, decode_unicode=False): + """Iterates over the response data. When stream=True is set on the + request, this avoids reading the content at once into memory for + large responses. The chunk size is the number of bytes it should + read into memory. This is not necessarily the length of each item + returned as decoding can take place. + + chunk_size must be of type int or None. A value of None will + function differently depending on the value of `stream`. + stream=True will read data as it arrives in whatever size the + chunks are received. If stream=False, data is returned as + a single chunk. + + If decode_unicode is True, content will be decoded using the best + available encoding based on the response. + """ + + def generate(): + # Special case for urllib3. + if hasattr(self.raw, 'stream'): + try: + for chunk in self.raw.stream(chunk_size, decode_content=True): + yield chunk + except ProtocolError as e: + raise ChunkedEncodingError(e) + except DecodeError as e: + raise ContentDecodingError(e) + except ReadTimeoutError as e: + raise ConnectionError(e) + else: + # Standard file-like object. + while True: + chunk = self.raw.read(chunk_size) + if not chunk: + break + yield chunk + + self._content_consumed = True + + if self._content_consumed and isinstance(self._content, bool): + raise StreamConsumedError() + elif chunk_size is not None and not isinstance(chunk_size, int): + raise TypeError("chunk_size must be an int, it is instead a %s." % type(chunk_size)) + # simulate reading small chunks of the content + reused_chunks = iter_slices(self._content, chunk_size) + + stream_chunks = generate() + + chunks = reused_chunks if self._content_consumed else stream_chunks + + if decode_unicode: + chunks = stream_decode_response_unicode(chunks, self) + + return chunks + + def iter_lines(self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=False, delimiter=None): + """Iterates over the response data, one line at a time. When + stream=True is set on the request, this avoids reading the + content at once into memory for large responses. + + .. note:: This method is not reentrant safe. + """ + + pending = None + + for chunk in self.iter_content(chunk_size=chunk_size, decode_unicode=decode_unicode): + + if pending is not None: + chunk = pending + chunk + + if delimiter: + lines = chunk.split(delimiter) + else: + lines = chunk.splitlines() + + if lines and lines[-1] and chunk and lines[-1][-1] == chunk[-1]: + pending = lines.pop() + else: + pending = None + + for line in lines: + yield line + + if pending is not None: + yield pending + + @property + def content(self): + """Content of the response, in bytes.""" + + if self._content is False: + # Read the contents. + if self._content_consumed: + raise RuntimeError( + 'The content for this response was already consumed') + + if self.status_code == 0 or self.raw is None: + self._content = None + else: + self._content = b''.join(self.iter_content(CONTENT_CHUNK_SIZE)) or b'' + + 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 + def text(self): + """Content of the response, in unicode. + + If Response.encoding is None, encoding will be guessed using + ``charset_normalizer`` or ``chardet``. + + The encoding of the response content is determined based solely on HTTP + headers, following RFC 2616 to the letter. If you can take advantage of + non-HTTP knowledge to make a better guess at the encoding, you should + set ``r.encoding`` appropriately before accessing this property. + """ + + # Try charset from content-type + content = None + encoding = self.encoding + + if not self.content: + return str('') + + # Fallback to auto-detected encoding. + if self.encoding is None: + encoding = self.apparent_encoding + + # Decode unicode from given encoding. + try: + content = str(self.content, encoding, errors='replace') + 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') + + return content + + def json(self, **kwargs): + r"""Returns the json-encoded content of a response, if any. + + :param \*\*kwargs: Optional arguments that ``json.loads`` takes. + :raises requests.exceptions.JSONDecodeError: If the response body does not + contain valid json. + """ + + if not self.encoding and self.content and len(self.content) > 3: + # No encoding set. JSON RFC 4627 section 3 states we should expect + # UTF-8, -16 or -32. Detect which one to use; If the detection or + # decoding fails, fall back to `self.text` (using charset_normalizer to make + # a best guess). + encoding = guess_json_utf(self.content) + if encoding is not None: + try: + return complexjson.loads( + self.content.decode(encoding), **kwargs + ) + except UnicodeDecodeError: + # Wrong UTF codec detected; usually because it's not UTF-8 + # but some other 8-bit codec. This is an RFC violation, + # and the server didn't bother to tell us what codec *was* + # used. + pass + + try: + return complexjson.loads(self.text, **kwargs) + except JSONDecodeError as e: + # Catch JSON-related errors and raise as requests.JSONDecodeError + # This aliases json.JSONDecodeError and simplejson.JSONDecodeError + if is_py2: # e is a ValueError + raise RequestsJSONDecodeError(e.message) + else: + raise RequestsJSONDecodeError(e.msg, e.doc, e.pos) + + @property + def links(self): + """Returns the parsed header links of the response, if any.""" + + header = self.headers.get('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 + + def raise_for_status(self): + """Raises :class:`HTTPError`, if one occurred.""" + + http_error_msg = '' + if isinstance(self.reason, bytes): + # We attempt to decode utf-8 first because some servers + # choose to localize their reason strings. If the string + # isn't utf-8, we fall back to iso-8859-1 for all other + # encodings. (See PR #3538) + try: + reason = self.reason.decode('utf-8') + except UnicodeDecodeError: + reason = self.reason.decode('iso-8859-1') + else: + reason = self.reason + + if 400 <= self.status_code < 500: + http_error_msg = u'%s Client Error: %s for url: %s' % (self.status_code, reason, self.url) + + elif 500 <= self.status_code < 600: + http_error_msg = u'%s Server Error: %s for url: %s' % (self.status_code, reason, self.url) + + if http_error_msg: + raise HTTPError(http_error_msg, response=self) + + def close(self): + """Releases the connection back to the pool. Once this method has been + called the underlying ``raw`` object must not be accessed again. + + *Note: Should not normally need to be called explicitly.* + """ + if not self._content_consumed: + self.raw.close() + + release_conn = getattr(self.raw, 'release_conn', None) + if release_conn is not None: + release_conn() diff --git a/openpype/vendor/python/python_2/requests/packages.py b/openpype/vendor/python/python_2/requests/packages.py new file mode 100644 index 0000000000..00196bff25 --- /dev/null +++ b/openpype/vendor/python/python_2/requests/packages.py @@ -0,0 +1,26 @@ +import sys + +try: + import chardet +except ImportError: + import charset_normalizer as chardet + import warnings + + warnings.filterwarnings('ignore', 'Trying to detect', module='charset_normalizer') + +# This code exists for backwards compatibility reasons. +# I don't like it either. Just look the other way. :) + +for package in ('urllib3', 'idna'): + locals()[package] = __import__(package) + # This traversal is apparently necessary such that the identities are + # preserved (requests.packages.urllib3.* is urllib3.*) + for mod in list(sys.modules): + if mod == package or mod.startswith(package + '.'): + sys.modules['requests.packages.' + mod] = sys.modules[mod] + +target = chardet.__name__ +for mod in list(sys.modules): + if mod == target or mod.startswith(target + '.'): + sys.modules['requests.packages.' + target.replace(target, 'chardet')] = sys.modules[mod] +# Kinda cool, though, right? diff --git a/openpype/vendor/python/python_2/requests/sessions.py b/openpype/vendor/python/python_2/requests/sessions.py new file mode 100644 index 0000000000..3f59cab922 --- /dev/null +++ b/openpype/vendor/python/python_2/requests/sessions.py @@ -0,0 +1,771 @@ +# -*- coding: utf-8 -*- + +""" +requests.sessions +~~~~~~~~~~~~~~~~~ + +This module provides a Session object to manage and persist settings across +requests (cookies, auth, proxies). +""" +import os +import sys +import time +from datetime import timedelta +from collections import OrderedDict + +from .auth import _basic_auth_str +from .compat import cookielib, is_py3, urljoin, urlparse, Mapping +from .cookies import ( + cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies) +from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT +from .hooks import default_hooks, dispatch_hook +from ._internal_utils import to_native_string +from .utils import to_key_val_list, default_headers, DEFAULT_PORTS +from .exceptions import ( + TooManyRedirects, InvalidSchema, ChunkedEncodingError, ContentDecodingError) + +from .structures import CaseInsensitiveDict +from .adapters import HTTPAdapter + +from .utils import ( + requote_uri, get_environ_proxies, get_netrc_auth, should_bypass_proxies, + get_auth_from_url, rewind_body, resolve_proxies +) + +from .status_codes import codes + +# formerly defined here, reexposed here for backward compatibility +from .models import REDIRECT_STATI + +# Preferred clock, based on which one is more accurate on a given system. +if sys.platform == 'win32': + try: # Python 3.4+ + preferred_clock = time.perf_counter + except AttributeError: # Earlier than Python 3. + preferred_clock = time.clock +else: + preferred_clock = time.time + + +def merge_setting(request_setting, session_setting, dict_class=OrderedDict): + """Determines appropriate setting for a given request, taking into account + the explicit setting on that request, and the setting in the session. If a + setting is a dictionary, they will be merged together using `dict_class` + """ + + if session_setting is None: + return request_setting + + if request_setting is None: + return session_setting + + # Bypass if not a dictionary (e.g. verify) + if not ( + isinstance(session_setting, Mapping) and + isinstance(request_setting, Mapping) + ): + return request_setting + + merged_setting = dict_class(to_key_val_list(session_setting)) + merged_setting.update(to_key_val_list(request_setting)) + + # Remove keys that are set to None. Extract keys first to avoid altering + # the dictionary during iteration. + none_keys = [k for (k, v) in merged_setting.items() if v is None] + for key in none_keys: + del merged_setting[key] + + return merged_setting + + +def merge_hooks(request_hooks, session_hooks, dict_class=OrderedDict): + """Properly merges both requests and session hooks. + + This is necessary because when request_hooks == {'response': []}, the + merge breaks Session hooks entirely. + """ + if session_hooks is None or session_hooks.get('response') == []: + return request_hooks + + if request_hooks is None or request_hooks.get('response') == []: + return session_hooks + + return merge_setting(request_hooks, session_hooks, dict_class) + + +class SessionRedirectMixin(object): + + def get_redirect_target(self, resp): + """Receives a Response. Returns a redirect URI or ``None``""" + # Due to the nature of how requests processes redirects this method will + # be called at least once upon the original response and at least twice + # on each subsequent redirect response (if any). + # If a custom mixin is used to handle this logic, it may be advantageous + # to cache the redirect location onto the response object as a private + # attribute. + if resp.is_redirect: + location = resp.headers['location'] + # Currently the underlying http module on py3 decode headers + # in latin1, but empirical evidence suggests that latin1 is very + # rarely used with non-ASCII characters in HTTP headers. + # It is more likely to get UTF8 header rather than latin1. + # This causes incorrect handling of UTF8 encoded location headers. + # To solve this, we re-encode the location in latin1. + if is_py3: + location = location.encode('latin1') + return to_native_string(location, 'utf8') + return None + + def should_strip_auth(self, old_url, new_url): + """Decide whether Authorization header should be removed when redirecting""" + old_parsed = urlparse(old_url) + new_parsed = urlparse(new_url) + if old_parsed.hostname != new_parsed.hostname: + return True + # Special case: allow http -> https redirect when using the standard + # ports. This isn't specified by RFC 7235, but is kept to avoid + # breaking backwards compatibility with older versions of requests + # that allowed any redirects on the same host. + if (old_parsed.scheme == 'http' and old_parsed.port in (80, None) + and new_parsed.scheme == 'https' and new_parsed.port in (443, None)): + return False + + # Handle default port usage corresponding to scheme. + changed_port = old_parsed.port != new_parsed.port + changed_scheme = old_parsed.scheme != new_parsed.scheme + default_port = (DEFAULT_PORTS.get(old_parsed.scheme, None), None) + if (not changed_scheme and old_parsed.port in default_port + and new_parsed.port in default_port): + return False + + # Standard case: root URI must match + return changed_port or changed_scheme + + def resolve_redirects(self, resp, req, stream=False, timeout=None, + verify=True, cert=None, proxies=None, yield_requests=False, **adapter_kwargs): + """Receives a Response. Returns a generator of Responses or Requests.""" + + hist = [] # keep track of history + + url = self.get_redirect_target(resp) + previous_fragment = urlparse(req.url).fragment + while url: + prepared_request = req.copy() + + # Update history and keep track of redirects. + # resp.history must ignore the original request in this loop + hist.append(resp) + resp.history = hist[1:] + + try: + resp.content # Consume socket so it can be released + except (ChunkedEncodingError, ContentDecodingError, RuntimeError): + resp.raw.read(decode_content=False) + + if len(resp.history) >= self.max_redirects: + raise TooManyRedirects('Exceeded {} redirects.'.format(self.max_redirects), response=resp) + + # Release the connection back into the pool. + resp.close() + + # Handle redirection without scheme (see: RFC 1808 Section 4) + if url.startswith('//'): + parsed_rurl = urlparse(resp.url) + url = ':'.join([to_native_string(parsed_rurl.scheme), url]) + + # Normalize url case and attach previous fragment if needed (RFC 7231 7.1.2) + parsed = urlparse(url) + if parsed.fragment == '' and previous_fragment: + parsed = parsed._replace(fragment=previous_fragment) + elif parsed.fragment: + previous_fragment = parsed.fragment + url = parsed.geturl() + + # Facilitate relative 'location' headers, as allowed by RFC 7231. + # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource') + # Compliant with RFC3986, we percent encode the url. + if not parsed.netloc: + url = urljoin(resp.url, requote_uri(url)) + else: + url = requote_uri(url) + + prepared_request.url = to_native_string(url) + + self.rebuild_method(prepared_request, resp) + + # https://github.com/psf/requests/issues/1084 + if resp.status_code not in (codes.temporary_redirect, codes.permanent_redirect): + # https://github.com/psf/requests/issues/3490 + purged_headers = ('Content-Length', 'Content-Type', 'Transfer-Encoding') + for header in purged_headers: + prepared_request.headers.pop(header, None) + prepared_request.body = None + + headers = prepared_request.headers + headers.pop('Cookie', None) + + # Extract any cookies sent on the response to the cookiejar + # in the new request. Because we've mutated our copied prepared + # request, use the old one that we haven't yet touched. + extract_cookies_to_jar(prepared_request._cookies, req, resp.raw) + merge_cookies(prepared_request._cookies, self.cookies) + prepared_request.prepare_cookies(prepared_request._cookies) + + # Rebuild auth and proxy information. + proxies = self.rebuild_proxies(prepared_request, proxies) + self.rebuild_auth(prepared_request, resp) + + # A failed tell() sets `_body_position` to `object()`. This non-None + # value ensures `rewindable` will be True, allowing us to raise an + # UnrewindableBodyError, instead of hanging the connection. + rewindable = ( + prepared_request._body_position is not None and + ('Content-Length' in headers or 'Transfer-Encoding' in headers) + ) + + # Attempt to rewind consumed file-like object. + if rewindable: + rewind_body(prepared_request) + + # Override the original request. + req = prepared_request + + if yield_requests: + yield req + else: + + resp = self.send( + req, + stream=stream, + timeout=timeout, + verify=verify, + cert=cert, + proxies=proxies, + allow_redirects=False, + **adapter_kwargs + ) + + extract_cookies_to_jar(self.cookies, prepared_request, resp.raw) + + # extract redirect url, if any, for the next loop + url = self.get_redirect_target(resp) + yield resp + + def rebuild_auth(self, prepared_request, response): + """When being redirected we may want to strip authentication from the + request to avoid leaking credentials. This method intelligently removes + and reapplies authentication where possible to avoid credential loss. + """ + headers = prepared_request.headers + url = prepared_request.url + + if 'Authorization' in headers and self.should_strip_auth(response.request.url, url): + # If we get redirected to a new host, we should strip out any + # authentication headers. + del headers['Authorization'] + + # .netrc might have more auth for us on our new host. + new_auth = get_netrc_auth(url) if self.trust_env else None + if new_auth is not None: + prepared_request.prepare_auth(new_auth) + + def rebuild_proxies(self, prepared_request, proxies): + """This method re-evaluates the proxy configuration by considering the + environment variables. If we are redirected to a URL covered by + NO_PROXY, we strip the proxy configuration. Otherwise, we set missing + proxy keys for this URL (in case they were stripped by a previous + redirect). + + This method also replaces the Proxy-Authorization header where + necessary. + + :rtype: dict + """ + headers = prepared_request.headers + scheme = urlparse(prepared_request.url).scheme + new_proxies = resolve_proxies(prepared_request, proxies, self.trust_env) + + if 'Proxy-Authorization' in headers: + del headers['Proxy-Authorization'] + + try: + username, password = get_auth_from_url(new_proxies[scheme]) + except KeyError: + username, password = None, None + + if username and password: + headers['Proxy-Authorization'] = _basic_auth_str(username, password) + + return new_proxies + + def rebuild_method(self, prepared_request, response): + """When being redirected we may want to change the method of the request + based on certain specs or browser behavior. + """ + method = prepared_request.method + + # https://tools.ietf.org/html/rfc7231#section-6.4.4 + if response.status_code == codes.see_other and method != 'HEAD': + method = 'GET' + + # Do what the browsers do, despite standards... + # First, turn 302s into GETs. + if response.status_code == codes.found and method != 'HEAD': + method = 'GET' + + # Second, if a POST is responded to with a 301, turn it into a GET. + # This bizarre behaviour is explained in Issue 1704. + if response.status_code == codes.moved and method == 'POST': + method = 'GET' + + prepared_request.method = method + + +class Session(SessionRedirectMixin): + """A Requests session. + + Provides cookie persistence, connection-pooling, and configuration. + + Basic Usage:: + + >>> import requests + >>> s = requests.Session() + >>> s.get('https://httpbin.org/get') + + + Or as a context manager:: + + >>> with requests.Session() as s: + ... s.get('https://httpbin.org/get') + + """ + + __attrs__ = [ + 'headers', 'cookies', 'auth', 'proxies', 'hooks', 'params', 'verify', + 'cert', 'adapters', 'stream', 'trust_env', + 'max_redirects', + ] + + def __init__(self): + + #: A case-insensitive dictionary of headers to be sent on each + #: :class:`Request ` sent from this + #: :class:`Session `. + self.headers = default_headers() + + #: Default Authentication tuple or object to attach to + #: :class:`Request `. + self.auth = None + + #: Dictionary mapping protocol or protocol and host to the URL of the proxy + #: (e.g. {'http': 'foo.bar:3128', 'http://host.name': 'foo.bar:4012'}) to + #: be used on each :class:`Request `. + self.proxies = {} + + #: Event-handling hooks. + self.hooks = default_hooks() + + #: Dictionary of querystring data to attach to each + #: :class:`Request `. The dictionary values may be lists for + #: representing multivalued query parameters. + self.params = {} + + #: Stream response content default. + self.stream = False + + #: SSL Verification default. + #: Defaults to `True`, requiring requests to verify the TLS certificate at the + #: remote end. + #: If verify is set to `False`, requests will accept any TLS certificate + #: presented by the server, and will ignore hostname mismatches and/or + #: expired certificates, which will make your application vulnerable to + #: man-in-the-middle (MitM) attacks. + #: Only set this to `False` for testing. + self.verify = True + + #: SSL client certificate default, if String, path to ssl client + #: cert file (.pem). If Tuple, ('cert', 'key') pair. + self.cert = None + + #: Maximum number of redirects allowed. If the request exceeds this + #: limit, a :class:`TooManyRedirects` exception is raised. + #: This defaults to requests.models.DEFAULT_REDIRECT_LIMIT, which is + #: 30. + self.max_redirects = DEFAULT_REDIRECT_LIMIT + + #: Trust environment settings for proxy configuration, default + #: authentication and similar. + self.trust_env = True + + #: A CookieJar containing all currently outstanding cookies set on this + #: session. By default it is a + #: :class:`RequestsCookieJar `, but + #: may be any other ``cookielib.CookieJar`` compatible object. + self.cookies = cookiejar_from_dict({}) + + # Default connection adapters. + self.adapters = OrderedDict() + self.mount('https://', HTTPAdapter()) + self.mount('http://', HTTPAdapter()) + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + def prepare_request(self, request): + """Constructs a :class:`PreparedRequest ` for + transmission and returns it. The :class:`PreparedRequest` has settings + merged from the :class:`Request ` instance and those of the + :class:`Session`. + + :param request: :class:`Request` instance to prepare with this + session's settings. + :rtype: requests.PreparedRequest + """ + cookies = request.cookies or {} + + # Bootstrap CookieJar. + if not isinstance(cookies, cookielib.CookieJar): + cookies = cookiejar_from_dict(cookies) + + # Merge with session cookies + merged_cookies = merge_cookies( + merge_cookies(RequestsCookieJar(), self.cookies), cookies) + + # Set environment's basic authentication if not explicitly set. + auth = request.auth + if self.trust_env and not auth and not self.auth: + auth = get_netrc_auth(request.url) + + p = PreparedRequest() + p.prepare( + method=request.method.upper(), + url=request.url, + files=request.files, + data=request.data, + json=request.json, + headers=merge_setting(request.headers, self.headers, dict_class=CaseInsensitiveDict), + params=merge_setting(request.params, self.params), + auth=merge_setting(auth, self.auth), + cookies=merged_cookies, + hooks=merge_hooks(request.hooks, self.hooks), + ) + return p + + def request(self, method, url, + params=None, data=None, headers=None, cookies=None, files=None, + auth=None, timeout=None, allow_redirects=True, proxies=None, + hooks=None, stream=None, verify=None, cert=None, json=None): + """Constructs a :class:`Request `, prepares it and sends it. + Returns :class:`Response ` object. + + :param method: method for the new :class:`Request` object. + :param url: URL for the new :class:`Request` object. + :param params: (optional) Dictionary or bytes to be sent in the query + string for the :class:`Request`. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) json to send in the body of the + :class:`Request`. + :param headers: (optional) Dictionary of HTTP Headers to send with the + :class:`Request`. + :param cookies: (optional) Dict or CookieJar object to send with the + :class:`Request`. + :param files: (optional) Dictionary of ``'filename': file-like-objects`` + for multipart encoding upload. + :param auth: (optional) Auth tuple or callable to enable + Basic/Digest/Custom HTTP Auth. + :param timeout: (optional) How long to wait for the server to send + data before giving up, as a float, or a :ref:`(connect timeout, + read timeout) ` tuple. + :type timeout: float or tuple + :param allow_redirects: (optional) Set to True by default. + :type allow_redirects: bool + :param proxies: (optional) Dictionary mapping protocol or protocol and + hostname to the URL of the proxy. + :param stream: (optional) whether to immediately download the response + content. Defaults to ``False``. + :param verify: (optional) Either a boolean, in which case it controls whether we verify + the server's TLS certificate, or a string, in which case it must be a path + to a CA bundle to use. Defaults to ``True``. When set to + ``False``, requests will accept any TLS certificate presented by + the server, and will ignore hostname mismatches and/or expired + certificates, which will make your application vulnerable to + man-in-the-middle (MitM) attacks. Setting verify to ``False`` + may be useful during local development or testing. + :param cert: (optional) if String, path to ssl client cert file (.pem). + If Tuple, ('cert', 'key') pair. + :rtype: requests.Response + """ + # Create the Request. + req = Request( + method=method.upper(), + url=url, + headers=headers, + files=files, + data=data or {}, + json=json, + params=params or {}, + auth=auth, + cookies=cookies, + hooks=hooks, + ) + prep = self.prepare_request(req) + + proxies = proxies or {} + + settings = self.merge_environment_settings( + prep.url, proxies, stream, verify, cert + ) + + # Send the request. + send_kwargs = { + 'timeout': timeout, + 'allow_redirects': allow_redirects, + } + send_kwargs.update(settings) + resp = self.send(prep, **send_kwargs) + + return resp + + def get(self, url, **kwargs): + r"""Sends a GET request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', True) + return self.request('GET', url, **kwargs) + + def options(self, url, **kwargs): + r"""Sends a OPTIONS request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', True) + return self.request('OPTIONS', url, **kwargs) + + def head(self, url, **kwargs): + r"""Sends a HEAD request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', False) + return self.request('HEAD', url, **kwargs) + + def post(self, url, data=None, json=None, **kwargs): + r"""Sends a POST request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) json to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + return self.request('POST', url, data=data, json=json, **kwargs) + + def put(self, url, data=None, **kwargs): + r"""Sends a PUT request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + return self.request('PUT', url, data=data, **kwargs) + + def patch(self, url, data=None, **kwargs): + r"""Sends a PATCH request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + return self.request('PATCH', url, data=data, **kwargs) + + def delete(self, url, **kwargs): + r"""Sends a DELETE request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + return self.request('DELETE', url, **kwargs) + + def send(self, request, **kwargs): + """Send a given PreparedRequest. + + :rtype: requests.Response + """ + # Set defaults that the hooks can utilize to ensure they always have + # the correct parameters to reproduce the previous request. + kwargs.setdefault('stream', self.stream) + kwargs.setdefault('verify', self.verify) + kwargs.setdefault('cert', self.cert) + if 'proxies' not in kwargs: + kwargs['proxies'] = resolve_proxies( + request, self.proxies, self.trust_env + ) + + # It's possible that users might accidentally send a Request object. + # Guard against that specific failure case. + if isinstance(request, Request): + raise ValueError('You can only send PreparedRequests.') + + # Set up variables needed for resolve_redirects and dispatching of hooks + allow_redirects = kwargs.pop('allow_redirects', True) + stream = kwargs.get('stream') + hooks = request.hooks + + # Get the appropriate adapter to use + adapter = self.get_adapter(url=request.url) + + # Start time (approximately) of the request + start = preferred_clock() + + # Send the request + r = adapter.send(request, **kwargs) + + # Total elapsed time of the request (approximately) + elapsed = preferred_clock() - start + r.elapsed = timedelta(seconds=elapsed) + + # Response manipulation hooks + r = dispatch_hook('response', hooks, r, **kwargs) + + # Persist cookies + if r.history: + + # If the hooks create history then we want those cookies too + for resp in r.history: + extract_cookies_to_jar(self.cookies, resp.request, resp.raw) + + extract_cookies_to_jar(self.cookies, request, r.raw) + + # Resolve redirects if allowed. + if allow_redirects: + # Redirect resolving generator. + gen = self.resolve_redirects(r, request, **kwargs) + history = [resp for resp in gen] + else: + history = [] + + # Shuffle things around if there's history. + if history: + # Insert the first (original) request at the start + history.insert(0, r) + # Get the last request made + r = history.pop() + r.history = history + + # If redirects aren't being followed, store the response on the Request for Response.next(). + if not allow_redirects: + try: + r._next = next(self.resolve_redirects(r, request, yield_requests=True, **kwargs)) + except StopIteration: + pass + + if not stream: + r.content + + return r + + def merge_environment_settings(self, url, proxies, stream, verify, cert): + """ + Check the environment and merge it with some settings. + + :rtype: dict + """ + # Gather clues from the surrounding environment. + if self.trust_env: + # Set environment's proxies. + no_proxy = proxies.get('no_proxy') if proxies is not None else None + env_proxies = get_environ_proxies(url, no_proxy=no_proxy) + for (k, v) in env_proxies.items(): + proxies.setdefault(k, v) + + # Look for requests environment configuration and be compatible + # with cURL. + if verify is True or verify is None: + verify = (os.environ.get('REQUESTS_CA_BUNDLE') or + os.environ.get('CURL_CA_BUNDLE')) + + # Merge all the kwargs. + proxies = merge_setting(proxies, self.proxies) + stream = merge_setting(stream, self.stream) + verify = merge_setting(verify, self.verify) + cert = merge_setting(cert, self.cert) + + return {'verify': verify, 'proxies': proxies, 'stream': stream, + 'cert': cert} + + def get_adapter(self, url): + """ + Returns the appropriate connection adapter for the given URL. + + :rtype: requests.adapters.BaseAdapter + """ + for (prefix, adapter) in self.adapters.items(): + + if url.lower().startswith(prefix.lower()): + return adapter + + # Nothing matches :-/ + raise InvalidSchema("No connection adapters were found for {!r}".format(url)) + + def close(self): + """Closes all adapters and as such the session""" + for v in self.adapters.values(): + v.close() + + def mount(self, prefix, adapter): + """Registers a connection adapter to a prefix. + + Adapters are sorted in descending order by prefix length. + """ + self.adapters[prefix] = adapter + keys_to_move = [k for k in self.adapters if len(k) < len(prefix)] + + for key in keys_to_move: + self.adapters[key] = self.adapters.pop(key) + + def __getstate__(self): + state = {attr: getattr(self, attr, None) for attr in self.__attrs__} + return state + + def __setstate__(self, state): + for attr, value in state.items(): + setattr(self, attr, value) + + +def session(): + """ + Returns a :class:`Session` for context-management. + + .. deprecated:: 1.0.0 + + This method has been deprecated since version 1.0.0 and is only kept for + backwards compatibility. New code should use :class:`~requests.sessions.Session` + to create a session. This may be removed at a future date. + + :rtype: Session + """ + return Session() diff --git a/openpype/vendor/python/python_2/requests/status_codes.py b/openpype/vendor/python/python_2/requests/status_codes.py new file mode 100644 index 0000000000..d80a7cd4dd --- /dev/null +++ b/openpype/vendor/python/python_2/requests/status_codes.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- + +r""" +The ``codes`` object defines a mapping from common names for HTTP statuses +to their numerical codes, accessible either as attributes or as dictionary +items. + +Example:: + + >>> import requests + >>> requests.codes['temporary_redirect'] + 307 + >>> requests.codes.teapot + 418 + >>> requests.codes['\o/'] + 200 + +Some codes have multiple names, and both upper- and lower-case versions of +the names are allowed. For example, ``codes.ok``, ``codes.OK``, and +``codes.okay`` all correspond to the HTTP status code 200. +""" + +from .structures import LookupDict + +_codes = { + + # Informational. + 100: ('continue',), + 101: ('switching_protocols',), + 102: ('processing',), + 103: ('checkpoint',), + 122: ('uri_too_long', 'request_uri_too_long'), + 200: ('ok', 'okay', 'all_ok', 'all_okay', 'all_good', '\\o/', '✓'), + 201: ('created',), + 202: ('accepted',), + 203: ('non_authoritative_info', 'non_authoritative_information'), + 204: ('no_content',), + 205: ('reset_content', 'reset'), + 206: ('partial_content', 'partial'), + 207: ('multi_status', 'multiple_status', 'multi_stati', 'multiple_stati'), + 208: ('already_reported',), + 226: ('im_used',), + + # Redirection. + 300: ('multiple_choices',), + 301: ('moved_permanently', 'moved', '\\o-'), + 302: ('found',), + 303: ('see_other', 'other'), + 304: ('not_modified',), + 305: ('use_proxy',), + 306: ('switch_proxy',), + 307: ('temporary_redirect', 'temporary_moved', 'temporary'), + 308: ('permanent_redirect', + 'resume_incomplete', 'resume',), # These 2 to be removed in 3.0 + + # Client Error. + 400: ('bad_request', 'bad'), + 401: ('unauthorized',), + 402: ('payment_required', 'payment'), + 403: ('forbidden',), + 404: ('not_found', '-o-'), + 405: ('method_not_allowed', 'not_allowed'), + 406: ('not_acceptable',), + 407: ('proxy_authentication_required', 'proxy_auth', 'proxy_authentication'), + 408: ('request_timeout', 'timeout'), + 409: ('conflict',), + 410: ('gone',), + 411: ('length_required',), + 412: ('precondition_failed', 'precondition'), + 413: ('request_entity_too_large',), + 414: ('request_uri_too_large',), + 415: ('unsupported_media_type', 'unsupported_media', 'media_type'), + 416: ('requested_range_not_satisfiable', 'requested_range', 'range_not_satisfiable'), + 417: ('expectation_failed',), + 418: ('im_a_teapot', 'teapot', 'i_am_a_teapot'), + 421: ('misdirected_request',), + 422: ('unprocessable_entity', 'unprocessable'), + 423: ('locked',), + 424: ('failed_dependency', 'dependency'), + 425: ('unordered_collection', 'unordered'), + 426: ('upgrade_required', 'upgrade'), + 428: ('precondition_required', 'precondition'), + 429: ('too_many_requests', 'too_many'), + 431: ('header_fields_too_large', 'fields_too_large'), + 444: ('no_response', 'none'), + 449: ('retry_with', 'retry'), + 450: ('blocked_by_windows_parental_controls', 'parental_controls'), + 451: ('unavailable_for_legal_reasons', 'legal_reasons'), + 499: ('client_closed_request',), + + # Server Error. + 500: ('internal_server_error', 'server_error', '/o\\', '✗'), + 501: ('not_implemented',), + 502: ('bad_gateway',), + 503: ('service_unavailable', 'unavailable'), + 504: ('gateway_timeout',), + 505: ('http_version_not_supported', 'http_version'), + 506: ('variant_also_negotiates',), + 507: ('insufficient_storage',), + 509: ('bandwidth_limit_exceeded', 'bandwidth'), + 510: ('not_extended',), + 511: ('network_authentication_required', 'network_auth', 'network_authentication'), +} + +codes = LookupDict(name='status_codes') + +def _init(): + for code, titles in _codes.items(): + for title in titles: + setattr(codes, title, code) + if not title.startswith(('\\', '/')): + setattr(codes, title.upper(), code) + + def doc(code): + names = ', '.join('``%s``' % n for n in _codes[code]) + return '* %d: %s' % (code, names) + + global __doc__ + __doc__ = (__doc__ + '\n' + + '\n'.join(doc(code) for code in sorted(_codes)) + if __doc__ is not None else None) + +_init() diff --git a/openpype/vendor/python/python_2/requests/structures.py b/openpype/vendor/python/python_2/requests/structures.py new file mode 100644 index 0000000000..8ee0ba7a08 --- /dev/null +++ b/openpype/vendor/python/python_2/requests/structures.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- + +""" +requests.structures +~~~~~~~~~~~~~~~~~~~ + +Data structures that power Requests. +""" + +from collections import OrderedDict + +from .compat import Mapping, MutableMapping + + +class CaseInsensitiveDict(MutableMapping): + """A case-insensitive ``dict``-like object. + + Implements all methods and operations of + ``MutableMapping`` as well as dict's ``copy``. Also + provides ``lower_items``. + + All keys are expected to be strings. The structure remembers the + case of the last key to be set, and ``iter(instance)``, + ``keys()``, ``items()``, ``iterkeys()``, and ``iteritems()`` + will contain case-sensitive keys. However, querying and contains + testing is case insensitive:: + + cid = CaseInsensitiveDict() + cid['Accept'] = 'application/json' + cid['aCCEPT'] == 'application/json' # True + list(cid) == ['Accept'] # True + + For example, ``headers['content-encoding']`` will return the + value of a ``'Content-Encoding'`` response header, regardless + of how the header name was originally stored. + + If the constructor, ``.update``, or equality comparison + operations are given keys that have equal ``.lower()``s, the + behavior is undefined. + """ + + def __init__(self, data=None, **kwargs): + self._store = OrderedDict() + if data is None: + data = {} + self.update(data, **kwargs) + + def __setitem__(self, key, value): + # Use the lowercased key for lookups, but store the actual + # key alongside the value. + self._store[key.lower()] = (key, value) + + def __getitem__(self, key): + return self._store[key.lower()][1] + + def __delitem__(self, key): + del self._store[key.lower()] + + def __iter__(self): + return (casedkey for casedkey, mappedvalue in self._store.values()) + + def __len__(self): + return len(self._store) + + def lower_items(self): + """Like iteritems(), but with all lowercase keys.""" + return ( + (lowerkey, keyval[1]) + for (lowerkey, keyval) + in self._store.items() + ) + + def __eq__(self, other): + if isinstance(other, Mapping): + other = CaseInsensitiveDict(other) + else: + return NotImplemented + # Compare insensitively + return dict(self.lower_items()) == dict(other.lower_items()) + + # Copy is required + def copy(self): + return CaseInsensitiveDict(self._store.values()) + + def __repr__(self): + return str(dict(self.items())) + + +class LookupDict(dict): + """Dictionary lookup object.""" + + def __init__(self, name=None): + self.name = name + super(LookupDict, self).__init__() + + def __repr__(self): + return '' % (self.name) + + def __getitem__(self, key): + # We allow fall-through here, so values default to None + + return self.__dict__.get(key, None) + + def get(self, key, default=None): + return self.__dict__.get(key, default) diff --git a/openpype/vendor/python/python_2/requests/utils.py b/openpype/vendor/python/python_2/requests/utils.py new file mode 100644 index 0000000000..153776c7f3 --- /dev/null +++ b/openpype/vendor/python/python_2/requests/utils.py @@ -0,0 +1,1060 @@ +# -*- coding: utf-8 -*- + +""" +requests.utils +~~~~~~~~~~~~~~ + +This module provides utility functions that are used within Requests +that are also useful for external consumption. +""" + +import codecs +import contextlib +import io +import os +import re +import socket +import struct +import sys +import tempfile +import warnings +import zipfile +from collections import OrderedDict +from urllib3.util import make_headers +from urllib3.util import parse_url + +from .__version__ import __version__ +from . import certs +# to_native_string is unused here, but imported here for backwards compatibility +from ._internal_utils import to_native_string +from .compat import parse_http_list as _parse_list_header +from .compat import ( + quote, urlparse, bytes, str, unquote, getproxies, + proxy_bypass, urlunparse, basestring, integer_types, is_py3, + proxy_bypass_environment, getproxies_environment, Mapping) +from .cookies import cookiejar_from_dict +from .structures import CaseInsensitiveDict +from .exceptions import ( + InvalidURL, InvalidHeader, FileModeWarning, UnrewindableBodyError) + +NETRC_FILES = ('.netrc', '_netrc') + +DEFAULT_CA_BUNDLE_PATH = certs.where() + +DEFAULT_PORTS = {'http': 80, 'https': 443} + +# Ensure that ', ' is used to preserve previous delimiter behavior. +DEFAULT_ACCEPT_ENCODING = ", ".join( + re.split(r",\s*", make_headers(accept_encoding=True)["accept-encoding"]) +) + + +if sys.platform == 'win32': + # provide a proxy_bypass version on Windows without DNS lookups + + def proxy_bypass_registry(host): + try: + if is_py3: + import winreg + else: + import _winreg as winreg + except ImportError: + return False + + try: + internetSettings = winreg.OpenKey(winreg.HKEY_CURRENT_USER, + r'Software\Microsoft\Windows\CurrentVersion\Internet Settings') + # ProxyEnable could be REG_SZ or REG_DWORD, normalizing it + proxyEnable = int(winreg.QueryValueEx(internetSettings, + 'ProxyEnable')[0]) + # ProxyOverride is almost always a string + proxyOverride = winreg.QueryValueEx(internetSettings, + 'ProxyOverride')[0] + except OSError: + return False + if not proxyEnable or not proxyOverride: + return False + + # make a check value list from the registry entry: replace the + # '' string by the localhost entry and the corresponding + # canonical entry. + proxyOverride = proxyOverride.split(';') + # now check if we match one of the registry values. + for test in proxyOverride: + if test == '': + if '.' not in host: + return True + test = test.replace(".", r"\.") # mask dots + test = test.replace("*", r".*") # change glob sequence + test = test.replace("?", r".") # change glob char + if re.match(test, host, re.I): + return True + return False + + def proxy_bypass(host): # noqa + """Return True, if the host should be bypassed. + + Checks proxy settings gathered from the environment, if specified, + or the registry. + """ + if getproxies_environment(): + return proxy_bypass_environment(host) + else: + return proxy_bypass_registry(host) + + +def dict_to_sequence(d): + """Returns an internal sequence dictionary update.""" + + if hasattr(d, 'items'): + d = d.items() + + return d + + +def super_len(o): + total_length = None + current_position = 0 + + if hasattr(o, '__len__'): + total_length = len(o) + + elif hasattr(o, 'len'): + total_length = o.len + + elif hasattr(o, 'fileno'): + try: + fileno = o.fileno() + except (io.UnsupportedOperation, AttributeError): + # AttributeError is a surprising exception, seeing as how we've just checked + # that `hasattr(o, 'fileno')`. It happens for objects obtained via + # `Tarfile.extractfile()`, per issue 5229. + pass + else: + total_length = os.fstat(fileno).st_size + + # Having used fstat to determine the file length, we need to + # confirm that this file was opened up in binary mode. + if 'b' not in o.mode: + warnings.warn(( + "Requests has determined the content-length for this " + "request using the binary size of the file: however, the " + "file has been opened in text mode (i.e. without the 'b' " + "flag in the mode). This may lead to an incorrect " + "content-length. In Requests 3.0, support will be removed " + "for files in text mode."), + FileModeWarning + ) + + if hasattr(o, 'tell'): + try: + current_position = o.tell() + except (OSError, IOError): + # This can happen in some weird situations, such as when the file + # is actually a special file descriptor like stdin. In this + # instance, we don't know what the length is, so set it to zero and + # let requests chunk it instead. + if total_length is not None: + current_position = total_length + else: + if hasattr(o, 'seek') and total_length is None: + # StringIO and BytesIO have seek but no usable fileno + try: + # seek to end of file + o.seek(0, 2) + total_length = o.tell() + + # seek back to current position to support + # partially read file-like objects + o.seek(current_position or 0) + except (OSError, IOError): + total_length = 0 + + if total_length is None: + total_length = 0 + + return max(0, total_length - current_position) + + +def get_netrc_auth(url, raise_errors=False): + """Returns the Requests tuple auth for a given url from netrc.""" + + netrc_file = os.environ.get('NETRC') + if netrc_file is not None: + netrc_locations = (netrc_file,) + else: + netrc_locations = ('~/{}'.format(f) for f in NETRC_FILES) + + try: + from netrc import netrc, NetrcParseError + + netrc_path = None + + for f in netrc_locations: + try: + loc = os.path.expanduser(f) + except KeyError: + # os.path.expanduser can fail when $HOME is undefined and + # getpwuid fails. See https://bugs.python.org/issue20164 & + # https://github.com/psf/requests/issues/1846 + return + + if os.path.exists(loc): + netrc_path = loc + break + + # Abort early if there isn't one. + if netrc_path is None: + return + + ri = urlparse(url) + + # Strip port numbers from netloc. This weird `if...encode`` dance is + # used for Python 3.2, which doesn't support unicode literals. + splitstr = b':' + if isinstance(url, str): + splitstr = splitstr.decode('ascii') + host = ri.netloc.split(splitstr)[0] + + try: + _netrc = netrc(netrc_path).authenticators(host) + if _netrc: + # Return with login / password + login_i = (0 if _netrc[0] else 1) + return (_netrc[login_i], _netrc[2]) + except (NetrcParseError, IOError): + # If there was a parsing error or a permissions issue reading the file, + # we'll just skip netrc auth unless explicitly asked to raise errors. + if raise_errors: + raise + + # App Engine hackiness. + except (ImportError, AttributeError): + pass + + +def guess_filename(obj): + """Tries to guess the filename of the given object.""" + name = getattr(obj, 'name', None) + if (name and isinstance(name, basestring) and name[0] != '<' and + name[-1] != '>'): + return os.path.basename(name) + + +def extract_zipped_paths(path): + """Replace nonexistent paths that look like they refer to a member of a zip + archive with the location of an extracted copy of the target, or else + just return the provided path unchanged. + """ + if os.path.exists(path): + # this is already a valid path, no need to do anything further + return path + + # find the first valid part of the provided path and treat that as a zip archive + # assume the rest of the path is the name of a member in the archive + archive, member = os.path.split(path) + while archive and not os.path.exists(archive): + archive, prefix = os.path.split(archive) + if not prefix: + # If we don't check for an empty prefix after the split (in other words, archive remains unchanged after the split), + # we _can_ end up in an infinite loop on a rare corner case affecting a small number of users + break + member = '/'.join([prefix, member]) + + if not zipfile.is_zipfile(archive): + return path + + zip_file = zipfile.ZipFile(archive) + if member not in zip_file.namelist(): + return path + + # we have a valid zip archive and a valid member of that archive + tmp = tempfile.gettempdir() + extracted_path = os.path.join(tmp, member.split('/')[-1]) + if not os.path.exists(extracted_path): + # use read + write to avoid the creating nested folders, we only want the file, avoids mkdir racing condition + with atomic_open(extracted_path) as file_handler: + file_handler.write(zip_file.read(member)) + return extracted_path + + +@contextlib.contextmanager +def atomic_open(filename): + """Write a file to the disk in an atomic fashion""" + replacer = os.rename if sys.version_info[0] == 2 else os.replace + tmp_descriptor, tmp_name = tempfile.mkstemp(dir=os.path.dirname(filename)) + try: + with os.fdopen(tmp_descriptor, 'wb') as tmp_handler: + yield tmp_handler + replacer(tmp_name, filename) + except BaseException: + os.remove(tmp_name) + raise + + +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') + Traceback (most recent call last): + ... + ValueError: cannot encode objects that are not 2-tuples + >>> from_key_val_list({'key': 'val'}) + OrderedDict([('key', 'val')]) + + :rtype: OrderedDict + """ + 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') + Traceback (most recent call last): + ... + ValueError: cannot encode objects that are not 2-tuples + + :rtype: list + """ + 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, Mapping): + 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. + + In particular, parse comma-separated lists where the elements of + the list may include quoted-strings. A quoted-string could + contain a comma. A non-quoted string could have quotes in the + middle. Quotes are removed automatically after parsing. + + It basically works like :func:`parse_set_header` just that items + may appear multiple times and case sensitivity is preserved. + + The return value is a standard :class:`list`: + + >>> parse_list_header('token, "quoted value"') + ['token', 'quoted value'] + + To create a header from the :class:`list` again, use the + :func:`dump_header` function. + + :param value: a string with a list header. + :return: :class:`list` + :rtype: list + """ + result = [] + for item in _parse_list_header(value): + if item[:1] == item[-1:] == '"': + item = unquote_header_value(item[1:-1]) + result.append(item) + return result + + +# From mitsuhiko/werkzeug (used with permission). +def parse_dict_header(value): + """Parse lists of key, value pairs as described by RFC 2068 Section 2 and + convert them into a python dict: + + >>> d = parse_dict_header('foo="is a fish", bar="as well"') + >>> type(d) is dict + True + >>> sorted(d.items()) + [('bar', 'as well'), ('foo', 'is a fish')] + + If there is no value for a key it will be `None`: + + >>> parse_dict_header('key_without_value') + {'key_without_value': None} + + To create a header from the :class:`dict` again, use the + :func:`dump_header` function. + + :param value: a string with a dict header. + :return: :class:`dict` + :rtype: dict + """ + result = {} + for item in _parse_list_header(value): + if '=' not in item: + result[item] = None + continue + name, value = item.split('=', 1) + if value[:1] == value[-1:] == '"': + value = unquote_header_value(value[1:-1]) + result[name] = value + return result + + +# From mitsuhiko/werkzeug (used with permission). +def unquote_header_value(value, is_filename=False): + r"""Unquotes a header value. (Reversal of :func:`quote_header_value`). + This does not use the real unquoting but what browsers are actually + using for quoting. + + :param value: the header value to unquote. + :rtype: str + """ + if value and value[0] == value[-1] == '"': + # this is not the real unquoting, but fixing this so that the + # RFC is met will result in bugs with internet explorer and + # probably some other browsers as well. IE for example is + # uploading files with "C:\foo\bar.txt" as filename + value = value[1:-1] + + # if this is a filename and the starting characters look like + # a UNC path, then just return the value without quotes. Using the + # replace sequence below on a UNC path has the effect of turning + # the leading double slash into a single slash and then + # _fix_ie_filename() doesn't work correctly. See #458. + if not is_filename or value[:2] != '\\\\': + return value.replace('\\\\', '\\').replace('\\"', '"') + return value + + +def dict_from_cookiejar(cj): + """Returns a key/value dictionary from a CookieJar. + + :param cj: CookieJar object to extract cookies from. + :rtype: dict + """ + + cookie_dict = {} + + for cookie in cj: + cookie_dict[cookie.name] = cookie.value + + return cookie_dict + + +def add_dict_to_cookiejar(cj, cookie_dict): + """Returns a CookieJar from a key/value dictionary. + + :param cj: CookieJar to insert cookies into. + :param cookie_dict: Dict of key/values to insert into CookieJar. + :rtype: CookieJar + """ + + return cookiejar_from_dict(cookie_dict, cj) + + +def get_encodings_from_content(content): + """Returns encodings from given content string. + + :param content: bytestring to extract encodings from. + """ + warnings.warn(( + 'In requests 3.0, get_encodings_from_content will be removed. For ' + 'more information, please see the discussion on issue #2266. (This' + ' warning should only appear once.)'), + DeprecationWarning) + + charset_re = re.compile(r']', flags=re.I) + pragma_re = re.compile(r']', flags=re.I) + xml_re = re.compile(r'^<\?xml.*?encoding=["\']*(.+?)["\'>]') + + return (charset_re.findall(content) + + pragma_re.findall(content) + + xml_re.findall(content)) + + +def _parse_content_type_header(header): + """Returns content type and parameters from given header + + :param header: string + :return: tuple containing content type and dictionary of + parameters + """ + + tokens = header.split(';') + content_type, params = tokens[0].strip(), tokens[1:] + params_dict = {} + items_to_strip = "\"' " + + for param in params: + param = param.strip() + if param: + key, value = param, True + index_of_equals = param.find("=") + if index_of_equals != -1: + key = param[:index_of_equals].strip(items_to_strip) + value = param[index_of_equals + 1:].strip(items_to_strip) + params_dict[key.lower()] = value + return content_type, params_dict + + +def get_encoding_from_headers(headers): + """Returns encodings from given HTTP Header Dict. + + :param headers: dictionary to extract encoding from. + :rtype: str + """ + + content_type = headers.get('content-type') + + if not content_type: + return None + + content_type, params = _parse_content_type_header(content_type) + + if 'charset' in params: + return params['charset'].strip("'\"") + + if 'text' in content_type: + return 'ISO-8859-1' + + if 'application/json' in content_type: + # Assume UTF-8 based on RFC 4627: https://www.ietf.org/rfc/rfc4627.txt since the charset was unset + return 'utf-8' + + +def stream_decode_response_unicode(iterator, r): + """Stream decodes a iterator.""" + + if r.encoding is None: + for item in iterator: + yield item + return + + decoder = codecs.getincrementaldecoder(r.encoding)(errors='replace') + for chunk in iterator: + rv = decoder.decode(chunk) + if rv: + yield rv + rv = decoder.decode(b'', final=True) + if rv: + yield rv + + +def iter_slices(string, slice_length): + """Iterate over slices of a string.""" + pos = 0 + if slice_length is None or slice_length <= 0: + slice_length = len(string) + 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. + + :param r: Response object to get unicode content from. + + Tried: + + 1. charset from content-type + 2. fall back and replace all unicode characters + + :rtype: str + """ + warnings.warn(( + 'In requests 3.0, get_unicode_from_response will be removed. For ' + 'more information, please see the discussion on issue #2266. (This' + ' warning should only appear once.)'), + DeprecationWarning) + + tried_encodings = [] + + # Try charset from content-type + encoding = get_encoding_from_headers(r.headers) + + if encoding: + try: + return str(r.content, encoding) + except UnicodeError: + tried_encodings.append(encoding) + + # Fall back: + try: + return str(r.content, encoding, errors='replace') + except TypeError: + return r.content + + +# The unreserved URI characters (RFC 3986) +UNRESERVED_SET = frozenset( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789-._~") + + +def unquote_unreserved(uri): + """Un-escape any percent-escape sequences in a URI that are unreserved + characters. This leaves all reserved, illegal and non-ASCII bytes encoded. + + :rtype: str + """ + parts = uri.split('%') + for i in range(1, len(parts)): + h = parts[i][0:2] + if len(h) == 2 and h.isalnum(): + try: + c = chr(int(h, 16)) + except ValueError: + raise InvalidURL("Invalid percent-escape sequence: '%s'" % h) + + if c in UNRESERVED_SET: + parts[i] = c + parts[i][2:] + else: + parts[i] = '%' + parts[i] + else: + parts[i] = '%' + parts[i] + return ''.join(parts) + + +def requote_uri(uri): + """Re-quote the given URI. + + This function passes the given URI through an unquote/quote cycle to + ensure that it is fully and consistently quoted. + + :rtype: str + """ + safe_with_percent = "!#$%&'()*+,/:;=?@[]~" + safe_without_percent = "!#$&'()*+,/:;=?@[]~" + try: + # Unquote only the unreserved characters + # Then quote only illegal characters (do not quote reserved, + # unreserved, or '%') + return quote(unquote_unreserved(uri), safe=safe_with_percent) + except InvalidURL: + # We couldn't unquote the given URI, so let's try quoting it, but + # there may be unquoted '%'s in the URI. We need to make sure they're + # properly quoted so they do not cause issues elsewhere. + return quote(uri, safe=safe_without_percent) + + +def address_in_network(ip, net): + """This function allows you to check if an IP belongs to a network subnet + + Example: returns True if ip = 192.168.1.1 and net = 192.168.1.0/24 + returns False if ip = 192.168.1.1 and net = 192.168.100.0/24 + + :rtype: bool + """ + ipaddr = struct.unpack('=L', socket.inet_aton(ip))[0] + netaddr, bits = net.split('/') + netmask = struct.unpack('=L', socket.inet_aton(dotted_netmask(int(bits))))[0] + network = struct.unpack('=L', socket.inet_aton(netaddr))[0] & netmask + return (ipaddr & netmask) == (network & netmask) + + +def dotted_netmask(mask): + """Converts mask from /xx format to xxx.xxx.xxx.xxx + + Example: if mask is 24 function returns 255.255.255.0 + + :rtype: str + """ + bits = 0xffffffff ^ (1 << 32 - mask) - 1 + return socket.inet_ntoa(struct.pack('>I', bits)) + + +def is_ipv4_address(string_ip): + """ + :rtype: bool + """ + try: + socket.inet_aton(string_ip) + except socket.error: + return False + return True + + +def is_valid_cidr(string_network): + """ + Very simple check of the cidr format in no_proxy variable. + + :rtype: bool + """ + if string_network.count('/') == 1: + try: + mask = int(string_network.split('/')[1]) + except ValueError: + return False + + if mask < 1 or mask > 32: + return False + + try: + socket.inet_aton(string_network.split('/')[0]) + except socket.error: + return False + else: + return False + return True + + +@contextlib.contextmanager +def set_environ(env_name, value): + """Set the environment variable 'env_name' to 'value' + + Save previous value, yield, and then restore the previous value stored in + the environment variable 'env_name'. + + If 'value' is None, do nothing""" + value_changed = value is not None + if value_changed: + old_value = os.environ.get(env_name) + os.environ[env_name] = value + try: + yield + finally: + if value_changed: + if old_value is None: + del os.environ[env_name] + else: + os.environ[env_name] = old_value + + +def should_bypass_proxies(url, no_proxy): + """ + Returns whether we should bypass proxies or not. + + :rtype: bool + """ + # Prioritize lowercase environment variables over uppercase + # to keep a consistent behaviour with other http projects (curl, wget). + get_proxy = lambda k: os.environ.get(k) or os.environ.get(k.upper()) + + # First check whether no_proxy is defined. If it is, check that the URL + # we're getting isn't in the no_proxy list. + no_proxy_arg = no_proxy + if no_proxy is None: + no_proxy = get_proxy('no_proxy') + parsed = urlparse(url) + + if parsed.hostname is None: + # URLs don't always have hostnames, e.g. file:/// urls. + return True + + if no_proxy: + # We need to check whether we match here. We need to see if we match + # the end of the hostname, both with and without the port. + no_proxy = ( + host for host in no_proxy.replace(' ', '').split(',') if host + ) + + if is_ipv4_address(parsed.hostname): + for proxy_ip in no_proxy: + if is_valid_cidr(proxy_ip): + if address_in_network(parsed.hostname, proxy_ip): + return True + elif parsed.hostname == proxy_ip: + # If no_proxy ip was defined in plain IP notation instead of cidr notation & + # matches the IP of the index + return True + else: + host_with_port = parsed.hostname + if parsed.port: + host_with_port += ':{}'.format(parsed.port) + + for host in no_proxy: + if parsed.hostname.endswith(host) or host_with_port.endswith(host): + # The URL does match something in no_proxy, so we don't want + # to apply the proxies on this URL. + return True + + with set_environ('no_proxy', no_proxy_arg): + # parsed.hostname can be `None` in cases such as a file URI. + try: + bypass = proxy_bypass(parsed.hostname) + except (TypeError, socket.gaierror): + bypass = False + + if bypass: + return True + + return False + + +def get_environ_proxies(url, no_proxy=None): + """ + Return a dict of environment proxies. + + :rtype: dict + """ + if should_bypass_proxies(url, no_proxy=no_proxy): + return {} + else: + return getproxies() + + +def select_proxy(url, proxies): + """Select a proxy for the url, if applicable. + + :param url: The url being for the request + :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs + """ + proxies = proxies or {} + urlparts = urlparse(url) + if urlparts.hostname is None: + return proxies.get(urlparts.scheme, proxies.get('all')) + + proxy_keys = [ + urlparts.scheme + '://' + urlparts.hostname, + urlparts.scheme, + 'all://' + urlparts.hostname, + 'all', + ] + proxy = None + for proxy_key in proxy_keys: + if proxy_key in proxies: + proxy = proxies[proxy_key] + break + + return proxy + + +def resolve_proxies(request, proxies, trust_env=True): + """This method takes proxy information from a request and configuration + input to resolve a mapping of target proxies. This will consider settings + such a NO_PROXY to strip proxy configurations. + + :param request: Request or PreparedRequest + :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs + :param trust_env: Boolean declaring whether to trust environment configs + + :rtype: dict + """ + proxies = proxies if proxies is not None else {} + url = request.url + scheme = urlparse(url).scheme + no_proxy = proxies.get('no_proxy') + new_proxies = proxies.copy() + + if trust_env and not should_bypass_proxies(url, no_proxy=no_proxy): + environ_proxies = get_environ_proxies(url, no_proxy=no_proxy) + + proxy = environ_proxies.get(scheme, environ_proxies.get('all')) + + if proxy: + new_proxies.setdefault(scheme, proxy) + return new_proxies + + +def default_user_agent(name="python-requests"): + """ + Return a string representing the default user agent. + + :rtype: str + """ + return '%s/%s' % (name, __version__) + + +def default_headers(): + """ + :rtype: requests.structures.CaseInsensitiveDict + """ + return CaseInsensitiveDict({ + 'User-Agent': default_user_agent(), + 'Accept-Encoding': DEFAULT_ACCEPT_ENCODING, + 'Accept': '*/*', + 'Connection': 'keep-alive', + }) + + +def parse_header_links(value): + """Return a list of parsed link headers proxies. + + i.e. Link: ; rel=front; type="image/jpeg",; rel=back;type="image/jpeg" + + :rtype: list + """ + + links = [] + + replace_chars = ' \'"' + + value = value.strip(replace_chars) + if not value: + return links + + for val in re.split(', *<', value): + try: + url, params = val.split(';', 1) + except ValueError: + url, params = val, '' + + 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 + + +# Null bytes; no need to recreate these on each call to guess_json_utf +_null = '\x00'.encode('ascii') # encoding to ASCII for Python 3 +_null2 = _null * 2 +_null3 = _null * 3 + + +def guess_json_utf(data): + """ + :rtype: str + """ + # JSON always starts with two ASCII characters, so detection is as + # easy as counting the nulls and from their location and count + # determine the encoding. Also detect a BOM, if present. + sample = data[:4] + if sample in (codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE): + return 'utf-32' # BOM included + if sample[:3] == codecs.BOM_UTF8: + return 'utf-8-sig' # BOM included, MS style (discouraged) + if sample[:2] in (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE): + return 'utf-16' # BOM included + nullcount = sample.count(_null) + if nullcount == 0: + return 'utf-8' + if nullcount == 2: + if sample[::2] == _null2: # 1st and 3rd are null + return 'utf-16-be' + if sample[1::2] == _null2: # 2nd and 4th are null + return 'utf-16-le' + # Did not detect 2 valid UTF-16 ascii-range characters + if nullcount == 3: + if sample[:3] == _null3: + return 'utf-32-be' + if sample[1:] == _null3: + return 'utf-32-le' + # Did not detect a valid UTF-32 ascii-range character + return None + + +def prepend_scheme_if_needed(url, new_scheme): + """Given a URL that may or may not have a scheme, prepend the given scheme. + Does not replace a present scheme with the one provided as an argument. + + :rtype: str + """ + parsed = parse_url(url) + scheme, auth, host, port, path, query, fragment = parsed + + # A defect in urlparse determines that there isn't a netloc present in some + # urls. We previously assumed parsing was overly cautious, and swapped the + # netloc and path. Due to a lack of tests on the original defect, this is + # maintained with parse_url for backwards compatibility. + netloc = parsed.netloc + if not netloc: + netloc, path = path, netloc + + if auth: + # parse_url doesn't provide the netloc with auth + # so we'll add it ourselves. + netloc = '@'.join([auth, netloc]) + if scheme is None: + scheme = new_scheme + if path is None: + path = '' + + return urlunparse((scheme, netloc, path, '', query, fragment)) + + +def get_auth_from_url(url): + """Given a url with authentication components, extract them into a tuple of + username,password. + + :rtype: (str,str) + """ + parsed = urlparse(url) + + try: + auth = (unquote(parsed.username), unquote(parsed.password)) + except (AttributeError, TypeError): + auth = ('', '') + + return auth + + +# Moved outside of function to avoid recompile every call +_CLEAN_HEADER_REGEX_BYTE = re.compile(b'^\\S[^\\r\\n]*$|^$') +_CLEAN_HEADER_REGEX_STR = re.compile(r'^\S[^\r\n]*$|^$') + + +def check_header_validity(header): + """Verifies that header value is a string which doesn't contain + leading whitespace or return characters. This prevents unintended + header injection. + + :param header: tuple, in the format (name, value). + """ + name, value = header + + if isinstance(value, bytes): + pat = _CLEAN_HEADER_REGEX_BYTE + else: + pat = _CLEAN_HEADER_REGEX_STR + try: + if not pat.match(value): + raise InvalidHeader("Invalid return character or leading space in header: %s" % name) + except TypeError: + raise InvalidHeader("Value for header {%s: %s} must be of type str or " + "bytes, not %s" % (name, value, type(value))) + + +def urldefragauth(url): + """ + Given a url remove the fragment and the authentication part. + + :rtype: str + """ + scheme, netloc, path, params, query, fragment = urlparse(url) + + # see func:`prepend_scheme_if_needed` + if not netloc: + netloc, path = path, netloc + + netloc = netloc.rsplit('@', 1)[-1] + + return urlunparse((scheme, netloc, path, params, query, '')) + + +def rewind_body(prepared_request): + """Move file pointer back to its recorded starting position + so it can be read again on redirect. + """ + body_seek = getattr(prepared_request.body, 'seek', None) + if body_seek is not None and isinstance(prepared_request._body_position, integer_types): + try: + body_seek(prepared_request._body_position) + except (IOError, OSError): + raise UnrewindableBodyError("An error occurred when rewinding request " + "body for redirect.") + else: + raise UnrewindableBodyError("Unable to rewind request body for redirect.") diff --git a/openpype/vendor/python/python_2/urllib3/__init__.py b/openpype/vendor/python/python_2/urllib3/__init__.py new file mode 100644 index 0000000000..fe86b59d78 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/__init__.py @@ -0,0 +1,85 @@ +""" +Python HTTP library with thread-safe connection pooling, file post support, user friendly, and more +""" +from __future__ import absolute_import + +# Set default logging handler to avoid "No handler found" warnings. +import logging +import warnings +from logging import NullHandler + +from . import exceptions +from ._version import __version__ +from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, connection_from_url +from .filepost import encode_multipart_formdata +from .poolmanager import PoolManager, ProxyManager, proxy_from_url +from .response import HTTPResponse +from .util.request import make_headers +from .util.retry import Retry +from .util.timeout import Timeout +from .util.url import get_host + +__author__ = "Andrey Petrov (andrey.petrov@shazow.net)" +__license__ = "MIT" +__version__ = __version__ + +__all__ = ( + "HTTPConnectionPool", + "HTTPSConnectionPool", + "PoolManager", + "ProxyManager", + "HTTPResponse", + "Retry", + "Timeout", + "add_stderr_logger", + "connection_from_url", + "disable_warnings", + "encode_multipart_formdata", + "get_host", + "make_headers", + "proxy_from_url", +) + +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 a stderr logging handler to logger: %s", __name__) + return handler + + +# ... Clean up. +del NullHandler + + +# All warning filters *must* be appended unless you're really certain that they +# shouldn't be: otherwise, it's very hard for users to use most Python +# mechanisms to silence them. +# SecurityWarning's always go off by default. +warnings.simplefilter("always", exceptions.SecurityWarning, append=True) +# SubjectAltNameWarning's should go off once per host +warnings.simplefilter("default", exceptions.SubjectAltNameWarning, append=True) +# InsecurePlatformWarning's don't vary between requests, so we keep it default. +warnings.simplefilter("default", exceptions.InsecurePlatformWarning, append=True) +# SNIMissingWarnings should go off only once. +warnings.simplefilter("default", exceptions.SNIMissingWarning, append=True) + + +def disable_warnings(category=exceptions.HTTPWarning): + """ + Helper for quickly disabling all urllib3 warnings. + """ + warnings.simplefilter("ignore", category) diff --git a/openpype/vendor/python/python_2/urllib3/_collections.py b/openpype/vendor/python/python_2/urllib3/_collections.py new file mode 100644 index 0000000000..da9857e986 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/_collections.py @@ -0,0 +1,337 @@ +from __future__ import absolute_import + +try: + from collections.abc import Mapping, MutableMapping +except ImportError: + from collections import Mapping, MutableMapping +try: + from threading import RLock +except ImportError: # Platform-specific: No threads available + + class RLock: + def __enter__(self): + pass + + def __exit__(self, exc_type, exc_value, traceback): + pass + + +from collections import OrderedDict + +from .exceptions import InvalidHeader +from .packages import six +from .packages.six import iterkeys, itervalues + +__all__ = ["RecentlyUsedContainer", "HTTPHeaderDict"] + + +_Null = object() + + +class RecentlyUsedContainer(MutableMapping): + """ + 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 + """ + + ContainerCls = OrderedDict + + def __init__(self, maxsize=10, dispose_func=None): + self._maxsize = maxsize + self.dispose_func = dispose_func + + self._container = self.ContainerCls() + self.lock = RLock() + + def __getitem__(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 + + 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 + + # 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 self.dispose_func and evicted_value is not _Null: + self.dispose_func(evicted_value) + + def __delitem__(self, key): + with self.lock: + value = self._container.pop(key) + + 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 + values = list(itervalues(self._container)) + self._container.clear() + + if self.dispose_func: + for value in values: + self.dispose_func(value) + + def keys(self): + with self.lock: + return list(iterkeys(self._container)) + + +class HTTPHeaderDict(MutableMapping): + """ + :param headers: + An iterable of field-value pairs. Must not contain multiple field names + when compared case-insensitively. + + :param kwargs: + Additional field-value pairs to pass in to ``dict.update``. + + A ``dict`` like container for storing HTTP Headers. + + Field names are stored and compared case-insensitively in compliance with + RFC 7230. Iteration provides the first case-sensitive key seen for each + case-insensitive pair. + + Using ``__setitem__`` syntax overwrites fields that compare equal + case-insensitively in order to maintain ``dict``'s api. For fields that + compare equal, instead create a new ``HTTPHeaderDict`` and use ``.add`` + in a loop. + + If multiple fields that are equal case-insensitively are passed to the + constructor or ``.update``, the behavior is undefined and some will be + lost. + + >>> headers = HTTPHeaderDict() + >>> headers.add('Set-Cookie', 'foo=bar') + >>> headers.add('set-cookie', 'baz=quxx') + >>> headers['content-length'] = '7' + >>> headers['SET-cookie'] + 'foo=bar, baz=quxx' + >>> headers['Content-Length'] + '7' + """ + + def __init__(self, headers=None, **kwargs): + super(HTTPHeaderDict, self).__init__() + self._container = OrderedDict() + if headers is not None: + if isinstance(headers, HTTPHeaderDict): + self._copy_from(headers) + else: + self.extend(headers) + if kwargs: + self.extend(kwargs) + + def __setitem__(self, key, val): + self._container[key.lower()] = [key, val] + return self._container[key.lower()] + + def __getitem__(self, key): + val = self._container[key.lower()] + return ", ".join(val[1:]) + + def __delitem__(self, key): + del self._container[key.lower()] + + def __contains__(self, key): + return key.lower() in self._container + + def __eq__(self, other): + if not isinstance(other, Mapping) and not hasattr(other, "keys"): + return False + if not isinstance(other, type(self)): + other = type(self)(other) + return dict((k.lower(), v) for k, v in self.itermerged()) == dict( + (k.lower(), v) for k, v in other.itermerged() + ) + + def __ne__(self, other): + return not self.__eq__(other) + + if six.PY2: # Python 2 + iterkeys = MutableMapping.iterkeys + itervalues = MutableMapping.itervalues + + __marker = object() + + def __len__(self): + return len(self._container) + + def __iter__(self): + # Only provide the originally cased names + for vals in self._container.values(): + yield vals[0] + + def pop(self, key, default=__marker): + """D.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. + """ + # Using the MutableMapping function directly fails due to the private marker. + # Using ordinary dict.pop would expose the internal structures. + # So let's reinvent the wheel. + try: + value = self[key] + except KeyError: + if default is self.__marker: + raise + return default + else: + del self[key] + return value + + def discard(self, key): + try: + del self[key] + except KeyError: + pass + + def add(self, key, val): + """Adds a (name, value) pair, doesn't overwrite the value if it already + exists. + + >>> headers = HTTPHeaderDict(foo='bar') + >>> headers.add('Foo', 'baz') + >>> headers['foo'] + 'bar, baz' + """ + key_lower = key.lower() + new_vals = [key, val] + # Keep the common case aka no item present as fast as possible + vals = self._container.setdefault(key_lower, new_vals) + if new_vals is not vals: + vals.append(val) + + def extend(self, *args, **kwargs): + """Generic import function for any type of header-like object. + Adapted version of MutableMapping.update in order to insert items + with self.add instead of self.__setitem__ + """ + if len(args) > 1: + raise TypeError( + "extend() takes at most 1 positional " + "arguments ({0} given)".format(len(args)) + ) + other = args[0] if len(args) >= 1 else () + + if isinstance(other, HTTPHeaderDict): + for key, val in other.iteritems(): + self.add(key, val) + elif isinstance(other, Mapping): + for key in other: + self.add(key, other[key]) + elif hasattr(other, "keys"): + for key in other.keys(): + self.add(key, other[key]) + else: + for key, value in other: + self.add(key, value) + + for key, value in kwargs.items(): + self.add(key, value) + + def getlist(self, key, default=__marker): + """Returns a list of all the values for the named field. Returns an + empty list if the key doesn't exist.""" + try: + vals = self._container[key.lower()] + except KeyError: + if default is self.__marker: + return [] + return default + else: + return vals[1:] + + # Backwards compatibility for httplib + getheaders = getlist + getallmatchingheaders = getlist + iget = getlist + + # Backwards compatibility for http.cookiejar + get_all = getlist + + def __repr__(self): + return "%s(%s)" % (type(self).__name__, dict(self.itermerged())) + + def _copy_from(self, other): + for key in other: + val = other.getlist(key) + if isinstance(val, list): + # Don't need to convert tuples + val = list(val) + self._container[key.lower()] = [key] + val + + def copy(self): + clone = type(self)() + clone._copy_from(self) + return clone + + def iteritems(self): + """Iterate over all header lines, including duplicate ones.""" + for key in self: + vals = self._container[key.lower()] + for val in vals[1:]: + yield vals[0], val + + def itermerged(self): + """Iterate over all headers, merging duplicate ones together.""" + for key in self: + val = self._container[key.lower()] + yield val[0], ", ".join(val[1:]) + + def items(self): + return list(self.iteritems()) + + @classmethod + def from_httplib(cls, message): # Python 2 + """Read headers from a Python 2 httplib message object.""" + # python2.7 does not expose a proper API for exporting multiheaders + # efficiently. This function re-reads raw lines from the message + # object and extracts the multiheaders properly. + obs_fold_continued_leaders = (" ", "\t") + headers = [] + + for line in message.headers: + if line.startswith(obs_fold_continued_leaders): + if not headers: + # We received a header line that starts with OWS as described + # in RFC-7230 S3.2.4. This indicates a multiline header, but + # there exists no previous header to which we can attach it. + raise InvalidHeader( + "Header continuation with no previous header: %s" % line + ) + else: + key, value = headers[-1] + headers[-1] = (key, value + " " + line.strip()) + continue + + key, value = line.split(":", 1) + headers.append((key, value.strip())) + + return cls(headers) diff --git a/openpype/vendor/python/python_2/urllib3/_version.py b/openpype/vendor/python/python_2/urllib3/_version.py new file mode 100644 index 0000000000..d905b69755 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/_version.py @@ -0,0 +1,2 @@ +# This file is protected via CODEOWNERS +__version__ = "1.26.9" diff --git a/openpype/vendor/python/python_2/urllib3/connection.py b/openpype/vendor/python/python_2/urllib3/connection.py new file mode 100644 index 0000000000..7bf395bdac --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/connection.py @@ -0,0 +1,567 @@ +from __future__ import absolute_import + +import datetime +import logging +import os +import re +import socket +import warnings +from socket import error as SocketError +from socket import timeout as SocketTimeout + +from .packages import six +from .packages.six.moves.http_client import HTTPConnection as _HTTPConnection +from .packages.six.moves.http_client import HTTPException # noqa: F401 +from .util.proxy import create_proxy_ssl_context + +try: # Compiled with SSL? + import ssl + + BaseSSLError = ssl.SSLError +except (ImportError, AttributeError): # Platform-specific: No SSL. + ssl = None + + class BaseSSLError(BaseException): + pass + + +try: + # Python 3: not a no-op, we're adding this to the namespace so it can be imported. + ConnectionError = ConnectionError +except NameError: + # Python 2 + class ConnectionError(Exception): + pass + + +try: # Python 3: + # Not a no-op, we're adding this to the namespace so it can be imported. + BrokenPipeError = BrokenPipeError +except NameError: # Python 2: + + class BrokenPipeError(Exception): + pass + + +from ._collections import HTTPHeaderDict # noqa (historical, removed in v2) +from ._version import __version__ +from .exceptions import ( + ConnectTimeoutError, + NewConnectionError, + SubjectAltNameWarning, + SystemTimeWarning, +) +from .util import SKIP_HEADER, SKIPPABLE_HEADERS, connection +from .util.ssl_ import ( + assert_fingerprint, + create_urllib3_context, + is_ipaddress, + resolve_cert_reqs, + resolve_ssl_version, + ssl_wrap_socket, +) +from .util.ssl_match_hostname import CertificateError, match_hostname + +log = logging.getLogger(__name__) + +port_by_scheme = {"http": 80, "https": 443} + +# When it comes time to update this value as a part of regular maintenance +# (ie test_recent_date is failing) update it to ~6 months before the current date. +RECENT_DATE = datetime.date(2020, 7, 1) + +_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]") + + +class HTTPConnection(_HTTPConnection, object): + """ + Based on :class:`http.client.HTTPConnection` but provides an extra constructor + backwards-compatibility layer between older and newer Pythons. + + Additional keyword parameters are used to configure attributes of the connection. + Accepted parameters include: + + - ``strict``: See the documentation on :class:`urllib3.connectionpool.HTTPConnectionPool` + - ``source_address``: Set the source address for the current connection. + - ``socket_options``: Set specific options on the underlying socket. If not specified, then + defaults are loaded from ``HTTPConnection.default_socket_options`` which includes disabling + Nagle's algorithm (sets TCP_NODELAY to 1) unless the connection is behind a proxy. + + For example, if you wish to enable TCP Keep Alive in addition to the defaults, + you might pass: + + .. code-block:: python + + HTTPConnection.default_socket_options + [ + (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1), + ] + + Or you may want to disable the defaults by passing an empty list (e.g., ``[]``). + """ + + default_port = port_by_scheme["http"] + + #: Disable Nagle's algorithm by default. + #: ``[(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]`` + default_socket_options = [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)] + + #: Whether this connection verifies the host's certificate. + is_verified = False + + #: Whether this proxy connection (if used) verifies the proxy host's + #: certificate. + proxy_is_verified = None + + def __init__(self, *args, **kw): + if not six.PY2: + kw.pop("strict", None) + + # Pre-set source_address. + self.source_address = kw.get("source_address") + + #: The socket options provided by the user. If no options are + #: provided, we use the default options. + self.socket_options = kw.pop("socket_options", self.default_socket_options) + + # Proxy options provided by the user. + self.proxy = kw.pop("proxy", None) + self.proxy_config = kw.pop("proxy_config", None) + + _HTTPConnection.__init__(self, *args, **kw) + + @property + def host(self): + """ + Getter method to remove any trailing dots that indicate the hostname is an FQDN. + + In general, SSL certificates don't include the trailing dot indicating a + fully-qualified domain name, and thus, they don't validate properly when + checked against a domain name that includes the dot. In addition, some + servers may not expect to receive the trailing dot when provided. + + However, the hostname with trailing dot is critical to DNS resolution; doing a + lookup with the trailing dot will properly only resolve the appropriate FQDN, + whereas a lookup without a trailing dot will search the system's search domain + list. Thus, it's important to keep the original host around for use only in + those cases where it's appropriate (i.e., when doing DNS lookup to establish the + actual TCP connection across which we're going to send HTTP requests). + """ + return self._dns_host.rstrip(".") + + @host.setter + def host(self, value): + """ + Setter for the `host` property. + + We assume that only urllib3 uses the _dns_host attribute; httplib itself + only uses `host`, and it seems reasonable that other libraries follow suit. + """ + self._dns_host = value + + def _new_conn(self): + """Establish a socket connection and set nodelay settings on it. + + :return: New socket connection. + """ + extra_kw = {} + if self.source_address: + extra_kw["source_address"] = self.source_address + + if self.socket_options: + extra_kw["socket_options"] = self.socket_options + + try: + conn = connection.create_connection( + (self._dns_host, self.port), self.timeout, **extra_kw + ) + + except SocketTimeout: + raise ConnectTimeoutError( + self, + "Connection to %s timed out. (connect timeout=%s)" + % (self.host, self.timeout), + ) + + except SocketError as e: + raise NewConnectionError( + self, "Failed to establish a new connection: %s" % e + ) + + return conn + + def _is_using_tunnel(self): + # Google App Engine's httplib does not define _tunnel_host + return getattr(self, "_tunnel_host", None) + + def _prepare_conn(self, conn): + self.sock = conn + if self._is_using_tunnel(): + # TODO: Fix tunnel so it doesn't depend on self.sock state. + self._tunnel() + # Mark this connection as not reusable + self.auto_open = 0 + + def connect(self): + conn = self._new_conn() + self._prepare_conn(conn) + + def putrequest(self, method, url, *args, **kwargs): + """ """ + # Empty docstring because the indentation of CPython's implementation + # is broken but we don't want this method in our documentation. + match = _CONTAINS_CONTROL_CHAR_RE.search(method) + if match: + raise ValueError( + "Method cannot contain non-token characters %r (found at least %r)" + % (method, match.group()) + ) + + return _HTTPConnection.putrequest(self, method, url, *args, **kwargs) + + def putheader(self, header, *values): + """ """ + if not any(isinstance(v, str) and v == SKIP_HEADER for v in values): + _HTTPConnection.putheader(self, header, *values) + elif six.ensure_str(header.lower()) not in SKIPPABLE_HEADERS: + raise ValueError( + "urllib3.util.SKIP_HEADER only supports '%s'" + % ("', '".join(map(str.title, sorted(SKIPPABLE_HEADERS))),) + ) + + def request(self, method, url, body=None, headers=None): + if headers is None: + headers = {} + else: + # Avoid modifying the headers passed into .request() + headers = headers.copy() + if "user-agent" not in (six.ensure_str(k.lower()) for k in headers): + headers["User-Agent"] = _get_default_user_agent() + super(HTTPConnection, self).request(method, url, body=body, headers=headers) + + def request_chunked(self, method, url, body=None, headers=None): + """ + Alternative to the common request method, which sends the + body with chunked encoding and not as one block + """ + headers = headers or {} + header_keys = set([six.ensure_str(k.lower()) for k in headers]) + skip_accept_encoding = "accept-encoding" in header_keys + skip_host = "host" in header_keys + self.putrequest( + method, url, skip_accept_encoding=skip_accept_encoding, skip_host=skip_host + ) + if "user-agent" not in header_keys: + self.putheader("User-Agent", _get_default_user_agent()) + for header, value in headers.items(): + self.putheader(header, value) + if "transfer-encoding" not in header_keys: + self.putheader("Transfer-Encoding", "chunked") + self.endheaders() + + if body is not None: + stringish_types = six.string_types + (bytes,) + if isinstance(body, stringish_types): + body = (body,) + for chunk in body: + if not chunk: + continue + if not isinstance(chunk, bytes): + chunk = chunk.encode("utf8") + len_str = hex(len(chunk))[2:] + to_send = bytearray(len_str.encode()) + to_send += b"\r\n" + to_send += chunk + to_send += b"\r\n" + self.send(to_send) + + # After the if clause, to always have a closed body + self.send(b"0\r\n\r\n") + + +class HTTPSConnection(HTTPConnection): + """ + Many of the parameters to this constructor are passed to the underlying SSL + socket by means of :py:func:`urllib3.util.ssl_wrap_socket`. + """ + + default_port = port_by_scheme["https"] + + cert_reqs = None + ca_certs = None + ca_cert_dir = None + ca_cert_data = None + ssl_version = None + assert_fingerprint = None + tls_in_tls_required = False + + def __init__( + self, + host, + port=None, + key_file=None, + cert_file=None, + key_password=None, + strict=None, + timeout=socket._GLOBAL_DEFAULT_TIMEOUT, + ssl_context=None, + server_hostname=None, + **kw + ): + + HTTPConnection.__init__(self, host, port, strict=strict, timeout=timeout, **kw) + + self.key_file = key_file + self.cert_file = cert_file + self.key_password = key_password + self.ssl_context = ssl_context + self.server_hostname = server_hostname + + # Required property for Google AppEngine 1.9.0 which otherwise causes + # HTTPS requests to go out as HTTP. (See Issue #356) + self._protocol = "https" + + def set_cert( + self, + key_file=None, + cert_file=None, + cert_reqs=None, + key_password=None, + ca_certs=None, + assert_hostname=None, + assert_fingerprint=None, + ca_cert_dir=None, + ca_cert_data=None, + ): + """ + This method should only be called once, before the connection is used. + """ + # If cert_reqs is not provided we'll assume CERT_REQUIRED unless we also + # have an SSLContext object in which case we'll use its verify_mode. + if cert_reqs is None: + if self.ssl_context is not None: + cert_reqs = self.ssl_context.verify_mode + else: + cert_reqs = resolve_cert_reqs(None) + + self.key_file = key_file + self.cert_file = cert_file + self.cert_reqs = cert_reqs + self.key_password = key_password + self.assert_hostname = assert_hostname + self.assert_fingerprint = assert_fingerprint + self.ca_certs = ca_certs and os.path.expanduser(ca_certs) + self.ca_cert_dir = ca_cert_dir and os.path.expanduser(ca_cert_dir) + self.ca_cert_data = ca_cert_data + + def connect(self): + # Add certificate verification + self.sock = conn = self._new_conn() + hostname = self.host + tls_in_tls = False + + if self._is_using_tunnel(): + if self.tls_in_tls_required: + self.sock = conn = self._connect_tls_proxy(hostname, conn) + tls_in_tls = True + + # Calls self._set_hostport(), so self.host is + # self._tunnel_host below. + self._tunnel() + # Mark this connection as not reusable + self.auto_open = 0 + + # Override the host with the one we're requesting data from. + hostname = self._tunnel_host + + server_hostname = hostname + if self.server_hostname is not None: + server_hostname = self.server_hostname + + is_time_off = datetime.date.today() < RECENT_DATE + if is_time_off: + warnings.warn( + ( + "System time is way off (before {0}). This will probably " + "lead to SSL verification errors" + ).format(RECENT_DATE), + SystemTimeWarning, + ) + + # Wrap socket using verification with the root certs in + # trusted_root_certs + default_ssl_context = False + if self.ssl_context is None: + default_ssl_context = True + self.ssl_context = create_urllib3_context( + ssl_version=resolve_ssl_version(self.ssl_version), + cert_reqs=resolve_cert_reqs(self.cert_reqs), + ) + + context = self.ssl_context + context.verify_mode = resolve_cert_reqs(self.cert_reqs) + + # Try to load OS default certs if none are given. + # Works well on Windows (requires Python3.4+) + if ( + not self.ca_certs + and not self.ca_cert_dir + and not self.ca_cert_data + and default_ssl_context + and hasattr(context, "load_default_certs") + ): + context.load_default_certs() + + self.sock = ssl_wrap_socket( + sock=conn, + keyfile=self.key_file, + certfile=self.cert_file, + key_password=self.key_password, + ca_certs=self.ca_certs, + ca_cert_dir=self.ca_cert_dir, + ca_cert_data=self.ca_cert_data, + server_hostname=server_hostname, + ssl_context=context, + tls_in_tls=tls_in_tls, + ) + + # If we're using all defaults and the connection + # is TLSv1 or TLSv1.1 we throw a DeprecationWarning + # for the host. + if ( + default_ssl_context + and self.ssl_version is None + and hasattr(self.sock, "version") + and self.sock.version() in {"TLSv1", "TLSv1.1"} + ): + warnings.warn( + "Negotiating TLSv1/TLSv1.1 by default is deprecated " + "and will be disabled in urllib3 v2.0.0. Connecting to " + "'%s' with '%s' can be enabled by explicitly opting-in " + "with 'ssl_version'" % (self.host, self.sock.version()), + DeprecationWarning, + ) + + if self.assert_fingerprint: + assert_fingerprint( + self.sock.getpeercert(binary_form=True), self.assert_fingerprint + ) + elif ( + context.verify_mode != ssl.CERT_NONE + and not getattr(context, "check_hostname", False) + and self.assert_hostname is not False + ): + # While urllib3 attempts to always turn off hostname matching from + # the TLS library, this cannot always be done. So we check whether + # the TLS Library still thinks it's matching hostnames. + cert = self.sock.getpeercert() + if not cert.get("subjectAltName", ()): + warnings.warn( + ( + "Certificate for {0} has no `subjectAltName`, falling back to check for a " + "`commonName` for now. This feature is being removed by major browsers and " + "deprecated by RFC 2818. (See https://github.com/urllib3/urllib3/issues/497 " + "for details.)".format(hostname) + ), + SubjectAltNameWarning, + ) + _match_hostname(cert, self.assert_hostname or server_hostname) + + self.is_verified = ( + context.verify_mode == ssl.CERT_REQUIRED + or self.assert_fingerprint is not None + ) + + def _connect_tls_proxy(self, hostname, conn): + """ + Establish a TLS connection to the proxy using the provided SSL context. + """ + proxy_config = self.proxy_config + ssl_context = proxy_config.ssl_context + if ssl_context: + # If the user provided a proxy context, we assume CA and client + # certificates have already been set + return ssl_wrap_socket( + sock=conn, + server_hostname=hostname, + ssl_context=ssl_context, + ) + + ssl_context = create_proxy_ssl_context( + self.ssl_version, + self.cert_reqs, + self.ca_certs, + self.ca_cert_dir, + self.ca_cert_data, + ) + + # If no cert was provided, use only the default options for server + # certificate validation + socket = ssl_wrap_socket( + sock=conn, + ca_certs=self.ca_certs, + ca_cert_dir=self.ca_cert_dir, + ca_cert_data=self.ca_cert_data, + server_hostname=hostname, + ssl_context=ssl_context, + ) + + if ssl_context.verify_mode != ssl.CERT_NONE and not getattr( + ssl_context, "check_hostname", False + ): + # While urllib3 attempts to always turn off hostname matching from + # the TLS library, this cannot always be done. So we check whether + # the TLS Library still thinks it's matching hostnames. + cert = socket.getpeercert() + if not cert.get("subjectAltName", ()): + warnings.warn( + ( + "Certificate for {0} has no `subjectAltName`, falling back to check for a " + "`commonName` for now. This feature is being removed by major browsers and " + "deprecated by RFC 2818. (See https://github.com/urllib3/urllib3/issues/497 " + "for details.)".format(hostname) + ), + SubjectAltNameWarning, + ) + _match_hostname(cert, hostname) + + self.proxy_is_verified = ssl_context.verify_mode == ssl.CERT_REQUIRED + return socket + + +def _match_hostname(cert, asserted_hostname): + # Our upstream implementation of ssl.match_hostname() + # only applies this normalization to IP addresses so it doesn't + # match DNS SANs so we do the same thing! + stripped_hostname = asserted_hostname.strip("u[]") + if is_ipaddress(stripped_hostname): + asserted_hostname = stripped_hostname + + try: + match_hostname(cert, asserted_hostname) + except CertificateError as e: + log.warning( + "Certificate did not match expected hostname: %s. Certificate: %s", + asserted_hostname, + cert, + ) + # Add cert to exception and reraise so client code can inspect + # the cert when catching the exception, if they want to + e._peer_cert = cert + raise + + +def _get_default_user_agent(): + return "python-urllib3/%s" % __version__ + + +class DummyConnection(object): + """Used to detect a failed ConnectionCls import.""" + + pass + + +if not ssl: + HTTPSConnection = DummyConnection # noqa: F811 + + +VerifiedHTTPSConnection = HTTPSConnection diff --git a/openpype/vendor/python/python_2/urllib3/connectionpool.py b/openpype/vendor/python/python_2/urllib3/connectionpool.py new file mode 100644 index 0000000000..15bffcb23a --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/connectionpool.py @@ -0,0 +1,1108 @@ +from __future__ import absolute_import + +import errno +import logging +import re +import socket +import sys +import warnings +from socket import error as SocketError +from socket import timeout as SocketTimeout + +from .connection import ( + BaseSSLError, + BrokenPipeError, + DummyConnection, + HTTPConnection, + HTTPException, + HTTPSConnection, + VerifiedHTTPSConnection, + port_by_scheme, +) +from .exceptions import ( + ClosedPoolError, + EmptyPoolError, + HeaderParsingError, + HostChangedError, + InsecureRequestWarning, + LocationValueError, + MaxRetryError, + NewConnectionError, + ProtocolError, + ProxyError, + ReadTimeoutError, + SSLError, + TimeoutError, +) +from .packages import six +from .packages.six.moves import queue +from .request import RequestMethods +from .response import HTTPResponse +from .util.connection import is_connection_dropped +from .util.proxy import connection_requires_http_tunnel +from .util.queue import LifoQueue +from .util.request import set_file_position +from .util.response import assert_header_parsing +from .util.retry import Retry +from .util.ssl_match_hostname import CertificateError +from .util.timeout import Timeout +from .util.url import Url, _encode_target +from .util.url import _normalize_host as normalize_host +from .util.url import get_host, parse_url + +xrange = six.moves.xrange + +log = logging.getLogger(__name__) + +_Default = object() + + +# Pool objects +class ConnectionPool(object): + """ + Base class for all connection pools, such as + :class:`.HTTPConnectionPool` and :class:`.HTTPSConnectionPool`. + + .. note:: + ConnectionPool.urlopen() does not normalize or percent-encode target URIs + which is useful if your target server doesn't support percent-encoded + target URIs. + """ + + scheme = None + QueueCls = LifoQueue + + def __init__(self, host, port=None): + if not host: + raise LocationValueError("No host specified.") + + self.host = _normalize_host(host, scheme=self.scheme) + self._proxy_host = host.lower() + self.port = port + + def __str__(self): + return "%s(host=%r, port=%r)" % (type(self).__name__, self.host, self.port) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + # Return False to re-raise any potential exceptions + return False + + def close(self): + """ + Close all pooled connections and disable the pool. + """ + pass + + +# This is taken from http://hg.python.org/cpython/file/7aaba721ebc0/Lib/socket.py#l252 +_blocking_errnos = {errno.EAGAIN, errno.EWOULDBLOCK} + + +class HTTPConnectionPool(ConnectionPool, RequestMethods): + """ + Thread-safe connection pool for one host. + + :param host: + Host used for this HTTP Connection (e.g. "localhost"), passed into + :class:`http.client.HTTPConnection`. + + :param port: + Port used for this HTTP Connection (None is equivalent to 80), passed + into :class:`http.client.HTTPConnection`. + + :param strict: + Causes BadStatusLine to be raised if the status line can't be parsed + as a valid HTTP/1.0 or 1.1 status line, passed into + :class:`http.client.HTTPConnection`. + + .. note:: + Only works in Python 2. This parameter is ignored in Python 3. + + :param timeout: + Socket timeout in seconds for each individual connection. This can + be a float or integer, which sets the timeout for the HTTP request, + or an instance of :class:`urllib3.util.Timeout` which gives you more + fine-grained control over request timeouts. After the constructor has + been parsed, this is always a `urllib3.util.Timeout` object. + + :param maxsize: + Number of connections to save that can be reused. More than 1 is useful + in multithreaded situations. If ``block`` is set to False, more + connections will be created but they will not be saved once they've + been used. + + :param block: + If set to True, no more than ``maxsize`` connections will be used at + a time. When no free connections are available, the call will block + until a connection has been released. This is a useful side effect for + particular multithreaded situations where one does not want to use more + than maxsize connections per host to prevent flooding. + + :param headers: + Headers to include with all requests, unless other headers are given + explicitly. + + :param retries: + Retry configuration to use by default with requests in this pool. + + :param _proxy: + Parsed proxy URL, should not be used directly, instead, see + :class:`urllib3.ProxyManager` + + :param _proxy_headers: + A dictionary with proxy headers, should not be used directly, + instead, see :class:`urllib3.ProxyManager` + + :param \\**conn_kw: + Additional parameters are used to create fresh :class:`urllib3.connection.HTTPConnection`, + :class:`urllib3.connection.HTTPSConnection` instances. + """ + + scheme = "http" + ConnectionCls = HTTPConnection + ResponseCls = HTTPResponse + + def __init__( + self, + host, + port=None, + strict=False, + timeout=Timeout.DEFAULT_TIMEOUT, + maxsize=1, + block=False, + headers=None, + retries=None, + _proxy=None, + _proxy_headers=None, + _proxy_config=None, + **conn_kw + ): + ConnectionPool.__init__(self, host, port) + RequestMethods.__init__(self, headers) + + self.strict = strict + + if not isinstance(timeout, Timeout): + timeout = Timeout.from_float(timeout) + + if retries is None: + retries = Retry.DEFAULT + + self.timeout = timeout + self.retries = retries + + self.pool = self.QueueCls(maxsize) + self.block = block + + self.proxy = _proxy + self.proxy_headers = _proxy_headers or {} + self.proxy_config = _proxy_config + + # Fill the queue up so that doing get() on it will block properly + for _ in xrange(maxsize): + self.pool.put(None) + + # These are mostly for testing and debugging purposes. + self.num_connections = 0 + self.num_requests = 0 + self.conn_kw = conn_kw + + if self.proxy: + # Enable Nagle's algorithm for proxies, to avoid packet fragmentation. + # We cannot know if the user has added default socket options, so we cannot replace the + # list. + self.conn_kw.setdefault("socket_options", []) + + self.conn_kw["proxy"] = self.proxy + self.conn_kw["proxy_config"] = self.proxy_config + + def _new_conn(self): + """ + Return a fresh :class:`HTTPConnection`. + """ + self.num_connections += 1 + log.debug( + "Starting new HTTP connection (%d): %s:%s", + self.num_connections, + self.host, + self.port or "80", + ) + + conn = self.ConnectionCls( + host=self.host, + port=self.port, + timeout=self.timeout.connect_timeout, + strict=self.strict, + **self.conn_kw + ) + return conn + + def _get_conn(self, timeout=None): + """ + Get a connection. Will return a pooled connection if one is available. + + If no connections are available and :prop:`.block` is ``False``, then a + fresh connection is returned. + + :param timeout: + Seconds to wait before giving up and raising + :class:`urllib3.exceptions.EmptyPoolError` if the pool is empty and + :prop:`.block` is ``True``. + """ + conn = None + try: + conn = self.pool.get(block=self.block, timeout=timeout) + + except AttributeError: # self.pool is None + raise ClosedPoolError(self, "Pool is closed.") + + except queue.Empty: + if self.block: + raise EmptyPoolError( + self, + "Pool reached maximum size and no more 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.debug("Resetting dropped connection: %s", self.host) + conn.close() + if getattr(conn, "auto_open", 1) == 0: + # This is a proxied connection that has been mutated by + # http.client._tunnel() and cannot be reused (since it would + # attempt to bypass the proxy) + conn = None + + return conn or self._new_conn() + + def _put_conn(self, conn): + """ + Put a connection back into the pool. + + :param conn: + 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 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 queue.Full: + # This should never happen if self.block == True + log.warning( + "Connection pool is full, discarding connection: %s. Connection pool size: %s", + self.host, + self.pool.qsize(), + ) + # Connection never got put back into the pool, close it. + if conn: + conn.close() + + def _validate_conn(self, conn): + """ + Called right before a request is made, after the socket is created. + """ + pass + + def _prepare_proxy(self, conn): + # Nothing to do for HTTP connections. + pass + + def _get_timeout(self, timeout): + """Helper that always returns a :class:`urllib3.util.Timeout`""" + if timeout is _Default: + return self.timeout.clone() + + if isinstance(timeout, Timeout): + return timeout.clone() + else: + # User passed us an int/float. This is for backwards compatibility, + # can be removed later + return Timeout.from_float(timeout) + + def _raise_timeout(self, err, url, timeout_value): + """Is the error actually a timeout? Will raise a ReadTimeout or pass""" + + if isinstance(err, SocketTimeout): + raise ReadTimeoutError( + self, url, "Read timed out. (read timeout=%s)" % timeout_value + ) + + # See the above comment about EAGAIN in Python 3. In Python 2 we have + # to specifically catch it and throw the timeout error + if hasattr(err, "errno") and err.errno in _blocking_errnos: + raise ReadTimeoutError( + self, url, "Read timed out. (read timeout=%s)" % timeout_value + ) + + # Catch possible read timeouts thrown as SSL errors. If not the + # case, rethrow the original. We need to do this because of: + # http://bugs.python.org/issue10272 + if "timed out" in str(err) or "did not complete (read)" in str( + err + ): # Python < 2.7.4 + raise ReadTimeoutError( + self, url, "Read timed out. (read timeout=%s)" % timeout_value + ) + + def _make_request( + self, conn, method, url, timeout=_Default, chunked=False, **httplib_request_kw + ): + """ + Perform a request on a given urllib connection object taken from our + pool. + + :param conn: + a connection from one of our connection pools + + :param timeout: + Socket timeout in seconds for the request. This can be a + float or integer, which will set the same timeout value for + the socket connect and the socket read, or an instance of + :class:`urllib3.util.Timeout`, which gives you more fine-grained + control over your timeouts. + """ + self.num_requests += 1 + + timeout_obj = self._get_timeout(timeout) + timeout_obj.start_connect() + conn.timeout = timeout_obj.connect_timeout + + # Trigger any extra validation we need to do. + try: + self._validate_conn(conn) + except (SocketTimeout, BaseSSLError) as e: + # Py2 raises this as a BaseSSLError, Py3 raises it as socket timeout. + self._raise_timeout(err=e, url=url, timeout_value=conn.timeout) + raise + + # conn.request() calls http.client.*.request, not the method in + # urllib3.request. It also calls makefile (recv) on the socket. + try: + if chunked: + conn.request_chunked(method, url, **httplib_request_kw) + else: + conn.request(method, url, **httplib_request_kw) + + # We are swallowing BrokenPipeError (errno.EPIPE) since the server is + # legitimately able to close the connection after sending a valid response. + # With this behaviour, the received response is still readable. + except BrokenPipeError: + # Python 3 + pass + except IOError as e: + # Python 2 and macOS/Linux + # EPIPE and ESHUTDOWN are BrokenPipeError on Python 2, and EPROTOTYPE is needed on macOS + # https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/ + if e.errno not in { + errno.EPIPE, + errno.ESHUTDOWN, + errno.EPROTOTYPE, + }: + raise + + # Reset the timeout for the recv() on the socket + read_timeout = timeout_obj.read_timeout + + # App Engine doesn't have a sock attr + if getattr(conn, "sock", None): + # In Python 3 socket.py will catch EAGAIN and return None when you + # try and read into the file pointer created by http.client, which + # instead raises a BadStatusLine exception. Instead of catching + # the exception and assuming all BadStatusLine exceptions are read + # timeouts, check for a zero timeout before making the request. + if read_timeout == 0: + raise ReadTimeoutError( + self, url, "Read timed out. (read timeout=%s)" % read_timeout + ) + if read_timeout is Timeout.DEFAULT_TIMEOUT: + conn.sock.settimeout(socket.getdefaulttimeout()) + else: # None or a value + conn.sock.settimeout(read_timeout) + + # Receive the response from the server + try: + try: + # Python 2.7, use buffering of HTTP responses + httplib_response = conn.getresponse(buffering=True) + except TypeError: + # Python 3 + try: + httplib_response = conn.getresponse() + except BaseException as e: + # Remove the TypeError from the exception chain in + # Python 3 (including for exceptions like SystemExit). + # Otherwise it looks like a bug in the code. + six.raise_from(e, None) + except (SocketTimeout, BaseSSLError, SocketError) as e: + self._raise_timeout(err=e, url=url, timeout_value=read_timeout) + raise + + # AppEngine doesn't have a version attr. + http_version = getattr(conn, "_http_vsn_str", "HTTP/?") + log.debug( + '%s://%s:%s "%s %s %s" %s %s', + self.scheme, + self.host, + self.port, + method, + url, + http_version, + httplib_response.status, + httplib_response.length, + ) + + try: + assert_header_parsing(httplib_response.msg) + except (HeaderParsingError, TypeError) as hpe: # Platform-specific: Python 3 + log.warning( + "Failed to parse headers (url=%s): %s", + self._absolute_url(url), + hpe, + exc_info=True, + ) + + return httplib_response + + def _absolute_url(self, path): + return Url(scheme=self.scheme, host=self.host, port=self.port, path=path).url + + def close(self): + """ + Close all pooled connections and disable the pool. + """ + if self.pool is None: + return + # 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 queue.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) + if host is not None: + host = _normalize_host(host, scheme=scheme) + + # Use explicit default port for comparison when none is given + if self.port and not port: + port = port_by_scheme.get(scheme) + elif not self.port and port == port_by_scheme.get(scheme): + port = None + + return (scheme, host, port) == (self.scheme, self.host, self.port) + + def urlopen( + self, + method, + url, + body=None, + headers=None, + retries=None, + redirect=True, + assert_same_host=True, + timeout=_Default, + pool_timeout=None, + release_conn=None, + chunked=False, + body_pos=None, + **response_kw + ): + """ + Get a connection from the pool and perform an HTTP request. This is the + lowest level call for making a request, so you'll need to specify all + the raw details. + + .. note:: + + More commonly, it's appropriate to use a convenience method provided + by :class:`.RequestMethods`, such as :meth:`request`. + + .. note:: + + `release_conn` will only behave as expected if + `preload_content=False` because we want to make + `preload_content=False` the default behaviour someday soon without + breaking backwards compatibility. + + :param method: + HTTP request method (such as GET, POST, PUT, etc.) + + :param url: + The URL to perform the request on. + + :param body: + Data to send in the request body, either :class:`str`, :class:`bytes`, + an iterable of :class:`str`/:class:`bytes`, or a file-like object. + + :param headers: + Dictionary of custom headers to send, such as User-Agent, + If-None-Match, etc. If None, pool headers are used. If provided, + these headers completely replace any pool-specific headers. + + :param retries: + Configure the number of retries to allow before raising a + :class:`~urllib3.exceptions.MaxRetryError` exception. + + Pass ``None`` to retry until you receive a response. Pass a + :class:`~urllib3.util.retry.Retry` object for fine-grained control + over different types of retries. + Pass an integer number to retry connection errors that many times, + but no other types of errors. Pass zero to never retry. + + If ``False``, then retries are disabled and any exception is raised + immediately. Also, instead of raising a MaxRetryError on redirects, + the redirect response will be returned. + + :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int. + + :param redirect: + If True, automatically handle redirects (status codes 301, 302, + 303, 307, 308). Each redirect counts as a retry. Disabling retries + will disable redirect, too. + + :param assert_same_host: + If ``True``, will make sure that the host of the pool requests is + consistent else will raise HostChangedError. When ``False``, you can + use the pool on an HTTP proxy and request foreign hosts. + + :param timeout: + If specified, overrides the default timeout for this one + request. It may be a float (in seconds) or an instance of + :class:`urllib3.util.Timeout`. + + :param pool_timeout: + If set and the pool is set to block=True, then this method will + block for ``pool_timeout`` seconds and raise EmptyPoolError if no + connection is available within the time period. + + :param release_conn: + If False, then the urlopen call will not release the connection + back into the pool once a response is received (but will release if + you read the entire contents of the response such as when + `preload_content=True`). This is useful if you're not preloading + the response's content immediately. You will need to call + ``r.release_conn()`` on the response ``r`` to return the connection + back into the pool. If None, it takes the value of + ``response_kw.get('preload_content', True)``. + + :param chunked: + If True, urllib3 will send the body using chunked transfer + encoding. Otherwise, urllib3 will send the body using the standard + content-length form. Defaults to False. + + :param int body_pos: + Position to seek to in file-like body in the event of a retry or + redirect. Typically this won't need to be set because urllib3 will + auto-populate the value when needed. + + :param \\**response_kw: + Additional parameters are passed to + :meth:`urllib3.response.HTTPResponse.from_httplib` + """ + + parsed_url = parse_url(url) + destination_scheme = parsed_url.scheme + + if headers is None: + headers = self.headers + + if not isinstance(retries, Retry): + retries = Retry.from_int(retries, redirect=redirect, default=self.retries) + + if release_conn is None: + release_conn = response_kw.get("preload_content", True) + + # Check host + if assert_same_host and not self.is_same_host(url): + raise HostChangedError(self, url, retries) + + # Ensure that the URL we're connecting to is properly encoded + if url.startswith("/"): + url = six.ensure_str(_encode_target(url)) + else: + url = six.ensure_str(parsed_url.url) + + conn = None + + # Track whether `conn` needs to be released before + # returning/raising/recursing. Update this variable if necessary, and + # leave `release_conn` constant throughout the function. That way, if + # the function recurses, the original value of `release_conn` will be + # passed down into the recursive call, and its value will be respected. + # + # See issue #651 [1] for details. + # + # [1] + release_this_conn = release_conn + + http_tunnel_required = connection_requires_http_tunnel( + self.proxy, self.proxy_config, destination_scheme + ) + + # Merge the proxy headers. Only done when not using HTTP CONNECT. We + # have to copy the headers dict so we can safely change it without those + # changes being reflected in anyone else's copy. + if not http_tunnel_required: + headers = headers.copy() + headers.update(self.proxy_headers) + + # Must keep the exception bound to a separate variable or else Python 3 + # complains about UnboundLocalError. + err = None + + # Keep track of whether we cleanly exited the except block. This + # ensures we do proper cleanup in finally. + clean_exit = False + + # Rewind body position, if needed. Record current position + # for future rewinds in the event of a redirect/retry. + body_pos = set_file_position(body, body_pos) + + try: + # Request a connection from the queue. + timeout_obj = self._get_timeout(timeout) + conn = self._get_conn(timeout=pool_timeout) + + conn.timeout = timeout_obj.connect_timeout + + is_new_proxy_conn = self.proxy is not None and not getattr( + conn, "sock", None + ) + if is_new_proxy_conn and http_tunnel_required: + self._prepare_proxy(conn) + + # Make the request on the httplib connection object. + httplib_response = self._make_request( + conn, + method, + url, + timeout=timeout_obj, + body=body, + headers=headers, + chunked=chunked, + ) + + # If we're going to release the connection in ``finally:``, then + # the response doesn't need to know about the connection. Otherwise + # it will also try to release it and we'll have a double-release + # mess. + response_conn = conn if not release_conn else None + + # Pass method to Response for length checking + response_kw["request_method"] = method + + # Import httplib's response into our own wrapper object + response = self.ResponseCls.from_httplib( + httplib_response, + pool=self, + connection=response_conn, + retries=retries, + **response_kw + ) + + # Everything went great! + clean_exit = True + + except EmptyPoolError: + # Didn't get a connection from the pool, no need to clean up + clean_exit = True + release_this_conn = False + raise + + except ( + TimeoutError, + HTTPException, + SocketError, + ProtocolError, + BaseSSLError, + SSLError, + CertificateError, + ) as e: + # Discard the connection for these exceptions. It will be + # replaced during the next _get_conn() call. + clean_exit = False + + def _is_ssl_error_message_from_http_proxy(ssl_error): + # We're trying to detect the message 'WRONG_VERSION_NUMBER' but + # SSLErrors are kinda all over the place when it comes to the message, + # so we try to cover our bases here! + message = " ".join(re.split("[^a-z]", str(ssl_error).lower())) + return ( + "wrong version number" in message or "unknown protocol" in message + ) + + # Try to detect a common user error with proxies which is to + # set an HTTP proxy to be HTTPS when it should be 'http://' + # (ie {'http': 'http://proxy', 'https': 'https://proxy'}) + # Instead we add a nice error message and point to a URL. + if ( + isinstance(e, BaseSSLError) + and self.proxy + and _is_ssl_error_message_from_http_proxy(e) + ): + e = ProxyError( + "Your proxy appears to only use HTTP and not HTTPS, " + "try changing your proxy URL to be HTTP. See: " + "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html" + "#https-proxy-error-http-proxy", + SSLError(e), + ) + elif isinstance(e, (BaseSSLError, CertificateError)): + e = SSLError(e) + elif isinstance(e, (SocketError, NewConnectionError)) and self.proxy: + e = ProxyError("Cannot connect to proxy.", e) + elif isinstance(e, (SocketError, HTTPException)): + e = ProtocolError("Connection aborted.", e) + + retries = retries.increment( + method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2] + ) + retries.sleep() + + # Keep track of the error for the retry warning. + err = e + + finally: + if not clean_exit: + # We hit some kind of exception, handled or otherwise. We need + # to throw the connection away unless explicitly told not to. + # Close the connection, set the variable to None, and make sure + # we put the None back in the pool to avoid leaking it. + conn = conn and conn.close() + release_this_conn = True + + if release_this_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.warning( + "Retrying (%r) after connection broken by '%r': %s", retries, err, url + ) + return self.urlopen( + method, + url, + body, + headers, + retries, + redirect, + assert_same_host, + timeout=timeout, + pool_timeout=pool_timeout, + release_conn=release_conn, + chunked=chunked, + body_pos=body_pos, + **response_kw + ) + + # Handle redirect? + redirect_location = redirect and response.get_redirect_location() + if redirect_location: + if response.status == 303: + method = "GET" + + try: + retries = retries.increment(method, url, response=response, _pool=self) + except MaxRetryError: + if retries.raise_on_redirect: + response.drain_conn() + raise + return response + + response.drain_conn() + retries.sleep_for_retry(response) + log.debug("Redirecting %s -> %s", url, redirect_location) + return self.urlopen( + method, + redirect_location, + body, + headers, + retries=retries, + redirect=redirect, + assert_same_host=assert_same_host, + timeout=timeout, + pool_timeout=pool_timeout, + release_conn=release_conn, + chunked=chunked, + body_pos=body_pos, + **response_kw + ) + + # Check if we should retry the HTTP response. + has_retry_after = bool(response.getheader("Retry-After")) + if retries.is_retry(method, response.status, has_retry_after): + try: + retries = retries.increment(method, url, response=response, _pool=self) + except MaxRetryError: + if retries.raise_on_status: + response.drain_conn() + raise + return response + + response.drain_conn() + retries.sleep(response) + log.debug("Retry: %s", url) + return self.urlopen( + method, + url, + body, + headers, + retries=retries, + redirect=redirect, + assert_same_host=assert_same_host, + timeout=timeout, + pool_timeout=pool_timeout, + release_conn=release_conn, + chunked=chunked, + body_pos=body_pos, + **response_kw + ) + + return response + + +class HTTPSConnectionPool(HTTPConnectionPool): + """ + Same as :class:`.HTTPConnectionPool`, but HTTPS. + + :class:`.HTTPSConnection` uses one of ``assert_fingerprint``, + ``assert_hostname`` and ``host`` in this order to verify connections. + If ``assert_hostname`` is False, no verification is done. + + The ``key_file``, ``cert_file``, ``cert_reqs``, ``ca_certs``, + ``ca_cert_dir``, ``ssl_version``, ``key_password`` are only used if :mod:`ssl` + is available and are fed into :meth:`urllib3.util.ssl_wrap_socket` to upgrade + the connection socket into an SSL socket. + """ + + scheme = "https" + ConnectionCls = HTTPSConnection + + def __init__( + self, + host, + port=None, + strict=False, + timeout=Timeout.DEFAULT_TIMEOUT, + maxsize=1, + block=False, + headers=None, + retries=None, + _proxy=None, + _proxy_headers=None, + key_file=None, + cert_file=None, + cert_reqs=None, + key_password=None, + ca_certs=None, + ssl_version=None, + assert_hostname=None, + assert_fingerprint=None, + ca_cert_dir=None, + **conn_kw + ): + + HTTPConnectionPool.__init__( + self, + host, + port, + strict, + timeout, + maxsize, + block, + headers, + retries, + _proxy, + _proxy_headers, + **conn_kw + ) + + self.key_file = key_file + self.cert_file = cert_file + self.cert_reqs = cert_reqs + self.key_password = key_password + self.ca_certs = ca_certs + self.ca_cert_dir = ca_cert_dir + self.ssl_version = ssl_version + self.assert_hostname = assert_hostname + self.assert_fingerprint = assert_fingerprint + + def _prepare_conn(self, conn): + """ + Prepare the ``connection`` for :meth:`urllib3.util.ssl_wrap_socket` + and establish the tunnel if proxy is used. + """ + + if isinstance(conn, VerifiedHTTPSConnection): + conn.set_cert( + key_file=self.key_file, + key_password=self.key_password, + cert_file=self.cert_file, + cert_reqs=self.cert_reqs, + ca_certs=self.ca_certs, + ca_cert_dir=self.ca_cert_dir, + assert_hostname=self.assert_hostname, + assert_fingerprint=self.assert_fingerprint, + ) + conn.ssl_version = self.ssl_version + return conn + + def _prepare_proxy(self, conn): + """ + Establishes a tunnel connection through HTTP CONNECT. + + Tunnel connection is established early because otherwise httplib would + improperly set Host: header to proxy's IP:port. + """ + + conn.set_tunnel(self._proxy_host, self.port, self.proxy_headers) + + if self.proxy.scheme == "https": + conn.tls_in_tls_required = True + + conn.connect() + + def _new_conn(self): + """ + Return a fresh :class:`http.client.HTTPSConnection`. + """ + self.num_connections += 1 + log.debug( + "Starting new HTTPS connection (%d): %s:%s", + self.num_connections, + self.host, + self.port or "443", + ) + + if not self.ConnectionCls or self.ConnectionCls is DummyConnection: + raise SSLError( + "Can't connect to HTTPS URL because the SSL module is not available." + ) + + actual_host = self.host + actual_port = self.port + if self.proxy is not None: + actual_host = self.proxy.host + actual_port = self.proxy.port + + conn = self.ConnectionCls( + host=actual_host, + port=actual_port, + timeout=self.timeout.connect_timeout, + strict=self.strict, + cert_file=self.cert_file, + key_file=self.key_file, + key_password=self.key_password, + **self.conn_kw + ) + + return self._prepare_conn(conn) + + def _validate_conn(self, conn): + """ + Called right before a request is made, after the socket is created. + """ + super(HTTPSConnectionPool, self)._validate_conn(conn) + + # Force connect early to allow us to validate the connection. + if not getattr(conn, "sock", None): # AppEngine might not have `.sock` + conn.connect() + + if not conn.is_verified: + warnings.warn( + ( + "Unverified HTTPS request is being made to host '%s'. " + "Adding certificate verification is strongly advised. See: " + "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html" + "#ssl-warnings" % conn.host + ), + InsecureRequestWarning, + ) + + if getattr(conn, "proxy_is_verified", None) is False: + warnings.warn( + ( + "Unverified HTTPS connection done to an HTTPS proxy. " + "Adding certificate verification is strongly advised. See: " + "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html" + "#ssl-warnings" + ), + InsecureRequestWarning, + ) + + +def connection_from_url(url, **kw): + """ + Given a url, return an :class:`.ConnectionPool` instance of its host. + + This is a shortcut for not having to parse out the scheme, host, and port + of the url before creating an :class:`.ConnectionPool` instance. + + :param url: + Absolute URL string that must include the scheme. Port is optional. + + :param \\**kw: + Passes additional parameters to the constructor of the appropriate + :class:`.ConnectionPool`. Useful for specifying things like + timeout, maxsize, headers, etc. + + Example:: + + >>> conn = connection_from_url('http://google.com/') + >>> r = conn.request('GET', '/') + """ + scheme, host, port = get_host(url) + port = port or port_by_scheme.get(scheme, 80) + if scheme == "https": + return HTTPSConnectionPool(host, port=port, **kw) + else: + return HTTPConnectionPool(host, port=port, **kw) + + +def _normalize_host(host, scheme): + """ + Normalize hosts for comparisons and use with sockets. + """ + + host = normalize_host(host, scheme) + + # httplib doesn't like it when we include brackets in IPv6 addresses + # Specifically, if we include brackets but also pass the port then + # httplib crazily doubles up the square brackets on the Host header. + # Instead, we need to make sure we never pass ``None`` as the port. + # However, for backward compatibility reasons we can't actually + # *assert* that. See http://bugs.python.org/issue28539 + if host.startswith("[") and host.endswith("]"): + host = host[1:-1] + return host diff --git a/openpype/vendor/python/python_2/urllib3/contrib/__init__.py b/openpype/vendor/python/python_2/urllib3/contrib/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openpype/vendor/python/python_2/urllib3/contrib/_appengine_environ.py b/openpype/vendor/python/python_2/urllib3/contrib/_appengine_environ.py new file mode 100644 index 0000000000..8765b907d7 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/contrib/_appengine_environ.py @@ -0,0 +1,36 @@ +""" +This module provides means to detect the App Engine environment. +""" + +import os + + +def is_appengine(): + return is_local_appengine() or is_prod_appengine() + + +def is_appengine_sandbox(): + """Reports if the app is running in the first generation sandbox. + + The second generation runtimes are technically still in a sandbox, but it + is much less restrictive, so generally you shouldn't need to check for it. + see https://cloud.google.com/appengine/docs/standard/runtimes + """ + return is_appengine() and os.environ["APPENGINE_RUNTIME"] == "python27" + + +def is_local_appengine(): + return "APPENGINE_RUNTIME" in os.environ and os.environ.get( + "SERVER_SOFTWARE", "" + ).startswith("Development/") + + +def is_prod_appengine(): + return "APPENGINE_RUNTIME" in os.environ and os.environ.get( + "SERVER_SOFTWARE", "" + ).startswith("Google App Engine/") + + +def is_prod_appengine_mvms(): + """Deprecated.""" + return False diff --git a/openpype/vendor/python/python_2/urllib3/contrib/_securetransport/__init__.py b/openpype/vendor/python/python_2/urllib3/contrib/_securetransport/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openpype/vendor/python/python_2/urllib3/contrib/_securetransport/bindings.py b/openpype/vendor/python/python_2/urllib3/contrib/_securetransport/bindings.py new file mode 100644 index 0000000000..264d564dbd --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/contrib/_securetransport/bindings.py @@ -0,0 +1,519 @@ +""" +This module uses ctypes to bind a whole bunch of functions and constants from +SecureTransport. The goal here is to provide the low-level API to +SecureTransport. These are essentially the C-level functions and constants, and +they're pretty gross to work with. + +This code is a bastardised version of the code found in Will Bond's oscrypto +library. An enormous debt is owed to him for blazing this trail for us. For +that reason, this code should be considered to be covered both by urllib3's +license and by oscrypto's: + + Copyright (c) 2015-2016 Will Bond + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +""" +from __future__ import absolute_import + +import platform +from ctypes import ( + CDLL, + CFUNCTYPE, + POINTER, + c_bool, + c_byte, + c_char_p, + c_int32, + c_long, + c_size_t, + c_uint32, + c_ulong, + c_void_p, +) +from ctypes.util import find_library + +from ...packages.six import raise_from + +if platform.system() != "Darwin": + raise ImportError("Only macOS is supported") + +version = platform.mac_ver()[0] +version_info = tuple(map(int, version.split("."))) +if version_info < (10, 8): + raise OSError( + "Only OS X 10.8 and newer are supported, not %s.%s" + % (version_info[0], version_info[1]) + ) + + +def load_cdll(name, macos10_16_path): + """Loads a CDLL by name, falling back to known path on 10.16+""" + try: + # Big Sur is technically 11 but we use 10.16 due to the Big Sur + # beta being labeled as 10.16. + if version_info >= (10, 16): + path = macos10_16_path + else: + path = find_library(name) + if not path: + raise OSError # Caught and reraised as 'ImportError' + return CDLL(path, use_errno=True) + except OSError: + raise_from(ImportError("The library %s failed to load" % name), None) + + +Security = load_cdll( + "Security", "/System/Library/Frameworks/Security.framework/Security" +) +CoreFoundation = load_cdll( + "CoreFoundation", + "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", +) + + +Boolean = c_bool +CFIndex = c_long +CFStringEncoding = c_uint32 +CFData = c_void_p +CFString = c_void_p +CFArray = c_void_p +CFMutableArray = c_void_p +CFDictionary = c_void_p +CFError = c_void_p +CFType = c_void_p +CFTypeID = c_ulong + +CFTypeRef = POINTER(CFType) +CFAllocatorRef = c_void_p + +OSStatus = c_int32 + +CFDataRef = POINTER(CFData) +CFStringRef = POINTER(CFString) +CFArrayRef = POINTER(CFArray) +CFMutableArrayRef = POINTER(CFMutableArray) +CFDictionaryRef = POINTER(CFDictionary) +CFArrayCallBacks = c_void_p +CFDictionaryKeyCallBacks = c_void_p +CFDictionaryValueCallBacks = c_void_p + +SecCertificateRef = POINTER(c_void_p) +SecExternalFormat = c_uint32 +SecExternalItemType = c_uint32 +SecIdentityRef = POINTER(c_void_p) +SecItemImportExportFlags = c_uint32 +SecItemImportExportKeyParameters = c_void_p +SecKeychainRef = POINTER(c_void_p) +SSLProtocol = c_uint32 +SSLCipherSuite = c_uint32 +SSLContextRef = POINTER(c_void_p) +SecTrustRef = POINTER(c_void_p) +SSLConnectionRef = c_uint32 +SecTrustResultType = c_uint32 +SecTrustOptionFlags = c_uint32 +SSLProtocolSide = c_uint32 +SSLConnectionType = c_uint32 +SSLSessionOption = c_uint32 + + +try: + Security.SecItemImport.argtypes = [ + CFDataRef, + CFStringRef, + POINTER(SecExternalFormat), + POINTER(SecExternalItemType), + SecItemImportExportFlags, + POINTER(SecItemImportExportKeyParameters), + SecKeychainRef, + POINTER(CFArrayRef), + ] + Security.SecItemImport.restype = OSStatus + + Security.SecCertificateGetTypeID.argtypes = [] + Security.SecCertificateGetTypeID.restype = CFTypeID + + Security.SecIdentityGetTypeID.argtypes = [] + Security.SecIdentityGetTypeID.restype = CFTypeID + + Security.SecKeyGetTypeID.argtypes = [] + Security.SecKeyGetTypeID.restype = CFTypeID + + Security.SecCertificateCreateWithData.argtypes = [CFAllocatorRef, CFDataRef] + Security.SecCertificateCreateWithData.restype = SecCertificateRef + + Security.SecCertificateCopyData.argtypes = [SecCertificateRef] + Security.SecCertificateCopyData.restype = CFDataRef + + Security.SecCopyErrorMessageString.argtypes = [OSStatus, c_void_p] + Security.SecCopyErrorMessageString.restype = CFStringRef + + Security.SecIdentityCreateWithCertificate.argtypes = [ + CFTypeRef, + SecCertificateRef, + POINTER(SecIdentityRef), + ] + Security.SecIdentityCreateWithCertificate.restype = OSStatus + + Security.SecKeychainCreate.argtypes = [ + c_char_p, + c_uint32, + c_void_p, + Boolean, + c_void_p, + POINTER(SecKeychainRef), + ] + Security.SecKeychainCreate.restype = OSStatus + + Security.SecKeychainDelete.argtypes = [SecKeychainRef] + Security.SecKeychainDelete.restype = OSStatus + + Security.SecPKCS12Import.argtypes = [ + CFDataRef, + CFDictionaryRef, + POINTER(CFArrayRef), + ] + Security.SecPKCS12Import.restype = OSStatus + + SSLReadFunc = CFUNCTYPE(OSStatus, SSLConnectionRef, c_void_p, POINTER(c_size_t)) + SSLWriteFunc = CFUNCTYPE( + OSStatus, SSLConnectionRef, POINTER(c_byte), POINTER(c_size_t) + ) + + Security.SSLSetIOFuncs.argtypes = [SSLContextRef, SSLReadFunc, SSLWriteFunc] + Security.SSLSetIOFuncs.restype = OSStatus + + Security.SSLSetPeerID.argtypes = [SSLContextRef, c_char_p, c_size_t] + Security.SSLSetPeerID.restype = OSStatus + + Security.SSLSetCertificate.argtypes = [SSLContextRef, CFArrayRef] + Security.SSLSetCertificate.restype = OSStatus + + Security.SSLSetCertificateAuthorities.argtypes = [SSLContextRef, CFTypeRef, Boolean] + Security.SSLSetCertificateAuthorities.restype = OSStatus + + Security.SSLSetConnection.argtypes = [SSLContextRef, SSLConnectionRef] + Security.SSLSetConnection.restype = OSStatus + + Security.SSLSetPeerDomainName.argtypes = [SSLContextRef, c_char_p, c_size_t] + Security.SSLSetPeerDomainName.restype = OSStatus + + Security.SSLHandshake.argtypes = [SSLContextRef] + Security.SSLHandshake.restype = OSStatus + + Security.SSLRead.argtypes = [SSLContextRef, c_char_p, c_size_t, POINTER(c_size_t)] + Security.SSLRead.restype = OSStatus + + Security.SSLWrite.argtypes = [SSLContextRef, c_char_p, c_size_t, POINTER(c_size_t)] + Security.SSLWrite.restype = OSStatus + + Security.SSLClose.argtypes = [SSLContextRef] + Security.SSLClose.restype = OSStatus + + Security.SSLGetNumberSupportedCiphers.argtypes = [SSLContextRef, POINTER(c_size_t)] + Security.SSLGetNumberSupportedCiphers.restype = OSStatus + + Security.SSLGetSupportedCiphers.argtypes = [ + SSLContextRef, + POINTER(SSLCipherSuite), + POINTER(c_size_t), + ] + Security.SSLGetSupportedCiphers.restype = OSStatus + + Security.SSLSetEnabledCiphers.argtypes = [ + SSLContextRef, + POINTER(SSLCipherSuite), + c_size_t, + ] + Security.SSLSetEnabledCiphers.restype = OSStatus + + Security.SSLGetNumberEnabledCiphers.argtype = [SSLContextRef, POINTER(c_size_t)] + Security.SSLGetNumberEnabledCiphers.restype = OSStatus + + Security.SSLGetEnabledCiphers.argtypes = [ + SSLContextRef, + POINTER(SSLCipherSuite), + POINTER(c_size_t), + ] + Security.SSLGetEnabledCiphers.restype = OSStatus + + Security.SSLGetNegotiatedCipher.argtypes = [SSLContextRef, POINTER(SSLCipherSuite)] + Security.SSLGetNegotiatedCipher.restype = OSStatus + + Security.SSLGetNegotiatedProtocolVersion.argtypes = [ + SSLContextRef, + POINTER(SSLProtocol), + ] + Security.SSLGetNegotiatedProtocolVersion.restype = OSStatus + + Security.SSLCopyPeerTrust.argtypes = [SSLContextRef, POINTER(SecTrustRef)] + Security.SSLCopyPeerTrust.restype = OSStatus + + Security.SecTrustSetAnchorCertificates.argtypes = [SecTrustRef, CFArrayRef] + Security.SecTrustSetAnchorCertificates.restype = OSStatus + + Security.SecTrustSetAnchorCertificatesOnly.argstypes = [SecTrustRef, Boolean] + Security.SecTrustSetAnchorCertificatesOnly.restype = OSStatus + + Security.SecTrustEvaluate.argtypes = [SecTrustRef, POINTER(SecTrustResultType)] + Security.SecTrustEvaluate.restype = OSStatus + + Security.SecTrustGetCertificateCount.argtypes = [SecTrustRef] + Security.SecTrustGetCertificateCount.restype = CFIndex + + Security.SecTrustGetCertificateAtIndex.argtypes = [SecTrustRef, CFIndex] + Security.SecTrustGetCertificateAtIndex.restype = SecCertificateRef + + Security.SSLCreateContext.argtypes = [ + CFAllocatorRef, + SSLProtocolSide, + SSLConnectionType, + ] + Security.SSLCreateContext.restype = SSLContextRef + + Security.SSLSetSessionOption.argtypes = [SSLContextRef, SSLSessionOption, Boolean] + Security.SSLSetSessionOption.restype = OSStatus + + Security.SSLSetProtocolVersionMin.argtypes = [SSLContextRef, SSLProtocol] + Security.SSLSetProtocolVersionMin.restype = OSStatus + + Security.SSLSetProtocolVersionMax.argtypes = [SSLContextRef, SSLProtocol] + Security.SSLSetProtocolVersionMax.restype = OSStatus + + try: + Security.SSLSetALPNProtocols.argtypes = [SSLContextRef, CFArrayRef] + Security.SSLSetALPNProtocols.restype = OSStatus + except AttributeError: + # Supported only in 10.12+ + pass + + Security.SecCopyErrorMessageString.argtypes = [OSStatus, c_void_p] + Security.SecCopyErrorMessageString.restype = CFStringRef + + Security.SSLReadFunc = SSLReadFunc + Security.SSLWriteFunc = SSLWriteFunc + Security.SSLContextRef = SSLContextRef + Security.SSLProtocol = SSLProtocol + Security.SSLCipherSuite = SSLCipherSuite + Security.SecIdentityRef = SecIdentityRef + Security.SecKeychainRef = SecKeychainRef + Security.SecTrustRef = SecTrustRef + Security.SecTrustResultType = SecTrustResultType + Security.SecExternalFormat = SecExternalFormat + Security.OSStatus = OSStatus + + Security.kSecImportExportPassphrase = CFStringRef.in_dll( + Security, "kSecImportExportPassphrase" + ) + Security.kSecImportItemIdentity = CFStringRef.in_dll( + Security, "kSecImportItemIdentity" + ) + + # CoreFoundation time! + CoreFoundation.CFRetain.argtypes = [CFTypeRef] + CoreFoundation.CFRetain.restype = CFTypeRef + + CoreFoundation.CFRelease.argtypes = [CFTypeRef] + CoreFoundation.CFRelease.restype = None + + CoreFoundation.CFGetTypeID.argtypes = [CFTypeRef] + CoreFoundation.CFGetTypeID.restype = CFTypeID + + CoreFoundation.CFStringCreateWithCString.argtypes = [ + CFAllocatorRef, + c_char_p, + CFStringEncoding, + ] + CoreFoundation.CFStringCreateWithCString.restype = CFStringRef + + CoreFoundation.CFStringGetCStringPtr.argtypes = [CFStringRef, CFStringEncoding] + CoreFoundation.CFStringGetCStringPtr.restype = c_char_p + + CoreFoundation.CFStringGetCString.argtypes = [ + CFStringRef, + c_char_p, + CFIndex, + CFStringEncoding, + ] + CoreFoundation.CFStringGetCString.restype = c_bool + + CoreFoundation.CFDataCreate.argtypes = [CFAllocatorRef, c_char_p, CFIndex] + CoreFoundation.CFDataCreate.restype = CFDataRef + + CoreFoundation.CFDataGetLength.argtypes = [CFDataRef] + CoreFoundation.CFDataGetLength.restype = CFIndex + + CoreFoundation.CFDataGetBytePtr.argtypes = [CFDataRef] + CoreFoundation.CFDataGetBytePtr.restype = c_void_p + + CoreFoundation.CFDictionaryCreate.argtypes = [ + CFAllocatorRef, + POINTER(CFTypeRef), + POINTER(CFTypeRef), + CFIndex, + CFDictionaryKeyCallBacks, + CFDictionaryValueCallBacks, + ] + CoreFoundation.CFDictionaryCreate.restype = CFDictionaryRef + + CoreFoundation.CFDictionaryGetValue.argtypes = [CFDictionaryRef, CFTypeRef] + CoreFoundation.CFDictionaryGetValue.restype = CFTypeRef + + CoreFoundation.CFArrayCreate.argtypes = [ + CFAllocatorRef, + POINTER(CFTypeRef), + CFIndex, + CFArrayCallBacks, + ] + CoreFoundation.CFArrayCreate.restype = CFArrayRef + + CoreFoundation.CFArrayCreateMutable.argtypes = [ + CFAllocatorRef, + CFIndex, + CFArrayCallBacks, + ] + CoreFoundation.CFArrayCreateMutable.restype = CFMutableArrayRef + + CoreFoundation.CFArrayAppendValue.argtypes = [CFMutableArrayRef, c_void_p] + CoreFoundation.CFArrayAppendValue.restype = None + + CoreFoundation.CFArrayGetCount.argtypes = [CFArrayRef] + CoreFoundation.CFArrayGetCount.restype = CFIndex + + CoreFoundation.CFArrayGetValueAtIndex.argtypes = [CFArrayRef, CFIndex] + CoreFoundation.CFArrayGetValueAtIndex.restype = c_void_p + + CoreFoundation.kCFAllocatorDefault = CFAllocatorRef.in_dll( + CoreFoundation, "kCFAllocatorDefault" + ) + CoreFoundation.kCFTypeArrayCallBacks = c_void_p.in_dll( + CoreFoundation, "kCFTypeArrayCallBacks" + ) + CoreFoundation.kCFTypeDictionaryKeyCallBacks = c_void_p.in_dll( + CoreFoundation, "kCFTypeDictionaryKeyCallBacks" + ) + CoreFoundation.kCFTypeDictionaryValueCallBacks = c_void_p.in_dll( + CoreFoundation, "kCFTypeDictionaryValueCallBacks" + ) + + CoreFoundation.CFTypeRef = CFTypeRef + CoreFoundation.CFArrayRef = CFArrayRef + CoreFoundation.CFStringRef = CFStringRef + CoreFoundation.CFDictionaryRef = CFDictionaryRef + +except (AttributeError): + raise ImportError("Error initializing ctypes") + + +class CFConst(object): + """ + A class object that acts as essentially a namespace for CoreFoundation + constants. + """ + + kCFStringEncodingUTF8 = CFStringEncoding(0x08000100) + + +class SecurityConst(object): + """ + A class object that acts as essentially a namespace for Security constants. + """ + + kSSLSessionOptionBreakOnServerAuth = 0 + + kSSLProtocol2 = 1 + kSSLProtocol3 = 2 + kTLSProtocol1 = 4 + kTLSProtocol11 = 7 + kTLSProtocol12 = 8 + # SecureTransport does not support TLS 1.3 even if there's a constant for it + kTLSProtocol13 = 10 + kTLSProtocolMaxSupported = 999 + + kSSLClientSide = 1 + kSSLStreamType = 0 + + kSecFormatPEMSequence = 10 + + kSecTrustResultInvalid = 0 + kSecTrustResultProceed = 1 + # This gap is present on purpose: this was kSecTrustResultConfirm, which + # is deprecated. + kSecTrustResultDeny = 3 + kSecTrustResultUnspecified = 4 + kSecTrustResultRecoverableTrustFailure = 5 + kSecTrustResultFatalTrustFailure = 6 + kSecTrustResultOtherError = 7 + + errSSLProtocol = -9800 + errSSLWouldBlock = -9803 + errSSLClosedGraceful = -9805 + errSSLClosedNoNotify = -9816 + errSSLClosedAbort = -9806 + + errSSLXCertChainInvalid = -9807 + errSSLCrypto = -9809 + errSSLInternal = -9810 + errSSLCertExpired = -9814 + errSSLCertNotYetValid = -9815 + errSSLUnknownRootCert = -9812 + errSSLNoRootCert = -9813 + errSSLHostNameMismatch = -9843 + errSSLPeerHandshakeFail = -9824 + errSSLPeerUserCancelled = -9839 + errSSLWeakPeerEphemeralDHKey = -9850 + errSSLServerAuthCompleted = -9841 + errSSLRecordOverflow = -9847 + + errSecVerifyFailed = -67808 + errSecNoTrustSettings = -25263 + errSecItemNotFound = -25300 + errSecInvalidTrustSettings = -25262 + + # Cipher suites. We only pick the ones our default cipher string allows. + # Source: https://developer.apple.com/documentation/security/1550981-ssl_cipher_suite_values + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030 + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA9 + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA8 + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024 + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028 + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014 + TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B + TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039 + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023 + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027 + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009 + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013 + TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067 + TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033 + TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D + TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C + TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D + TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C + TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035 + TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F + TLS_AES_128_GCM_SHA256 = 0x1301 + TLS_AES_256_GCM_SHA384 = 0x1302 + TLS_AES_128_CCM_8_SHA256 = 0x1305 + TLS_AES_128_CCM_SHA256 = 0x1304 diff --git a/openpype/vendor/python/python_2/urllib3/contrib/_securetransport/low_level.py b/openpype/vendor/python/python_2/urllib3/contrib/_securetransport/low_level.py new file mode 100644 index 0000000000..fa0b245d27 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/contrib/_securetransport/low_level.py @@ -0,0 +1,397 @@ +""" +Low-level helpers for the SecureTransport bindings. + +These are Python functions that are not directly related to the high-level APIs +but are necessary to get them to work. They include a whole bunch of low-level +CoreFoundation messing about and memory management. The concerns in this module +are almost entirely about trying to avoid memory leaks and providing +appropriate and useful assistance to the higher-level code. +""" +import base64 +import ctypes +import itertools +import os +import re +import ssl +import struct +import tempfile + +from .bindings import CFConst, CoreFoundation, Security + +# This regular expression is used to grab PEM data out of a PEM bundle. +_PEM_CERTS_RE = re.compile( + b"-----BEGIN CERTIFICATE-----\n(.*?)\n-----END CERTIFICATE-----", re.DOTALL +) + + +def _cf_data_from_bytes(bytestring): + """ + Given a bytestring, create a CFData object from it. This CFData object must + be CFReleased by the caller. + """ + return CoreFoundation.CFDataCreate( + CoreFoundation.kCFAllocatorDefault, bytestring, len(bytestring) + ) + + +def _cf_dictionary_from_tuples(tuples): + """ + Given a list of Python tuples, create an associated CFDictionary. + """ + dictionary_size = len(tuples) + + # We need to get the dictionary keys and values out in the same order. + keys = (t[0] for t in tuples) + values = (t[1] for t in tuples) + cf_keys = (CoreFoundation.CFTypeRef * dictionary_size)(*keys) + cf_values = (CoreFoundation.CFTypeRef * dictionary_size)(*values) + + return CoreFoundation.CFDictionaryCreate( + CoreFoundation.kCFAllocatorDefault, + cf_keys, + cf_values, + dictionary_size, + CoreFoundation.kCFTypeDictionaryKeyCallBacks, + CoreFoundation.kCFTypeDictionaryValueCallBacks, + ) + + +def _cfstr(py_bstr): + """ + Given a Python binary data, create a CFString. + The string must be CFReleased by the caller. + """ + c_str = ctypes.c_char_p(py_bstr) + cf_str = CoreFoundation.CFStringCreateWithCString( + CoreFoundation.kCFAllocatorDefault, + c_str, + CFConst.kCFStringEncodingUTF8, + ) + return cf_str + + +def _create_cfstring_array(lst): + """ + Given a list of Python binary data, create an associated CFMutableArray. + The array must be CFReleased by the caller. + + Raises an ssl.SSLError on failure. + """ + cf_arr = None + try: + cf_arr = CoreFoundation.CFArrayCreateMutable( + CoreFoundation.kCFAllocatorDefault, + 0, + ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks), + ) + if not cf_arr: + raise MemoryError("Unable to allocate memory!") + for item in lst: + cf_str = _cfstr(item) + if not cf_str: + raise MemoryError("Unable to allocate memory!") + try: + CoreFoundation.CFArrayAppendValue(cf_arr, cf_str) + finally: + CoreFoundation.CFRelease(cf_str) + except BaseException as e: + if cf_arr: + CoreFoundation.CFRelease(cf_arr) + raise ssl.SSLError("Unable to allocate array: %s" % (e,)) + return cf_arr + + +def _cf_string_to_unicode(value): + """ + Creates a Unicode string from a CFString object. Used entirely for error + reporting. + + Yes, it annoys me quite a lot that this function is this complex. + """ + value_as_void_p = ctypes.cast(value, ctypes.POINTER(ctypes.c_void_p)) + + string = CoreFoundation.CFStringGetCStringPtr( + value_as_void_p, CFConst.kCFStringEncodingUTF8 + ) + if string is None: + buffer = ctypes.create_string_buffer(1024) + result = CoreFoundation.CFStringGetCString( + value_as_void_p, buffer, 1024, CFConst.kCFStringEncodingUTF8 + ) + if not result: + raise OSError("Error copying C string from CFStringRef") + string = buffer.value + if string is not None: + string = string.decode("utf-8") + return string + + +def _assert_no_error(error, exception_class=None): + """ + Checks the return code and throws an exception if there is an error to + report + """ + if error == 0: + return + + cf_error_string = Security.SecCopyErrorMessageString(error, None) + output = _cf_string_to_unicode(cf_error_string) + CoreFoundation.CFRelease(cf_error_string) + + if output is None or output == u"": + output = u"OSStatus %s" % error + + if exception_class is None: + exception_class = ssl.SSLError + + raise exception_class(output) + + +def _cert_array_from_pem(pem_bundle): + """ + Given a bundle of certs in PEM format, turns them into a CFArray of certs + that can be used to validate a cert chain. + """ + # Normalize the PEM bundle's line endings. + pem_bundle = pem_bundle.replace(b"\r\n", b"\n") + + der_certs = [ + base64.b64decode(match.group(1)) for match in _PEM_CERTS_RE.finditer(pem_bundle) + ] + if not der_certs: + raise ssl.SSLError("No root certificates specified") + + cert_array = CoreFoundation.CFArrayCreateMutable( + CoreFoundation.kCFAllocatorDefault, + 0, + ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks), + ) + if not cert_array: + raise ssl.SSLError("Unable to allocate memory!") + + try: + for der_bytes in der_certs: + certdata = _cf_data_from_bytes(der_bytes) + if not certdata: + raise ssl.SSLError("Unable to allocate memory!") + cert = Security.SecCertificateCreateWithData( + CoreFoundation.kCFAllocatorDefault, certdata + ) + CoreFoundation.CFRelease(certdata) + if not cert: + raise ssl.SSLError("Unable to build cert object!") + + CoreFoundation.CFArrayAppendValue(cert_array, cert) + CoreFoundation.CFRelease(cert) + except Exception: + # We need to free the array before the exception bubbles further. + # We only want to do that if an error occurs: otherwise, the caller + # should free. + CoreFoundation.CFRelease(cert_array) + raise + + return cert_array + + +def _is_cert(item): + """ + Returns True if a given CFTypeRef is a certificate. + """ + expected = Security.SecCertificateGetTypeID() + return CoreFoundation.CFGetTypeID(item) == expected + + +def _is_identity(item): + """ + Returns True if a given CFTypeRef is an identity. + """ + expected = Security.SecIdentityGetTypeID() + return CoreFoundation.CFGetTypeID(item) == expected + + +def _temporary_keychain(): + """ + This function creates a temporary Mac keychain that we can use to work with + credentials. This keychain uses a one-time password and a temporary file to + store the data. We expect to have one keychain per socket. The returned + SecKeychainRef must be freed by the caller, including calling + SecKeychainDelete. + + Returns a tuple of the SecKeychainRef and the path to the temporary + directory that contains it. + """ + # Unfortunately, SecKeychainCreate requires a path to a keychain. This + # means we cannot use mkstemp to use a generic temporary file. Instead, + # we're going to create a temporary directory and a filename to use there. + # This filename will be 8 random bytes expanded into base64. We also need + # some random bytes to password-protect the keychain we're creating, so we + # ask for 40 random bytes. + random_bytes = os.urandom(40) + filename = base64.b16encode(random_bytes[:8]).decode("utf-8") + password = base64.b16encode(random_bytes[8:]) # Must be valid UTF-8 + tempdirectory = tempfile.mkdtemp() + + keychain_path = os.path.join(tempdirectory, filename).encode("utf-8") + + # We now want to create the keychain itself. + keychain = Security.SecKeychainRef() + status = Security.SecKeychainCreate( + keychain_path, len(password), password, False, None, ctypes.byref(keychain) + ) + _assert_no_error(status) + + # Having created the keychain, we want to pass it off to the caller. + return keychain, tempdirectory + + +def _load_items_from_file(keychain, path): + """ + Given a single file, loads all the trust objects from it into arrays and + the keychain. + Returns a tuple of lists: the first list is a list of identities, the + second a list of certs. + """ + certificates = [] + identities = [] + result_array = None + + with open(path, "rb") as f: + raw_filedata = f.read() + + try: + filedata = CoreFoundation.CFDataCreate( + CoreFoundation.kCFAllocatorDefault, raw_filedata, len(raw_filedata) + ) + result_array = CoreFoundation.CFArrayRef() + result = Security.SecItemImport( + filedata, # cert data + None, # Filename, leaving it out for now + None, # What the type of the file is, we don't care + None, # what's in the file, we don't care + 0, # import flags + None, # key params, can include passphrase in the future + keychain, # The keychain to insert into + ctypes.byref(result_array), # Results + ) + _assert_no_error(result) + + # A CFArray is not very useful to us as an intermediary + # representation, so we are going to extract the objects we want + # and then free the array. We don't need to keep hold of keys: the + # keychain already has them! + result_count = CoreFoundation.CFArrayGetCount(result_array) + for index in range(result_count): + item = CoreFoundation.CFArrayGetValueAtIndex(result_array, index) + item = ctypes.cast(item, CoreFoundation.CFTypeRef) + + if _is_cert(item): + CoreFoundation.CFRetain(item) + certificates.append(item) + elif _is_identity(item): + CoreFoundation.CFRetain(item) + identities.append(item) + finally: + if result_array: + CoreFoundation.CFRelease(result_array) + + CoreFoundation.CFRelease(filedata) + + return (identities, certificates) + + +def _load_client_cert_chain(keychain, *paths): + """ + Load certificates and maybe keys from a number of files. Has the end goal + of returning a CFArray containing one SecIdentityRef, and then zero or more + SecCertificateRef objects, suitable for use as a client certificate trust + chain. + """ + # Ok, the strategy. + # + # This relies on knowing that macOS will not give you a SecIdentityRef + # unless you have imported a key into a keychain. This is a somewhat + # artificial limitation of macOS (for example, it doesn't necessarily + # affect iOS), but there is nothing inside Security.framework that lets you + # get a SecIdentityRef without having a key in a keychain. + # + # So the policy here is we take all the files and iterate them in order. + # Each one will use SecItemImport to have one or more objects loaded from + # it. We will also point at a keychain that macOS can use to work with the + # private key. + # + # Once we have all the objects, we'll check what we actually have. If we + # already have a SecIdentityRef in hand, fab: we'll use that. Otherwise, + # we'll take the first certificate (which we assume to be our leaf) and + # ask the keychain to give us a SecIdentityRef with that cert's associated + # key. + # + # We'll then return a CFArray containing the trust chain: one + # SecIdentityRef and then zero-or-more SecCertificateRef objects. The + # responsibility for freeing this CFArray will be with the caller. This + # CFArray must remain alive for the entire connection, so in practice it + # will be stored with a single SSLSocket, along with the reference to the + # keychain. + certificates = [] + identities = [] + + # Filter out bad paths. + paths = (path for path in paths if path) + + try: + for file_path in paths: + new_identities, new_certs = _load_items_from_file(keychain, file_path) + identities.extend(new_identities) + certificates.extend(new_certs) + + # Ok, we have everything. The question is: do we have an identity? If + # not, we want to grab one from the first cert we have. + if not identities: + new_identity = Security.SecIdentityRef() + status = Security.SecIdentityCreateWithCertificate( + keychain, certificates[0], ctypes.byref(new_identity) + ) + _assert_no_error(status) + identities.append(new_identity) + + # We now want to release the original certificate, as we no longer + # need it. + CoreFoundation.CFRelease(certificates.pop(0)) + + # We now need to build a new CFArray that holds the trust chain. + trust_chain = CoreFoundation.CFArrayCreateMutable( + CoreFoundation.kCFAllocatorDefault, + 0, + ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks), + ) + for item in itertools.chain(identities, certificates): + # ArrayAppendValue does a CFRetain on the item. That's fine, + # because the finally block will release our other refs to them. + CoreFoundation.CFArrayAppendValue(trust_chain, item) + + return trust_chain + finally: + for obj in itertools.chain(identities, certificates): + CoreFoundation.CFRelease(obj) + + +TLS_PROTOCOL_VERSIONS = { + "SSLv2": (0, 2), + "SSLv3": (3, 0), + "TLSv1": (3, 1), + "TLSv1.1": (3, 2), + "TLSv1.2": (3, 3), +} + + +def _build_tls_unknown_ca_alert(version): + """ + Builds a TLS alert record for an unknown CA. + """ + ver_maj, ver_min = TLS_PROTOCOL_VERSIONS[version] + severity_fatal = 0x02 + description_unknown_ca = 0x30 + msg = struct.pack(">BB", severity_fatal, description_unknown_ca) + msg_len = len(msg) + record_type_alert = 0x15 + record = struct.pack(">BBBH", record_type_alert, ver_maj, ver_min, msg_len) + msg + return record diff --git a/openpype/vendor/python/python_2/urllib3/contrib/appengine.py b/openpype/vendor/python/python_2/urllib3/contrib/appengine.py new file mode 100644 index 0000000000..f91bdd6e77 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/contrib/appengine.py @@ -0,0 +1,314 @@ +""" +This module provides a pool manager that uses Google App Engine's +`URLFetch Service `_. + +Example usage:: + + from urllib3 import PoolManager + from urllib3.contrib.appengine import AppEngineManager, is_appengine_sandbox + + if is_appengine_sandbox(): + # AppEngineManager uses AppEngine's URLFetch API behind the scenes + http = AppEngineManager() + else: + # PoolManager uses a socket-level API behind the scenes + http = PoolManager() + + r = http.request('GET', 'https://google.com/') + +There are `limitations `_ to the URLFetch service and it may not be +the best choice for your application. There are three options for using +urllib3 on Google App Engine: + +1. You can use :class:`AppEngineManager` with URLFetch. URLFetch is + cost-effective in many circumstances as long as your usage is within the + limitations. +2. You can use a normal :class:`~urllib3.PoolManager` by enabling sockets. + Sockets also have `limitations and restrictions + `_ and have a lower free quota than URLFetch. + To use sockets, be sure to specify the following in your ``app.yaml``:: + + env_variables: + GAE_USE_SOCKETS_HTTPLIB : 'true' + +3. If you are using `App Engine Flexible +`_, you can use the standard +:class:`PoolManager` without any configuration or special environment variables. +""" + +from __future__ import absolute_import + +import io +import logging +import warnings + +from ..exceptions import ( + HTTPError, + HTTPWarning, + MaxRetryError, + ProtocolError, + SSLError, + TimeoutError, +) +from ..packages.six.moves.urllib.parse import urljoin +from ..request import RequestMethods +from ..response import HTTPResponse +from ..util.retry import Retry +from ..util.timeout import Timeout +from . import _appengine_environ + +try: + from google.appengine.api import urlfetch +except ImportError: + urlfetch = None + + +log = logging.getLogger(__name__) + + +class AppEnginePlatformWarning(HTTPWarning): + pass + + +class AppEnginePlatformError(HTTPError): + pass + + +class AppEngineManager(RequestMethods): + """ + Connection manager for Google App Engine sandbox applications. + + This manager uses the URLFetch service directly instead of using the + emulated httplib, and is subject to URLFetch limitations as described in + the App Engine documentation `here + `_. + + Notably it will raise an :class:`AppEnginePlatformError` if: + * URLFetch is not available. + * If you attempt to use this on App Engine Flexible, as full socket + support is available. + * If a request size is more than 10 megabytes. + * If a response size is more than 32 megabytes. + * If you use an unsupported request method such as OPTIONS. + + Beyond those cases, it will raise normal urllib3 errors. + """ + + def __init__( + self, + headers=None, + retries=None, + validate_certificate=True, + urlfetch_retries=True, + ): + if not urlfetch: + raise AppEnginePlatformError( + "URLFetch is not available in this environment." + ) + + warnings.warn( + "urllib3 is using URLFetch on Google App Engine sandbox instead " + "of sockets. To use sockets directly instead of URLFetch see " + "https://urllib3.readthedocs.io/en/1.26.x/reference/urllib3.contrib.html.", + AppEnginePlatformWarning, + ) + + RequestMethods.__init__(self, headers) + self.validate_certificate = validate_certificate + self.urlfetch_retries = urlfetch_retries + + self.retries = retries or Retry.DEFAULT + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + # Return False to re-raise any potential exceptions + return False + + def urlopen( + self, + method, + url, + body=None, + headers=None, + retries=None, + redirect=True, + timeout=Timeout.DEFAULT_TIMEOUT, + **response_kw + ): + + retries = self._get_retries(retries, redirect) + + try: + follow_redirects = redirect and retries.redirect != 0 and retries.total + response = urlfetch.fetch( + url, + payload=body, + method=method, + headers=headers or {}, + allow_truncated=False, + follow_redirects=self.urlfetch_retries and follow_redirects, + deadline=self._get_absolute_timeout(timeout), + validate_certificate=self.validate_certificate, + ) + except urlfetch.DeadlineExceededError as e: + raise TimeoutError(self, e) + + except urlfetch.InvalidURLError as e: + if "too large" in str(e): + raise AppEnginePlatformError( + "URLFetch request too large, URLFetch only " + "supports requests up to 10mb in size.", + e, + ) + raise ProtocolError(e) + + except urlfetch.DownloadError as e: + if "Too many redirects" in str(e): + raise MaxRetryError(self, url, reason=e) + raise ProtocolError(e) + + except urlfetch.ResponseTooLargeError as e: + raise AppEnginePlatformError( + "URLFetch response too large, URLFetch only supports" + "responses up to 32mb in size.", + e, + ) + + except urlfetch.SSLCertificateError as e: + raise SSLError(e) + + except urlfetch.InvalidMethodError as e: + raise AppEnginePlatformError( + "URLFetch does not support method: %s" % method, e + ) + + http_response = self._urlfetch_response_to_http_response( + response, retries=retries, **response_kw + ) + + # Handle redirect? + redirect_location = redirect and http_response.get_redirect_location() + if redirect_location: + # Check for redirect response + if self.urlfetch_retries and retries.raise_on_redirect: + raise MaxRetryError(self, url, "too many redirects") + else: + if http_response.status == 303: + method = "GET" + + try: + retries = retries.increment( + method, url, response=http_response, _pool=self + ) + except MaxRetryError: + if retries.raise_on_redirect: + raise MaxRetryError(self, url, "too many redirects") + return http_response + + retries.sleep_for_retry(http_response) + log.debug("Redirecting %s -> %s", url, redirect_location) + redirect_url = urljoin(url, redirect_location) + return self.urlopen( + method, + redirect_url, + body, + headers, + retries=retries, + redirect=redirect, + timeout=timeout, + **response_kw + ) + + # Check if we should retry the HTTP response. + has_retry_after = bool(http_response.getheader("Retry-After")) + if retries.is_retry(method, http_response.status, has_retry_after): + retries = retries.increment(method, url, response=http_response, _pool=self) + log.debug("Retry: %s", url) + retries.sleep(http_response) + return self.urlopen( + method, + url, + body=body, + headers=headers, + retries=retries, + redirect=redirect, + timeout=timeout, + **response_kw + ) + + return http_response + + def _urlfetch_response_to_http_response(self, urlfetch_resp, **response_kw): + + if is_prod_appengine(): + # Production GAE handles deflate encoding automatically, but does + # not remove the encoding header. + content_encoding = urlfetch_resp.headers.get("content-encoding") + + if content_encoding == "deflate": + del urlfetch_resp.headers["content-encoding"] + + transfer_encoding = urlfetch_resp.headers.get("transfer-encoding") + # We have a full response's content, + # so let's make sure we don't report ourselves as chunked data. + if transfer_encoding == "chunked": + encodings = transfer_encoding.split(",") + encodings.remove("chunked") + urlfetch_resp.headers["transfer-encoding"] = ",".join(encodings) + + original_response = HTTPResponse( + # In order for decoding to work, we must present the content as + # a file-like object. + body=io.BytesIO(urlfetch_resp.content), + msg=urlfetch_resp.header_msg, + headers=urlfetch_resp.headers, + status=urlfetch_resp.status_code, + **response_kw + ) + + return HTTPResponse( + body=io.BytesIO(urlfetch_resp.content), + headers=urlfetch_resp.headers, + status=urlfetch_resp.status_code, + original_response=original_response, + **response_kw + ) + + def _get_absolute_timeout(self, timeout): + if timeout is Timeout.DEFAULT_TIMEOUT: + return None # Defer to URLFetch's default. + if isinstance(timeout, Timeout): + if timeout._read is not None or timeout._connect is not None: + warnings.warn( + "URLFetch does not support granular timeout settings, " + "reverting to total or default URLFetch timeout.", + AppEnginePlatformWarning, + ) + return timeout.total + return timeout + + def _get_retries(self, retries, redirect): + if not isinstance(retries, Retry): + retries = Retry.from_int(retries, redirect=redirect, default=self.retries) + + if retries.connect or retries.read or retries.redirect: + warnings.warn( + "URLFetch only supports total retries and does not " + "recognize connect, read, or redirect retry parameters.", + AppEnginePlatformWarning, + ) + + return retries + + +# Alias methods from _appengine_environ to maintain public API interface. + +is_appengine = _appengine_environ.is_appengine +is_appengine_sandbox = _appengine_environ.is_appengine_sandbox +is_local_appengine = _appengine_environ.is_local_appengine +is_prod_appengine = _appengine_environ.is_prod_appengine +is_prod_appengine_mvms = _appengine_environ.is_prod_appengine_mvms diff --git a/openpype/vendor/python/python_2/urllib3/contrib/ntlmpool.py b/openpype/vendor/python/python_2/urllib3/contrib/ntlmpool.py new file mode 100644 index 0000000000..41a8fd174c --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/contrib/ntlmpool.py @@ -0,0 +1,130 @@ +""" +NTLM authenticating pool, contributed by erikcederstran + +Issue #10, see: http://code.google.com/p/urllib3/issues/detail?id=10 +""" +from __future__ import absolute_import + +import warnings +from logging import getLogger + +from ntlm import ntlm + +from .. import HTTPSConnectionPool +from ..packages.six.moves.http_client import HTTPSConnection + +warnings.warn( + "The 'urllib3.contrib.ntlmpool' module is deprecated and will be removed " + "in urllib3 v2.0 release, urllib3 is not able to support it properly due " + "to reasons listed in issue: https://github.com/urllib3/urllib3/issues/2282. " + "If you are a user of this module please comment in the mentioned issue.", + DeprecationWarning, +) + +log = getLogger(__name__) + + +class NTLMConnectionPool(HTTPSConnectionPool): + """ + Implements an NTLM authentication version of an urllib3 connection pool + """ + + scheme = "https" + + def __init__(self, user, pw, authurl, *args, **kwargs): + """ + authurl is a random URL on the server that is protected by NTLM. + user is the Windows user, probably in the DOMAIN\\username format. + pw is the password for the user. + """ + super(NTLMConnectionPool, self).__init__(*args, **kwargs) + self.authurl = authurl + self.rawuser = user + user_parts = user.split("\\", 1) + self.domain = user_parts[0].upper() + self.user = user_parts[1] + self.pw = pw + + def _new_conn(self): + # Performs the NTLM handshake that secures the connection. The socket + # must be kept open while requests are performed. + self.num_connections += 1 + log.debug( + "Starting NTLM HTTPS connection no. %d: https://%s%s", + self.num_connections, + self.host, + self.authurl, + ) + + headers = {"Connection": "Keep-Alive"} + req_header = "Authorization" + resp_header = "www-authenticate" + + conn = HTTPSConnection(host=self.host, port=self.port) + + # Send negotiation message + headers[req_header] = "NTLM %s" % ntlm.create_NTLM_NEGOTIATE_MESSAGE( + self.rawuser + ) + log.debug("Request headers: %s", headers) + conn.request("GET", self.authurl, None, headers) + res = conn.getresponse() + reshdr = dict(res.getheaders()) + log.debug("Response status: %s %s", res.status, res.reason) + log.debug("Response headers: %s", reshdr) + log.debug("Response data: %s [...]", res.read(100)) + + # Remove the reference to the socket, so that it can not be closed by + # the response object (we want to keep the socket open) + res.fp = None + + # Server should respond with a challenge message + auth_header_values = reshdr[resp_header].split(", ") + auth_header_value = None + for s in auth_header_values: + if s[:5] == "NTLM ": + auth_header_value = s[5:] + if auth_header_value is None: + raise Exception( + "Unexpected %s response header: %s" % (resp_header, reshdr[resp_header]) + ) + + # Send authentication message + ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE( + auth_header_value + ) + auth_msg = ntlm.create_NTLM_AUTHENTICATE_MESSAGE( + ServerChallenge, self.user, self.domain, self.pw, NegotiateFlags + ) + headers[req_header] = "NTLM %s" % auth_msg + log.debug("Request headers: %s", headers) + conn.request("GET", self.authurl, None, headers) + res = conn.getresponse() + log.debug("Response status: %s %s", res.status, res.reason) + log.debug("Response headers: %s", dict(res.getheaders())) + log.debug("Response data: %s [...]", res.read()[:100]) + if res.status != 200: + if res.status == 401: + raise Exception("Server rejected request: wrong username or password") + raise Exception("Wrong server response: %s %s" % (res.status, res.reason)) + + res.fp = None + log.debug("Connection established") + return conn + + def urlopen( + self, + method, + url, + body=None, + headers=None, + retries=3, + redirect=True, + assert_same_host=True, + ): + if headers is None: + headers = {} + headers["Connection"] = "Keep-Alive" + return super(NTLMConnectionPool, self).urlopen( + method, url, body, headers, retries, redirect, assert_same_host + ) diff --git a/openpype/vendor/python/python_2/urllib3/contrib/pyopenssl.py b/openpype/vendor/python/python_2/urllib3/contrib/pyopenssl.py new file mode 100644 index 0000000000..def83afdb2 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/contrib/pyopenssl.py @@ -0,0 +1,511 @@ +""" +TLS with SNI_-support for Python 2. Follow these instructions if you would +like to verify TLS certificates in Python 2. Note, the default libraries do +*not* do certificate checking; you need to do additional work to validate +certificates yourself. + +This needs the following packages installed: + +* `pyOpenSSL`_ (tested with 16.0.0) +* `cryptography`_ (minimum 1.3.4, from pyopenssl) +* `idna`_ (minimum 2.0, from cryptography) + +However, pyopenssl depends on cryptography, which depends on idna, so while we +use all three directly here we end up having relatively few packages required. + +You can install them with the following command: + +.. code-block:: bash + + $ python -m pip install pyopenssl cryptography idna + +To activate certificate checking, call +:func:`~urllib3.contrib.pyopenssl.inject_into_urllib3` from your Python code +before you begin making HTTP requests. This can be done in a ``sitecustomize`` +module, or at any other time before your application begins using ``urllib3``, +like this: + +.. code-block:: python + + try: + import urllib3.contrib.pyopenssl + urllib3.contrib.pyopenssl.inject_into_urllib3() + except ImportError: + pass + +Now you can use :mod:`urllib3` as you normally would, and it will support SNI +when the required modules are installed. + +Activating this module also has the positive side effect of disabling SSL/TLS +compression in Python 2 (see `CRIME attack`_). + +.. _sni: https://en.wikipedia.org/wiki/Server_Name_Indication +.. _crime attack: https://en.wikipedia.org/wiki/CRIME_(security_exploit) +.. _pyopenssl: https://www.pyopenssl.org +.. _cryptography: https://cryptography.io +.. _idna: https://github.com/kjd/idna +""" +from __future__ import absolute_import + +import OpenSSL.SSL +from cryptography import x509 +from cryptography.hazmat.backends.openssl import backend as openssl_backend +from cryptography.hazmat.backends.openssl.x509 import _Certificate + +try: + from cryptography.x509 import UnsupportedExtension +except ImportError: + # UnsupportedExtension is gone in cryptography >= 2.1.0 + class UnsupportedExtension(Exception): + pass + + +from io import BytesIO +from socket import error as SocketError +from socket import timeout + +try: # Platform-specific: Python 2 + from socket import _fileobject +except ImportError: # Platform-specific: Python 3 + _fileobject = None + from ..packages.backports.makefile import backport_makefile + +import logging +import ssl +import sys + +from .. import util +from ..packages import six +from ..util.ssl_ import PROTOCOL_TLS_CLIENT + +__all__ = ["inject_into_urllib3", "extract_from_urllib3"] + +# SNI always works. +HAS_SNI = True + +# Map from urllib3 to PyOpenSSL compatible parameter-values. +_openssl_versions = { + util.PROTOCOL_TLS: OpenSSL.SSL.SSLv23_METHOD, + PROTOCOL_TLS_CLIENT: OpenSSL.SSL.SSLv23_METHOD, + ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_METHOD, +} + +if hasattr(ssl, "PROTOCOL_SSLv3") and hasattr(OpenSSL.SSL, "SSLv3_METHOD"): + _openssl_versions[ssl.PROTOCOL_SSLv3] = OpenSSL.SSL.SSLv3_METHOD + +if hasattr(ssl, "PROTOCOL_TLSv1_1") and hasattr(OpenSSL.SSL, "TLSv1_1_METHOD"): + _openssl_versions[ssl.PROTOCOL_TLSv1_1] = OpenSSL.SSL.TLSv1_1_METHOD + +if hasattr(ssl, "PROTOCOL_TLSv1_2") and hasattr(OpenSSL.SSL, "TLSv1_2_METHOD"): + _openssl_versions[ssl.PROTOCOL_TLSv1_2] = OpenSSL.SSL.TLSv1_2_METHOD + + +_stdlib_to_openssl_verify = { + ssl.CERT_NONE: OpenSSL.SSL.VERIFY_NONE, + ssl.CERT_OPTIONAL: OpenSSL.SSL.VERIFY_PEER, + ssl.CERT_REQUIRED: OpenSSL.SSL.VERIFY_PEER + + OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT, +} +_openssl_to_stdlib_verify = dict((v, k) for k, v in _stdlib_to_openssl_verify.items()) + +# OpenSSL will only write 16K at a time +SSL_WRITE_BLOCKSIZE = 16384 + +orig_util_HAS_SNI = util.HAS_SNI +orig_util_SSLContext = util.ssl_.SSLContext + + +log = logging.getLogger(__name__) + + +def inject_into_urllib3(): + "Monkey-patch urllib3 with PyOpenSSL-backed SSL-support." + + _validate_dependencies_met() + + util.SSLContext = PyOpenSSLContext + util.ssl_.SSLContext = PyOpenSSLContext + util.HAS_SNI = HAS_SNI + util.ssl_.HAS_SNI = HAS_SNI + util.IS_PYOPENSSL = True + util.ssl_.IS_PYOPENSSL = True + + +def extract_from_urllib3(): + "Undo monkey-patching by :func:`inject_into_urllib3`." + + util.SSLContext = orig_util_SSLContext + util.ssl_.SSLContext = orig_util_SSLContext + util.HAS_SNI = orig_util_HAS_SNI + util.ssl_.HAS_SNI = orig_util_HAS_SNI + util.IS_PYOPENSSL = False + util.ssl_.IS_PYOPENSSL = False + + +def _validate_dependencies_met(): + """ + Verifies that PyOpenSSL's package-level dependencies have been met. + Throws `ImportError` if they are not met. + """ + # Method added in `cryptography==1.1`; not available in older versions + from cryptography.x509.extensions import Extensions + + if getattr(Extensions, "get_extension_for_class", None) is None: + raise ImportError( + "'cryptography' module missing required functionality. " + "Try upgrading to v1.3.4 or newer." + ) + + # pyOpenSSL 0.14 and above use cryptography for OpenSSL bindings. The _x509 + # attribute is only present on those versions. + from OpenSSL.crypto import X509 + + x509 = X509() + if getattr(x509, "_x509", None) is None: + raise ImportError( + "'pyOpenSSL' module missing required functionality. " + "Try upgrading to v0.14 or newer." + ) + + +def _dnsname_to_stdlib(name): + """ + Converts a dNSName SubjectAlternativeName field to the form used by the + standard library on the given Python version. + + Cryptography produces a dNSName as a unicode string that was idna-decoded + from ASCII bytes. We need to idna-encode that string to get it back, and + then on Python 3 we also need to convert to unicode via UTF-8 (the stdlib + uses PyUnicode_FromStringAndSize on it, which decodes via UTF-8). + + If the name cannot be idna-encoded then we return None signalling that + the name given should be skipped. + """ + + def idna_encode(name): + """ + Borrowed wholesale from the Python Cryptography Project. It turns out + that we can't just safely call `idna.encode`: it can explode for + wildcard names. This avoids that problem. + """ + import idna + + try: + for prefix in [u"*.", u"."]: + if name.startswith(prefix): + name = name[len(prefix) :] + return prefix.encode("ascii") + idna.encode(name) + return idna.encode(name) + except idna.core.IDNAError: + return None + + # Don't send IPv6 addresses through the IDNA encoder. + if ":" in name: + return name + + name = idna_encode(name) + if name is None: + return None + elif sys.version_info >= (3, 0): + name = name.decode("utf-8") + return name + + +def get_subj_alt_name(peer_cert): + """ + Given an PyOpenSSL certificate, provides all the subject alternative names. + """ + # Pass the cert to cryptography, which has much better APIs for this. + if hasattr(peer_cert, "to_cryptography"): + cert = peer_cert.to_cryptography() + else: + # This is technically using private APIs, but should work across all + # relevant versions before PyOpenSSL got a proper API for this. + cert = _Certificate(openssl_backend, peer_cert._x509) + + # We want to find the SAN extension. Ask Cryptography to locate it (it's + # faster than looping in Python) + try: + ext = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName).value + except x509.ExtensionNotFound: + # No such extension, return the empty list. + return [] + except ( + x509.DuplicateExtension, + UnsupportedExtension, + x509.UnsupportedGeneralNameType, + UnicodeError, + ) as e: + # A problem has been found with the quality of the certificate. Assume + # no SAN field is present. + log.warning( + "A problem was encountered with the certificate that prevented " + "urllib3 from finding the SubjectAlternativeName field. This can " + "affect certificate validation. The error was %s", + e, + ) + return [] + + # We want to return dNSName and iPAddress fields. We need to cast the IPs + # back to strings because the match_hostname function wants them as + # strings. + # Sadly the DNS names need to be idna encoded and then, on Python 3, UTF-8 + # decoded. This is pretty frustrating, but that's what the standard library + # does with certificates, and so we need to attempt to do the same. + # We also want to skip over names which cannot be idna encoded. + names = [ + ("DNS", name) + for name in map(_dnsname_to_stdlib, ext.get_values_for_type(x509.DNSName)) + if name is not None + ] + names.extend( + ("IP Address", str(name)) for name in ext.get_values_for_type(x509.IPAddress) + ) + + return names + + +class WrappedSocket(object): + """API-compatibility wrapper for Python OpenSSL's Connection-class. + + Note: _makefile_refs, _drop() and _reuse() are needed for the garbage + collector of pypy. + """ + + def __init__(self, connection, socket, suppress_ragged_eofs=True): + self.connection = connection + self.socket = socket + self.suppress_ragged_eofs = suppress_ragged_eofs + self._makefile_refs = 0 + self._closed = False + + def fileno(self): + return self.socket.fileno() + + # Copy-pasted from Python 3.5 source code + def _decref_socketios(self): + if self._makefile_refs > 0: + self._makefile_refs -= 1 + if self._closed: + self.close() + + def recv(self, *args, **kwargs): + try: + data = self.connection.recv(*args, **kwargs) + except OpenSSL.SSL.SysCallError as e: + if self.suppress_ragged_eofs and e.args == (-1, "Unexpected EOF"): + return b"" + else: + raise SocketError(str(e)) + except OpenSSL.SSL.ZeroReturnError: + if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: + return b"" + else: + raise + except OpenSSL.SSL.WantReadError: + if not util.wait_for_read(self.socket, self.socket.gettimeout()): + raise timeout("The read operation timed out") + else: + return self.recv(*args, **kwargs) + + # TLS 1.3 post-handshake authentication + except OpenSSL.SSL.Error as e: + raise ssl.SSLError("read error: %r" % e) + else: + return data + + def recv_into(self, *args, **kwargs): + try: + return self.connection.recv_into(*args, **kwargs) + except OpenSSL.SSL.SysCallError as e: + if self.suppress_ragged_eofs and e.args == (-1, "Unexpected EOF"): + return 0 + else: + raise SocketError(str(e)) + except OpenSSL.SSL.ZeroReturnError: + if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: + return 0 + else: + raise + except OpenSSL.SSL.WantReadError: + if not util.wait_for_read(self.socket, self.socket.gettimeout()): + raise timeout("The read operation timed out") + else: + return self.recv_into(*args, **kwargs) + + # TLS 1.3 post-handshake authentication + except OpenSSL.SSL.Error as e: + raise ssl.SSLError("read error: %r" % e) + + def settimeout(self, timeout): + return self.socket.settimeout(timeout) + + def _send_until_done(self, data): + while True: + try: + return self.connection.send(data) + except OpenSSL.SSL.WantWriteError: + if not util.wait_for_write(self.socket, self.socket.gettimeout()): + raise timeout() + continue + except OpenSSL.SSL.SysCallError as e: + raise SocketError(str(e)) + + def sendall(self, data): + total_sent = 0 + while total_sent < len(data): + sent = self._send_until_done( + data[total_sent : total_sent + SSL_WRITE_BLOCKSIZE] + ) + total_sent += sent + + def shutdown(self): + # FIXME rethrow compatible exceptions should we ever use this + self.connection.shutdown() + + def close(self): + if self._makefile_refs < 1: + try: + self._closed = True + return self.connection.close() + except OpenSSL.SSL.Error: + return + else: + self._makefile_refs -= 1 + + def getpeercert(self, binary_form=False): + x509 = self.connection.get_peer_certificate() + + if not x509: + return x509 + + if binary_form: + return OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_ASN1, x509) + + return { + "subject": ((("commonName", x509.get_subject().CN),),), + "subjectAltName": get_subj_alt_name(x509), + } + + def version(self): + return self.connection.get_protocol_version_name() + + def _reuse(self): + self._makefile_refs += 1 + + def _drop(self): + if self._makefile_refs < 1: + self.close() + else: + self._makefile_refs -= 1 + + +if _fileobject: # Platform-specific: Python 2 + + def makefile(self, mode, bufsize=-1): + self._makefile_refs += 1 + return _fileobject(self, mode, bufsize, close=True) + + +else: # Platform-specific: Python 3 + makefile = backport_makefile + +WrappedSocket.makefile = makefile + + +class PyOpenSSLContext(object): + """ + I am a wrapper class for the PyOpenSSL ``Context`` object. I am responsible + for translating the interface of the standard library ``SSLContext`` object + to calls into PyOpenSSL. + """ + + def __init__(self, protocol): + self.protocol = _openssl_versions[protocol] + self._ctx = OpenSSL.SSL.Context(self.protocol) + self._options = 0 + self.check_hostname = False + + @property + def options(self): + return self._options + + @options.setter + def options(self, value): + self._options = value + self._ctx.set_options(value) + + @property + def verify_mode(self): + return _openssl_to_stdlib_verify[self._ctx.get_verify_mode()] + + @verify_mode.setter + def verify_mode(self, value): + self._ctx.set_verify(_stdlib_to_openssl_verify[value], _verify_callback) + + def set_default_verify_paths(self): + self._ctx.set_default_verify_paths() + + def set_ciphers(self, ciphers): + if isinstance(ciphers, six.text_type): + ciphers = ciphers.encode("utf-8") + self._ctx.set_cipher_list(ciphers) + + def load_verify_locations(self, cafile=None, capath=None, cadata=None): + if cafile is not None: + cafile = cafile.encode("utf-8") + if capath is not None: + capath = capath.encode("utf-8") + try: + self._ctx.load_verify_locations(cafile, capath) + if cadata is not None: + self._ctx.load_verify_locations(BytesIO(cadata)) + except OpenSSL.SSL.Error as e: + raise ssl.SSLError("unable to load trusted certificates: %r" % e) + + def load_cert_chain(self, certfile, keyfile=None, password=None): + self._ctx.use_certificate_chain_file(certfile) + if password is not None: + if not isinstance(password, six.binary_type): + password = password.encode("utf-8") + self._ctx.set_passwd_cb(lambda *_: password) + self._ctx.use_privatekey_file(keyfile or certfile) + + def set_alpn_protocols(self, protocols): + protocols = [six.ensure_binary(p) for p in protocols] + return self._ctx.set_alpn_protos(protocols) + + def wrap_socket( + self, + sock, + server_side=False, + do_handshake_on_connect=True, + suppress_ragged_eofs=True, + server_hostname=None, + ): + cnx = OpenSSL.SSL.Connection(self._ctx, sock) + + if isinstance(server_hostname, six.text_type): # Platform-specific: Python 3 + server_hostname = server_hostname.encode("utf-8") + + if server_hostname is not None: + cnx.set_tlsext_host_name(server_hostname) + + cnx.set_connect_state() + + while True: + try: + cnx.do_handshake() + except OpenSSL.SSL.WantReadError: + if not util.wait_for_read(sock, sock.gettimeout()): + raise timeout("select timed out") + continue + except OpenSSL.SSL.Error as e: + raise ssl.SSLError("bad handshake: %r" % e) + break + + return WrappedSocket(cnx, sock) + + +def _verify_callback(cnx, x509, err_no, err_depth, return_code): + return err_no == 0 diff --git a/openpype/vendor/python/python_2/urllib3/contrib/securetransport.py b/openpype/vendor/python/python_2/urllib3/contrib/securetransport.py new file mode 100644 index 0000000000..554c015fed --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/contrib/securetransport.py @@ -0,0 +1,922 @@ +""" +SecureTranport support for urllib3 via ctypes. + +This makes platform-native TLS available to urllib3 users on macOS without the +use of a compiler. This is an important feature because the Python Package +Index is moving to become a TLSv1.2-or-higher server, and the default OpenSSL +that ships with macOS is not capable of doing TLSv1.2. The only way to resolve +this is to give macOS users an alternative solution to the problem, and that +solution is to use SecureTransport. + +We use ctypes here because this solution must not require a compiler. That's +because pip is not allowed to require a compiler either. + +This is not intended to be a seriously long-term solution to this problem. +The hope is that PEP 543 will eventually solve this issue for us, at which +point we can retire this contrib module. But in the short term, we need to +solve the impending tire fire that is Python on Mac without this kind of +contrib module. So...here we are. + +To use this module, simply import and inject it:: + + import urllib3.contrib.securetransport + urllib3.contrib.securetransport.inject_into_urllib3() + +Happy TLSing! + +This code is a bastardised version of the code found in Will Bond's oscrypto +library. An enormous debt is owed to him for blazing this trail for us. For +that reason, this code should be considered to be covered both by urllib3's +license and by oscrypto's: + +.. code-block:: + + Copyright (c) 2015-2016 Will Bond + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +""" +from __future__ import absolute_import + +import contextlib +import ctypes +import errno +import os.path +import shutil +import socket +import ssl +import struct +import threading +import weakref + +import six + +from .. import util +from ..util.ssl_ import PROTOCOL_TLS_CLIENT +from ._securetransport.bindings import CoreFoundation, Security, SecurityConst +from ._securetransport.low_level import ( + _assert_no_error, + _build_tls_unknown_ca_alert, + _cert_array_from_pem, + _create_cfstring_array, + _load_client_cert_chain, + _temporary_keychain, +) + +try: # Platform-specific: Python 2 + from socket import _fileobject +except ImportError: # Platform-specific: Python 3 + _fileobject = None + from ..packages.backports.makefile import backport_makefile + +__all__ = ["inject_into_urllib3", "extract_from_urllib3"] + +# SNI always works +HAS_SNI = True + +orig_util_HAS_SNI = util.HAS_SNI +orig_util_SSLContext = util.ssl_.SSLContext + +# This dictionary is used by the read callback to obtain a handle to the +# calling wrapped socket. This is a pretty silly approach, but for now it'll +# do. I feel like I should be able to smuggle a handle to the wrapped socket +# directly in the SSLConnectionRef, but for now this approach will work I +# guess. +# +# We need to lock around this structure for inserts, but we don't do it for +# reads/writes in the callbacks. The reasoning here goes as follows: +# +# 1. It is not possible to call into the callbacks before the dictionary is +# populated, so once in the callback the id must be in the dictionary. +# 2. The callbacks don't mutate the dictionary, they only read from it, and +# so cannot conflict with any of the insertions. +# +# This is good: if we had to lock in the callbacks we'd drastically slow down +# the performance of this code. +_connection_refs = weakref.WeakValueDictionary() +_connection_ref_lock = threading.Lock() + +# Limit writes to 16kB. This is OpenSSL's limit, but we'll cargo-cult it over +# for no better reason than we need *a* limit, and this one is right there. +SSL_WRITE_BLOCKSIZE = 16384 + +# This is our equivalent of util.ssl_.DEFAULT_CIPHERS, but expanded out to +# individual cipher suites. We need to do this because this is how +# SecureTransport wants them. +CIPHER_SUITES = [ + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + SecurityConst.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + SecurityConst.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + SecurityConst.TLS_AES_256_GCM_SHA384, + SecurityConst.TLS_AES_128_GCM_SHA256, + SecurityConst.TLS_RSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_RSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_AES_128_CCM_8_SHA256, + SecurityConst.TLS_AES_128_CCM_SHA256, + SecurityConst.TLS_RSA_WITH_AES_256_CBC_SHA256, + SecurityConst.TLS_RSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_RSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_RSA_WITH_AES_128_CBC_SHA, +] + +# Basically this is simple: for PROTOCOL_SSLv23 we turn it into a low of +# TLSv1 and a high of TLSv1.2. For everything else, we pin to that version. +# TLSv1 to 1.2 are supported on macOS 10.8+ +_protocol_to_min_max = { + util.PROTOCOL_TLS: (SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocol12), + PROTOCOL_TLS_CLIENT: (SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocol12), +} + +if hasattr(ssl, "PROTOCOL_SSLv2"): + _protocol_to_min_max[ssl.PROTOCOL_SSLv2] = ( + SecurityConst.kSSLProtocol2, + SecurityConst.kSSLProtocol2, + ) +if hasattr(ssl, "PROTOCOL_SSLv3"): + _protocol_to_min_max[ssl.PROTOCOL_SSLv3] = ( + SecurityConst.kSSLProtocol3, + SecurityConst.kSSLProtocol3, + ) +if hasattr(ssl, "PROTOCOL_TLSv1"): + _protocol_to_min_max[ssl.PROTOCOL_TLSv1] = ( + SecurityConst.kTLSProtocol1, + SecurityConst.kTLSProtocol1, + ) +if hasattr(ssl, "PROTOCOL_TLSv1_1"): + _protocol_to_min_max[ssl.PROTOCOL_TLSv1_1] = ( + SecurityConst.kTLSProtocol11, + SecurityConst.kTLSProtocol11, + ) +if hasattr(ssl, "PROTOCOL_TLSv1_2"): + _protocol_to_min_max[ssl.PROTOCOL_TLSv1_2] = ( + SecurityConst.kTLSProtocol12, + SecurityConst.kTLSProtocol12, + ) + + +def inject_into_urllib3(): + """ + Monkey-patch urllib3 with SecureTransport-backed SSL-support. + """ + util.SSLContext = SecureTransportContext + util.ssl_.SSLContext = SecureTransportContext + util.HAS_SNI = HAS_SNI + util.ssl_.HAS_SNI = HAS_SNI + util.IS_SECURETRANSPORT = True + util.ssl_.IS_SECURETRANSPORT = True + + +def extract_from_urllib3(): + """ + Undo monkey-patching by :func:`inject_into_urllib3`. + """ + util.SSLContext = orig_util_SSLContext + util.ssl_.SSLContext = orig_util_SSLContext + util.HAS_SNI = orig_util_HAS_SNI + util.ssl_.HAS_SNI = orig_util_HAS_SNI + util.IS_SECURETRANSPORT = False + util.ssl_.IS_SECURETRANSPORT = False + + +def _read_callback(connection_id, data_buffer, data_length_pointer): + """ + SecureTransport read callback. This is called by ST to request that data + be returned from the socket. + """ + wrapped_socket = None + try: + wrapped_socket = _connection_refs.get(connection_id) + if wrapped_socket is None: + return SecurityConst.errSSLInternal + base_socket = wrapped_socket.socket + + requested_length = data_length_pointer[0] + + timeout = wrapped_socket.gettimeout() + error = None + read_count = 0 + + try: + while read_count < requested_length: + if timeout is None or timeout >= 0: + if not util.wait_for_read(base_socket, timeout): + raise socket.error(errno.EAGAIN, "timed out") + + remaining = requested_length - read_count + buffer = (ctypes.c_char * remaining).from_address( + data_buffer + read_count + ) + chunk_size = base_socket.recv_into(buffer, remaining) + read_count += chunk_size + if not chunk_size: + if not read_count: + return SecurityConst.errSSLClosedGraceful + break + except (socket.error) as e: + error = e.errno + + if error is not None and error != errno.EAGAIN: + data_length_pointer[0] = read_count + if error == errno.ECONNRESET or error == errno.EPIPE: + return SecurityConst.errSSLClosedAbort + raise + + data_length_pointer[0] = read_count + + if read_count != requested_length: + return SecurityConst.errSSLWouldBlock + + return 0 + except Exception as e: + if wrapped_socket is not None: + wrapped_socket._exception = e + return SecurityConst.errSSLInternal + + +def _write_callback(connection_id, data_buffer, data_length_pointer): + """ + SecureTransport write callback. This is called by ST to request that data + actually be sent on the network. + """ + wrapped_socket = None + try: + wrapped_socket = _connection_refs.get(connection_id) + if wrapped_socket is None: + return SecurityConst.errSSLInternal + base_socket = wrapped_socket.socket + + bytes_to_write = data_length_pointer[0] + data = ctypes.string_at(data_buffer, bytes_to_write) + + timeout = wrapped_socket.gettimeout() + error = None + sent = 0 + + try: + while sent < bytes_to_write: + if timeout is None or timeout >= 0: + if not util.wait_for_write(base_socket, timeout): + raise socket.error(errno.EAGAIN, "timed out") + chunk_sent = base_socket.send(data) + sent += chunk_sent + + # This has some needless copying here, but I'm not sure there's + # much value in optimising this data path. + data = data[chunk_sent:] + except (socket.error) as e: + error = e.errno + + if error is not None and error != errno.EAGAIN: + data_length_pointer[0] = sent + if error == errno.ECONNRESET or error == errno.EPIPE: + return SecurityConst.errSSLClosedAbort + raise + + data_length_pointer[0] = sent + + if sent != bytes_to_write: + return SecurityConst.errSSLWouldBlock + + return 0 + except Exception as e: + if wrapped_socket is not None: + wrapped_socket._exception = e + return SecurityConst.errSSLInternal + + +# We need to keep these two objects references alive: if they get GC'd while +# in use then SecureTransport could attempt to call a function that is in freed +# memory. That would be...uh...bad. Yeah, that's the word. Bad. +_read_callback_pointer = Security.SSLReadFunc(_read_callback) +_write_callback_pointer = Security.SSLWriteFunc(_write_callback) + + +class WrappedSocket(object): + """ + API-compatibility wrapper for Python's OpenSSL wrapped socket object. + + Note: _makefile_refs, _drop(), and _reuse() are needed for the garbage + collector of PyPy. + """ + + def __init__(self, socket): + self.socket = socket + self.context = None + self._makefile_refs = 0 + self._closed = False + self._exception = None + self._keychain = None + self._keychain_dir = None + self._client_cert_chain = None + + # We save off the previously-configured timeout and then set it to + # zero. This is done because we use select and friends to handle the + # timeouts, but if we leave the timeout set on the lower socket then + # Python will "kindly" call select on that socket again for us. Avoid + # that by forcing the timeout to zero. + self._timeout = self.socket.gettimeout() + self.socket.settimeout(0) + + @contextlib.contextmanager + def _raise_on_error(self): + """ + A context manager that can be used to wrap calls that do I/O from + SecureTransport. If any of the I/O callbacks hit an exception, this + context manager will correctly propagate the exception after the fact. + This avoids silently swallowing those exceptions. + + It also correctly forces the socket closed. + """ + self._exception = None + + # We explicitly don't catch around this yield because in the unlikely + # event that an exception was hit in the block we don't want to swallow + # it. + yield + if self._exception is not None: + exception, self._exception = self._exception, None + self.close() + raise exception + + def _set_ciphers(self): + """ + Sets up the allowed ciphers. By default this matches the set in + util.ssl_.DEFAULT_CIPHERS, at least as supported by macOS. This is done + custom and doesn't allow changing at this time, mostly because parsing + OpenSSL cipher strings is going to be a freaking nightmare. + """ + ciphers = (Security.SSLCipherSuite * len(CIPHER_SUITES))(*CIPHER_SUITES) + result = Security.SSLSetEnabledCiphers( + self.context, ciphers, len(CIPHER_SUITES) + ) + _assert_no_error(result) + + def _set_alpn_protocols(self, protocols): + """ + Sets up the ALPN protocols on the context. + """ + if not protocols: + return + protocols_arr = _create_cfstring_array(protocols) + try: + result = Security.SSLSetALPNProtocols(self.context, protocols_arr) + _assert_no_error(result) + finally: + CoreFoundation.CFRelease(protocols_arr) + + def _custom_validate(self, verify, trust_bundle): + """ + Called when we have set custom validation. We do this in two cases: + first, when cert validation is entirely disabled; and second, when + using a custom trust DB. + Raises an SSLError if the connection is not trusted. + """ + # If we disabled cert validation, just say: cool. + if not verify: + return + + successes = ( + SecurityConst.kSecTrustResultUnspecified, + SecurityConst.kSecTrustResultProceed, + ) + try: + trust_result = self._evaluate_trust(trust_bundle) + if trust_result in successes: + return + reason = "error code: %d" % (trust_result,) + except Exception as e: + # Do not trust on error + reason = "exception: %r" % (e,) + + # SecureTransport does not send an alert nor shuts down the connection. + rec = _build_tls_unknown_ca_alert(self.version()) + self.socket.sendall(rec) + # close the connection immediately + # l_onoff = 1, activate linger + # l_linger = 0, linger for 0 seoncds + opts = struct.pack("ii", 1, 0) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, opts) + self.close() + raise ssl.SSLError("certificate verify failed, %s" % reason) + + def _evaluate_trust(self, trust_bundle): + # We want data in memory, so load it up. + if os.path.isfile(trust_bundle): + with open(trust_bundle, "rb") as f: + trust_bundle = f.read() + + cert_array = None + trust = Security.SecTrustRef() + + try: + # Get a CFArray that contains the certs we want. + cert_array = _cert_array_from_pem(trust_bundle) + + # Ok, now the hard part. We want to get the SecTrustRef that ST has + # created for this connection, shove our CAs into it, tell ST to + # ignore everything else it knows, and then ask if it can build a + # chain. This is a buuuunch of code. + result = Security.SSLCopyPeerTrust(self.context, ctypes.byref(trust)) + _assert_no_error(result) + if not trust: + raise ssl.SSLError("Failed to copy trust reference") + + result = Security.SecTrustSetAnchorCertificates(trust, cert_array) + _assert_no_error(result) + + result = Security.SecTrustSetAnchorCertificatesOnly(trust, True) + _assert_no_error(result) + + trust_result = Security.SecTrustResultType() + result = Security.SecTrustEvaluate(trust, ctypes.byref(trust_result)) + _assert_no_error(result) + finally: + if trust: + CoreFoundation.CFRelease(trust) + + if cert_array is not None: + CoreFoundation.CFRelease(cert_array) + + return trust_result.value + + def handshake( + self, + server_hostname, + verify, + trust_bundle, + min_version, + max_version, + client_cert, + client_key, + client_key_passphrase, + alpn_protocols, + ): + """ + Actually performs the TLS handshake. This is run automatically by + wrapped socket, and shouldn't be needed in user code. + """ + # First, we do the initial bits of connection setup. We need to create + # a context, set its I/O funcs, and set the connection reference. + self.context = Security.SSLCreateContext( + None, SecurityConst.kSSLClientSide, SecurityConst.kSSLStreamType + ) + result = Security.SSLSetIOFuncs( + self.context, _read_callback_pointer, _write_callback_pointer + ) + _assert_no_error(result) + + # Here we need to compute the handle to use. We do this by taking the + # id of self modulo 2**31 - 1. If this is already in the dictionary, we + # just keep incrementing by one until we find a free space. + with _connection_ref_lock: + handle = id(self) % 2147483647 + while handle in _connection_refs: + handle = (handle + 1) % 2147483647 + _connection_refs[handle] = self + + result = Security.SSLSetConnection(self.context, handle) + _assert_no_error(result) + + # If we have a server hostname, we should set that too. + if server_hostname: + if not isinstance(server_hostname, bytes): + server_hostname = server_hostname.encode("utf-8") + + result = Security.SSLSetPeerDomainName( + self.context, server_hostname, len(server_hostname) + ) + _assert_no_error(result) + + # Setup the ciphers. + self._set_ciphers() + + # Setup the ALPN protocols. + self._set_alpn_protocols(alpn_protocols) + + # Set the minimum and maximum TLS versions. + result = Security.SSLSetProtocolVersionMin(self.context, min_version) + _assert_no_error(result) + + result = Security.SSLSetProtocolVersionMax(self.context, max_version) + _assert_no_error(result) + + # If there's a trust DB, we need to use it. We do that by telling + # SecureTransport to break on server auth. We also do that if we don't + # want to validate the certs at all: we just won't actually do any + # authing in that case. + if not verify or trust_bundle is not None: + result = Security.SSLSetSessionOption( + self.context, SecurityConst.kSSLSessionOptionBreakOnServerAuth, True + ) + _assert_no_error(result) + + # If there's a client cert, we need to use it. + if client_cert: + self._keychain, self._keychain_dir = _temporary_keychain() + self._client_cert_chain = _load_client_cert_chain( + self._keychain, client_cert, client_key + ) + result = Security.SSLSetCertificate(self.context, self._client_cert_chain) + _assert_no_error(result) + + while True: + with self._raise_on_error(): + result = Security.SSLHandshake(self.context) + + if result == SecurityConst.errSSLWouldBlock: + raise socket.timeout("handshake timed out") + elif result == SecurityConst.errSSLServerAuthCompleted: + self._custom_validate(verify, trust_bundle) + continue + else: + _assert_no_error(result) + break + + def fileno(self): + return self.socket.fileno() + + # Copy-pasted from Python 3.5 source code + def _decref_socketios(self): + if self._makefile_refs > 0: + self._makefile_refs -= 1 + if self._closed: + self.close() + + def recv(self, bufsiz): + buffer = ctypes.create_string_buffer(bufsiz) + bytes_read = self.recv_into(buffer, bufsiz) + data = buffer[:bytes_read] + return data + + def recv_into(self, buffer, nbytes=None): + # Read short on EOF. + if self._closed: + return 0 + + if nbytes is None: + nbytes = len(buffer) + + buffer = (ctypes.c_char * nbytes).from_buffer(buffer) + processed_bytes = ctypes.c_size_t(0) + + with self._raise_on_error(): + result = Security.SSLRead( + self.context, buffer, nbytes, ctypes.byref(processed_bytes) + ) + + # There are some result codes that we want to treat as "not always + # errors". Specifically, those are errSSLWouldBlock, + # errSSLClosedGraceful, and errSSLClosedNoNotify. + if result == SecurityConst.errSSLWouldBlock: + # If we didn't process any bytes, then this was just a time out. + # However, we can get errSSLWouldBlock in situations when we *did* + # read some data, and in those cases we should just read "short" + # and return. + if processed_bytes.value == 0: + # Timed out, no data read. + raise socket.timeout("recv timed out") + elif result in ( + SecurityConst.errSSLClosedGraceful, + SecurityConst.errSSLClosedNoNotify, + ): + # The remote peer has closed this connection. We should do so as + # well. Note that we don't actually return here because in + # principle this could actually be fired along with return data. + # It's unlikely though. + self.close() + else: + _assert_no_error(result) + + # Ok, we read and probably succeeded. We should return whatever data + # was actually read. + return processed_bytes.value + + def settimeout(self, timeout): + self._timeout = timeout + + def gettimeout(self): + return self._timeout + + def send(self, data): + processed_bytes = ctypes.c_size_t(0) + + with self._raise_on_error(): + result = Security.SSLWrite( + self.context, data, len(data), ctypes.byref(processed_bytes) + ) + + if result == SecurityConst.errSSLWouldBlock and processed_bytes.value == 0: + # Timed out + raise socket.timeout("send timed out") + else: + _assert_no_error(result) + + # We sent, and probably succeeded. Tell them how much we sent. + return processed_bytes.value + + def sendall(self, data): + total_sent = 0 + while total_sent < len(data): + sent = self.send(data[total_sent : total_sent + SSL_WRITE_BLOCKSIZE]) + total_sent += sent + + def shutdown(self): + with self._raise_on_error(): + Security.SSLClose(self.context) + + def close(self): + # TODO: should I do clean shutdown here? Do I have to? + if self._makefile_refs < 1: + self._closed = True + if self.context: + CoreFoundation.CFRelease(self.context) + self.context = None + if self._client_cert_chain: + CoreFoundation.CFRelease(self._client_cert_chain) + self._client_cert_chain = None + if self._keychain: + Security.SecKeychainDelete(self._keychain) + CoreFoundation.CFRelease(self._keychain) + shutil.rmtree(self._keychain_dir) + self._keychain = self._keychain_dir = None + return self.socket.close() + else: + self._makefile_refs -= 1 + + def getpeercert(self, binary_form=False): + # Urgh, annoying. + # + # Here's how we do this: + # + # 1. Call SSLCopyPeerTrust to get hold of the trust object for this + # connection. + # 2. Call SecTrustGetCertificateAtIndex for index 0 to get the leaf. + # 3. To get the CN, call SecCertificateCopyCommonName and process that + # string so that it's of the appropriate type. + # 4. To get the SAN, we need to do something a bit more complex: + # a. Call SecCertificateCopyValues to get the data, requesting + # kSecOIDSubjectAltName. + # b. Mess about with this dictionary to try to get the SANs out. + # + # This is gross. Really gross. It's going to be a few hundred LoC extra + # just to repeat something that SecureTransport can *already do*. So my + # operating assumption at this time is that what we want to do is + # instead to just flag to urllib3 that it shouldn't do its own hostname + # validation when using SecureTransport. + if not binary_form: + raise ValueError("SecureTransport only supports dumping binary certs") + trust = Security.SecTrustRef() + certdata = None + der_bytes = None + + try: + # Grab the trust store. + result = Security.SSLCopyPeerTrust(self.context, ctypes.byref(trust)) + _assert_no_error(result) + if not trust: + # Probably we haven't done the handshake yet. No biggie. + return None + + cert_count = Security.SecTrustGetCertificateCount(trust) + if not cert_count: + # Also a case that might happen if we haven't handshaked. + # Handshook? Handshaken? + return None + + leaf = Security.SecTrustGetCertificateAtIndex(trust, 0) + assert leaf + + # Ok, now we want the DER bytes. + certdata = Security.SecCertificateCopyData(leaf) + assert certdata + + data_length = CoreFoundation.CFDataGetLength(certdata) + data_buffer = CoreFoundation.CFDataGetBytePtr(certdata) + der_bytes = ctypes.string_at(data_buffer, data_length) + finally: + if certdata: + CoreFoundation.CFRelease(certdata) + if trust: + CoreFoundation.CFRelease(trust) + + return der_bytes + + def version(self): + protocol = Security.SSLProtocol() + result = Security.SSLGetNegotiatedProtocolVersion( + self.context, ctypes.byref(protocol) + ) + _assert_no_error(result) + if protocol.value == SecurityConst.kTLSProtocol13: + raise ssl.SSLError("SecureTransport does not support TLS 1.3") + elif protocol.value == SecurityConst.kTLSProtocol12: + return "TLSv1.2" + elif protocol.value == SecurityConst.kTLSProtocol11: + return "TLSv1.1" + elif protocol.value == SecurityConst.kTLSProtocol1: + return "TLSv1" + elif protocol.value == SecurityConst.kSSLProtocol3: + return "SSLv3" + elif protocol.value == SecurityConst.kSSLProtocol2: + return "SSLv2" + else: + raise ssl.SSLError("Unknown TLS version: %r" % protocol) + + def _reuse(self): + self._makefile_refs += 1 + + def _drop(self): + if self._makefile_refs < 1: + self.close() + else: + self._makefile_refs -= 1 + + +if _fileobject: # Platform-specific: Python 2 + + def makefile(self, mode, bufsize=-1): + self._makefile_refs += 1 + return _fileobject(self, mode, bufsize, close=True) + + +else: # Platform-specific: Python 3 + + def makefile(self, mode="r", buffering=None, *args, **kwargs): + # We disable buffering with SecureTransport because it conflicts with + # the buffering that ST does internally (see issue #1153 for more). + buffering = 0 + return backport_makefile(self, mode, buffering, *args, **kwargs) + + +WrappedSocket.makefile = makefile + + +class SecureTransportContext(object): + """ + I am a wrapper class for the SecureTransport library, to translate the + interface of the standard library ``SSLContext`` object to calls into + SecureTransport. + """ + + def __init__(self, protocol): + self._min_version, self._max_version = _protocol_to_min_max[protocol] + self._options = 0 + self._verify = False + self._trust_bundle = None + self._client_cert = None + self._client_key = None + self._client_key_passphrase = None + self._alpn_protocols = None + + @property + def check_hostname(self): + """ + SecureTransport cannot have its hostname checking disabled. For more, + see the comment on getpeercert() in this file. + """ + return True + + @check_hostname.setter + def check_hostname(self, value): + """ + SecureTransport cannot have its hostname checking disabled. For more, + see the comment on getpeercert() in this file. + """ + pass + + @property + def options(self): + # TODO: Well, crap. + # + # So this is the bit of the code that is the most likely to cause us + # trouble. Essentially we need to enumerate all of the SSL options that + # users might want to use and try to see if we can sensibly translate + # them, or whether we should just ignore them. + return self._options + + @options.setter + def options(self, value): + # TODO: Update in line with above. + self._options = value + + @property + def verify_mode(self): + return ssl.CERT_REQUIRED if self._verify else ssl.CERT_NONE + + @verify_mode.setter + def verify_mode(self, value): + self._verify = True if value == ssl.CERT_REQUIRED else False + + def set_default_verify_paths(self): + # So, this has to do something a bit weird. Specifically, what it does + # is nothing. + # + # This means that, if we had previously had load_verify_locations + # called, this does not undo that. We need to do that because it turns + # out that the rest of the urllib3 code will attempt to load the + # default verify paths if it hasn't been told about any paths, even if + # the context itself was sometime earlier. We resolve that by just + # ignoring it. + pass + + def load_default_certs(self): + return self.set_default_verify_paths() + + def set_ciphers(self, ciphers): + # For now, we just require the default cipher string. + if ciphers != util.ssl_.DEFAULT_CIPHERS: + raise ValueError("SecureTransport doesn't support custom cipher strings") + + def load_verify_locations(self, cafile=None, capath=None, cadata=None): + # OK, we only really support cadata and cafile. + if capath is not None: + raise ValueError("SecureTransport does not support cert directories") + + # Raise if cafile does not exist. + if cafile is not None: + with open(cafile): + pass + + self._trust_bundle = cafile or cadata + + def load_cert_chain(self, certfile, keyfile=None, password=None): + self._client_cert = certfile + self._client_key = keyfile + self._client_cert_passphrase = password + + def set_alpn_protocols(self, protocols): + """ + Sets the ALPN protocols that will later be set on the context. + + Raises a NotImplementedError if ALPN is not supported. + """ + if not hasattr(Security, "SSLSetALPNProtocols"): + raise NotImplementedError( + "SecureTransport supports ALPN only in macOS 10.12+" + ) + self._alpn_protocols = [six.ensure_binary(p) for p in protocols] + + def wrap_socket( + self, + sock, + server_side=False, + do_handshake_on_connect=True, + suppress_ragged_eofs=True, + server_hostname=None, + ): + # So, what do we do here? Firstly, we assert some properties. This is a + # stripped down shim, so there is some functionality we don't support. + # See PEP 543 for the real deal. + assert not server_side + assert do_handshake_on_connect + assert suppress_ragged_eofs + + # Ok, we're good to go. Now we want to create the wrapped socket object + # and store it in the appropriate place. + wrapped_socket = WrappedSocket(sock) + + # Now we can handshake + wrapped_socket.handshake( + server_hostname, + self._verify, + self._trust_bundle, + self._min_version, + self._max_version, + self._client_cert, + self._client_key, + self._client_key_passphrase, + self._alpn_protocols, + ) + return wrapped_socket diff --git a/openpype/vendor/python/python_2/urllib3/contrib/socks.py b/openpype/vendor/python/python_2/urllib3/contrib/socks.py new file mode 100644 index 0000000000..c326e80dd1 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/contrib/socks.py @@ -0,0 +1,216 @@ +# -*- coding: utf-8 -*- +""" +This module contains provisional support for SOCKS proxies from within +urllib3. This module supports SOCKS4, SOCKS4A (an extension of SOCKS4), and +SOCKS5. To enable its functionality, either install PySocks or install this +module with the ``socks`` extra. + +The SOCKS implementation supports the full range of urllib3 features. It also +supports the following SOCKS features: + +- SOCKS4A (``proxy_url='socks4a://...``) +- SOCKS4 (``proxy_url='socks4://...``) +- SOCKS5 with remote DNS (``proxy_url='socks5h://...``) +- SOCKS5 with local DNS (``proxy_url='socks5://...``) +- Usernames and passwords for the SOCKS proxy + +.. note:: + It is recommended to use ``socks5h://`` or ``socks4a://`` schemes in + your ``proxy_url`` to ensure that DNS resolution is done from the remote + server instead of client-side when connecting to a domain name. + +SOCKS4 supports IPv4 and domain names with the SOCKS4A extension. SOCKS5 +supports IPv4, IPv6, and domain names. + +When connecting to a SOCKS4 proxy the ``username`` portion of the ``proxy_url`` +will be sent as the ``userid`` section of the SOCKS request: + +.. code-block:: python + + proxy_url="socks4a://@proxy-host" + +When connecting to a SOCKS5 proxy the ``username`` and ``password`` portion +of the ``proxy_url`` will be sent as the username/password to authenticate +with the proxy: + +.. code-block:: python + + proxy_url="socks5h://:@proxy-host" + +""" +from __future__ import absolute_import + +try: + import socks +except ImportError: + import warnings + + from ..exceptions import DependencyWarning + + warnings.warn( + ( + "SOCKS support in urllib3 requires the installation of optional " + "dependencies: specifically, PySocks. For more information, see " + "https://urllib3.readthedocs.io/en/1.26.x/contrib.html#socks-proxies" + ), + DependencyWarning, + ) + raise + +from socket import error as SocketError +from socket import timeout as SocketTimeout + +from ..connection import HTTPConnection, HTTPSConnection +from ..connectionpool import HTTPConnectionPool, HTTPSConnectionPool +from ..exceptions import ConnectTimeoutError, NewConnectionError +from ..poolmanager import PoolManager +from ..util.url import parse_url + +try: + import ssl +except ImportError: + ssl = None + + +class SOCKSConnection(HTTPConnection): + """ + A plain-text HTTP connection that connects via a SOCKS proxy. + """ + + def __init__(self, *args, **kwargs): + self._socks_options = kwargs.pop("_socks_options") + super(SOCKSConnection, self).__init__(*args, **kwargs) + + def _new_conn(self): + """ + Establish a new connection via the SOCKS proxy. + """ + extra_kw = {} + if self.source_address: + extra_kw["source_address"] = self.source_address + + if self.socket_options: + extra_kw["socket_options"] = self.socket_options + + try: + conn = socks.create_connection( + (self.host, self.port), + proxy_type=self._socks_options["socks_version"], + proxy_addr=self._socks_options["proxy_host"], + proxy_port=self._socks_options["proxy_port"], + proxy_username=self._socks_options["username"], + proxy_password=self._socks_options["password"], + proxy_rdns=self._socks_options["rdns"], + timeout=self.timeout, + **extra_kw + ) + + except SocketTimeout: + raise ConnectTimeoutError( + self, + "Connection to %s timed out. (connect timeout=%s)" + % (self.host, self.timeout), + ) + + except socks.ProxyError as e: + # This is fragile as hell, but it seems to be the only way to raise + # useful errors here. + if e.socket_err: + error = e.socket_err + if isinstance(error, SocketTimeout): + raise ConnectTimeoutError( + self, + "Connection to %s timed out. (connect timeout=%s)" + % (self.host, self.timeout), + ) + else: + raise NewConnectionError( + self, "Failed to establish a new connection: %s" % error + ) + else: + raise NewConnectionError( + self, "Failed to establish a new connection: %s" % e + ) + + except SocketError as e: # Defensive: PySocks should catch all these. + raise NewConnectionError( + self, "Failed to establish a new connection: %s" % e + ) + + return conn + + +# We don't need to duplicate the Verified/Unverified distinction from +# urllib3/connection.py here because the HTTPSConnection will already have been +# correctly set to either the Verified or Unverified form by that module. This +# means the SOCKSHTTPSConnection will automatically be the correct type. +class SOCKSHTTPSConnection(SOCKSConnection, HTTPSConnection): + pass + + +class SOCKSHTTPConnectionPool(HTTPConnectionPool): + ConnectionCls = SOCKSConnection + + +class SOCKSHTTPSConnectionPool(HTTPSConnectionPool): + ConnectionCls = SOCKSHTTPSConnection + + +class SOCKSProxyManager(PoolManager): + """ + A version of the urllib3 ProxyManager that routes connections via the + defined SOCKS proxy. + """ + + pool_classes_by_scheme = { + "http": SOCKSHTTPConnectionPool, + "https": SOCKSHTTPSConnectionPool, + } + + def __init__( + self, + proxy_url, + username=None, + password=None, + num_pools=10, + headers=None, + **connection_pool_kw + ): + parsed = parse_url(proxy_url) + + if username is None and password is None and parsed.auth is not None: + split = parsed.auth.split(":") + if len(split) == 2: + username, password = split + if parsed.scheme == "socks5": + socks_version = socks.PROXY_TYPE_SOCKS5 + rdns = False + elif parsed.scheme == "socks5h": + socks_version = socks.PROXY_TYPE_SOCKS5 + rdns = True + elif parsed.scheme == "socks4": + socks_version = socks.PROXY_TYPE_SOCKS4 + rdns = False + elif parsed.scheme == "socks4a": + socks_version = socks.PROXY_TYPE_SOCKS4 + rdns = True + else: + raise ValueError("Unable to determine SOCKS version from %s" % proxy_url) + + self.proxy_url = proxy_url + + socks_options = { + "socks_version": socks_version, + "proxy_host": parsed.host, + "proxy_port": parsed.port, + "username": username, + "password": password, + "rdns": rdns, + } + connection_pool_kw["_socks_options"] = socks_options + + super(SOCKSProxyManager, self).__init__( + num_pools, headers, **connection_pool_kw + ) + + self.pool_classes_by_scheme = SOCKSProxyManager.pool_classes_by_scheme diff --git a/openpype/vendor/python/python_2/urllib3/exceptions.py b/openpype/vendor/python/python_2/urllib3/exceptions.py new file mode 100644 index 0000000000..cba6f3f560 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/exceptions.py @@ -0,0 +1,323 @@ +from __future__ import absolute_import + +from .packages.six.moves.http_client import IncompleteRead as httplib_IncompleteRead + +# Base Exceptions + + +class HTTPError(Exception): + """Base exception used by this module.""" + + pass + + +class HTTPWarning(Warning): + """Base warning used by this module.""" + + pass + + +class PoolError(HTTPError): + """Base exception for errors caused within a pool.""" + + def __init__(self, pool, message): + self.pool = pool + HTTPError.__init__(self, "%s: %s" % (pool, message)) + + def __reduce__(self): + # For pickling purposes. + return self.__class__, (None, None) + + +class RequestError(PoolError): + """Base exception for PoolErrors that have associated URLs.""" + + def __init__(self, pool, url, message): + self.url = url + PoolError.__init__(self, pool, message) + + def __reduce__(self): + # For pickling purposes. + return self.__class__, (None, self.url, None) + + +class SSLError(HTTPError): + """Raised when SSL certificate fails in an HTTPS connection.""" + + pass + + +class ProxyError(HTTPError): + """Raised when the connection to a proxy fails.""" + + def __init__(self, message, error, *args): + super(ProxyError, self).__init__(message, error, *args) + self.original_error = error + + +class DecodeError(HTTPError): + """Raised when automatic decoding based on Content-Type fails.""" + + pass + + +class ProtocolError(HTTPError): + """Raised when something unexpected happens mid-request/response.""" + + pass + + +#: Renamed to ProtocolError but aliased for backwards compatibility. +ConnectionError = ProtocolError + + +# Leaf Exceptions + + +class MaxRetryError(RequestError): + """Raised when the maximum number of retries is exceeded. + + :param pool: The connection pool + :type pool: :class:`~urllib3.connectionpool.HTTPConnectionPool` + :param string url: The requested Url + :param exceptions.Exception reason: The underlying error + + """ + + def __init__(self, pool, url, reason=None): + self.reason = reason + + message = "Max retries exceeded with url: %s (Caused by %r)" % (url, reason) + + RequestError.__init__(self, pool, url, message) + + +class HostChangedError(RequestError): + """Raised when an existing pool gets a request for a foreign host.""" + + def __init__(self, pool, url, retries=3): + message = "Tried to open a foreign host with url: %s" % url + RequestError.__init__(self, pool, url, message) + self.retries = retries + + +class TimeoutStateError(HTTPError): + """Raised when passing an invalid state to a timeout""" + + pass + + +class TimeoutError(HTTPError): + """Raised when a socket timeout error occurs. + + Catching this error will catch both :exc:`ReadTimeoutErrors + ` and :exc:`ConnectTimeoutErrors `. + """ + + pass + + +class ReadTimeoutError(TimeoutError, RequestError): + """Raised when a socket timeout occurs while receiving data from a server""" + + pass + + +# This timeout error does not have a URL attached and needs to inherit from the +# base HTTPError +class ConnectTimeoutError(TimeoutError): + """Raised when a socket timeout occurs while connecting to a server""" + + pass + + +class NewConnectionError(ConnectTimeoutError, PoolError): + """Raised when we fail to establish a new connection. Usually ECONNREFUSED.""" + + pass + + +class EmptyPoolError(PoolError): + """Raised when a pool runs out of connections and no more are allowed.""" + + pass + + +class ClosedPoolError(PoolError): + """Raised when a request enters a pool after the pool has been closed.""" + + pass + + +class LocationValueError(ValueError, HTTPError): + """Raised when there is something wrong with a given URL input.""" + + pass + + +class LocationParseError(LocationValueError): + """Raised when get_host or similar fails to parse the URL input.""" + + def __init__(self, location): + message = "Failed to parse: %s" % location + HTTPError.__init__(self, message) + + self.location = location + + +class URLSchemeUnknown(LocationValueError): + """Raised when a URL input has an unsupported scheme.""" + + def __init__(self, scheme): + message = "Not supported URL scheme %s" % scheme + super(URLSchemeUnknown, self).__init__(message) + + self.scheme = scheme + + +class ResponseError(HTTPError): + """Used as a container for an error reason supplied in a MaxRetryError.""" + + GENERIC_ERROR = "too many error responses" + SPECIFIC_ERROR = "too many {status_code} error responses" + + +class SecurityWarning(HTTPWarning): + """Warned when performing security reducing actions""" + + pass + + +class SubjectAltNameWarning(SecurityWarning): + """Warned when connecting to a host with a certificate missing a SAN.""" + + pass + + +class InsecureRequestWarning(SecurityWarning): + """Warned when making an unverified HTTPS request.""" + + pass + + +class SystemTimeWarning(SecurityWarning): + """Warned when system time is suspected to be wrong""" + + pass + + +class InsecurePlatformWarning(SecurityWarning): + """Warned when certain TLS/SSL configuration is not available on a platform.""" + + pass + + +class SNIMissingWarning(HTTPWarning): + """Warned when making a HTTPS request without SNI available.""" + + pass + + +class DependencyWarning(HTTPWarning): + """ + Warned when an attempt is made to import a module with missing optional + dependencies. + """ + + pass + + +class ResponseNotChunked(ProtocolError, ValueError): + """Response needs to be chunked in order to read it as chunks.""" + + pass + + +class BodyNotHttplibCompatible(HTTPError): + """ + Body should be :class:`http.client.HTTPResponse` like + (have an fp attribute which returns raw chunks) for read_chunked(). + """ + + pass + + +class IncompleteRead(HTTPError, httplib_IncompleteRead): + """ + Response length doesn't match expected Content-Length + + Subclass of :class:`http.client.IncompleteRead` to allow int value + for ``partial`` to avoid creating large objects on streamed reads. + """ + + def __init__(self, partial, expected): + super(IncompleteRead, self).__init__(partial, expected) + + def __repr__(self): + return "IncompleteRead(%i bytes read, %i more expected)" % ( + self.partial, + self.expected, + ) + + +class InvalidChunkLength(HTTPError, httplib_IncompleteRead): + """Invalid chunk length in a chunked response.""" + + def __init__(self, response, length): + super(InvalidChunkLength, self).__init__( + response.tell(), response.length_remaining + ) + self.response = response + self.length = length + + def __repr__(self): + return "InvalidChunkLength(got length %r, %i bytes read)" % ( + self.length, + self.partial, + ) + + +class InvalidHeader(HTTPError): + """The header provided was somehow invalid.""" + + pass + + +class ProxySchemeUnknown(AssertionError, URLSchemeUnknown): + """ProxyManager does not support the supplied scheme""" + + # TODO(t-8ch): Stop inheriting from AssertionError in v2.0. + + def __init__(self, scheme): + # 'localhost' is here because our URL parser parses + # localhost:8080 -> scheme=localhost, remove if we fix this. + if scheme == "localhost": + scheme = None + if scheme is None: + message = "Proxy URL had no scheme, should start with http:// or https://" + else: + message = ( + "Proxy URL had unsupported scheme %s, should use http:// or https://" + % scheme + ) + super(ProxySchemeUnknown, self).__init__(message) + + +class ProxySchemeUnsupported(ValueError): + """Fetching HTTPS resources through HTTPS proxies is unsupported""" + + pass + + +class HeaderParsingError(HTTPError): + """Raised by assert_header_parsing, but we convert it to a log.warning statement.""" + + def __init__(self, defects, unparsed_data): + message = "%s, unparsed data: %r" % (defects or "Unknown", unparsed_data) + super(HeaderParsingError, self).__init__(message) + + +class UnrewindableBodyError(HTTPError): + """urllib3 encountered an error when trying to rewind a body""" + + pass diff --git a/openpype/vendor/python/python_2/urllib3/fields.py b/openpype/vendor/python/python_2/urllib3/fields.py new file mode 100644 index 0000000000..9d630f491d --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/fields.py @@ -0,0 +1,274 @@ +from __future__ import absolute_import + +import email.utils +import mimetypes +import re + +from .packages import six + + +def guess_content_type(filename, default="application/octet-stream"): + """ + Guess the "Content-Type" of a file. + + :param filename: + The filename to guess the "Content-Type" of using :mod:`mimetypes`. + :param default: + If no "Content-Type" can be guessed, default to `default`. + """ + if filename: + return mimetypes.guess_type(filename)[0] or default + return default + + +def format_header_param_rfc2231(name, value): + """ + Helper function to format and quote a single header parameter using the + strategy defined in RFC 2231. + + Particularly useful for header parameters which might contain + non-ASCII values, like file names. This follows + `RFC 2388 Section 4.4 `_. + + :param name: + The name of the parameter, a string expected to be ASCII only. + :param value: + The value of the parameter, provided as ``bytes`` or `str``. + :ret: + An RFC-2231-formatted unicode string. + """ + if isinstance(value, six.binary_type): + value = value.decode("utf-8") + + if not any(ch in value for ch in '"\\\r\n'): + result = u'%s="%s"' % (name, value) + try: + result.encode("ascii") + except (UnicodeEncodeError, UnicodeDecodeError): + pass + else: + return result + + if six.PY2: # Python 2: + value = value.encode("utf-8") + + # encode_rfc2231 accepts an encoded string and returns an ascii-encoded + # string in Python 2 but accepts and returns unicode strings in Python 3 + value = email.utils.encode_rfc2231(value, "utf-8") + value = "%s*=%s" % (name, value) + + if six.PY2: # Python 2: + value = value.decode("utf-8") + + return value + + +_HTML5_REPLACEMENTS = { + u"\u0022": u"%22", + # Replace "\" with "\\". + u"\u005C": u"\u005C\u005C", +} + +# All control characters from 0x00 to 0x1F *except* 0x1B. +_HTML5_REPLACEMENTS.update( + { + six.unichr(cc): u"%{:02X}".format(cc) + for cc in range(0x00, 0x1F + 1) + if cc not in (0x1B,) + } +) + + +def _replace_multiple(value, needles_and_replacements): + def replacer(match): + return needles_and_replacements[match.group(0)] + + pattern = re.compile( + r"|".join([re.escape(needle) for needle in needles_and_replacements.keys()]) + ) + + result = pattern.sub(replacer, value) + + return result + + +def format_header_param_html5(name, value): + """ + Helper function to format and quote a single header parameter using the + HTML5 strategy. + + Particularly useful for header parameters which might contain + non-ASCII values, like file names. This follows the `HTML5 Working Draft + Section 4.10.22.7`_ and matches the behavior of curl and modern browsers. + + .. _HTML5 Working Draft Section 4.10.22.7: + https://w3c.github.io/html/sec-forms.html#multipart-form-data + + :param name: + The name of the parameter, a string expected to be ASCII only. + :param value: + The value of the parameter, provided as ``bytes`` or `str``. + :ret: + A unicode string, stripped of troublesome characters. + """ + if isinstance(value, six.binary_type): + value = value.decode("utf-8") + + value = _replace_multiple(value, _HTML5_REPLACEMENTS) + + return u'%s="%s"' % (name, value) + + +# For backwards-compatibility. +format_header_param = format_header_param_html5 + + +class RequestField(object): + """ + A data container for request body parameters. + + :param name: + The name of this request field. Must be unicode. + :param data: + The data/value body. + :param filename: + An optional filename of the request field. Must be unicode. + :param headers: + An optional dict-like object of headers to initially use for the field. + :param header_formatter: + An optional callable that is used to encode and format the headers. By + default, this is :func:`format_header_param_html5`. + """ + + def __init__( + self, + name, + data, + filename=None, + headers=None, + header_formatter=format_header_param_html5, + ): + self._name = name + self._filename = filename + self.data = data + self.headers = {} + if headers: + self.headers = dict(headers) + self.header_formatter = header_formatter + + @classmethod + def from_tuples(cls, fieldname, value, header_formatter=format_header_param_html5): + """ + A :class:`~urllib3.fields.RequestField` factory from old-style tuple parameters. + + Supports constructing :class:`~urllib3.fields.RequestField` from + parameter of key/value strings AND key/filetuple. A filetuple is a + (filename, data, MIME type) tuple where the MIME type is optional. + For example:: + + 'foo': 'bar', + 'fakefile': ('foofile.txt', 'contents of foofile'), + 'realfile': ('barfile.txt', open('realfile').read()), + 'typedfile': ('bazfile.bin', open('bazfile').read(), 'image/jpeg'), + 'nonamefile': 'contents of nonamefile field', + + Field names and filenames must be unicode. + """ + if isinstance(value, tuple): + if len(value) == 3: + filename, data, content_type = value + else: + filename, data = value + content_type = guess_content_type(filename) + else: + filename = None + content_type = None + data = value + + request_param = cls( + fieldname, data, filename=filename, header_formatter=header_formatter + ) + request_param.make_multipart(content_type=content_type) + + return request_param + + def _render_part(self, name, value): + """ + Overridable helper function to format a single header parameter. By + default, this calls ``self.header_formatter``. + + :param name: + The name of the parameter, a string expected to be ASCII only. + :param value: + The value of the parameter, provided as a unicode string. + """ + + return self.header_formatter(name, value) + + def _render_parts(self, header_parts): + """ + Helper function to format and quote a single header. + + Useful for single headers that are composed of multiple items. E.g., + 'Content-Disposition' fields. + + :param header_parts: + A sequence of (k, v) tuples or a :class:`dict` of (k, v) to format + as `k1="v1"; k2="v2"; ...`. + """ + parts = [] + iterable = header_parts + if isinstance(header_parts, dict): + iterable = header_parts.items() + + for name, value in iterable: + if value is not None: + parts.append(self._render_part(name, value)) + + return u"; ".join(parts) + + def render_headers(self): + """ + Renders the headers for this request field. + """ + lines = [] + + sort_keys = ["Content-Disposition", "Content-Type", "Content-Location"] + for sort_key in sort_keys: + if self.headers.get(sort_key, False): + lines.append(u"%s: %s" % (sort_key, self.headers[sort_key])) + + for header_name, header_value in self.headers.items(): + if header_name not in sort_keys: + if header_value: + lines.append(u"%s: %s" % (header_name, header_value)) + + lines.append(u"\r\n") + return u"\r\n".join(lines) + + def make_multipart( + self, content_disposition=None, content_type=None, content_location=None + ): + """ + Makes this request field into a multipart request field. + + This method overrides "Content-Disposition", "Content-Type" and + "Content-Location" headers to the request parameter. + + :param content_type: + The 'Content-Type' of the request body. + :param content_location: + The 'Content-Location' of the request body. + + """ + self.headers["Content-Disposition"] = content_disposition or u"form-data" + self.headers["Content-Disposition"] += u"; ".join( + [ + u"", + self._render_parts( + ((u"name", self._name), (u"filename", self._filename)) + ), + ] + ) + self.headers["Content-Type"] = content_type + self.headers["Content-Location"] = content_location diff --git a/openpype/vendor/python/python_2/urllib3/filepost.py b/openpype/vendor/python/python_2/urllib3/filepost.py new file mode 100644 index 0000000000..36c9252c64 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/filepost.py @@ -0,0 +1,98 @@ +from __future__ import absolute_import + +import binascii +import codecs +import os +from io import BytesIO + +from .fields import RequestField +from .packages import six +from .packages.six import b + +writer = codecs.lookup("utf-8")[3] + + +def choose_boundary(): + """ + Our embarrassingly-simple replacement for mimetools.choose_boundary. + """ + boundary = binascii.hexlify(os.urandom(16)) + if not six.PY2: + boundary = boundary.decode("ascii") + return boundary + + +def iter_field_objects(fields): + """ + Iterate over fields. + + Supports list of (k, v) tuples and dicts, and lists of + :class:`~urllib3.fields.RequestField`. + + """ + if isinstance(fields, dict): + i = six.iteritems(fields) + else: + i = iter(fields) + + for field in i: + if isinstance(field, RequestField): + yield field + else: + yield RequestField.from_tuples(*field) + + +def iter_fields(fields): + """ + .. deprecated:: 1.6 + + Iterate over fields. + + The addition of :class:`~urllib3.fields.RequestField` makes this function + obsolete. Instead, use :func:`iter_field_objects`, which returns + :class:`~urllib3.fields.RequestField` objects. + + Supports list of (k, v) tuples and dicts. + """ + if isinstance(fields, dict): + return ((k, v) for k, v in six.iteritems(fields)) + + return ((k, v) for k, v in fields) + + +def encode_multipart_formdata(fields, boundary=None): + """ + Encode a dictionary of ``fields`` using the multipart/form-data MIME format. + + :param fields: + Dictionary of fields or list of (key, :class:`~urllib3.fields.RequestField`). + + :param boundary: + If not specified, then a random boundary will be generated using + :func:`urllib3.filepost.choose_boundary`. + """ + body = BytesIO() + if boundary is None: + boundary = choose_boundary() + + for field in iter_field_objects(fields): + body.write(b("--%s\r\n" % (boundary))) + + writer(body).write(field.render_headers()) + data = field.data + + if isinstance(data, int): + data = str(data) # Backwards compatibility + + if isinstance(data, six.text_type): + writer(body).write(data) + else: + body.write(data) + + body.write(b"\r\n") + + body.write(b("--%s--\r\n" % (boundary))) + + content_type = str("multipart/form-data; boundary=%s" % boundary) + + return body.getvalue(), content_type diff --git a/openpype/vendor/python/python_2/urllib3/packages/__init__.py b/openpype/vendor/python/python_2/urllib3/packages/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openpype/vendor/python/python_2/urllib3/packages/backports/__init__.py b/openpype/vendor/python/python_2/urllib3/packages/backports/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openpype/vendor/python/python_2/urllib3/packages/backports/makefile.py b/openpype/vendor/python/python_2/urllib3/packages/backports/makefile.py new file mode 100644 index 0000000000..b8fb2154b6 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/packages/backports/makefile.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +""" +backports.makefile +~~~~~~~~~~~~~~~~~~ + +Backports the Python 3 ``socket.makefile`` method for use with anything that +wants to create a "fake" socket object. +""" +import io +from socket import SocketIO + + +def backport_makefile( + self, mode="r", buffering=None, encoding=None, errors=None, newline=None +): + """ + Backport of ``socket.makefile`` from Python 3.5. + """ + if not set(mode) <= {"r", "w", "b"}: + raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,)) + writing = "w" in mode + reading = "r" in mode or not writing + assert reading or writing + binary = "b" in mode + rawmode = "" + if reading: + rawmode += "r" + if writing: + rawmode += "w" + raw = SocketIO(self, rawmode) + self._makefile_refs += 1 + if buffering is None: + buffering = -1 + if buffering < 0: + buffering = io.DEFAULT_BUFFER_SIZE + if buffering == 0: + if not binary: + raise ValueError("unbuffered streams must be binary") + return raw + if reading and writing: + buffer = io.BufferedRWPair(raw, raw, buffering) + elif reading: + buffer = io.BufferedReader(raw, buffering) + else: + assert writing + buffer = io.BufferedWriter(raw, buffering) + if binary: + return buffer + text = io.TextIOWrapper(buffer, encoding, errors, newline) + text.mode = mode + return text diff --git a/openpype/vendor/python/python_2/urllib3/packages/six.py b/openpype/vendor/python/python_2/urllib3/packages/six.py new file mode 100644 index 0000000000..ba50acb062 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/packages/six.py @@ -0,0 +1,1077 @@ +# Copyright (c) 2010-2020 Benjamin Peterson +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +"""Utilities for writing code that runs on Python 2 and 3""" + +from __future__ import absolute_import + +import functools +import itertools +import operator +import sys +import types + +__author__ = "Benjamin Peterson " +__version__ = "1.16.0" + + +# Useful for very coarse version differentiation. +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 +PY34 = sys.version_info[0:2] >= (3, 4) + +if PY3: + string_types = (str,) + integer_types = (int,) + class_types = (type,) + text_type = str + binary_type = bytes + + MAXSIZE = sys.maxsize +else: + string_types = (basestring,) + integer_types = (int, long) + class_types = (type, types.ClassType) + text_type = unicode + binary_type = str + + if sys.platform.startswith("java"): + # Jython always uses 32 bits. + MAXSIZE = int((1 << 31) - 1) + else: + # It's possible to have sizeof(long) != sizeof(Py_ssize_t). + class X(object): + def __len__(self): + return 1 << 31 + + try: + len(X()) + except OverflowError: + # 32-bit + MAXSIZE = int((1 << 31) - 1) + else: + # 64-bit + MAXSIZE = int((1 << 63) - 1) + del X + +if PY34: + from importlib.util import spec_from_loader +else: + spec_from_loader = None + + +def _add_doc(func, doc): + """Add documentation to a function.""" + func.__doc__ = doc + + +def _import_module(name): + """Import module, returning the module after the last dot.""" + __import__(name) + return sys.modules[name] + + +class _LazyDescr(object): + def __init__(self, name): + self.name = name + + def __get__(self, obj, tp): + result = self._resolve() + setattr(obj, self.name, result) # Invokes __set__. + try: + # This is a bit ugly, but it avoids running this again by + # removing this descriptor. + delattr(obj.__class__, self.name) + except AttributeError: + pass + return result + + +class MovedModule(_LazyDescr): + def __init__(self, name, old, new=None): + super(MovedModule, self).__init__(name) + if PY3: + if new is None: + new = name + self.mod = new + else: + self.mod = old + + def _resolve(self): + return _import_module(self.mod) + + def __getattr__(self, attr): + _module = self._resolve() + value = getattr(_module, attr) + setattr(self, attr, value) + return value + + +class _LazyModule(types.ModuleType): + def __init__(self, name): + super(_LazyModule, self).__init__(name) + self.__doc__ = self.__class__.__doc__ + + def __dir__(self): + attrs = ["__doc__", "__name__"] + attrs += [attr.name for attr in self._moved_attributes] + return attrs + + # Subclasses should override this + _moved_attributes = [] + + +class MovedAttribute(_LazyDescr): + def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): + super(MovedAttribute, self).__init__(name) + if PY3: + if new_mod is None: + new_mod = name + self.mod = new_mod + if new_attr is None: + if old_attr is None: + new_attr = name + else: + new_attr = old_attr + self.attr = new_attr + else: + self.mod = old_mod + if old_attr is None: + old_attr = name + self.attr = old_attr + + def _resolve(self): + module = _import_module(self.mod) + return getattr(module, self.attr) + + +class _SixMetaPathImporter(object): + + """ + A meta path importer to import six.moves and its submodules. + + This class implements a PEP302 finder and loader. It should be compatible + with Python 2.5 and all existing versions of Python3 + """ + + def __init__(self, six_module_name): + self.name = six_module_name + self.known_modules = {} + + def _add_module(self, mod, *fullnames): + for fullname in fullnames: + self.known_modules[self.name + "." + fullname] = mod + + def _get_module(self, fullname): + return self.known_modules[self.name + "." + fullname] + + def find_module(self, fullname, path=None): + if fullname in self.known_modules: + return self + return None + + def find_spec(self, fullname, path, target=None): + if fullname in self.known_modules: + return spec_from_loader(fullname, self) + return None + + def __get_module(self, fullname): + try: + return self.known_modules[fullname] + except KeyError: + raise ImportError("This loader does not know module " + fullname) + + def load_module(self, fullname): + try: + # in case of a reload + return sys.modules[fullname] + except KeyError: + pass + mod = self.__get_module(fullname) + if isinstance(mod, MovedModule): + mod = mod._resolve() + else: + mod.__loader__ = self + sys.modules[fullname] = mod + return mod + + def is_package(self, fullname): + """ + Return true, if the named module is a package. + + We need this method to get correct spec objects with + Python 3.4 (see PEP451) + """ + return hasattr(self.__get_module(fullname), "__path__") + + def get_code(self, fullname): + """Return None + + Required, if is_package is implemented""" + self.__get_module(fullname) # eventually raises ImportError + return None + + get_source = get_code # same as get_code + + def create_module(self, spec): + return self.load_module(spec.name) + + def exec_module(self, module): + pass + + +_importer = _SixMetaPathImporter(__name__) + + +class _MovedItems(_LazyModule): + + """Lazy loading of moved objects""" + + __path__ = [] # mark as package + + +_moved_attributes = [ + MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), + MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), + MovedAttribute( + "filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse" + ), + MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), + MovedAttribute("intern", "__builtin__", "sys"), + MovedAttribute("map", "itertools", "builtins", "imap", "map"), + MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), + MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), + MovedAttribute("getoutput", "commands", "subprocess"), + MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute( + "reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload" + ), + MovedAttribute("reduce", "__builtin__", "functools"), + MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), + MovedAttribute("StringIO", "StringIO", "io"), + MovedAttribute("UserDict", "UserDict", "collections"), + MovedAttribute("UserList", "UserList", "collections"), + MovedAttribute("UserString", "UserString", "collections"), + MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), + MovedAttribute( + "zip_longest", "itertools", "itertools", "izip_longest", "zip_longest" + ), + MovedModule("builtins", "__builtin__"), + MovedModule("configparser", "ConfigParser"), + MovedModule( + "collections_abc", + "collections", + "collections.abc" if sys.version_info >= (3, 3) else "collections", + ), + MovedModule("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"), + MovedModule( + "_dummy_thread", + "dummy_thread", + "_dummy_thread" if sys.version_info < (3, 9) else "_thread", + ), + MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), + MovedModule("http_cookies", "Cookie", "http.cookies"), + MovedModule("html_entities", "htmlentitydefs", "html.entities"), + MovedModule("html_parser", "HTMLParser", "html.parser"), + MovedModule("http_client", "httplib", "http.client"), + MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), + MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"), + MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), + MovedModule( + "email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart" + ), + MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), + MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), + MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), + MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), + MovedModule("cPickle", "cPickle", "pickle"), + MovedModule("queue", "Queue"), + MovedModule("reprlib", "repr"), + MovedModule("socketserver", "SocketServer"), + MovedModule("_thread", "thread", "_thread"), + MovedModule("tkinter", "Tkinter"), + MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), + MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), + MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), + MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), + MovedModule("tkinter_tix", "Tix", "tkinter.tix"), + MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), + MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), + MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), + MovedModule("tkinter_colorchooser", "tkColorChooser", "tkinter.colorchooser"), + MovedModule("tkinter_commondialog", "tkCommonDialog", "tkinter.commondialog"), + MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), + MovedModule("tkinter_font", "tkFont", "tkinter.font"), + MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), + MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"), + MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), + MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), + MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), + MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), + MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), + MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), +] +# Add windows specific modules. +if sys.platform == "win32": + _moved_attributes += [ + MovedModule("winreg", "_winreg"), + ] + +for attr in _moved_attributes: + setattr(_MovedItems, attr.name, attr) + if isinstance(attr, MovedModule): + _importer._add_module(attr, "moves." + attr.name) +del attr + +_MovedItems._moved_attributes = _moved_attributes + +moves = _MovedItems(__name__ + ".moves") +_importer._add_module(moves, "moves") + + +class Module_six_moves_urllib_parse(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_parse""" + + +_urllib_parse_moved_attributes = [ + MovedAttribute("ParseResult", "urlparse", "urllib.parse"), + MovedAttribute("SplitResult", "urlparse", "urllib.parse"), + MovedAttribute("parse_qs", "urlparse", "urllib.parse"), + MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), + MovedAttribute("urldefrag", "urlparse", "urllib.parse"), + MovedAttribute("urljoin", "urlparse", "urllib.parse"), + MovedAttribute("urlparse", "urlparse", "urllib.parse"), + MovedAttribute("urlsplit", "urlparse", "urllib.parse"), + MovedAttribute("urlunparse", "urlparse", "urllib.parse"), + MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), + MovedAttribute("quote", "urllib", "urllib.parse"), + MovedAttribute("quote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote", "urllib", "urllib.parse"), + MovedAttribute("unquote_plus", "urllib", "urllib.parse"), + MovedAttribute( + "unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes" + ), + MovedAttribute("urlencode", "urllib", "urllib.parse"), + MovedAttribute("splitquery", "urllib", "urllib.parse"), + MovedAttribute("splittag", "urllib", "urllib.parse"), + MovedAttribute("splituser", "urllib", "urllib.parse"), + MovedAttribute("splitvalue", "urllib", "urllib.parse"), + MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), + MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), + MovedAttribute("uses_params", "urlparse", "urllib.parse"), + MovedAttribute("uses_query", "urlparse", "urllib.parse"), + MovedAttribute("uses_relative", "urlparse", "urllib.parse"), +] +for attr in _urllib_parse_moved_attributes: + setattr(Module_six_moves_urllib_parse, attr.name, attr) +del attr + +Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes + +_importer._add_module( + Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), + "moves.urllib_parse", + "moves.urllib.parse", +) + + +class Module_six_moves_urllib_error(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_error""" + + +_urllib_error_moved_attributes = [ + MovedAttribute("URLError", "urllib2", "urllib.error"), + MovedAttribute("HTTPError", "urllib2", "urllib.error"), + MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), +] +for attr in _urllib_error_moved_attributes: + setattr(Module_six_moves_urllib_error, attr.name, attr) +del attr + +Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes + +_importer._add_module( + Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), + "moves.urllib_error", + "moves.urllib.error", +) + + +class Module_six_moves_urllib_request(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_request""" + + +_urllib_request_moved_attributes = [ + MovedAttribute("urlopen", "urllib2", "urllib.request"), + MovedAttribute("install_opener", "urllib2", "urllib.request"), + MovedAttribute("build_opener", "urllib2", "urllib.request"), + MovedAttribute("pathname2url", "urllib", "urllib.request"), + MovedAttribute("url2pathname", "urllib", "urllib.request"), + MovedAttribute("getproxies", "urllib", "urllib.request"), + MovedAttribute("Request", "urllib2", "urllib.request"), + MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), + MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), + MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), + MovedAttribute("BaseHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), + MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), + MovedAttribute("FileHandler", "urllib2", "urllib.request"), + MovedAttribute("FTPHandler", "urllib2", "urllib.request"), + MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), + MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), + MovedAttribute("urlretrieve", "urllib", "urllib.request"), + MovedAttribute("urlcleanup", "urllib", "urllib.request"), + MovedAttribute("URLopener", "urllib", "urllib.request"), + MovedAttribute("FancyURLopener", "urllib", "urllib.request"), + MovedAttribute("proxy_bypass", "urllib", "urllib.request"), + MovedAttribute("parse_http_list", "urllib2", "urllib.request"), + MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"), +] +for attr in _urllib_request_moved_attributes: + setattr(Module_six_moves_urllib_request, attr.name, attr) +del attr + +Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes + +_importer._add_module( + Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), + "moves.urllib_request", + "moves.urllib.request", +) + + +class Module_six_moves_urllib_response(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_response""" + + +_urllib_response_moved_attributes = [ + MovedAttribute("addbase", "urllib", "urllib.response"), + MovedAttribute("addclosehook", "urllib", "urllib.response"), + MovedAttribute("addinfo", "urllib", "urllib.response"), + MovedAttribute("addinfourl", "urllib", "urllib.response"), +] +for attr in _urllib_response_moved_attributes: + setattr(Module_six_moves_urllib_response, attr.name, attr) +del attr + +Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes + +_importer._add_module( + Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), + "moves.urllib_response", + "moves.urllib.response", +) + + +class Module_six_moves_urllib_robotparser(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_robotparser""" + + +_urllib_robotparser_moved_attributes = [ + MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), +] +for attr in _urllib_robotparser_moved_attributes: + setattr(Module_six_moves_urllib_robotparser, attr.name, attr) +del attr + +Module_six_moves_urllib_robotparser._moved_attributes = ( + _urllib_robotparser_moved_attributes +) + +_importer._add_module( + Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), + "moves.urllib_robotparser", + "moves.urllib.robotparser", +) + + +class Module_six_moves_urllib(types.ModuleType): + + """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" + + __path__ = [] # mark as package + parse = _importer._get_module("moves.urllib_parse") + error = _importer._get_module("moves.urllib_error") + request = _importer._get_module("moves.urllib_request") + response = _importer._get_module("moves.urllib_response") + robotparser = _importer._get_module("moves.urllib_robotparser") + + def __dir__(self): + return ["parse", "error", "request", "response", "robotparser"] + + +_importer._add_module( + Module_six_moves_urllib(__name__ + ".moves.urllib"), "moves.urllib" +) + + +def add_move(move): + """Add an item to six.moves.""" + setattr(_MovedItems, move.name, move) + + +def remove_move(name): + """Remove item from six.moves.""" + try: + delattr(_MovedItems, name) + except AttributeError: + try: + del moves.__dict__[name] + except KeyError: + raise AttributeError("no such move, %r" % (name,)) + + +if PY3: + _meth_func = "__func__" + _meth_self = "__self__" + + _func_closure = "__closure__" + _func_code = "__code__" + _func_defaults = "__defaults__" + _func_globals = "__globals__" +else: + _meth_func = "im_func" + _meth_self = "im_self" + + _func_closure = "func_closure" + _func_code = "func_code" + _func_defaults = "func_defaults" + _func_globals = "func_globals" + + +try: + advance_iterator = next +except NameError: + + def advance_iterator(it): + return it.next() + + +next = advance_iterator + + +try: + callable = callable +except NameError: + + def callable(obj): + return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) + + +if PY3: + + def get_unbound_function(unbound): + return unbound + + create_bound_method = types.MethodType + + def create_unbound_method(func, cls): + return func + + Iterator = object +else: + + def get_unbound_function(unbound): + return unbound.im_func + + def create_bound_method(func, obj): + return types.MethodType(func, obj, obj.__class__) + + def create_unbound_method(func, cls): + return types.MethodType(func, None, cls) + + class Iterator(object): + def next(self): + return type(self).__next__(self) + + callable = callable +_add_doc( + get_unbound_function, """Get the function out of a possibly unbound function""" +) + + +get_method_function = operator.attrgetter(_meth_func) +get_method_self = operator.attrgetter(_meth_self) +get_function_closure = operator.attrgetter(_func_closure) +get_function_code = operator.attrgetter(_func_code) +get_function_defaults = operator.attrgetter(_func_defaults) +get_function_globals = operator.attrgetter(_func_globals) + + +if PY3: + + def iterkeys(d, **kw): + return iter(d.keys(**kw)) + + def itervalues(d, **kw): + return iter(d.values(**kw)) + + def iteritems(d, **kw): + return iter(d.items(**kw)) + + def iterlists(d, **kw): + return iter(d.lists(**kw)) + + viewkeys = operator.methodcaller("keys") + + viewvalues = operator.methodcaller("values") + + viewitems = operator.methodcaller("items") +else: + + def iterkeys(d, **kw): + return d.iterkeys(**kw) + + def itervalues(d, **kw): + return d.itervalues(**kw) + + def iteritems(d, **kw): + return d.iteritems(**kw) + + def iterlists(d, **kw): + return d.iterlists(**kw) + + viewkeys = operator.methodcaller("viewkeys") + + viewvalues = operator.methodcaller("viewvalues") + + viewitems = operator.methodcaller("viewitems") + +_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") +_add_doc(itervalues, "Return an iterator over the values of a dictionary.") +_add_doc(iteritems, "Return an iterator over the (key, value) pairs of a dictionary.") +_add_doc( + iterlists, "Return an iterator over the (key, [values]) pairs of a dictionary." +) + + +if PY3: + + def b(s): + return s.encode("latin-1") + + def u(s): + return s + + unichr = chr + import struct + + int2byte = struct.Struct(">B").pack + del struct + byte2int = operator.itemgetter(0) + indexbytes = operator.getitem + iterbytes = iter + import io + + StringIO = io.StringIO + BytesIO = io.BytesIO + del io + _assertCountEqual = "assertCountEqual" + if sys.version_info[1] <= 1: + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + _assertNotRegex = "assertNotRegexpMatches" + else: + _assertRaisesRegex = "assertRaisesRegex" + _assertRegex = "assertRegex" + _assertNotRegex = "assertNotRegex" +else: + + def b(s): + return s + + # Workaround for standalone backslash + + def u(s): + return unicode(s.replace(r"\\", r"\\\\"), "unicode_escape") + + unichr = unichr + int2byte = chr + + def byte2int(bs): + return ord(bs[0]) + + def indexbytes(buf, i): + return ord(buf[i]) + + iterbytes = functools.partial(itertools.imap, ord) + import StringIO + + StringIO = BytesIO = StringIO.StringIO + _assertCountEqual = "assertItemsEqual" + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + _assertNotRegex = "assertNotRegexpMatches" +_add_doc(b, """Byte literal""") +_add_doc(u, """Text literal""") + + +def assertCountEqual(self, *args, **kwargs): + return getattr(self, _assertCountEqual)(*args, **kwargs) + + +def assertRaisesRegex(self, *args, **kwargs): + return getattr(self, _assertRaisesRegex)(*args, **kwargs) + + +def assertRegex(self, *args, **kwargs): + return getattr(self, _assertRegex)(*args, **kwargs) + + +def assertNotRegex(self, *args, **kwargs): + return getattr(self, _assertNotRegex)(*args, **kwargs) + + +if PY3: + exec_ = getattr(moves.builtins, "exec") + + def reraise(tp, value, tb=None): + try: + if value is None: + value = tp() + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + finally: + value = None + tb = None + + +else: + + def exec_(_code_, _globs_=None, _locs_=None): + """Execute code in a namespace.""" + if _globs_ is None: + frame = sys._getframe(1) + _globs_ = frame.f_globals + if _locs_ is None: + _locs_ = frame.f_locals + del frame + elif _locs_ is None: + _locs_ = _globs_ + exec ("""exec _code_ in _globs_, _locs_""") + + exec_( + """def reraise(tp, value, tb=None): + try: + raise tp, value, tb + finally: + tb = None +""" + ) + + +if sys.version_info[:2] > (3,): + exec_( + """def raise_from(value, from_value): + try: + raise value from from_value + finally: + value = None +""" + ) +else: + + def raise_from(value, from_value): + raise value + + +print_ = getattr(moves.builtins, "print", None) +if print_ is None: + + def print_(*args, **kwargs): + """The new-style print function for Python 2.4 and 2.5.""" + fp = kwargs.pop("file", sys.stdout) + if fp is None: + return + + def write(data): + if not isinstance(data, basestring): + data = str(data) + # If the file has an encoding, encode unicode with it. + if ( + isinstance(fp, file) + and isinstance(data, unicode) + and fp.encoding is not None + ): + errors = getattr(fp, "errors", None) + if errors is None: + errors = "strict" + data = data.encode(fp.encoding, errors) + fp.write(data) + + want_unicode = False + sep = kwargs.pop("sep", None) + if sep is not None: + if isinstance(sep, unicode): + want_unicode = True + elif not isinstance(sep, str): + raise TypeError("sep must be None or a string") + end = kwargs.pop("end", None) + if end is not None: + if isinstance(end, unicode): + want_unicode = True + elif not isinstance(end, str): + raise TypeError("end must be None or a string") + if kwargs: + raise TypeError("invalid keyword arguments to print()") + if not want_unicode: + for arg in args: + if isinstance(arg, unicode): + want_unicode = True + break + if want_unicode: + newline = unicode("\n") + space = unicode(" ") + else: + newline = "\n" + space = " " + if sep is None: + sep = space + if end is None: + end = newline + for i, arg in enumerate(args): + if i: + write(sep) + write(arg) + write(end) + + +if sys.version_info[:2] < (3, 3): + _print = print_ + + def print_(*args, **kwargs): + fp = kwargs.get("file", sys.stdout) + flush = kwargs.pop("flush", False) + _print(*args, **kwargs) + if flush and fp is not None: + fp.flush() + + +_add_doc(reraise, """Reraise an exception.""") + +if sys.version_info[0:2] < (3, 4): + # This does exactly the same what the :func:`py3:functools.update_wrapper` + # function does on Python versions after 3.2. It sets the ``__wrapped__`` + # attribute on ``wrapper`` object and it doesn't raise an error if any of + # the attributes mentioned in ``assigned`` and ``updated`` are missing on + # ``wrapped`` object. + def _update_wrapper( + wrapper, + wrapped, + assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES, + ): + for attr in assigned: + try: + value = getattr(wrapped, attr) + except AttributeError: + continue + else: + setattr(wrapper, attr, value) + for attr in updated: + getattr(wrapper, attr).update(getattr(wrapped, attr, {})) + wrapper.__wrapped__ = wrapped + return wrapper + + _update_wrapper.__doc__ = functools.update_wrapper.__doc__ + + def wraps( + wrapped, + assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES, + ): + return functools.partial( + _update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated + ) + + wraps.__doc__ = functools.wraps.__doc__ + +else: + wraps = functools.wraps + + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(type): + def __new__(cls, name, this_bases, d): + if sys.version_info[:2] >= (3, 7): + # This version introduced PEP 560 that requires a bit + # of extra care (we mimic what is done by __build_class__). + resolved_bases = types.resolve_bases(bases) + if resolved_bases is not bases: + d["__orig_bases__"] = bases + else: + resolved_bases = bases + return meta(name, resolved_bases, d) + + @classmethod + def __prepare__(cls, name, this_bases): + return meta.__prepare__(name, bases) + + return type.__new__(metaclass, "temporary_class", (), {}) + + +def add_metaclass(metaclass): + """Class decorator for creating a class with a metaclass.""" + + def wrapper(cls): + orig_vars = cls.__dict__.copy() + slots = orig_vars.get("__slots__") + if slots is not None: + if isinstance(slots, str): + slots = [slots] + for slots_var in slots: + orig_vars.pop(slots_var) + orig_vars.pop("__dict__", None) + orig_vars.pop("__weakref__", None) + if hasattr(cls, "__qualname__"): + orig_vars["__qualname__"] = cls.__qualname__ + return metaclass(cls.__name__, cls.__bases__, orig_vars) + + return wrapper + + +def ensure_binary(s, encoding="utf-8", errors="strict"): + """Coerce **s** to six.binary_type. + + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + + For Python 3: + - `str` -> encoded to `bytes` + - `bytes` -> `bytes` + """ + if isinstance(s, binary_type): + return s + if isinstance(s, text_type): + return s.encode(encoding, errors) + raise TypeError("not expecting type '%s'" % type(s)) + + +def ensure_str(s, encoding="utf-8", errors="strict"): + """Coerce *s* to `str`. + + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + # Optimization: Fast return for the common case. + if type(s) is str: + return s + if PY2 and isinstance(s, text_type): + return s.encode(encoding, errors) + elif PY3 and isinstance(s, binary_type): + return s.decode(encoding, errors) + elif not isinstance(s, (text_type, binary_type)): + raise TypeError("not expecting type '%s'" % type(s)) + return s + + +def ensure_text(s, encoding="utf-8", errors="strict"): + """Coerce *s* to six.text_type. + + For Python 2: + - `unicode` -> `unicode` + - `str` -> `unicode` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + if isinstance(s, binary_type): + return s.decode(encoding, errors) + elif isinstance(s, text_type): + return s + else: + raise TypeError("not expecting type '%s'" % type(s)) + + +def python_2_unicode_compatible(klass): + """ + A class decorator that defines __unicode__ and __str__ methods under Python 2. + Under Python 3 it does nothing. + + To support Python 2 and 3 with a single code base, define a __str__ method + returning text and apply this decorator to the class. + """ + if PY2: + if "__str__" not in klass.__dict__: + raise ValueError( + "@python_2_unicode_compatible cannot be applied " + "to %s because it doesn't define __str__()." % klass.__name__ + ) + klass.__unicode__ = klass.__str__ + klass.__str__ = lambda self: self.__unicode__().encode("utf-8") + return klass + + +# Complete the moves implementation. +# This code is at the end of this module to speed up module loading. +# Turn this module into a package. +__path__ = [] # required for PEP 302 and PEP 451 +__package__ = __name__ # see PEP 366 @ReservedAssignment +if globals().get("__spec__") is not None: + __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable +# Remove other six meta path importers, since they cause problems. This can +# happen if six is removed from sys.modules and then reloaded. (Setuptools does +# this for some reason.) +if sys.meta_path: + for i, importer in enumerate(sys.meta_path): + # Here's some real nastiness: Another "instance" of the six module might + # be floating around. Therefore, we can't use isinstance() to check for + # the six meta path importer, since the other six instance will have + # inserted an importer with different class. + if ( + type(importer).__name__ == "_SixMetaPathImporter" + and importer.name == __name__ + ): + del sys.meta_path[i] + break + del i, importer +# Finally, add the importer to the meta path import hook. +sys.meta_path.append(_importer) diff --git a/openpype/vendor/python/python_2/urllib3/poolmanager.py b/openpype/vendor/python/python_2/urllib3/poolmanager.py new file mode 100644 index 0000000000..ca4ec34118 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/poolmanager.py @@ -0,0 +1,537 @@ +from __future__ import absolute_import + +import collections +import functools +import logging + +from ._collections import RecentlyUsedContainer +from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, port_by_scheme +from .exceptions import ( + LocationValueError, + MaxRetryError, + ProxySchemeUnknown, + ProxySchemeUnsupported, + URLSchemeUnknown, +) +from .packages import six +from .packages.six.moves.urllib.parse import urljoin +from .request import RequestMethods +from .util.proxy import connection_requires_http_tunnel +from .util.retry import Retry +from .util.url import parse_url + +__all__ = ["PoolManager", "ProxyManager", "proxy_from_url"] + + +log = logging.getLogger(__name__) + +SSL_KEYWORDS = ( + "key_file", + "cert_file", + "cert_reqs", + "ca_certs", + "ssl_version", + "ca_cert_dir", + "ssl_context", + "key_password", + "server_hostname", +) + +# All known keyword arguments that could be provided to the pool manager, its +# pools, or the underlying connections. This is used to construct a pool key. +_key_fields = ( + "key_scheme", # str + "key_host", # str + "key_port", # int + "key_timeout", # int or float or Timeout + "key_retries", # int or Retry + "key_strict", # bool + "key_block", # bool + "key_source_address", # str + "key_key_file", # str + "key_key_password", # str + "key_cert_file", # str + "key_cert_reqs", # str + "key_ca_certs", # str + "key_ssl_version", # str + "key_ca_cert_dir", # str + "key_ssl_context", # instance of ssl.SSLContext or urllib3.util.ssl_.SSLContext + "key_maxsize", # int + "key_headers", # dict + "key__proxy", # parsed proxy url + "key__proxy_headers", # dict + "key__proxy_config", # class + "key_socket_options", # list of (level (int), optname (int), value (int or str)) tuples + "key__socks_options", # dict + "key_assert_hostname", # bool or string + "key_assert_fingerprint", # str + "key_server_hostname", # str +) + +#: The namedtuple class used to construct keys for the connection pool. +#: All custom key schemes should include the fields in this key at a minimum. +PoolKey = collections.namedtuple("PoolKey", _key_fields) + +_proxy_config_fields = ("ssl_context", "use_forwarding_for_https") +ProxyConfig = collections.namedtuple("ProxyConfig", _proxy_config_fields) + + +def _default_key_normalizer(key_class, request_context): + """ + Create a pool key out of a request context dictionary. + + According to RFC 3986, both the scheme and host are case-insensitive. + Therefore, this function normalizes both before constructing the pool + key for an HTTPS request. If you wish to change this behaviour, provide + alternate callables to ``key_fn_by_scheme``. + + :param key_class: + The class to use when constructing the key. This should be a namedtuple + with the ``scheme`` and ``host`` keys at a minimum. + :type key_class: namedtuple + :param request_context: + A dictionary-like object that contain the context for a request. + :type request_context: dict + + :return: A namedtuple that can be used as a connection pool key. + :rtype: PoolKey + """ + # Since we mutate the dictionary, make a copy first + context = request_context.copy() + context["scheme"] = context["scheme"].lower() + context["host"] = context["host"].lower() + + # These are both dictionaries and need to be transformed into frozensets + for key in ("headers", "_proxy_headers", "_socks_options"): + if key in context and context[key] is not None: + context[key] = frozenset(context[key].items()) + + # The socket_options key may be a list and needs to be transformed into a + # tuple. + socket_opts = context.get("socket_options") + if socket_opts is not None: + context["socket_options"] = tuple(socket_opts) + + # Map the kwargs to the names in the namedtuple - this is necessary since + # namedtuples can't have fields starting with '_'. + for key in list(context.keys()): + context["key_" + key] = context.pop(key) + + # Default to ``None`` for keys missing from the context + for field in key_class._fields: + if field not in context: + context[field] = None + + return key_class(**context) + + +#: A dictionary that maps a scheme to a callable that creates a pool key. +#: This can be used to alter the way pool keys are constructed, if desired. +#: Each PoolManager makes a copy of this dictionary so they can be configured +#: globally here, or individually on the instance. +key_fn_by_scheme = { + "http": functools.partial(_default_key_normalizer, PoolKey), + "https": functools.partial(_default_key_normalizer, PoolKey), +} + +pool_classes_by_scheme = {"http": HTTPConnectionPool, "https": HTTPSConnectionPool} + + +class PoolManager(RequestMethods): + """ + Allows for arbitrary requests while transparently keeping track of + necessary connection pools for you. + + :param num_pools: + Number of connection pools to cache before discarding the least + recently used pool. + + :param headers: + Headers to include with all requests, unless other headers are given + explicitly. + + :param \\**connection_pool_kw: + Additional parameters are used to create fresh + :class:`urllib3.connectionpool.ConnectionPool` instances. + + Example:: + + >>> manager = PoolManager(num_pools=2) + >>> r = manager.request('GET', 'http://google.com/') + >>> r = manager.request('GET', 'http://google.com/mail') + >>> r = manager.request('GET', 'http://yahoo.com/') + >>> len(manager.pools) + 2 + + """ + + proxy = None + proxy_config = None + + def __init__(self, num_pools=10, headers=None, **connection_pool_kw): + RequestMethods.__init__(self, headers) + self.connection_pool_kw = connection_pool_kw + self.pools = RecentlyUsedContainer(num_pools, dispose_func=lambda p: p.close()) + + # Locally set the pool classes and keys so other PoolManagers can + # override them. + self.pool_classes_by_scheme = pool_classes_by_scheme + self.key_fn_by_scheme = key_fn_by_scheme.copy() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.clear() + # Return False to re-raise any potential exceptions + return False + + def _new_pool(self, scheme, host, port, request_context=None): + """ + Create a new :class:`urllib3.connectionpool.ConnectionPool` based on host, port, scheme, and + any additional pool keyword arguments. + + If ``request_context`` is provided, it is provided as keyword arguments + to the pool class used. This method is used to actually create the + connection pools handed out by :meth:`connection_from_url` and + companion methods. It is intended to be overridden for customization. + """ + pool_cls = self.pool_classes_by_scheme[scheme] + if request_context is None: + request_context = self.connection_pool_kw.copy() + + # Although the context has everything necessary to create the pool, + # this function has historically only used the scheme, host, and port + # in the positional args. When an API change is acceptable these can + # be removed. + for key in ("scheme", "host", "port"): + request_context.pop(key, None) + + if scheme == "http": + for kw in SSL_KEYWORDS: + request_context.pop(kw, None) + + return pool_cls(host, port, **request_context) + + 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", pool_kwargs=None): + """ + Get a :class:`urllib3.connectionpool.ConnectionPool` based on the host, port, and scheme. + + If ``port`` isn't given, it will be derived from the ``scheme`` using + ``urllib3.connectionpool.port_by_scheme``. If ``pool_kwargs`` is + provided, it is merged with the instance's ``connection_pool_kw`` + variable and used to create the new connection pool, if one is + needed. + """ + + if not host: + raise LocationValueError("No host specified.") + + request_context = self._merge_pool_kwargs(pool_kwargs) + request_context["scheme"] = scheme or "http" + if not port: + port = port_by_scheme.get(request_context["scheme"].lower(), 80) + request_context["port"] = port + request_context["host"] = host + + return self.connection_from_context(request_context) + + def connection_from_context(self, request_context): + """ + Get a :class:`urllib3.connectionpool.ConnectionPool` based on the request context. + + ``request_context`` must at least contain the ``scheme`` key and its + value must be a key in ``key_fn_by_scheme`` instance variable. + """ + scheme = request_context["scheme"].lower() + pool_key_constructor = self.key_fn_by_scheme.get(scheme) + if not pool_key_constructor: + raise URLSchemeUnknown(scheme) + pool_key = pool_key_constructor(request_context) + + return self.connection_from_pool_key(pool_key, request_context=request_context) + + def connection_from_pool_key(self, pool_key, request_context=None): + """ + Get a :class:`urllib3.connectionpool.ConnectionPool` based on the provided pool key. + + ``pool_key`` should be a namedtuple that only contains immutable + objects. At a minimum it must have the ``scheme``, ``host``, and + ``port`` fields. + """ + with self.pools.lock: + # If the scheme, host, or port doesn't match existing open + # connections, open a new ConnectionPool. + pool = self.pools.get(pool_key) + if pool: + return pool + + # Make a fresh ConnectionPool of the desired type + scheme = request_context["scheme"] + host = request_context["host"] + port = request_context["port"] + pool = self._new_pool(scheme, host, port, request_context=request_context) + self.pools[pool_key] = pool + + return pool + + def connection_from_url(self, url, pool_kwargs=None): + """ + Similar to :func:`urllib3.connectionpool.connection_from_url`. + + If ``pool_kwargs`` is not provided and a new pool needs to be + constructed, ``self.connection_pool_kw`` is used to initialize + the :class:`urllib3.connectionpool.ConnectionPool`. If ``pool_kwargs`` + is provided, it is used instead. Note that if a new pool does not + need to be created for the request, the provided ``pool_kwargs`` are + not used. + """ + u = parse_url(url) + return self.connection_from_host( + u.host, port=u.port, scheme=u.scheme, pool_kwargs=pool_kwargs + ) + + def _merge_pool_kwargs(self, override): + """ + Merge a dictionary of override values for self.connection_pool_kw. + + This does not modify self.connection_pool_kw and returns a new dict. + Any keys in the override dictionary with a value of ``None`` are + removed from the merged dictionary. + """ + base_pool_kwargs = self.connection_pool_kw.copy() + if override: + for key, value in override.items(): + if value is None: + try: + del base_pool_kwargs[key] + except KeyError: + pass + else: + base_pool_kwargs[key] = value + return base_pool_kwargs + + def _proxy_requires_url_absolute_form(self, parsed_url): + """ + Indicates if the proxy requires the complete destination URL in the + request. Normally this is only needed when not using an HTTP CONNECT + tunnel. + """ + if self.proxy is None: + return False + + return not connection_requires_http_tunnel( + self.proxy, self.proxy_config, parsed_url.scheme + ) + + def _validate_proxy_scheme_url_selection(self, url_scheme): + """ + Validates that were not attempting to do TLS in TLS connections on + Python2 or with unsupported SSL implementations. + """ + if self.proxy is None or url_scheme != "https": + return + + if self.proxy.scheme != "https": + return + + if six.PY2 and not self.proxy_config.use_forwarding_for_https: + raise ProxySchemeUnsupported( + "Contacting HTTPS destinations through HTTPS proxies " + "'via CONNECT tunnels' is not supported in Python 2" + ) + + def urlopen(self, method, url, redirect=True, **kw): + """ + Same as :meth:`urllib3.HTTPConnectionPool.urlopen` + with custom cross-host redirect logic and only sends the request-uri + portion of the ``url``. + + The given ``url`` parameter must be absolute, such that an appropriate + :class:`urllib3.connectionpool.ConnectionPool` can be chosen for it. + """ + u = parse_url(url) + self._validate_proxy_scheme_url_selection(u.scheme) + + conn = self.connection_from_host(u.host, port=u.port, scheme=u.scheme) + + kw["assert_same_host"] = False + kw["redirect"] = False + + if "headers" not in kw: + kw["headers"] = self.headers.copy() + + if self._proxy_requires_url_absolute_form(u): + response = conn.urlopen(method, url, **kw) + else: + response = conn.urlopen(method, u.request_uri, **kw) + + redirect_location = redirect and response.get_redirect_location() + if not redirect_location: + return response + + # Support relative URLs for redirecting. + redirect_location = urljoin(url, redirect_location) + + # RFC 7231, Section 6.4.4 + if response.status == 303: + method = "GET" + + retries = kw.get("retries") + if not isinstance(retries, Retry): + retries = Retry.from_int(retries, redirect=redirect) + + # Strip headers marked as unsafe to forward to the redirected location. + # Check remove_headers_on_redirect to avoid a potential network call within + # conn.is_same_host() which may use socket.gethostbyname() in the future. + if retries.remove_headers_on_redirect and not conn.is_same_host( + redirect_location + ): + headers = list(six.iterkeys(kw["headers"])) + for header in headers: + if header.lower() in retries.remove_headers_on_redirect: + kw["headers"].pop(header, None) + + try: + retries = retries.increment(method, url, response=response, _pool=conn) + except MaxRetryError: + if retries.raise_on_redirect: + response.drain_conn() + raise + return response + + kw["retries"] = retries + kw["redirect"] = redirect + + log.info("Redirecting %s -> %s", url, redirect_location) + + response.drain_conn() + return self.urlopen(method, redirect_location, **kw) + + +class ProxyManager(PoolManager): + """ + Behaves just like :class:`PoolManager`, but sends all requests through + the defined proxy, using the CONNECT method for HTTPS URLs. + + :param proxy_url: + The URL of the proxy to be used. + + :param proxy_headers: + A dictionary containing headers that will be sent to the proxy. In case + of HTTP they are being sent with each request, while in the + HTTPS/CONNECT case they are sent only once. Could be used for proxy + authentication. + + :param proxy_ssl_context: + The proxy SSL context is used to establish the TLS connection to the + proxy when using HTTPS proxies. + + :param use_forwarding_for_https: + (Defaults to False) If set to True will forward requests to the HTTPS + proxy to be made on behalf of the client instead of creating a TLS + tunnel via the CONNECT method. **Enabling this flag means that request + and response headers and content will be visible from the HTTPS proxy** + whereas tunneling keeps request and response headers and content + private. IP address, target hostname, SNI, and port are always visible + to an HTTPS proxy even when this flag is disabled. + + Example: + >>> proxy = urllib3.ProxyManager('http://localhost:3128/') + >>> r1 = proxy.request('GET', 'http://google.com/') + >>> r2 = proxy.request('GET', 'http://httpbin.org/') + >>> len(proxy.pools) + 1 + >>> r3 = proxy.request('GET', 'https://httpbin.org/') + >>> r4 = proxy.request('GET', 'https://twitter.com/') + >>> len(proxy.pools) + 3 + + """ + + def __init__( + self, + proxy_url, + num_pools=10, + headers=None, + proxy_headers=None, + proxy_ssl_context=None, + use_forwarding_for_https=False, + **connection_pool_kw + ): + + if isinstance(proxy_url, HTTPConnectionPool): + proxy_url = "%s://%s:%i" % ( + proxy_url.scheme, + proxy_url.host, + proxy_url.port, + ) + proxy = parse_url(proxy_url) + + if proxy.scheme not in ("http", "https"): + raise ProxySchemeUnknown(proxy.scheme) + + if not proxy.port: + port = port_by_scheme.get(proxy.scheme, 80) + proxy = proxy._replace(port=port) + + self.proxy = proxy + self.proxy_headers = proxy_headers or {} + self.proxy_ssl_context = proxy_ssl_context + self.proxy_config = ProxyConfig(proxy_ssl_context, use_forwarding_for_https) + + connection_pool_kw["_proxy"] = self.proxy + connection_pool_kw["_proxy_headers"] = self.proxy_headers + connection_pool_kw["_proxy_config"] = self.proxy_config + + super(ProxyManager, self).__init__(num_pools, headers, **connection_pool_kw) + + def connection_from_host(self, host, port=None, scheme="http", pool_kwargs=None): + if scheme == "https": + return super(ProxyManager, self).connection_from_host( + host, port, scheme, pool_kwargs=pool_kwargs + ) + + return super(ProxyManager, self).connection_from_host( + self.proxy.host, self.proxy.port, self.proxy.scheme, pool_kwargs=pool_kwargs + ) + + def _set_proxy_headers(self, url, headers=None): + """ + Sets headers needed by proxies: specifically, the Accept and Host + headers. Only sets headers not provided by the user. + """ + headers_ = {"Accept": "*/*"} + + netloc = parse_url(url).netloc + if netloc: + headers_["Host"] = netloc + + if headers: + headers_.update(headers) + return headers_ + + def urlopen(self, method, url, redirect=True, **kw): + "Same as HTTP(S)ConnectionPool.urlopen, ``url`` must be absolute." + u = parse_url(url) + if not connection_requires_http_tunnel(self.proxy, self.proxy_config, u.scheme): + # For connections using HTTP CONNECT, httplib sets the necessary + # headers on the CONNECT to the proxy. If we're not using CONNECT, + # we'll definitely need to set 'Host' at the very least. + headers = kw.get("headers", self.headers) + kw["headers"] = self._set_proxy_headers(url, headers) + + return super(ProxyManager, self).urlopen(method, url, redirect=redirect, **kw) + + +def proxy_from_url(url, **kw): + return ProxyManager(proxy_url=url, **kw) diff --git a/openpype/vendor/python/python_2/urllib3/request.py b/openpype/vendor/python/python_2/urllib3/request.py new file mode 100644 index 0000000000..398386a5b9 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/request.py @@ -0,0 +1,170 @@ +from __future__ import absolute_import + +from .filepost import encode_multipart_formdata +from .packages.six.moves.urllib.parse import urlencode + +__all__ = ["RequestMethods"] + + +class RequestMethods(object): + """ + Convenience mixin for classes who implement a :meth:`urlopen` method, such + as :class:`urllib3.HTTPConnectionPool` and + :class:`urllib3.PoolManager`. + + Provides behavior for making common types of HTTP request methods and + decides which type of request field encoding to use. + + Specifically, + + :meth:`.request_encode_url` is for sending requests whose fields are + encoded in the URL (such as GET, HEAD, DELETE). + + :meth:`.request_encode_body` is for sending requests whose fields are + encoded in the *body* of the request using multipart or www-form-urlencoded + (such as for POST, PUT, PATCH). + + :meth:`.request` is for making any kind of request, it will look up the + appropriate encoding format and use one of the above two methods to make + the request. + + Initializer parameters: + + :param headers: + Headers to include with all requests, unless other headers are given + explicitly. + """ + + _encode_url_methods = {"DELETE", "GET", "HEAD", "OPTIONS"} + + def __init__(self, headers=None): + self.headers = headers or {} + + def urlopen( + self, + method, + url, + body=None, + headers=None, + encode_multipart=True, + multipart_boundary=None, + **kw + ): # Abstract + raise NotImplementedError( + "Classes extending RequestMethods must implement " + "their own ``urlopen`` method." + ) + + def request(self, method, url, fields=None, headers=None, **urlopen_kw): + """ + Make a request using :meth:`urlopen` with the appropriate encoding of + ``fields`` based on the ``method`` used. + + This is a convenience method that requires the least amount of manual + effort. It can be used in most situations, while still having the + option to drop down to more specific methods when necessary, such as + :meth:`request_encode_url`, :meth:`request_encode_body`, + or even the lowest level :meth:`urlopen`. + """ + method = method.upper() + + urlopen_kw["request_url"] = url + + if method in self._encode_url_methods: + return self.request_encode_url( + method, url, fields=fields, headers=headers, **urlopen_kw + ) + else: + return self.request_encode_body( + method, url, fields=fields, headers=headers, **urlopen_kw + ) + + def request_encode_url(self, method, url, fields=None, headers=None, **urlopen_kw): + """ + Make a request using :meth:`urlopen` with the ``fields`` encoded in + the url. This is useful for request methods like GET, HEAD, DELETE, etc. + """ + if headers is None: + headers = self.headers + + extra_kw = {"headers": headers} + extra_kw.update(urlopen_kw) + + if fields: + url += "?" + urlencode(fields) + + return self.urlopen(method, url, **extra_kw) + + def request_encode_body( + self, + method, + url, + fields=None, + headers=None, + encode_multipart=True, + multipart_boundary=None, + **urlopen_kw + ): + """ + Make a request using :meth:`urlopen` with the ``fields`` encoded in + the body. This is useful for request methods like POST, PUT, PATCH, etc. + + When ``encode_multipart=True`` (default), then + :func:`urllib3.encode_multipart_formdata` is used to encode + the payload with the appropriate content type. Otherwise + :func:`urllib.parse.urlencode` is used with the + 'application/x-www-form-urlencoded' content type. + + Multipart encoding must be used when posting files, and it's reasonably + safe to use it in other times too. However, it may break request + signing, such as with OAuth. + + Supports an optional ``fields`` parameter of key/value strings AND + key/filetuple. A filetuple is a (filename, data, MIME type) tuple where + the MIME type is optional. For example:: + + fields = { + 'foo': 'bar', + 'fakefile': ('foofile.txt', 'contents of foofile'), + 'realfile': ('barfile.txt', open('realfile').read()), + 'typedfile': ('bazfile.bin', open('bazfile').read(), + 'image/jpeg'), + 'nonamefile': 'contents of nonamefile field', + } + + When uploading a file, providing a filename (the first parameter of the + tuple) is optional but recommended to best mimic behavior of browsers. + + Note that if ``headers`` are supplied, the 'Content-Type' header will + be overwritten because it depends on the dynamic random boundary string + which is used to compose the body of the request. The random boundary + string can be explicitly set with the ``multipart_boundary`` parameter. + """ + if headers is None: + headers = self.headers + + extra_kw = {"headers": {}} + + if fields: + if "body" in urlopen_kw: + raise TypeError( + "request got values for both 'fields' and 'body', can only specify one." + ) + + if encode_multipart: + body, content_type = encode_multipart_formdata( + fields, boundary=multipart_boundary + ) + else: + body, content_type = ( + urlencode(fields), + "application/x-www-form-urlencoded", + ) + + extra_kw["body"] = body + extra_kw["headers"] = {"Content-Type": content_type} + + extra_kw["headers"].update(headers) + extra_kw.update(urlopen_kw) + + return self.urlopen(method, url, **extra_kw) diff --git a/openpype/vendor/python/python_2/urllib3/response.py b/openpype/vendor/python/python_2/urllib3/response.py new file mode 100644 index 0000000000..fdb50ddb2f --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/response.py @@ -0,0 +1,824 @@ +from __future__ import absolute_import + +import io +import logging +import zlib +from contextlib import contextmanager +from socket import error as SocketError +from socket import timeout as SocketTimeout + +try: + try: + import brotlicffi as brotli + except ImportError: + import brotli +except ImportError: + brotli = None + +from ._collections import HTTPHeaderDict +from .connection import BaseSSLError, HTTPException +from .exceptions import ( + BodyNotHttplibCompatible, + DecodeError, + HTTPError, + IncompleteRead, + InvalidChunkLength, + InvalidHeader, + ProtocolError, + ReadTimeoutError, + ResponseNotChunked, + SSLError, +) +from .packages import six +from .util.response import is_fp_closed, is_response_to_head + +log = logging.getLogger(__name__) + + +class DeflateDecoder(object): + def __init__(self): + self._first_try = True + self._data = b"" + self._obj = zlib.decompressobj() + + def __getattr__(self, name): + return getattr(self._obj, name) + + def decompress(self, data): + if not data: + return data + + if not self._first_try: + return self._obj.decompress(data) + + self._data += data + try: + decompressed = self._obj.decompress(data) + if decompressed: + self._first_try = False + self._data = None + return decompressed + except zlib.error: + self._first_try = False + self._obj = zlib.decompressobj(-zlib.MAX_WBITS) + try: + return self.decompress(self._data) + finally: + self._data = None + + +class GzipDecoderState(object): + + FIRST_MEMBER = 0 + OTHER_MEMBERS = 1 + SWALLOW_DATA = 2 + + +class GzipDecoder(object): + def __init__(self): + self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) + self._state = GzipDecoderState.FIRST_MEMBER + + def __getattr__(self, name): + return getattr(self._obj, name) + + def decompress(self, data): + ret = bytearray() + if self._state == GzipDecoderState.SWALLOW_DATA or not data: + return bytes(ret) + while True: + try: + ret += self._obj.decompress(data) + except zlib.error: + previous_state = self._state + # Ignore data after the first error + self._state = GzipDecoderState.SWALLOW_DATA + if previous_state == GzipDecoderState.OTHER_MEMBERS: + # Allow trailing garbage acceptable in other gzip clients + return bytes(ret) + raise + data = self._obj.unused_data + if not data: + return bytes(ret) + self._state = GzipDecoderState.OTHER_MEMBERS + self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) + + +if brotli is not None: + + class BrotliDecoder(object): + # Supports both 'brotlipy' and 'Brotli' packages + # since they share an import name. The top branches + # are for 'brotlipy' and bottom branches for 'Brotli' + def __init__(self): + self._obj = brotli.Decompressor() + if hasattr(self._obj, "decompress"): + self.decompress = self._obj.decompress + else: + self.decompress = self._obj.process + + def flush(self): + if hasattr(self._obj, "flush"): + return self._obj.flush() + return b"" + + +class MultiDecoder(object): + """ + From RFC7231: + If one or more encodings have been applied to a representation, the + sender that applied the encodings MUST generate a Content-Encoding + header field that lists the content codings in the order in which + they were applied. + """ + + def __init__(self, modes): + self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")] + + def flush(self): + return self._decoders[0].flush() + + def decompress(self, data): + for d in reversed(self._decoders): + data = d.decompress(data) + return data + + +def _get_decoder(mode): + if "," in mode: + return MultiDecoder(mode) + + if mode == "gzip": + return GzipDecoder() + + if brotli is not None and mode == "br": + return BrotliDecoder() + + return DeflateDecoder() + + +class HTTPResponse(io.IOBase): + """ + HTTP Response container. + + Backwards-compatible with :class:`http.client.HTTPResponse` but the response ``body`` is + loaded and decoded on-demand when the ``data`` property is accessed. This + class is also compatible with the Python standard library's :mod:`io` + module, and can hence be treated as a readable object in the context of that + framework. + + Extra parameters for behaviour not present in :class:`http.client.HTTPResponse`: + + :param preload_content: + If True, the response's body will be preloaded during construction. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + + :param original_response: + When this HTTPResponse wrapper is generated from an :class:`http.client.HTTPResponse` + object, it's convenient to include the original for debug purposes. It's + otherwise unused. + + :param retries: + The retries contains the last :class:`~urllib3.util.retry.Retry` that + was used during the request. + + :param enforce_content_length: + Enforce content length checking. Body returned by server must match + value of Content-Length header, if present. Otherwise, raise error. + """ + + CONTENT_DECODERS = ["gzip", "deflate"] + if brotli is not None: + CONTENT_DECODERS += ["br"] + REDIRECT_STATUSES = [301, 302, 303, 307, 308] + + def __init__( + self, + body="", + headers=None, + status=0, + version=0, + reason=None, + strict=0, + preload_content=True, + decode_content=True, + original_response=None, + pool=None, + connection=None, + msg=None, + retries=None, + enforce_content_length=False, + request_method=None, + request_url=None, + auto_close=True, + ): + + if isinstance(headers, HTTPHeaderDict): + self.headers = headers + else: + self.headers = HTTPHeaderDict(headers) + self.status = status + self.version = version + self.reason = reason + self.strict = strict + self.decode_content = decode_content + self.retries = retries + self.enforce_content_length = enforce_content_length + self.auto_close = auto_close + + self._decoder = None + self._body = None + self._fp = None + self._original_response = original_response + self._fp_bytes_read = 0 + self.msg = msg + self._request_url = request_url + + if body and isinstance(body, (six.string_types, bytes)): + self._body = body + + self._pool = pool + self._connection = connection + + if hasattr(body, "read"): + self._fp = body + + # Are we using the chunked-style of transfer encoding? + self.chunked = False + self.chunk_left = None + tr_enc = self.headers.get("transfer-encoding", "").lower() + # Don't incur the penalty of creating a list and then discarding it + encodings = (enc.strip() for enc in tr_enc.split(",")) + if "chunked" in encodings: + self.chunked = True + + # Determine length of response + self.length_remaining = self._init_length(request_method) + + # If requested, preload the body. + if preload_content and not self._body: + self._body = self.read(decode_content=decode_content) + + def get_redirect_location(self): + """ + Should we redirect and where to? + + :returns: Truthy redirect location string if we got a redirect status + code and valid location. ``None`` if redirect status and no + location. ``False`` if not a redirect status code. + """ + if self.status in self.REDIRECT_STATUSES: + return self.headers.get("location") + + return False + + def release_conn(self): + if not self._pool or not self._connection: + return + + self._pool._put_conn(self._connection) + self._connection = None + + def drain_conn(self): + """ + Read and discard any remaining HTTP response data in the response connection. + + Unread data in the HTTPResponse connection blocks the connection from being released back to the pool. + """ + try: + self.read() + except (HTTPError, SocketError, BaseSSLError, HTTPException): + pass + + @property + def data(self): + # For backwards-compat with earlier urllib3 0.4 and earlier. + if self._body: + return self._body + + if self._fp: + return self.read(cache_content=True) + + @property + def connection(self): + return self._connection + + def isclosed(self): + return is_fp_closed(self._fp) + + def tell(self): + """ + Obtain the number of bytes pulled over the wire so far. May differ from + the amount of content returned by :meth:``urllib3.response.HTTPResponse.read`` + if bytes are encoded on the wire (e.g, compressed). + """ + return self._fp_bytes_read + + def _init_length(self, request_method): + """ + Set initial length value for Response content if available. + """ + length = self.headers.get("content-length") + + if length is not None: + if self.chunked: + # This Response will fail with an IncompleteRead if it can't be + # received as chunked. This method falls back to attempt reading + # the response before raising an exception. + log.warning( + "Received response with both Content-Length and " + "Transfer-Encoding set. This is expressly forbidden " + "by RFC 7230 sec 3.3.2. Ignoring Content-Length and " + "attempting to process response as Transfer-Encoding: " + "chunked." + ) + return None + + try: + # RFC 7230 section 3.3.2 specifies multiple content lengths can + # be sent in a single Content-Length header + # (e.g. Content-Length: 42, 42). This line ensures the values + # are all valid ints and that as long as the `set` length is 1, + # all values are the same. Otherwise, the header is invalid. + lengths = set([int(val) for val in length.split(",")]) + if len(lengths) > 1: + raise InvalidHeader( + "Content-Length contained multiple " + "unmatching values (%s)" % length + ) + length = lengths.pop() + except ValueError: + length = None + else: + if length < 0: + length = None + + # Convert status to int for comparison + # In some cases, httplib returns a status of "_UNKNOWN" + try: + status = int(self.status) + except ValueError: + status = 0 + + # Check for responses that shouldn't include a body + if status in (204, 304) or 100 <= status < 200 or request_method == "HEAD": + length = 0 + + return length + + def _init_decoder(self): + """ + Set-up the _decoder attribute if necessary. + """ + # Note: content-encoding value should be case-insensitive, per RFC 7230 + # Section 3.2 + content_encoding = self.headers.get("content-encoding", "").lower() + if self._decoder is None: + if content_encoding in self.CONTENT_DECODERS: + self._decoder = _get_decoder(content_encoding) + elif "," in content_encoding: + encodings = [ + e.strip() + for e in content_encoding.split(",") + if e.strip() in self.CONTENT_DECODERS + ] + if len(encodings): + self._decoder = _get_decoder(content_encoding) + + DECODER_ERROR_CLASSES = (IOError, zlib.error) + if brotli is not None: + DECODER_ERROR_CLASSES += (brotli.error,) + + def _decode(self, data, decode_content, flush_decoder): + """ + Decode the data passed in and potentially flush the decoder. + """ + if not decode_content: + return data + + try: + if self._decoder: + data = self._decoder.decompress(data) + except self.DECODER_ERROR_CLASSES as e: + content_encoding = self.headers.get("content-encoding", "").lower() + raise DecodeError( + "Received response with content-encoding: %s, but " + "failed to decode it." % content_encoding, + e, + ) + if flush_decoder: + data += self._flush_decoder() + + return data + + def _flush_decoder(self): + """ + Flushes the decoder. Should only be called if the decoder is actually + being used. + """ + if self._decoder: + buf = self._decoder.decompress(b"") + return buf + self._decoder.flush() + + return b"" + + @contextmanager + def _error_catcher(self): + """ + Catch low-level python exceptions, instead re-raising urllib3 + variants, so that low-level exceptions are not leaked in the + high-level api. + + On exit, release the connection back to the pool. + """ + clean_exit = False + + try: + try: + yield + + except SocketTimeout: + # FIXME: Ideally we'd like to include the url in the ReadTimeoutError but + # there is yet no clean way to get at it from this context. + raise ReadTimeoutError(self._pool, None, "Read timed out.") + + except BaseSSLError as e: + # FIXME: Is there a better way to differentiate between SSLErrors? + if "read operation timed out" not in str(e): + # SSL errors related to framing/MAC get wrapped and reraised here + raise SSLError(e) + + raise ReadTimeoutError(self._pool, None, "Read timed out.") + + except (HTTPException, SocketError) as e: + # This includes IncompleteRead. + raise ProtocolError("Connection broken: %r" % e, e) + + # If no exception is thrown, we should avoid cleaning up + # unnecessarily. + clean_exit = True + finally: + # If we didn't terminate cleanly, we need to throw away our + # connection. + if not clean_exit: + # The response may not be closed but we're not going to use it + # anymore so close it now to ensure that the connection is + # released back to the pool. + if self._original_response: + self._original_response.close() + + # Closing the response may not actually be sufficient to close + # everything, so if we have a hold of the connection close that + # too. + if self._connection: + self._connection.close() + + # If we hold the original response but it's closed now, we should + # return the connection back to the pool. + if self._original_response and self._original_response.isclosed(): + self.release_conn() + + def read(self, amt=None, decode_content=None, cache_content=False): + """ + Similar to :meth:`http.client.HTTPResponse.read`, but with two additional + parameters: ``decode_content`` and ``cache_content``. + + :param amt: + How much of the content to read. If specified, caching is skipped + because it doesn't make sense to cache partial content as the full + response. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + + :param cache_content: + If True, will save the returned data such that the same result is + returned despite of the state of the underlying file object. This + is useful if you want the ``.data`` property to continue working + after having ``.read()`` the file object. (Overridden if ``amt`` is + set.) + """ + self._init_decoder() + if decode_content is None: + decode_content = self.decode_content + + if self._fp is None: + return + + flush_decoder = False + fp_closed = getattr(self._fp, "closed", False) + + with self._error_catcher(): + if amt is None: + # cStringIO doesn't like amt=None + data = self._fp.read() if not fp_closed else b"" + flush_decoder = True + else: + cache_content = False + data = self._fp.read(amt) if not fp_closed else b"" + if ( + amt != 0 and not data + ): # Platform-specific: Buggy versions of Python. + # Close the connection when no data is returned + # + # This is redundant to what httplib/http.client _should_ + # already do. However, versions of python released before + # December 15, 2012 (http://bugs.python.org/issue16298) do + # not properly close the connection in all cases. There is + # no harm in redundantly calling close. + self._fp.close() + flush_decoder = True + if self.enforce_content_length and self.length_remaining not in ( + 0, + None, + ): + # This is an edge case that httplib failed to cover due + # to concerns of backward compatibility. We're + # addressing it here to make sure IncompleteRead is + # raised during streaming, so all calls with incorrect + # Content-Length are caught. + raise IncompleteRead(self._fp_bytes_read, self.length_remaining) + + if data: + self._fp_bytes_read += len(data) + if self.length_remaining is not None: + self.length_remaining -= len(data) + + data = self._decode(data, decode_content, flush_decoder) + + if cache_content: + self._body = data + + return data + + def stream(self, amt=2 ** 16, decode_content=None): + """ + A generator wrapper for the read() method. A call will block until + ``amt`` bytes have been read from the connection or until the + connection is closed. + + :param amt: + How much of the content to read. The generator will return up to + much data per iteration, but may return less. This is particularly + likely when using compressed data. However, the empty string will + never be returned. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + """ + if self.chunked and self.supports_chunked_reads(): + for line in self.read_chunked(amt, decode_content=decode_content): + yield line + else: + while not is_fp_closed(self._fp): + data = self.read(amt=amt, decode_content=decode_content) + + if data: + yield data + + @classmethod + def from_httplib(ResponseCls, r, **response_kw): + """ + Given an :class:`http.client.HTTPResponse` instance ``r``, return a + corresponding :class:`urllib3.response.HTTPResponse` object. + + Remaining parameters are passed to the HTTPResponse constructor, along + with ``original_response=r``. + """ + headers = r.msg + + if not isinstance(headers, HTTPHeaderDict): + if six.PY2: + # Python 2.7 + headers = HTTPHeaderDict.from_httplib(headers) + else: + headers = HTTPHeaderDict(headers.items()) + + # HTTPResponse objects in Python 3 don't have a .strict attribute + strict = getattr(r, "strict", 0) + resp = ResponseCls( + body=r, + headers=headers, + status=r.status, + version=r.version, + reason=r.reason, + strict=strict, + original_response=r, + **response_kw + ) + return resp + + # Backwards-compatibility methods for http.client.HTTPResponse + def getheaders(self): + return self.headers + + def getheader(self, name, default=None): + return self.headers.get(name, default) + + # Backwards compatibility for http.cookiejar + def info(self): + return self.headers + + # Overrides from io.IOBase + def close(self): + if not self.closed: + self._fp.close() + + if self._connection: + self._connection.close() + + if not self.auto_close: + io.IOBase.close(self) + + @property + def closed(self): + if not self.auto_close: + return io.IOBase.closed.__get__(self) + elif self._fp is None: + return True + elif hasattr(self._fp, "isclosed"): + return self._fp.isclosed() + elif hasattr(self._fp, "closed"): + return self._fp.closed + else: + return True + + def fileno(self): + if self._fp is None: + raise IOError("HTTPResponse has no file to get a fileno from") + elif hasattr(self._fp, "fileno"): + return self._fp.fileno() + else: + raise IOError( + "The file-like object this HTTPResponse is wrapped " + "around has no file descriptor" + ) + + def flush(self): + if ( + self._fp is not None + and hasattr(self._fp, "flush") + and not getattr(self._fp, "closed", False) + ): + return self._fp.flush() + + def readable(self): + # This method is required for `io` module compatibility. + return True + + def readinto(self, b): + # This method is required for `io` module compatibility. + temp = self.read(len(b)) + if len(temp) == 0: + return 0 + else: + b[: len(temp)] = temp + return len(temp) + + def supports_chunked_reads(self): + """ + Checks if the underlying file-like object looks like a + :class:`http.client.HTTPResponse` object. We do this by testing for + the fp attribute. If it is present we assume it returns raw chunks as + processed by read_chunked(). + """ + return hasattr(self._fp, "fp") + + def _update_chunk_length(self): + # First, we'll figure out length of a chunk and then + # we'll try to read it from socket. + if self.chunk_left is not None: + return + line = self._fp.fp.readline() + line = line.split(b";", 1)[0] + try: + self.chunk_left = int(line, 16) + except ValueError: + # Invalid chunked protocol response, abort. + self.close() + raise InvalidChunkLength(self, line) + + def _handle_chunk(self, amt): + returned_chunk = None + if amt is None: + chunk = self._fp._safe_read(self.chunk_left) + returned_chunk = chunk + self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. + self.chunk_left = None + elif amt < self.chunk_left: + value = self._fp._safe_read(amt) + self.chunk_left = self.chunk_left - amt + returned_chunk = value + elif amt == self.chunk_left: + value = self._fp._safe_read(amt) + self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. + self.chunk_left = None + returned_chunk = value + else: # amt > self.chunk_left + returned_chunk = self._fp._safe_read(self.chunk_left) + self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. + self.chunk_left = None + return returned_chunk + + def read_chunked(self, amt=None, decode_content=None): + """ + Similar to :meth:`HTTPResponse.read`, but with an additional + parameter: ``decode_content``. + + :param amt: + How much of the content to read. If specified, caching is skipped + because it doesn't make sense to cache partial content as the full + response. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + """ + self._init_decoder() + # FIXME: Rewrite this method and make it a class with a better structured logic. + if not self.chunked: + raise ResponseNotChunked( + "Response is not chunked. " + "Header 'transfer-encoding: chunked' is missing." + ) + if not self.supports_chunked_reads(): + raise BodyNotHttplibCompatible( + "Body should be http.client.HTTPResponse like. " + "It should have have an fp attribute which returns raw chunks." + ) + + with self._error_catcher(): + # Don't bother reading the body of a HEAD request. + if self._original_response and is_response_to_head(self._original_response): + self._original_response.close() + return + + # If a response is already read and closed + # then return immediately. + if self._fp.fp is None: + return + + while True: + self._update_chunk_length() + if self.chunk_left == 0: + break + chunk = self._handle_chunk(amt) + decoded = self._decode( + chunk, decode_content=decode_content, flush_decoder=False + ) + if decoded: + yield decoded + + if decode_content: + # On CPython and PyPy, we should never need to flush the + # decoder. However, on Jython we *might* need to, so + # lets defensively do it anyway. + decoded = self._flush_decoder() + if decoded: # Platform-specific: Jython. + yield decoded + + # Chunk content ends with \r\n: discard it. + while True: + line = self._fp.fp.readline() + if not line: + # Some sites may not end with '\r\n'. + break + if line == b"\r\n": + break + + # We read everything; close the "file". + if self._original_response: + self._original_response.close() + + def geturl(self): + """ + Returns the URL that was the source of this response. + If the request that generated this response redirected, this method + will return the final redirect location. + """ + if self.retries is not None and len(self.retries.history): + return self.retries.history[-1].redirect_location + else: + return self._request_url + + def __iter__(self): + buffer = [] + for chunk in self.stream(decode_content=True): + if b"\n" in chunk: + chunk = chunk.split(b"\n") + yield b"".join(buffer) + chunk[0] + b"\n" + for x in chunk[1:-1]: + yield x + b"\n" + if chunk[-1]: + buffer = [chunk[-1]] + else: + buffer = [] + else: + buffer.append(chunk) + if buffer: + yield b"".join(buffer) diff --git a/openpype/vendor/python/python_2/urllib3/util/__init__.py b/openpype/vendor/python/python_2/urllib3/util/__init__.py new file mode 100644 index 0000000000..4547fc522b --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/util/__init__.py @@ -0,0 +1,49 @@ +from __future__ import absolute_import + +# For backwards compatibility, provide imports that used to be here. +from .connection import is_connection_dropped +from .request import SKIP_HEADER, SKIPPABLE_HEADERS, make_headers +from .response import is_fp_closed +from .retry import Retry +from .ssl_ import ( + ALPN_PROTOCOLS, + HAS_SNI, + IS_PYOPENSSL, + IS_SECURETRANSPORT, + PROTOCOL_TLS, + SSLContext, + assert_fingerprint, + resolve_cert_reqs, + resolve_ssl_version, + ssl_wrap_socket, +) +from .timeout import Timeout, current_time +from .url import Url, get_host, parse_url, split_first +from .wait import wait_for_read, wait_for_write + +__all__ = ( + "HAS_SNI", + "IS_PYOPENSSL", + "IS_SECURETRANSPORT", + "SSLContext", + "PROTOCOL_TLS", + "ALPN_PROTOCOLS", + "Retry", + "Timeout", + "Url", + "assert_fingerprint", + "current_time", + "is_connection_dropped", + "is_fp_closed", + "get_host", + "parse_url", + "make_headers", + "resolve_cert_reqs", + "resolve_ssl_version", + "split_first", + "ssl_wrap_socket", + "wait_for_read", + "wait_for_write", + "SKIP_HEADER", + "SKIPPABLE_HEADERS", +) diff --git a/openpype/vendor/python/python_2/urllib3/util/connection.py b/openpype/vendor/python/python_2/urllib3/util/connection.py new file mode 100644 index 0000000000..6af1138f26 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/util/connection.py @@ -0,0 +1,149 @@ +from __future__ import absolute_import + +import socket + +from ..contrib import _appengine_environ +from ..exceptions import LocationParseError +from ..packages import six +from .wait import NoWayToWaitForSocketError, wait_for_read + + +def is_connection_dropped(conn): # Platform-specific + """ + Returns True if the connection is dropped and should be closed. + + :param conn: + :class:`http.client.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 sock is False: # Platform-specific: AppEngine + return False + if sock is None: # Connection already closed (such as by httplib). + return True + try: + # Returns True if readable, which here means it's been dropped + return wait_for_read(sock, timeout=0.0) + except NoWayToWaitForSocketError: # Platform-specific: AppEngine + return False + + +# This function is copied from socket.py in the Python 2.7 standard +# library test suite. Added to its signature is only `socket_options`. +# One additional modification is that we avoid binding to IPv6 servers +# discovered in DNS if the system doesn't have IPv6 functionality. +def create_connection( + address, + timeout=socket._GLOBAL_DEFAULT_TIMEOUT, + source_address=None, + socket_options=None, +): + """Connect to *address* and return the socket object. + + Convenience function. Connect to *address* (a 2-tuple ``(host, + port)``) and return the socket object. Passing the optional + *timeout* parameter will set the timeout on the socket instance + before attempting to connect. If no *timeout* is supplied, the + global default timeout setting returned by :func:`socket.getdefaulttimeout` + is used. If *source_address* is set it must be a tuple of (host, port) + for the socket to bind as a source address before making the connection. + An host of '' or port 0 tells the OS to use the default. + """ + + host, port = address + if host.startswith("["): + host = host.strip("[]") + err = None + + # Using the value from allowed_gai_family() in the context of getaddrinfo lets + # us select whether to work with IPv4 DNS records, IPv6 records, or both. + # The original create_connection function always returns all records. + family = allowed_gai_family() + + try: + host.encode("idna") + except UnicodeError: + return six.raise_from( + LocationParseError(u"'%s', label empty or too long" % host), None + ) + + for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM): + af, socktype, proto, canonname, sa = res + sock = None + try: + sock = socket.socket(af, socktype, proto) + + # If provided, set socket level options before connecting. + _set_socket_options(sock, socket_options) + + if timeout is not socket._GLOBAL_DEFAULT_TIMEOUT: + sock.settimeout(timeout) + if source_address: + sock.bind(source_address) + sock.connect(sa) + return sock + + except socket.error as e: + err = e + if sock is not None: + sock.close() + sock = None + + if err is not None: + raise err + + raise socket.error("getaddrinfo returns an empty list") + + +def _set_socket_options(sock, options): + if options is None: + return + + for opt in options: + sock.setsockopt(*opt) + + +def allowed_gai_family(): + """This function is designed to work in the context of + getaddrinfo, where family=socket.AF_UNSPEC is the default and + will perform a DNS search for both IPv6 and IPv4 records.""" + + family = socket.AF_INET + if HAS_IPV6: + family = socket.AF_UNSPEC + return family + + +def _has_ipv6(host): + """Returns True if the system can bind an IPv6 address.""" + sock = None + has_ipv6 = False + + # App Engine doesn't support IPV6 sockets and actually has a quota on the + # number of sockets that can be used, so just early out here instead of + # creating a socket needlessly. + # See https://github.com/urllib3/urllib3/issues/1446 + if _appengine_environ.is_appengine_sandbox(): + return False + + if socket.has_ipv6: + # has_ipv6 returns true if cPython was compiled with IPv6 support. + # It does not tell us if the system has IPv6 support enabled. To + # determine that we must bind to an IPv6 address. + # https://github.com/urllib3/urllib3/pull/611 + # https://bugs.python.org/issue658327 + try: + sock = socket.socket(socket.AF_INET6) + sock.bind((host, 0)) + has_ipv6 = True + except Exception: + pass + + if sock: + sock.close() + return has_ipv6 + + +HAS_IPV6 = _has_ipv6("::1") diff --git a/openpype/vendor/python/python_2/urllib3/util/proxy.py b/openpype/vendor/python/python_2/urllib3/util/proxy.py new file mode 100644 index 0000000000..2199cc7b7f --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/util/proxy.py @@ -0,0 +1,57 @@ +from .ssl_ import create_urllib3_context, resolve_cert_reqs, resolve_ssl_version + + +def connection_requires_http_tunnel( + proxy_url=None, proxy_config=None, destination_scheme=None +): + """ + Returns True if the connection requires an HTTP CONNECT through the proxy. + + :param URL proxy_url: + URL of the proxy. + :param ProxyConfig proxy_config: + Proxy configuration from poolmanager.py + :param str destination_scheme: + The scheme of the destination. (i.e https, http, etc) + """ + # If we're not using a proxy, no way to use a tunnel. + if proxy_url is None: + return False + + # HTTP destinations never require tunneling, we always forward. + if destination_scheme == "http": + return False + + # Support for forwarding with HTTPS proxies and HTTPS destinations. + if ( + proxy_url.scheme == "https" + and proxy_config + and proxy_config.use_forwarding_for_https + ): + return False + + # Otherwise always use a tunnel. + return True + + +def create_proxy_ssl_context( + ssl_version, cert_reqs, ca_certs=None, ca_cert_dir=None, ca_cert_data=None +): + """ + Generates a default proxy ssl context if one hasn't been provided by the + user. + """ + ssl_context = create_urllib3_context( + ssl_version=resolve_ssl_version(ssl_version), + cert_reqs=resolve_cert_reqs(cert_reqs), + ) + + if ( + not ca_certs + and not ca_cert_dir + and not ca_cert_data + and hasattr(ssl_context, "load_default_certs") + ): + ssl_context.load_default_certs() + + return ssl_context diff --git a/openpype/vendor/python/python_2/urllib3/util/queue.py b/openpype/vendor/python/python_2/urllib3/util/queue.py new file mode 100644 index 0000000000..41784104ee --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/util/queue.py @@ -0,0 +1,22 @@ +import collections + +from ..packages import six +from ..packages.six.moves import queue + +if six.PY2: + # Queue is imported for side effects on MS Windows. See issue #229. + import Queue as _unused_module_Queue # noqa: F401 + + +class LifoQueue(queue.Queue): + def _init(self, _): + self.queue = collections.deque() + + def _qsize(self, len=len): + return len(self.queue) + + def _put(self, item): + self.queue.append(item) + + def _get(self): + return self.queue.pop() diff --git a/openpype/vendor/python/python_2/urllib3/util/request.py b/openpype/vendor/python/python_2/urllib3/util/request.py new file mode 100644 index 0000000000..b574b081e9 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/util/request.py @@ -0,0 +1,146 @@ +from __future__ import absolute_import + +from base64 import b64encode + +from ..exceptions import UnrewindableBodyError +from ..packages.six import b, integer_types + +# Pass as a value within ``headers`` to skip +# emitting some HTTP headers that are added automatically. +# The only headers that are supported are ``Accept-Encoding``, +# ``Host``, and ``User-Agent``. +SKIP_HEADER = "@@@SKIP_HEADER@@@" +SKIPPABLE_HEADERS = frozenset(["accept-encoding", "host", "user-agent"]) + +ACCEPT_ENCODING = "gzip,deflate" +try: + try: + import brotlicffi as _unused_module_brotli # noqa: F401 + except ImportError: + import brotli as _unused_module_brotli # noqa: F401 +except ImportError: + pass +else: + ACCEPT_ENCODING += ",br" + +_FAILEDTELL = object() + + +def make_headers( + keep_alive=None, + accept_encoding=None, + user_agent=None, + basic_auth=None, + proxy_basic_auth=None, + disable_cache=None, +): + """ + Shortcuts for generating request headers. + + :param keep_alive: + If ``True``, adds 'connection: keep-alive' header. + + :param accept_encoding: + Can be a boolean, list, or string. + ``True`` translates to 'gzip,deflate'. + List will get joined by comma. + String will be used as provided. + + :param user_agent: + String representing the user-agent you want, such as + "python-urllib3/0.6" + + :param basic_auth: + Colon-separated username:password string for 'authorization: basic ...' + auth header. + + :param proxy_basic_auth: + Colon-separated username:password string for 'proxy-authorization: basic ...' + auth header. + + :param disable_cache: + If ``True``, adds 'cache-control: no-cache' header. + + Example:: + + >>> make_headers(keep_alive=True, user_agent="Batman/1.0") + {'connection': 'keep-alive', 'user-agent': 'Batman/1.0'} + >>> make_headers(accept_encoding=True) + {'accept-encoding': 'gzip,deflate'} + """ + headers = {} + if accept_encoding: + if isinstance(accept_encoding, str): + pass + elif isinstance(accept_encoding, list): + accept_encoding = ",".join(accept_encoding) + else: + accept_encoding = ACCEPT_ENCODING + headers["accept-encoding"] = accept_encoding + + if user_agent: + headers["user-agent"] = user_agent + + if keep_alive: + headers["connection"] = "keep-alive" + + if basic_auth: + headers["authorization"] = "Basic " + b64encode(b(basic_auth)).decode("utf-8") + + if proxy_basic_auth: + headers["proxy-authorization"] = "Basic " + b64encode( + b(proxy_basic_auth) + ).decode("utf-8") + + if disable_cache: + headers["cache-control"] = "no-cache" + + return headers + + +def set_file_position(body, pos): + """ + If a position is provided, move file to that point. + Otherwise, we'll attempt to record a position for future use. + """ + if pos is not None: + rewind_body(body, pos) + elif getattr(body, "tell", None) is not None: + try: + pos = body.tell() + except (IOError, OSError): + # This differentiates from None, allowing us to catch + # a failed `tell()` later when trying to rewind the body. + pos = _FAILEDTELL + + return pos + + +def rewind_body(body, body_pos): + """ + Attempt to rewind body to a certain position. + Primarily used for request redirects and retries. + + :param body: + File-like object that supports seek. + + :param int pos: + Position to seek to in file. + """ + body_seek = getattr(body, "seek", None) + if body_seek is not None and isinstance(body_pos, integer_types): + try: + body_seek(body_pos) + except (IOError, OSError): + raise UnrewindableBodyError( + "An error occurred when rewinding request body for redirect/retry." + ) + elif body_pos is _FAILEDTELL: + raise UnrewindableBodyError( + "Unable to record file position for rewinding " + "request body during a redirect/retry." + ) + else: + raise ValueError( + "body_pos must be of type integer, instead it was %s." % type(body_pos) + ) diff --git a/openpype/vendor/python/python_2/urllib3/util/response.py b/openpype/vendor/python/python_2/urllib3/util/response.py new file mode 100644 index 0000000000..5ea609cced --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/util/response.py @@ -0,0 +1,107 @@ +from __future__ import absolute_import + +from email.errors import MultipartInvariantViolationDefect, StartBoundaryNotFoundDefect + +from ..exceptions import HeaderParsingError +from ..packages.six.moves import http_client as httplib + + +def is_fp_closed(obj): + """ + Checks whether a given file-like object is closed. + + :param obj: + The file-like object to check. + """ + + try: + # Check `isclosed()` first, in case Python3 doesn't set `closed`. + # GH Issue #928 + return obj.isclosed() + except AttributeError: + pass + + try: + # Check via the official file-like-object way. + return obj.closed + except AttributeError: + pass + + try: + # Check if the object is a container for another file-like object that + # gets released on exhaustion (e.g. HTTPResponse). + return obj.fp is None + except AttributeError: + pass + + raise ValueError("Unable to determine whether fp is closed.") + + +def assert_header_parsing(headers): + """ + Asserts whether all headers have been successfully parsed. + Extracts encountered errors from the result of parsing headers. + + Only works on Python 3. + + :param http.client.HTTPMessage headers: Headers to verify. + + :raises urllib3.exceptions.HeaderParsingError: + If parsing errors are found. + """ + + # This will fail silently if we pass in the wrong kind of parameter. + # To make debugging easier add an explicit check. + if not isinstance(headers, httplib.HTTPMessage): + raise TypeError("expected httplib.Message, got {0}.".format(type(headers))) + + defects = getattr(headers, "defects", None) + get_payload = getattr(headers, "get_payload", None) + + unparsed_data = None + if get_payload: + # get_payload is actually email.message.Message.get_payload; + # we're only interested in the result if it's not a multipart message + if not headers.is_multipart(): + payload = get_payload() + + if isinstance(payload, (bytes, str)): + unparsed_data = payload + if defects: + # httplib is assuming a response body is available + # when parsing headers even when httplib only sends + # header data to parse_headers() This results in + # defects on multipart responses in particular. + # See: https://github.com/urllib3/urllib3/issues/800 + + # So we ignore the following defects: + # - StartBoundaryNotFoundDefect: + # The claimed start boundary was never found. + # - MultipartInvariantViolationDefect: + # A message claimed to be a multipart but no subparts were found. + defects = [ + defect + for defect in defects + if not isinstance( + defect, (StartBoundaryNotFoundDefect, MultipartInvariantViolationDefect) + ) + ] + + if defects or unparsed_data: + raise HeaderParsingError(defects=defects, unparsed_data=unparsed_data) + + +def is_response_to_head(response): + """ + Checks whether the request of a response has been a HEAD-request. + Handles the quirks of AppEngine. + + :param http.client.HTTPResponse response: + Response to check if the originating request + used 'HEAD' as a method. + """ + # FIXME: Can we do this somehow without accessing private httplib _method? + method = response._method + if isinstance(method, int): # Platform-specific: Appengine + return method == 3 + return method.upper() == "HEAD" diff --git a/openpype/vendor/python/python_2/urllib3/util/retry.py b/openpype/vendor/python/python_2/urllib3/util/retry.py new file mode 100644 index 0000000000..3398323fd7 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/util/retry.py @@ -0,0 +1,620 @@ +from __future__ import absolute_import + +import email +import logging +import re +import time +import warnings +from collections import namedtuple +from itertools import takewhile + +from ..exceptions import ( + ConnectTimeoutError, + InvalidHeader, + MaxRetryError, + ProtocolError, + ProxyError, + ReadTimeoutError, + ResponseError, +) +from ..packages import six + +log = logging.getLogger(__name__) + + +# Data structure for representing the metadata of requests that result in a retry. +RequestHistory = namedtuple( + "RequestHistory", ["method", "url", "error", "status", "redirect_location"] +) + + +# TODO: In v2 we can remove this sentinel and metaclass with deprecated options. +_Default = object() + + +class _RetryMeta(type): + @property + def DEFAULT_METHOD_WHITELIST(cls): + warnings.warn( + "Using 'Retry.DEFAULT_METHOD_WHITELIST' is deprecated and " + "will be removed in v2.0. Use 'Retry.DEFAULT_ALLOWED_METHODS' instead", + DeprecationWarning, + ) + return cls.DEFAULT_ALLOWED_METHODS + + @DEFAULT_METHOD_WHITELIST.setter + def DEFAULT_METHOD_WHITELIST(cls, value): + warnings.warn( + "Using 'Retry.DEFAULT_METHOD_WHITELIST' is deprecated and " + "will be removed in v2.0. Use 'Retry.DEFAULT_ALLOWED_METHODS' instead", + DeprecationWarning, + ) + cls.DEFAULT_ALLOWED_METHODS = value + + @property + def DEFAULT_REDIRECT_HEADERS_BLACKLIST(cls): + warnings.warn( + "Using 'Retry.DEFAULT_REDIRECT_HEADERS_BLACKLIST' is deprecated and " + "will be removed in v2.0. Use 'Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT' instead", + DeprecationWarning, + ) + return cls.DEFAULT_REMOVE_HEADERS_ON_REDIRECT + + @DEFAULT_REDIRECT_HEADERS_BLACKLIST.setter + def DEFAULT_REDIRECT_HEADERS_BLACKLIST(cls, value): + warnings.warn( + "Using 'Retry.DEFAULT_REDIRECT_HEADERS_BLACKLIST' is deprecated and " + "will be removed in v2.0. Use 'Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT' instead", + DeprecationWarning, + ) + cls.DEFAULT_REMOVE_HEADERS_ON_REDIRECT = value + + @property + def BACKOFF_MAX(cls): + warnings.warn( + "Using 'Retry.BACKOFF_MAX' is deprecated and " + "will be removed in v2.0. Use 'Retry.DEFAULT_BACKOFF_MAX' instead", + DeprecationWarning, + ) + return cls.DEFAULT_BACKOFF_MAX + + @BACKOFF_MAX.setter + def BACKOFF_MAX(cls, value): + warnings.warn( + "Using 'Retry.BACKOFF_MAX' is deprecated and " + "will be removed in v2.0. Use 'Retry.DEFAULT_BACKOFF_MAX' instead", + DeprecationWarning, + ) + cls.DEFAULT_BACKOFF_MAX = value + + +@six.add_metaclass(_RetryMeta) +class Retry(object): + """Retry configuration. + + Each retry attempt will create a new Retry object with updated values, so + they can be safely reused. + + Retries can be defined as a default for a pool:: + + retries = Retry(connect=5, read=2, redirect=5) + http = PoolManager(retries=retries) + response = http.request('GET', 'http://example.com/') + + Or per-request (which overrides the default for the pool):: + + response = http.request('GET', 'http://example.com/', retries=Retry(10)) + + Retries can be disabled by passing ``False``:: + + response = http.request('GET', 'http://example.com/', retries=False) + + Errors will be wrapped in :class:`~urllib3.exceptions.MaxRetryError` unless + retries are disabled, in which case the causing exception will be raised. + + :param int total: + Total number of retries to allow. Takes precedence over other counts. + + Set to ``None`` to remove this constraint and fall back on other + counts. + + Set to ``0`` to fail on the first retry. + + Set to ``False`` to disable and imply ``raise_on_redirect=False``. + + :param int connect: + How many connection-related errors to retry on. + + These are errors raised before the request is sent to the remote server, + which we assume has not triggered the server to process the request. + + Set to ``0`` to fail on the first retry of this type. + + :param int read: + How many times to retry on read errors. + + These errors are raised after the request was sent to the server, so the + request may have side-effects. + + Set to ``0`` to fail on the first retry of this type. + + :param int redirect: + How many redirects to perform. Limit this to avoid infinite redirect + loops. + + A redirect is a HTTP response with a status code 301, 302, 303, 307 or + 308. + + Set to ``0`` to fail on the first retry of this type. + + Set to ``False`` to disable and imply ``raise_on_redirect=False``. + + :param int status: + How many times to retry on bad status codes. + + These are retries made on responses, where status code matches + ``status_forcelist``. + + Set to ``0`` to fail on the first retry of this type. + + :param int other: + How many times to retry on other errors. + + Other errors are errors that are not connect, read, redirect or status errors. + These errors might be raised after the request was sent to the server, so the + request might have side-effects. + + Set to ``0`` to fail on the first retry of this type. + + If ``total`` is not set, it's a good idea to set this to 0 to account + for unexpected edge cases and avoid infinite retry loops. + + :param iterable allowed_methods: + Set of uppercased HTTP method verbs that we should retry on. + + By default, we only retry on methods which are considered to be + idempotent (multiple requests with the same parameters end with the + same state). See :attr:`Retry.DEFAULT_ALLOWED_METHODS`. + + Set to a ``False`` value to retry on any verb. + + .. warning:: + + Previously this parameter was named ``method_whitelist``, that + usage is deprecated in v1.26.0 and will be removed in v2.0. + + :param iterable status_forcelist: + A set of integer HTTP status codes that we should force a retry on. + A retry is initiated if the request method is in ``allowed_methods`` + and the response status code is in ``status_forcelist``. + + By default, this is disabled with ``None``. + + :param float backoff_factor: + A backoff factor to apply between attempts after the second try + (most errors are resolved immediately by a second try without a + delay). urllib3 will sleep for:: + + {backoff factor} * (2 ** ({number of total retries} - 1)) + + seconds. If the backoff_factor is 0.1, then :func:`.sleep` will sleep + for [0.0s, 0.2s, 0.4s, ...] between retries. It will never be longer + than :attr:`Retry.DEFAULT_BACKOFF_MAX`. + + By default, backoff is disabled (set to 0). + + :param bool raise_on_redirect: Whether, if the number of redirects is + exhausted, to raise a MaxRetryError, or to return a response with a + response code in the 3xx range. + + :param bool raise_on_status: Similar meaning to ``raise_on_redirect``: + whether we should raise an exception, or return a response, + if status falls in ``status_forcelist`` range and retries have + been exhausted. + + :param tuple history: The history of the request encountered during + each call to :meth:`~Retry.increment`. The list is in the order + the requests occurred. Each list item is of class :class:`RequestHistory`. + + :param bool respect_retry_after_header: + Whether to respect Retry-After header on status codes defined as + :attr:`Retry.RETRY_AFTER_STATUS_CODES` or not. + + :param iterable remove_headers_on_redirect: + Sequence of headers to remove from the request when a response + indicating a redirect is returned before firing off the redirected + request. + """ + + #: Default methods to be used for ``allowed_methods`` + DEFAULT_ALLOWED_METHODS = frozenset( + ["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE"] + ) + + #: Default status codes to be used for ``status_forcelist`` + RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503]) + + #: Default headers to be used for ``remove_headers_on_redirect`` + DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Authorization"]) + + #: Maximum backoff time. + DEFAULT_BACKOFF_MAX = 120 + + def __init__( + self, + total=10, + connect=None, + read=None, + redirect=None, + status=None, + other=None, + allowed_methods=_Default, + status_forcelist=None, + backoff_factor=0, + raise_on_redirect=True, + raise_on_status=True, + history=None, + respect_retry_after_header=True, + remove_headers_on_redirect=_Default, + # TODO: Deprecated, remove in v2.0 + method_whitelist=_Default, + ): + + if method_whitelist is not _Default: + if allowed_methods is not _Default: + raise ValueError( + "Using both 'allowed_methods' and " + "'method_whitelist' together is not allowed. " + "Instead only use 'allowed_methods'" + ) + warnings.warn( + "Using 'method_whitelist' with Retry is deprecated and " + "will be removed in v2.0. Use 'allowed_methods' instead", + DeprecationWarning, + stacklevel=2, + ) + allowed_methods = method_whitelist + if allowed_methods is _Default: + allowed_methods = self.DEFAULT_ALLOWED_METHODS + if remove_headers_on_redirect is _Default: + remove_headers_on_redirect = self.DEFAULT_REMOVE_HEADERS_ON_REDIRECT + + self.total = total + self.connect = connect + self.read = read + self.status = status + self.other = other + + if redirect is False or total is False: + redirect = 0 + raise_on_redirect = False + + self.redirect = redirect + self.status_forcelist = status_forcelist or set() + self.allowed_methods = allowed_methods + self.backoff_factor = backoff_factor + self.raise_on_redirect = raise_on_redirect + self.raise_on_status = raise_on_status + self.history = history or tuple() + self.respect_retry_after_header = respect_retry_after_header + self.remove_headers_on_redirect = frozenset( + [h.lower() for h in remove_headers_on_redirect] + ) + + def new(self, **kw): + params = dict( + total=self.total, + connect=self.connect, + read=self.read, + redirect=self.redirect, + status=self.status, + other=self.other, + status_forcelist=self.status_forcelist, + backoff_factor=self.backoff_factor, + raise_on_redirect=self.raise_on_redirect, + raise_on_status=self.raise_on_status, + history=self.history, + remove_headers_on_redirect=self.remove_headers_on_redirect, + respect_retry_after_header=self.respect_retry_after_header, + ) + + # TODO: If already given in **kw we use what's given to us + # If not given we need to figure out what to pass. We decide + # based on whether our class has the 'method_whitelist' property + # and if so we pass the deprecated 'method_whitelist' otherwise + # we use 'allowed_methods'. Remove in v2.0 + if "method_whitelist" not in kw and "allowed_methods" not in kw: + if "method_whitelist" in self.__dict__: + warnings.warn( + "Using 'method_whitelist' with Retry is deprecated and " + "will be removed in v2.0. Use 'allowed_methods' instead", + DeprecationWarning, + ) + params["method_whitelist"] = self.allowed_methods + else: + params["allowed_methods"] = self.allowed_methods + + params.update(kw) + return type(self)(**params) + + @classmethod + def from_int(cls, retries, redirect=True, default=None): + """Backwards-compatibility for the old retries format.""" + if retries is None: + retries = default if default is not None else cls.DEFAULT + + if isinstance(retries, Retry): + return retries + + redirect = bool(redirect) and None + new_retries = cls(retries, redirect=redirect) + log.debug("Converted retries value: %r -> %r", retries, new_retries) + return new_retries + + def get_backoff_time(self): + """Formula for computing the current backoff + + :rtype: float + """ + # We want to consider only the last consecutive errors sequence (Ignore redirects). + consecutive_errors_len = len( + list( + takewhile(lambda x: x.redirect_location is None, reversed(self.history)) + ) + ) + if consecutive_errors_len <= 1: + return 0 + + backoff_value = self.backoff_factor * (2 ** (consecutive_errors_len - 1)) + return min(self.DEFAULT_BACKOFF_MAX, backoff_value) + + def parse_retry_after(self, retry_after): + # Whitespace: https://tools.ietf.org/html/rfc7230#section-3.2.4 + if re.match(r"^\s*[0-9]+\s*$", retry_after): + seconds = int(retry_after) + else: + retry_date_tuple = email.utils.parsedate_tz(retry_after) + if retry_date_tuple is None: + raise InvalidHeader("Invalid Retry-After header: %s" % retry_after) + if retry_date_tuple[9] is None: # Python 2 + # Assume UTC if no timezone was specified + # On Python2.7, parsedate_tz returns None for a timezone offset + # instead of 0 if no timezone is given, where mktime_tz treats + # a None timezone offset as local time. + retry_date_tuple = retry_date_tuple[:9] + (0,) + retry_date_tuple[10:] + + retry_date = email.utils.mktime_tz(retry_date_tuple) + seconds = retry_date - time.time() + + if seconds < 0: + seconds = 0 + + return seconds + + def get_retry_after(self, response): + """Get the value of Retry-After in seconds.""" + + retry_after = response.getheader("Retry-After") + + if retry_after is None: + return None + + return self.parse_retry_after(retry_after) + + def sleep_for_retry(self, response=None): + retry_after = self.get_retry_after(response) + if retry_after: + time.sleep(retry_after) + return True + + return False + + def _sleep_backoff(self): + backoff = self.get_backoff_time() + if backoff <= 0: + return + time.sleep(backoff) + + def sleep(self, response=None): + """Sleep between retry attempts. + + This method will respect a server's ``Retry-After`` response header + and sleep the duration of the time requested. If that is not present, it + will use an exponential backoff. By default, the backoff factor is 0 and + this method will return immediately. + """ + + if self.respect_retry_after_header and response: + slept = self.sleep_for_retry(response) + if slept: + return + + self._sleep_backoff() + + def _is_connection_error(self, err): + """Errors when we're fairly sure that the server did not receive the + request, so it should be safe to retry. + """ + if isinstance(err, ProxyError): + err = err.original_error + return isinstance(err, ConnectTimeoutError) + + def _is_read_error(self, err): + """Errors that occur after the request has been started, so we should + assume that the server began processing it. + """ + return isinstance(err, (ReadTimeoutError, ProtocolError)) + + def _is_method_retryable(self, method): + """Checks if a given HTTP method should be retried upon, depending if + it is included in the allowed_methods + """ + # TODO: For now favor if the Retry implementation sets its own method_whitelist + # property outside of our constructor to avoid breaking custom implementations. + if "method_whitelist" in self.__dict__: + warnings.warn( + "Using 'method_whitelist' with Retry is deprecated and " + "will be removed in v2.0. Use 'allowed_methods' instead", + DeprecationWarning, + ) + allowed_methods = self.method_whitelist + else: + allowed_methods = self.allowed_methods + + if allowed_methods and method.upper() not in allowed_methods: + return False + return True + + def is_retry(self, method, status_code, has_retry_after=False): + """Is this method/status code retryable? (Based on allowlists and control + variables such as the number of total retries to allow, whether to + respect the Retry-After header, whether this header is present, and + whether the returned status code is on the list of status codes to + be retried upon on the presence of the aforementioned header) + """ + if not self._is_method_retryable(method): + return False + + if self.status_forcelist and status_code in self.status_forcelist: + return True + + return ( + self.total + and self.respect_retry_after_header + and has_retry_after + and (status_code in self.RETRY_AFTER_STATUS_CODES) + ) + + def is_exhausted(self): + """Are we out of retries?""" + retry_counts = ( + self.total, + self.connect, + self.read, + self.redirect, + self.status, + self.other, + ) + retry_counts = list(filter(None, retry_counts)) + if not retry_counts: + return False + + return min(retry_counts) < 0 + + def increment( + self, + method=None, + url=None, + response=None, + error=None, + _pool=None, + _stacktrace=None, + ): + """Return a new Retry object with incremented retry counters. + + :param response: A response object, or None, if the server did not + return a response. + :type response: :class:`~urllib3.response.HTTPResponse` + :param Exception error: An error encountered during the request, or + None if the response was received successfully. + + :return: A new ``Retry`` object. + """ + if self.total is False and error: + # Disabled, indicate to re-raise the error. + raise six.reraise(type(error), error, _stacktrace) + + total = self.total + if total is not None: + total -= 1 + + connect = self.connect + read = self.read + redirect = self.redirect + status_count = self.status + other = self.other + cause = "unknown" + status = None + redirect_location = None + + if error and self._is_connection_error(error): + # Connect retry? + if connect is False: + raise six.reraise(type(error), error, _stacktrace) + elif connect is not None: + connect -= 1 + + elif error and self._is_read_error(error): + # Read retry? + if read is False or not self._is_method_retryable(method): + raise six.reraise(type(error), error, _stacktrace) + elif read is not None: + read -= 1 + + elif error: + # Other retry? + if other is not None: + other -= 1 + + elif response and response.get_redirect_location(): + # Redirect retry? + if redirect is not None: + redirect -= 1 + cause = "too many redirects" + redirect_location = response.get_redirect_location() + status = response.status + + else: + # Incrementing because of a server error like a 500 in + # status_forcelist and the given method is in the allowed_methods + cause = ResponseError.GENERIC_ERROR + if response and response.status: + if status_count is not None: + status_count -= 1 + cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status) + status = response.status + + history = self.history + ( + RequestHistory(method, url, error, status, redirect_location), + ) + + new_retry = self.new( + total=total, + connect=connect, + read=read, + redirect=redirect, + status=status_count, + other=other, + history=history, + ) + + if new_retry.is_exhausted(): + raise MaxRetryError(_pool, url, error or ResponseError(cause)) + + log.debug("Incremented Retry for (url='%s'): %r", url, new_retry) + + return new_retry + + def __repr__(self): + return ( + "{cls.__name__}(total={self.total}, connect={self.connect}, " + "read={self.read}, redirect={self.redirect}, status={self.status})" + ).format(cls=type(self), self=self) + + def __getattr__(self, item): + if item == "method_whitelist": + # TODO: Remove this deprecated alias in v2.0 + warnings.warn( + "Using 'method_whitelist' with Retry is deprecated and " + "will be removed in v2.0. Use 'allowed_methods' instead", + DeprecationWarning, + ) + return self.allowed_methods + try: + return getattr(super(Retry, self), item) + except AttributeError: + return getattr(Retry, item) + + +# For backwards compatibility (equivalent to pre-v1.9): +Retry.DEFAULT = Retry(3) diff --git a/openpype/vendor/python/python_2/urllib3/util/ssl_.py b/openpype/vendor/python/python_2/urllib3/util/ssl_.py new file mode 100644 index 0000000000..8f867812a5 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/util/ssl_.py @@ -0,0 +1,495 @@ +from __future__ import absolute_import + +import hmac +import os +import sys +import warnings +from binascii import hexlify, unhexlify +from hashlib import md5, sha1, sha256 + +from ..exceptions import ( + InsecurePlatformWarning, + ProxySchemeUnsupported, + SNIMissingWarning, + SSLError, +) +from ..packages import six +from .url import BRACELESS_IPV6_ADDRZ_RE, IPV4_RE + +SSLContext = None +SSLTransport = None +HAS_SNI = False +IS_PYOPENSSL = False +IS_SECURETRANSPORT = False +ALPN_PROTOCOLS = ["http/1.1"] + +# Maps the length of a digest to a possible hash function producing this digest +HASHFUNC_MAP = {32: md5, 40: sha1, 64: sha256} + + +def _const_compare_digest_backport(a, b): + """ + Compare two digests of equal length in constant time. + + The digests must be of type str/bytes. + Returns True if the digests match, and False otherwise. + """ + result = abs(len(a) - len(b)) + for left, right in zip(bytearray(a), bytearray(b)): + result |= left ^ right + return result == 0 + + +_const_compare_digest = getattr(hmac, "compare_digest", _const_compare_digest_backport) + +try: # Test for SSL features + import ssl + from ssl import CERT_REQUIRED, wrap_socket +except ImportError: + pass + +try: + from ssl import HAS_SNI # Has SNI? +except ImportError: + pass + +try: + from .ssltransport import SSLTransport +except ImportError: + pass + + +try: # Platform-specific: Python 3.6 + from ssl import PROTOCOL_TLS + + PROTOCOL_SSLv23 = PROTOCOL_TLS +except ImportError: + try: + from ssl import PROTOCOL_SSLv23 as PROTOCOL_TLS + + PROTOCOL_SSLv23 = PROTOCOL_TLS + except ImportError: + PROTOCOL_SSLv23 = PROTOCOL_TLS = 2 + +try: + from ssl import PROTOCOL_TLS_CLIENT +except ImportError: + PROTOCOL_TLS_CLIENT = PROTOCOL_TLS + + +try: + from ssl import OP_NO_COMPRESSION, OP_NO_SSLv2, OP_NO_SSLv3 +except ImportError: + OP_NO_SSLv2, OP_NO_SSLv3 = 0x1000000, 0x2000000 + OP_NO_COMPRESSION = 0x20000 + + +try: # OP_NO_TICKET was added in Python 3.6 + from ssl import OP_NO_TICKET +except ImportError: + OP_NO_TICKET = 0x4000 + + +# A secure default. +# Sources for more information on TLS ciphers: +# +# - https://wiki.mozilla.org/Security/Server_Side_TLS +# - https://www.ssllabs.com/projects/best-practices/index.html +# - https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ +# +# The general intent is: +# - prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE), +# - prefer ECDHE over DHE for better performance, +# - prefer any AES-GCM and ChaCha20 over any AES-CBC for better performance and +# security, +# - prefer AES-GCM over ChaCha20 because hardware-accelerated AES is common, +# - disable NULL authentication, MD5 MACs, DSS, and other +# insecure ciphers for security reasons. +# - NOTE: TLS 1.3 cipher suites are managed through a different interface +# not exposed by CPython (yet!) and are enabled by default if they're available. +DEFAULT_CIPHERS = ":".join( + [ + "ECDHE+AESGCM", + "ECDHE+CHACHA20", + "DHE+AESGCM", + "DHE+CHACHA20", + "ECDH+AESGCM", + "DH+AESGCM", + "ECDH+AES", + "DH+AES", + "RSA+AESGCM", + "RSA+AES", + "!aNULL", + "!eNULL", + "!MD5", + "!DSS", + ] +) + +try: + from ssl import SSLContext # Modern SSL? +except ImportError: + + class SSLContext(object): # Platform-specific: Python 2 + def __init__(self, protocol_version): + self.protocol = protocol_version + # Use default values from a real SSLContext + self.check_hostname = False + self.verify_mode = ssl.CERT_NONE + self.ca_certs = None + self.options = 0 + self.certfile = None + self.keyfile = None + self.ciphers = None + + def load_cert_chain(self, certfile, keyfile): + self.certfile = certfile + self.keyfile = keyfile + + def load_verify_locations(self, cafile=None, capath=None, cadata=None): + self.ca_certs = cafile + + if capath is not None: + raise SSLError("CA directories not supported in older Pythons") + + if cadata is not None: + raise SSLError("CA data not supported in older Pythons") + + def set_ciphers(self, cipher_suite): + self.ciphers = cipher_suite + + def wrap_socket(self, socket, server_hostname=None, server_side=False): + warnings.warn( + "A true SSLContext object is not available. This prevents " + "urllib3 from configuring SSL appropriately and may cause " + "certain SSL connections to fail. You can upgrade to a newer " + "version of Python to solve this. For more information, see " + "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html" + "#ssl-warnings", + InsecurePlatformWarning, + ) + kwargs = { + "keyfile": self.keyfile, + "certfile": self.certfile, + "ca_certs": self.ca_certs, + "cert_reqs": self.verify_mode, + "ssl_version": self.protocol, + "server_side": server_side, + } + return wrap_socket(socket, ciphers=self.ciphers, **kwargs) + + +def assert_fingerprint(cert, fingerprint): + """ + Checks if given fingerprint matches the supplied certificate. + + :param cert: + Certificate as bytes object. + :param fingerprint: + Fingerprint as string of hexdigits, can be interspersed by colons. + """ + + fingerprint = fingerprint.replace(":", "").lower() + digest_length = len(fingerprint) + hashfunc = HASHFUNC_MAP.get(digest_length) + if not hashfunc: + raise SSLError("Fingerprint of invalid length: {0}".format(fingerprint)) + + # We need encode() here for py32; works on py2 and p33. + fingerprint_bytes = unhexlify(fingerprint.encode()) + + cert_digest = hashfunc(cert).digest() + + if not _const_compare_digest(cert_digest, fingerprint_bytes): + raise SSLError( + 'Fingerprints did not match. Expected "{0}", got "{1}".'.format( + fingerprint, hexlify(cert_digest) + ) + ) + + +def resolve_cert_reqs(candidate): + """ + Resolves the argument to a numeric constant, which can be passed to + the wrap_socket function/method from the ssl module. + Defaults to :data:`ssl.CERT_REQUIRED`. + If given a string it is assumed to be the name of the constant in the + :mod:`ssl` module or its abbreviation. + (So you can specify `REQUIRED` instead of `CERT_REQUIRED`. + If it's neither `None` nor a string we assume it is already the numeric + constant which can directly be passed to wrap_socket. + """ + if candidate is None: + return CERT_REQUIRED + + if isinstance(candidate, str): + res = getattr(ssl, candidate, None) + if res is None: + res = getattr(ssl, "CERT_" + candidate) + return res + + return candidate + + +def resolve_ssl_version(candidate): + """ + like resolve_cert_reqs + """ + if candidate is None: + return PROTOCOL_TLS + + if isinstance(candidate, str): + res = getattr(ssl, candidate, None) + if res is None: + res = getattr(ssl, "PROTOCOL_" + candidate) + return res + + return candidate + + +def create_urllib3_context( + ssl_version=None, cert_reqs=None, options=None, ciphers=None +): + """All arguments have the same meaning as ``ssl_wrap_socket``. + + By default, this function does a lot of the same work that + ``ssl.create_default_context`` does on Python 3.4+. It: + + - Disables SSLv2, SSLv3, and compression + - Sets a restricted set of server ciphers + + If you wish to enable SSLv3, you can do:: + + from urllib3.util import ssl_ + context = ssl_.create_urllib3_context() + context.options &= ~ssl_.OP_NO_SSLv3 + + You can do the same to enable compression (substituting ``COMPRESSION`` + for ``SSLv3`` in the last line above). + + :param ssl_version: + The desired protocol version to use. This will default to + PROTOCOL_SSLv23 which will negotiate the highest protocol that both + the server and your installation of OpenSSL support. + :param cert_reqs: + Whether to require the certificate verification. This defaults to + ``ssl.CERT_REQUIRED``. + :param options: + Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``, + ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``, and ``ssl.OP_NO_TICKET``. + :param ciphers: + Which cipher suites to allow the server to select. + :returns: + Constructed SSLContext object with specified options + :rtype: SSLContext + """ + # PROTOCOL_TLS is deprecated in Python 3.10 + if not ssl_version or ssl_version == PROTOCOL_TLS: + ssl_version = PROTOCOL_TLS_CLIENT + + context = SSLContext(ssl_version) + + context.set_ciphers(ciphers or DEFAULT_CIPHERS) + + # Setting the default here, as we may have no ssl module on import + cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs + + if options is None: + options = 0 + # SSLv2 is easily broken and is considered harmful and dangerous + options |= OP_NO_SSLv2 + # SSLv3 has several problems and is now dangerous + options |= OP_NO_SSLv3 + # Disable compression to prevent CRIME attacks for OpenSSL 1.0+ + # (issue #309) + options |= OP_NO_COMPRESSION + # TLSv1.2 only. Unless set explicitly, do not request tickets. + # This may save some bandwidth on wire, and although the ticket is encrypted, + # there is a risk associated with it being on wire, + # if the server is not rotating its ticketing keys properly. + options |= OP_NO_TICKET + + context.options |= options + + # Enable post-handshake authentication for TLS 1.3, see GH #1634. PHA is + # necessary for conditional client cert authentication with TLS 1.3. + # The attribute is None for OpenSSL <= 1.1.0 or does not exist in older + # versions of Python. We only enable on Python 3.7.4+ or if certificate + # verification is enabled to work around Python issue #37428 + # See: https://bugs.python.org/issue37428 + if (cert_reqs == ssl.CERT_REQUIRED or sys.version_info >= (3, 7, 4)) and getattr( + context, "post_handshake_auth", None + ) is not None: + context.post_handshake_auth = True + + def disable_check_hostname(): + if ( + getattr(context, "check_hostname", None) is not None + ): # Platform-specific: Python 3.2 + # We do our own verification, including fingerprints and alternative + # hostnames. So disable it here + context.check_hostname = False + + # The order of the below lines setting verify_mode and check_hostname + # matter due to safe-guards SSLContext has to prevent an SSLContext with + # check_hostname=True, verify_mode=NONE/OPTIONAL. This is made even more + # complex because we don't know whether PROTOCOL_TLS_CLIENT will be used + # or not so we don't know the initial state of the freshly created SSLContext. + if cert_reqs == ssl.CERT_REQUIRED: + context.verify_mode = cert_reqs + disable_check_hostname() + else: + disable_check_hostname() + context.verify_mode = cert_reqs + + # Enable logging of TLS session keys via defacto standard environment variable + # 'SSLKEYLOGFILE', if the feature is available (Python 3.8+). Skip empty values. + if hasattr(context, "keylog_filename"): + sslkeylogfile = os.environ.get("SSLKEYLOGFILE") + if sslkeylogfile: + context.keylog_filename = sslkeylogfile + + return context + + +def ssl_wrap_socket( + sock, + keyfile=None, + certfile=None, + cert_reqs=None, + ca_certs=None, + server_hostname=None, + ssl_version=None, + ciphers=None, + ssl_context=None, + ca_cert_dir=None, + key_password=None, + ca_cert_data=None, + tls_in_tls=False, +): + """ + All arguments except for server_hostname, ssl_context, and ca_cert_dir have + the same meaning as they do when using :func:`ssl.wrap_socket`. + + :param server_hostname: + When SNI is supported, the expected hostname of the certificate + :param ssl_context: + A pre-made :class:`SSLContext` object. If none is provided, one will + be created using :func:`create_urllib3_context`. + :param ciphers: + A string of ciphers we wish the client to support. + :param ca_cert_dir: + A directory containing CA certificates in multiple separate files, as + supported by OpenSSL's -CApath flag or the capath argument to + SSLContext.load_verify_locations(). + :param key_password: + Optional password if the keyfile is encrypted. + :param ca_cert_data: + Optional string containing CA certificates in PEM format suitable for + passing as the cadata parameter to SSLContext.load_verify_locations() + :param tls_in_tls: + Use SSLTransport to wrap the existing socket. + """ + context = ssl_context + if context is None: + # Note: This branch of code and all the variables in it are no longer + # used by urllib3 itself. We should consider deprecating and removing + # this code. + context = create_urllib3_context(ssl_version, cert_reqs, ciphers=ciphers) + + if ca_certs or ca_cert_dir or ca_cert_data: + try: + context.load_verify_locations(ca_certs, ca_cert_dir, ca_cert_data) + except (IOError, OSError) as e: + raise SSLError(e) + + elif ssl_context is None and hasattr(context, "load_default_certs"): + # try to load OS default certs; works well on Windows (require Python3.4+) + context.load_default_certs() + + # Attempt to detect if we get the goofy behavior of the + # keyfile being encrypted and OpenSSL asking for the + # passphrase via the terminal and instead error out. + if keyfile and key_password is None and _is_key_file_encrypted(keyfile): + raise SSLError("Client private key is encrypted, password is required") + + if certfile: + if key_password is None: + context.load_cert_chain(certfile, keyfile) + else: + context.load_cert_chain(certfile, keyfile, key_password) + + try: + if hasattr(context, "set_alpn_protocols"): + context.set_alpn_protocols(ALPN_PROTOCOLS) + except NotImplementedError: # Defensive: in CI, we always have set_alpn_protocols + pass + + # If we detect server_hostname is an IP address then the SNI + # extension should not be used according to RFC3546 Section 3.1 + use_sni_hostname = server_hostname and not is_ipaddress(server_hostname) + # SecureTransport uses server_hostname in certificate verification. + send_sni = (use_sni_hostname and HAS_SNI) or ( + IS_SECURETRANSPORT and server_hostname + ) + # Do not warn the user if server_hostname is an invalid SNI hostname. + if not HAS_SNI and use_sni_hostname: + warnings.warn( + "An HTTPS request has been made, but the SNI (Server Name " + "Indication) extension to TLS is not available on this platform. " + "This may cause the server to present an incorrect TLS " + "certificate, which can cause validation failures. You can upgrade to " + "a newer version of Python to solve this. For more information, see " + "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html" + "#ssl-warnings", + SNIMissingWarning, + ) + + if send_sni: + ssl_sock = _ssl_wrap_socket_impl( + sock, context, tls_in_tls, server_hostname=server_hostname + ) + else: + ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls) + return ssl_sock + + +def is_ipaddress(hostname): + """Detects whether the hostname given is an IPv4 or IPv6 address. + Also detects IPv6 addresses with Zone IDs. + + :param str hostname: Hostname to examine. + :return: True if the hostname is an IP address, False otherwise. + """ + if not six.PY2 and isinstance(hostname, bytes): + # IDN A-label bytes are ASCII compatible. + hostname = hostname.decode("ascii") + return bool(IPV4_RE.match(hostname) or BRACELESS_IPV6_ADDRZ_RE.match(hostname)) + + +def _is_key_file_encrypted(key_file): + """Detects if a key file is encrypted or not.""" + with open(key_file, "r") as f: + for line in f: + # Look for Proc-Type: 4,ENCRYPTED + if "ENCRYPTED" in line: + return True + + return False + + +def _ssl_wrap_socket_impl(sock, ssl_context, tls_in_tls, server_hostname=None): + if tls_in_tls: + if not SSLTransport: + # Import error, ssl is not available. + raise ProxySchemeUnsupported( + "TLS in TLS requires support for the 'ssl' module" + ) + + SSLTransport._validate_ssl_context_for_tls_in_tls(ssl_context) + return SSLTransport(sock, ssl_context, server_hostname) + + if server_hostname: + return ssl_context.wrap_socket(sock, server_hostname=server_hostname) + else: + return ssl_context.wrap_socket(sock) diff --git a/openpype/vendor/python/python_2/urllib3/util/ssl_match_hostname.py b/openpype/vendor/python/python_2/urllib3/util/ssl_match_hostname.py new file mode 100644 index 0000000000..1dd950c489 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/util/ssl_match_hostname.py @@ -0,0 +1,159 @@ +"""The match_hostname() function from Python 3.3.3, essential when using SSL.""" + +# Note: This file is under the PSF license as the code comes from the python +# stdlib. http://docs.python.org/3/license.html + +import re +import sys + +# ipaddress has been backported to 2.6+ in pypi. If it is installed on the +# system, use it to handle IPAddress ServerAltnames (this was added in +# python-3.5) otherwise only do DNS matching. This allows +# util.ssl_match_hostname to continue to be used in Python 2.7. +try: + import ipaddress +except ImportError: + ipaddress = None + +__version__ = "3.5.0.1" + + +class CertificateError(ValueError): + pass + + +def _dnsname_match(dn, hostname, max_wildcards=1): + """Matching according to RFC 6125, section 6.4.3 + + http://tools.ietf.org/html/rfc6125#section-6.4.3 + """ + pats = [] + if not dn: + return False + + # Ported from python3-syntax: + # leftmost, *remainder = dn.split(r'.') + parts = dn.split(r".") + leftmost = parts[0] + remainder = parts[1:] + + wildcards = leftmost.count("*") + if wildcards > max_wildcards: + # Issue #17980: avoid denials of service by refusing more + # than one wildcard per fragment. A survey of established + # policy among SSL implementations showed it to be a + # reasonable choice. + raise CertificateError( + "too many wildcards in certificate DNS name: " + repr(dn) + ) + + # speed up common case w/o wildcards + if not wildcards: + return dn.lower() == hostname.lower() + + # RFC 6125, section 6.4.3, subitem 1. + # The client SHOULD NOT attempt to match a presented identifier in which + # the wildcard character comprises a label other than the left-most label. + if leftmost == "*": + # When '*' is a fragment by itself, it matches a non-empty dotless + # fragment. + pats.append("[^.]+") + elif leftmost.startswith("xn--") or hostname.startswith("xn--"): + # RFC 6125, section 6.4.3, subitem 3. + # The client SHOULD NOT attempt to match a presented identifier + # where the wildcard character is embedded within an A-label or + # U-label of an internationalized domain name. + pats.append(re.escape(leftmost)) + else: + # Otherwise, '*' matches any dotless string, e.g. www* + pats.append(re.escape(leftmost).replace(r"\*", "[^.]*")) + + # add the remaining fragments, ignore any wildcards + for frag in remainder: + pats.append(re.escape(frag)) + + pat = re.compile(r"\A" + r"\.".join(pats) + r"\Z", re.IGNORECASE) + return pat.match(hostname) + + +def _to_unicode(obj): + if isinstance(obj, str) and sys.version_info < (3,): + # ignored flake8 # F821 to support python 2.7 function + obj = unicode(obj, encoding="ascii", errors="strict") # noqa: F821 + return obj + + +def _ipaddress_match(ipname, host_ip): + """Exact matching of IP addresses. + + RFC 6125 explicitly doesn't define an algorithm for this + (section 1.7.2 - "Out of Scope"). + """ + # OpenSSL may add a trailing newline to a subjectAltName's IP address + # Divergence from upstream: ipaddress can't handle byte str + ip = ipaddress.ip_address(_to_unicode(ipname).rstrip()) + return ip == host_ip + + +def match_hostname(cert, hostname): + """Verify that *cert* (in decoded format as returned by + SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 + rules are followed, but IP addresses are not accepted for *hostname*. + + CertificateError is raised on failure. On success, the function + returns nothing. + """ + if not cert: + raise ValueError( + "empty or no certificate, match_hostname needs a " + "SSL socket or SSL context with either " + "CERT_OPTIONAL or CERT_REQUIRED" + ) + try: + # Divergence from upstream: ipaddress can't handle byte str + host_ip = ipaddress.ip_address(_to_unicode(hostname)) + except (UnicodeError, ValueError): + # ValueError: Not an IP address (common case) + # UnicodeError: Divergence from upstream: Have to deal with ipaddress not taking + # byte strings. addresses should be all ascii, so we consider it not + # an ipaddress in this case + host_ip = None + except AttributeError: + # Divergence from upstream: Make ipaddress library optional + if ipaddress is None: + host_ip = None + else: # Defensive + raise + dnsnames = [] + san = cert.get("subjectAltName", ()) + for key, value in san: + if key == "DNS": + if host_ip is None and _dnsname_match(value, hostname): + return + dnsnames.append(value) + elif key == "IP Address": + if host_ip is not None and _ipaddress_match(value, host_ip): + return + dnsnames.append(value) + if not dnsnames: + # The subject is only checked when there is no dNSName entry + # in subjectAltName + for sub in cert.get("subject", ()): + for key, value in sub: + # XXX according to RFC 2818, the most specific Common Name + # must be used. + if key == "commonName": + if _dnsname_match(value, hostname): + return + dnsnames.append(value) + if len(dnsnames) > 1: + raise CertificateError( + "hostname %r " + "doesn't match either of %s" % (hostname, ", ".join(map(repr, dnsnames))) + ) + elif len(dnsnames) == 1: + raise CertificateError("hostname %r doesn't match %r" % (hostname, dnsnames[0])) + else: + raise CertificateError( + "no appropriate commonName or subjectAltName fields were found" + ) diff --git a/openpype/vendor/python/python_2/urllib3/util/ssltransport.py b/openpype/vendor/python/python_2/urllib3/util/ssltransport.py new file mode 100644 index 0000000000..4a7105d179 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/util/ssltransport.py @@ -0,0 +1,221 @@ +import io +import socket +import ssl + +from ..exceptions import ProxySchemeUnsupported +from ..packages import six + +SSL_BLOCKSIZE = 16384 + + +class SSLTransport: + """ + The SSLTransport wraps an existing socket and establishes an SSL connection. + + Contrary to Python's implementation of SSLSocket, it allows you to chain + multiple TLS connections together. It's particularly useful if you need to + implement TLS within TLS. + + The class supports most of the socket API operations. + """ + + @staticmethod + def _validate_ssl_context_for_tls_in_tls(ssl_context): + """ + Raises a ProxySchemeUnsupported if the provided ssl_context can't be used + for TLS in TLS. + + The only requirement is that the ssl_context provides the 'wrap_bio' + methods. + """ + + if not hasattr(ssl_context, "wrap_bio"): + if six.PY2: + raise ProxySchemeUnsupported( + "TLS in TLS requires SSLContext.wrap_bio() which isn't " + "supported on Python 2" + ) + else: + raise ProxySchemeUnsupported( + "TLS in TLS requires SSLContext.wrap_bio() which isn't " + "available on non-native SSLContext" + ) + + def __init__( + self, socket, ssl_context, server_hostname=None, suppress_ragged_eofs=True + ): + """ + Create an SSLTransport around socket using the provided ssl_context. + """ + self.incoming = ssl.MemoryBIO() + self.outgoing = ssl.MemoryBIO() + + self.suppress_ragged_eofs = suppress_ragged_eofs + self.socket = socket + + self.sslobj = ssl_context.wrap_bio( + self.incoming, self.outgoing, server_hostname=server_hostname + ) + + # Perform initial handshake. + self._ssl_io_loop(self.sslobj.do_handshake) + + def __enter__(self): + return self + + def __exit__(self, *_): + self.close() + + def fileno(self): + return self.socket.fileno() + + def read(self, len=1024, buffer=None): + return self._wrap_ssl_read(len, buffer) + + def recv(self, len=1024, flags=0): + if flags != 0: + raise ValueError("non-zero flags not allowed in calls to recv") + return self._wrap_ssl_read(len) + + def recv_into(self, buffer, nbytes=None, flags=0): + if flags != 0: + raise ValueError("non-zero flags not allowed in calls to recv_into") + if buffer and (nbytes is None): + nbytes = len(buffer) + elif nbytes is None: + nbytes = 1024 + return self.read(nbytes, buffer) + + def sendall(self, data, flags=0): + if flags != 0: + raise ValueError("non-zero flags not allowed in calls to sendall") + count = 0 + with memoryview(data) as view, view.cast("B") as byte_view: + amount = len(byte_view) + while count < amount: + v = self.send(byte_view[count:]) + count += v + + def send(self, data, flags=0): + if flags != 0: + raise ValueError("non-zero flags not allowed in calls to send") + response = self._ssl_io_loop(self.sslobj.write, data) + return response + + def makefile( + self, mode="r", buffering=None, encoding=None, errors=None, newline=None + ): + """ + Python's httpclient uses makefile and buffered io when reading HTTP + messages and we need to support it. + + This is unfortunately a copy and paste of socket.py makefile with small + changes to point to the socket directly. + """ + if not set(mode) <= {"r", "w", "b"}: + raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,)) + + writing = "w" in mode + reading = "r" in mode or not writing + assert reading or writing + binary = "b" in mode + rawmode = "" + if reading: + rawmode += "r" + if writing: + rawmode += "w" + raw = socket.SocketIO(self, rawmode) + self.socket._io_refs += 1 + if buffering is None: + buffering = -1 + if buffering < 0: + buffering = io.DEFAULT_BUFFER_SIZE + if buffering == 0: + if not binary: + raise ValueError("unbuffered streams must be binary") + return raw + if reading and writing: + buffer = io.BufferedRWPair(raw, raw, buffering) + elif reading: + buffer = io.BufferedReader(raw, buffering) + else: + assert writing + buffer = io.BufferedWriter(raw, buffering) + if binary: + return buffer + text = io.TextIOWrapper(buffer, encoding, errors, newline) + text.mode = mode + return text + + def unwrap(self): + self._ssl_io_loop(self.sslobj.unwrap) + + def close(self): + self.socket.close() + + def getpeercert(self, binary_form=False): + return self.sslobj.getpeercert(binary_form) + + def version(self): + return self.sslobj.version() + + def cipher(self): + return self.sslobj.cipher() + + def selected_alpn_protocol(self): + return self.sslobj.selected_alpn_protocol() + + def selected_npn_protocol(self): + return self.sslobj.selected_npn_protocol() + + def shared_ciphers(self): + return self.sslobj.shared_ciphers() + + def compression(self): + return self.sslobj.compression() + + def settimeout(self, value): + self.socket.settimeout(value) + + def gettimeout(self): + return self.socket.gettimeout() + + def _decref_socketios(self): + self.socket._decref_socketios() + + def _wrap_ssl_read(self, len, buffer=None): + try: + return self._ssl_io_loop(self.sslobj.read, len, buffer) + except ssl.SSLError as e: + if e.errno == ssl.SSL_ERROR_EOF and self.suppress_ragged_eofs: + return 0 # eof, return 0. + else: + raise + + def _ssl_io_loop(self, func, *args): + """Performs an I/O loop between incoming/outgoing and the socket.""" + should_loop = True + ret = None + + while should_loop: + errno = None + try: + ret = func(*args) + except ssl.SSLError as e: + if e.errno not in (ssl.SSL_ERROR_WANT_READ, ssl.SSL_ERROR_WANT_WRITE): + # WANT_READ, and WANT_WRITE are expected, others are not. + raise e + errno = e.errno + + buf = self.outgoing.read() + self.socket.sendall(buf) + + if errno is None: + should_loop = False + elif errno == ssl.SSL_ERROR_WANT_READ: + buf = self.socket.recv(SSL_BLOCKSIZE) + if buf: + self.incoming.write(buf) + else: + self.incoming.write_eof() + return ret diff --git a/openpype/vendor/python/python_2/urllib3/util/timeout.py b/openpype/vendor/python/python_2/urllib3/util/timeout.py new file mode 100644 index 0000000000..ff69593b05 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/util/timeout.py @@ -0,0 +1,268 @@ +from __future__ import absolute_import + +import time + +# The default socket timeout, used by httplib to indicate that no timeout was +# specified by the user +from socket import _GLOBAL_DEFAULT_TIMEOUT + +from ..exceptions import TimeoutStateError + +# A sentinel value to indicate that no timeout was specified by the user in +# urllib3 +_Default = object() + + +# Use time.monotonic if available. +current_time = getattr(time, "monotonic", time.time) + + +class Timeout(object): + """Timeout configuration. + + Timeouts can be defined as a default for a pool: + + .. code-block:: python + + timeout = Timeout(connect=2.0, read=7.0) + http = PoolManager(timeout=timeout) + response = http.request('GET', 'http://example.com/') + + Or per-request (which overrides the default for the pool): + + .. code-block:: python + + response = http.request('GET', 'http://example.com/', timeout=Timeout(10)) + + Timeouts can be disabled by setting all the parameters to ``None``: + + .. code-block:: python + + no_timeout = Timeout(connect=None, read=None) + response = http.request('GET', 'http://example.com/, timeout=no_timeout) + + + :param total: + This combines the connect and read timeouts into one; the read timeout + will be set to the time leftover from the connect attempt. In the + event that both a connect timeout and a total are specified, or a read + timeout and a total are specified, the shorter timeout will be applied. + + Defaults to None. + + :type total: int, float, or None + + :param connect: + The maximum amount of time (in seconds) to wait for a connection + attempt to a server to succeed. Omitting the parameter will default the + connect timeout to the system default, probably `the global default + timeout in socket.py + `_. + None will set an infinite timeout for connection attempts. + + :type connect: int, float, or None + + :param read: + The maximum amount of time (in seconds) to wait between consecutive + read operations for a response from the server. Omitting the parameter + will default the read timeout to the system default, probably `the + global default timeout in socket.py + `_. + None will set an infinite timeout. + + :type read: int, float, or None + + .. note:: + + Many factors can affect the total amount of time for urllib3 to return + an HTTP response. + + For example, Python's DNS resolver does not obey the timeout specified + on the socket. Other factors that can affect total request time include + high CPU load, high swap, the program running at a low priority level, + or other behaviors. + + In addition, the read and total timeouts only measure the time between + read operations on the socket connecting the client and the server, + not the total amount of time for the request to return a complete + response. For most requests, the timeout is raised because the server + has not sent the first byte in the specified time. This is not always + the case; if a server streams one byte every fifteen seconds, a timeout + of 20 seconds will not trigger, even though the request will take + several minutes to complete. + + If your goal is to cut off any request after a set amount of wall clock + time, consider having a second "watcher" thread to cut off a slow + request. + """ + + #: A sentinel object representing the default timeout value + DEFAULT_TIMEOUT = _GLOBAL_DEFAULT_TIMEOUT + + def __init__(self, total=None, connect=_Default, read=_Default): + self._connect = self._validate_timeout(connect, "connect") + self._read = self._validate_timeout(read, "read") + self.total = self._validate_timeout(total, "total") + self._start_connect = None + + def __repr__(self): + return "%s(connect=%r, read=%r, total=%r)" % ( + type(self).__name__, + self._connect, + self._read, + self.total, + ) + + # __str__ provided for backwards compatibility + __str__ = __repr__ + + @classmethod + def _validate_timeout(cls, value, name): + """Check that a timeout attribute is valid. + + :param value: The timeout value to validate + :param name: The name of the timeout attribute to validate. This is + used to specify in error messages. + :return: The validated and casted version of the given value. + :raises ValueError: If it is a numeric value less than or equal to + zero, or the type is not an integer, float, or None. + """ + if value is _Default: + return cls.DEFAULT_TIMEOUT + + if value is None or value is cls.DEFAULT_TIMEOUT: + return value + + if isinstance(value, bool): + raise ValueError( + "Timeout cannot be a boolean value. It must " + "be an int, float or None." + ) + try: + float(value) + except (TypeError, ValueError): + raise ValueError( + "Timeout value %s was %s, but it must be an " + "int, float or None." % (name, value) + ) + + try: + if value <= 0: + raise ValueError( + "Attempted to set %s timeout to %s, but the " + "timeout cannot be set to a value less " + "than or equal to 0." % (name, value) + ) + except TypeError: + # Python 3 + raise ValueError( + "Timeout value %s was %s, but it must be an " + "int, float or None." % (name, value) + ) + + return value + + @classmethod + def from_float(cls, timeout): + """Create a new Timeout from a legacy timeout value. + + The timeout value used by httplib.py sets the same timeout on the + connect(), and recv() socket requests. This creates a :class:`Timeout` + object that sets the individual timeouts to the ``timeout`` value + passed to this function. + + :param timeout: The legacy timeout value. + :type timeout: integer, float, sentinel default object, or None + :return: Timeout object + :rtype: :class:`Timeout` + """ + return Timeout(read=timeout, connect=timeout) + + def clone(self): + """Create a copy of the timeout object + + Timeout properties are stored per-pool but each request needs a fresh + Timeout object to ensure each one has its own start/stop configured. + + :return: a copy of the timeout object + :rtype: :class:`Timeout` + """ + # We can't use copy.deepcopy because that will also create a new object + # for _GLOBAL_DEFAULT_TIMEOUT, which socket.py uses as a sentinel to + # detect the user default. + return Timeout(connect=self._connect, read=self._read, total=self.total) + + def start_connect(self): + """Start the timeout clock, used during a connect() attempt + + :raises urllib3.exceptions.TimeoutStateError: if you attempt + to start a timer that has been started already. + """ + if self._start_connect is not None: + raise TimeoutStateError("Timeout timer has already been started.") + self._start_connect = current_time() + return self._start_connect + + def get_connect_duration(self): + """Gets the time elapsed since the call to :meth:`start_connect`. + + :return: Elapsed time in seconds. + :rtype: float + :raises urllib3.exceptions.TimeoutStateError: if you attempt + to get duration for a timer that hasn't been started. + """ + if self._start_connect is None: + raise TimeoutStateError( + "Can't get connect duration for timer that has not started." + ) + return current_time() - self._start_connect + + @property + def connect_timeout(self): + """Get the value to use when setting a connection timeout. + + This will be a positive float or integer, the value None + (never timeout), or the default system timeout. + + :return: Connect timeout. + :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None + """ + if self.total is None: + return self._connect + + if self._connect is None or self._connect is self.DEFAULT_TIMEOUT: + return self.total + + return min(self._connect, self.total) + + @property + def read_timeout(self): + """Get the value for the read timeout. + + This assumes some time has elapsed in the connection timeout and + computes the read timeout appropriately. + + If self.total is set, the read timeout is dependent on the amount of + time taken by the connect timeout. If the connection time has not been + established, a :exc:`~urllib3.exceptions.TimeoutStateError` will be + raised. + + :return: Value to use for the read timeout. + :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None + :raises urllib3.exceptions.TimeoutStateError: If :meth:`start_connect` + has not yet been called on this object. + """ + if ( + self.total is not None + and self.total is not self.DEFAULT_TIMEOUT + and self._read is not None + and self._read is not self.DEFAULT_TIMEOUT + ): + # In case the connect timeout has not yet been established. + if self._start_connect is None: + return self._read + return max(0, min(self.total - self.get_connect_duration(), self._read)) + elif self.total is not None and self.total is not self.DEFAULT_TIMEOUT: + return max(0, self.total - self.get_connect_duration()) + else: + return self._read diff --git a/openpype/vendor/python/python_2/urllib3/util/url.py b/openpype/vendor/python/python_2/urllib3/util/url.py new file mode 100644 index 0000000000..81a03da9e3 --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/util/url.py @@ -0,0 +1,432 @@ +from __future__ import absolute_import + +import re +from collections import namedtuple + +from ..exceptions import LocationParseError +from ..packages import six + +url_attrs = ["scheme", "auth", "host", "port", "path", "query", "fragment"] + +# We only want to normalize urls with an HTTP(S) scheme. +# urllib3 infers URLs without a scheme (None) to be http. +NORMALIZABLE_SCHEMES = ("http", "https", None) + +# Almost all of these patterns were derived from the +# 'rfc3986' module: https://github.com/python-hyper/rfc3986 +PERCENT_RE = re.compile(r"%[a-fA-F0-9]{2}") +SCHEME_RE = re.compile(r"^(?:[a-zA-Z][a-zA-Z0-9+-]*:|/)") +URI_RE = re.compile( + r"^(?:([a-zA-Z][a-zA-Z0-9+.-]*):)?" + r"(?://([^\\/?#]*))?" + r"([^?#]*)" + r"(?:\?([^#]*))?" + r"(?:#(.*))?$", + re.UNICODE | re.DOTALL, +) + +IPV4_PAT = r"(?:[0-9]{1,3}\.){3}[0-9]{1,3}" +HEX_PAT = "[0-9A-Fa-f]{1,4}" +LS32_PAT = "(?:{hex}:{hex}|{ipv4})".format(hex=HEX_PAT, ipv4=IPV4_PAT) +_subs = {"hex": HEX_PAT, "ls32": LS32_PAT} +_variations = [ + # 6( h16 ":" ) ls32 + "(?:%(hex)s:){6}%(ls32)s", + # "::" 5( h16 ":" ) ls32 + "::(?:%(hex)s:){5}%(ls32)s", + # [ h16 ] "::" 4( h16 ":" ) ls32 + "(?:%(hex)s)?::(?:%(hex)s:){4}%(ls32)s", + # [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 + "(?:(?:%(hex)s:)?%(hex)s)?::(?:%(hex)s:){3}%(ls32)s", + # [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 + "(?:(?:%(hex)s:){0,2}%(hex)s)?::(?:%(hex)s:){2}%(ls32)s", + # [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 + "(?:(?:%(hex)s:){0,3}%(hex)s)?::%(hex)s:%(ls32)s", + # [ *4( h16 ":" ) h16 ] "::" ls32 + "(?:(?:%(hex)s:){0,4}%(hex)s)?::%(ls32)s", + # [ *5( h16 ":" ) h16 ] "::" h16 + "(?:(?:%(hex)s:){0,5}%(hex)s)?::%(hex)s", + # [ *6( h16 ":" ) h16 ] "::" + "(?:(?:%(hex)s:){0,6}%(hex)s)?::", +] + +UNRESERVED_PAT = r"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._!\-~" +IPV6_PAT = "(?:" + "|".join([x % _subs for x in _variations]) + ")" +ZONE_ID_PAT = "(?:%25|%)(?:[" + UNRESERVED_PAT + "]|%[a-fA-F0-9]{2})+" +IPV6_ADDRZ_PAT = r"\[" + IPV6_PAT + r"(?:" + ZONE_ID_PAT + r")?\]" +REG_NAME_PAT = r"(?:[^\[\]%:/?#]|%[a-fA-F0-9]{2})*" +TARGET_RE = re.compile(r"^(/[^?#]*)(?:\?([^#]*))?(?:#.*)?$") + +IPV4_RE = re.compile("^" + IPV4_PAT + "$") +IPV6_RE = re.compile("^" + IPV6_PAT + "$") +IPV6_ADDRZ_RE = re.compile("^" + IPV6_ADDRZ_PAT + "$") +BRACELESS_IPV6_ADDRZ_RE = re.compile("^" + IPV6_ADDRZ_PAT[2:-2] + "$") +ZONE_ID_RE = re.compile("(" + ZONE_ID_PAT + r")\]$") + +_HOST_PORT_PAT = ("^(%s|%s|%s)(?::([0-9]{0,5}))?$") % ( + REG_NAME_PAT, + IPV4_PAT, + IPV6_ADDRZ_PAT, +) +_HOST_PORT_RE = re.compile(_HOST_PORT_PAT, re.UNICODE | re.DOTALL) + +UNRESERVED_CHARS = set( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-~" +) +SUB_DELIM_CHARS = set("!$&'()*+,;=") +USERINFO_CHARS = UNRESERVED_CHARS | SUB_DELIM_CHARS | {":"} +PATH_CHARS = USERINFO_CHARS | {"@", "/"} +QUERY_CHARS = FRAGMENT_CHARS = PATH_CHARS | {"?"} + + +class Url(namedtuple("Url", url_attrs)): + """ + Data structure for representing an HTTP URL. Used as a return value for + :func:`parse_url`. Both the scheme and host are normalized as they are + both case-insensitive according to RFC 3986. + """ + + __slots__ = () + + def __new__( + cls, + scheme=None, + auth=None, + host=None, + port=None, + path=None, + query=None, + fragment=None, + ): + if path and not path.startswith("/"): + path = "/" + path + if scheme is not None: + scheme = scheme.lower() + 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 + + @property + def netloc(self): + """Network location including host and port""" + if self.port: + return "%s:%d" % (self.host, self.port) + return self.host + + @property + def url(self): + """ + Convert self into a url + + This function should more or less round-trip with :func:`.parse_url`. The + returned url may not be exactly the same as the url inputted to + :func:`.parse_url`, but it should be equivalent by the RFC (e.g., urls + with a blank port will have : removed). + + Example: :: + + >>> U = parse_url('http://google.com/mail/') + >>> U.url + 'http://google.com/mail/' + >>> Url('http', 'username:password', 'host.com', 80, + ... '/path', 'query', 'fragment').url + 'http://username:password@host.com:80/path?query#fragment' + """ + scheme, auth, host, port, path, query, fragment = self + url = u"" + + # We use "is not None" we want things to happen with empty strings (or 0 port) + if scheme is not None: + url += scheme + u"://" + if auth is not None: + url += auth + u"@" + if host is not None: + url += host + if port is not None: + url += u":" + str(port) + if path is not None: + url += path + if query is not None: + url += u"?" + query + if fragment is not None: + url += u"#" + fragment + + return url + + def __str__(self): + return self.url + + +def split_first(s, delims): + """ + .. deprecated:: 1.25 + + 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 _encode_invalid_chars(component, allowed_chars, encoding="utf-8"): + """Percent-encodes a URI component without reapplying + onto an already percent-encoded component. + """ + if component is None: + return component + + component = six.ensure_text(component) + + # Normalize existing percent-encoded bytes. + # Try to see if the component we're encoding is already percent-encoded + # so we can skip all '%' characters but still encode all others. + component, percent_encodings = PERCENT_RE.subn( + lambda match: match.group(0).upper(), component + ) + + uri_bytes = component.encode("utf-8", "surrogatepass") + is_percent_encoded = percent_encodings == uri_bytes.count(b"%") + encoded_component = bytearray() + + for i in range(0, len(uri_bytes)): + # Will return a single character bytestring on both Python 2 & 3 + byte = uri_bytes[i : i + 1] + byte_ord = ord(byte) + if (is_percent_encoded and byte == b"%") or ( + byte_ord < 128 and byte.decode() in allowed_chars + ): + encoded_component += byte + continue + encoded_component.extend(b"%" + (hex(byte_ord)[2:].encode().zfill(2).upper())) + + return encoded_component.decode(encoding) + + +def _remove_path_dot_segments(path): + # See http://tools.ietf.org/html/rfc3986#section-5.2.4 for pseudo-code + segments = path.split("/") # Turn the path into a list of segments + output = [] # Initialize the variable to use to store output + + for segment in segments: + # '.' is the current directory, so ignore it, it is superfluous + if segment == ".": + continue + # Anything other than '..', should be appended to the output + elif segment != "..": + output.append(segment) + # In this case segment == '..', if we can, we should pop the last + # element + elif output: + output.pop() + + # If the path starts with '/' and the output is empty or the first string + # is non-empty + if path.startswith("/") and (not output or output[0]): + output.insert(0, "") + + # If the path starts with '/.' or '/..' ensure we add one more empty + # string to add a trailing '/' + if path.endswith(("/.", "/..")): + output.append("") + + return "/".join(output) + + +def _normalize_host(host, scheme): + if host: + if isinstance(host, six.binary_type): + host = six.ensure_str(host) + + if scheme in NORMALIZABLE_SCHEMES: + is_ipv6 = IPV6_ADDRZ_RE.match(host) + if is_ipv6: + match = ZONE_ID_RE.search(host) + if match: + start, end = match.span(1) + zone_id = host[start:end] + + if zone_id.startswith("%25") and zone_id != "%25": + zone_id = zone_id[3:] + else: + zone_id = zone_id[1:] + zone_id = "%" + _encode_invalid_chars(zone_id, UNRESERVED_CHARS) + return host[:start].lower() + zone_id + host[end:] + else: + return host.lower() + elif not IPV4_RE.match(host): + return six.ensure_str( + b".".join([_idna_encode(label) for label in host.split(".")]) + ) + return host + + +def _idna_encode(name): + if name and any([ord(x) > 128 for x in name]): + try: + import idna + except ImportError: + six.raise_from( + LocationParseError("Unable to parse URL without the 'idna' module"), + None, + ) + try: + return idna.encode(name.lower(), strict=True, std3_rules=True) + except idna.IDNAError: + six.raise_from( + LocationParseError(u"Name '%s' is not a valid IDNA label" % name), None + ) + return name.lower().encode("ascii") + + +def _encode_target(target): + """Percent-encodes a request target so that there are no invalid characters""" + path, query = TARGET_RE.match(target).groups() + target = _encode_invalid_chars(path, PATH_CHARS) + query = _encode_invalid_chars(query, QUERY_CHARS) + if query is not None: + target += "?" + query + return target + + +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. + This parser is RFC 3986 compliant. + + The parser logic and helper functions are based heavily on + work done in the ``rfc3986`` module. + + :param str url: URL to parse into a :class:`.Url` namedtuple. + + Partly backwards-compatible with :mod:`urlparse`. + + Example:: + + >>> parse_url('http://google.com/mail/') + Url(scheme='http', host='google.com', port=None, path='/mail/', ...) + >>> parse_url('google.com:80') + Url(scheme=None, host='google.com', port=80, path=None, ...) + >>> parse_url('/foo?bar') + Url(scheme=None, host=None, port=None, path='/foo', query='bar', ...) + """ + if not url: + # Empty + return Url() + + source_url = url + if not SCHEME_RE.search(url): + url = "//" + url + + try: + scheme, authority, path, query, fragment = URI_RE.match(url).groups() + normalize_uri = scheme is None or scheme.lower() in NORMALIZABLE_SCHEMES + + if scheme: + scheme = scheme.lower() + + if authority: + auth, _, host_port = authority.rpartition("@") + auth = auth or None + host, port = _HOST_PORT_RE.match(host_port).groups() + if auth and normalize_uri: + auth = _encode_invalid_chars(auth, USERINFO_CHARS) + if port == "": + port = None + else: + auth, host, port = None, None, None + + if port is not None: + port = int(port) + if not (0 <= port <= 65535): + raise LocationParseError(url) + + host = _normalize_host(host, scheme) + + if normalize_uri and path: + path = _remove_path_dot_segments(path) + path = _encode_invalid_chars(path, PATH_CHARS) + if normalize_uri and query: + query = _encode_invalid_chars(query, QUERY_CHARS) + if normalize_uri and fragment: + fragment = _encode_invalid_chars(fragment, FRAGMENT_CHARS) + + except (ValueError, AttributeError): + return six.raise_from(LocationParseError(source_url), None) + + # For the sake of backwards compatibility we put empty + # string values for path if there are any defined values + # beyond the path in the URL. + # TODO: Remove this when we break backwards compatibility. + if not path: + if query is not None or fragment is not None: + path = "" + else: + path = None + + # Ensure that each part of the URL is a `str` for + # backwards compatibility. + if isinstance(url, six.text_type): + ensure_func = six.ensure_text + else: + ensure_func = six.ensure_str + + def ensure_type(x): + return x if x is None else ensure_func(x) + + return Url( + scheme=ensure_type(scheme), + auth=ensure_type(auth), + host=ensure_type(host), + port=port, + path=ensure_type(path), + query=ensure_type(query), + fragment=ensure_type(fragment), + ) + + +def get_host(url): + """ + Deprecated. Use :func:`parse_url` instead. + """ + p = parse_url(url) + return p.scheme or "http", p.hostname, p.port diff --git a/openpype/vendor/python/python_2/urllib3/util/wait.py b/openpype/vendor/python/python_2/urllib3/util/wait.py new file mode 100644 index 0000000000..c280646c7b --- /dev/null +++ b/openpype/vendor/python/python_2/urllib3/util/wait.py @@ -0,0 +1,153 @@ +import errno +import select +import sys +from functools import partial + +try: + from time import monotonic +except ImportError: + from time import time as monotonic + +__all__ = ["NoWayToWaitForSocketError", "wait_for_read", "wait_for_write"] + + +class NoWayToWaitForSocketError(Exception): + pass + + +# How should we wait on sockets? +# +# There are two types of APIs you can use for waiting on sockets: the fancy +# modern stateful APIs like epoll/kqueue, and the older stateless APIs like +# select/poll. The stateful APIs are more efficient when you have a lots of +# sockets to keep track of, because you can set them up once and then use them +# lots of times. But we only ever want to wait on a single socket at a time +# and don't want to keep track of state, so the stateless APIs are actually +# more efficient. So we want to use select() or poll(). +# +# Now, how do we choose between select() and poll()? On traditional Unixes, +# select() has a strange calling convention that makes it slow, or fail +# altogether, for high-numbered file descriptors. The point of poll() is to fix +# that, so on Unixes, we prefer poll(). +# +# On Windows, there is no poll() (or at least Python doesn't provide a wrapper +# for it), but that's OK, because on Windows, select() doesn't have this +# strange calling convention; plain select() works fine. +# +# So: on Windows we use select(), and everywhere else we use poll(). We also +# fall back to select() in case poll() is somehow broken or missing. + +if sys.version_info >= (3, 5): + # Modern Python, that retries syscalls by default + def _retry_on_intr(fn, timeout): + return fn(timeout) + + +else: + # Old and broken Pythons. + def _retry_on_intr(fn, timeout): + if timeout is None: + deadline = float("inf") + else: + deadline = monotonic() + timeout + + while True: + try: + return fn(timeout) + # OSError for 3 <= pyver < 3.5, select.error for pyver <= 2.7 + except (OSError, select.error) as e: + # 'e.args[0]' incantation works for both OSError and select.error + if e.args[0] != errno.EINTR: + raise + else: + timeout = deadline - monotonic() + if timeout < 0: + timeout = 0 + if timeout == float("inf"): + timeout = None + continue + + +def select_wait_for_socket(sock, read=False, write=False, timeout=None): + if not read and not write: + raise RuntimeError("must specify at least one of read=True, write=True") + rcheck = [] + wcheck = [] + if read: + rcheck.append(sock) + if write: + wcheck.append(sock) + # When doing a non-blocking connect, most systems signal success by + # marking the socket writable. Windows, though, signals success by marked + # it as "exceptional". We paper over the difference by checking the write + # sockets for both conditions. (The stdlib selectors module does the same + # thing.) + fn = partial(select.select, rcheck, wcheck, wcheck) + rready, wready, xready = _retry_on_intr(fn, timeout) + return bool(rready or wready or xready) + + +def poll_wait_for_socket(sock, read=False, write=False, timeout=None): + if not read and not write: + raise RuntimeError("must specify at least one of read=True, write=True") + mask = 0 + if read: + mask |= select.POLLIN + if write: + mask |= select.POLLOUT + poll_obj = select.poll() + poll_obj.register(sock, mask) + + # For some reason, poll() takes timeout in milliseconds + def do_poll(t): + if t is not None: + t *= 1000 + return poll_obj.poll(t) + + return bool(_retry_on_intr(do_poll, timeout)) + + +def null_wait_for_socket(*args, **kwargs): + raise NoWayToWaitForSocketError("no select-equivalent available") + + +def _have_working_poll(): + # Apparently some systems have a select.poll that fails as soon as you try + # to use it, either due to strange configuration or broken monkeypatching + # from libraries like eventlet/greenlet. + try: + poll_obj = select.poll() + _retry_on_intr(poll_obj.poll, 0) + except (AttributeError, OSError): + return False + else: + return True + + +def wait_for_socket(*args, **kwargs): + # We delay choosing which implementation to use until the first time we're + # called. We could do it at import time, but then we might make the wrong + # decision if someone goes wild with monkeypatching select.poll after + # we're imported. + global wait_for_socket + if _have_working_poll(): + wait_for_socket = poll_wait_for_socket + elif hasattr(select, "select"): + wait_for_socket = select_wait_for_socket + else: # Platform-specific: Appengine. + wait_for_socket = null_wait_for_socket + return wait_for_socket(*args, **kwargs) + + +def wait_for_read(sock, timeout=None): + """Waits for reading to be available on a given socket. + Returns True if the socket is readable, or False if the timeout expired. + """ + return wait_for_socket(sock, read=True, timeout=timeout) + + +def wait_for_write(sock, timeout=None): + """Waits for writing to be available on a given socket. + Returns True if the socket is readable, or False if the timeout expired. + """ + return wait_for_socket(sock, write=True, timeout=timeout) From 1494c09d2aa39a4e8b4e7d480c4b0719b0d2116a Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 8 Jun 2022 16:17:03 +0200 Subject: [PATCH 343/350] added websocket, socketio and engineio into python 2 vendor --- .../python/python_2/engineio/__init__.py | 25 + .../python/python_2/engineio/async_aiohttp.py | 129 ++++ .../python/python_2/engineio/async_asgi.py | 223 ++++++ .../engineio/async_drivers/__init__.py | 0 .../engineio/async_drivers/aiohttp.py | 128 ++++ .../python_2/engineio/async_drivers/asgi.py | 214 ++++++ .../engineio/async_drivers/eventlet.py | 30 + .../python_2/engineio/async_drivers/gevent.py | 63 ++ .../engineio/async_drivers/gevent_uwsgi.py | 156 ++++ .../python_2/engineio/async_drivers/sanic.py | 144 ++++ .../engineio/async_drivers/threading.py | 17 + .../engineio/async_drivers/tornado.py | 184 +++++ .../python_2/engineio/async_eventlet.py | 30 + .../python/python_2/engineio/async_gevent.py | 63 ++ .../python_2/engineio/async_gevent_uwsgi.py | 155 ++++ .../python/python_2/engineio/async_sanic.py | 145 ++++ .../python_2/engineio/async_threading.py | 17 + .../python/python_2/engineio/async_tornado.py | 154 ++++ .../python_2/engineio/asyncio_client.py | 556 ++++++++++++++ .../python_2/engineio/asyncio_server.py | 444 +++++++++++ .../python_2/engineio/asyncio_socket.py | 235 ++++++ .../vendor/python/python_2/engineio/client.py | 641 ++++++++++++++++ .../python/python_2/engineio/exceptions.py | 22 + .../python/python_2/engineio/middleware.py | 87 +++ .../vendor/python/python_2/engineio/packet.py | 92 +++ .../python/python_2/engineio/payload.py | 80 ++ .../vendor/python/python_2/engineio/server.py | 633 +++++++++++++++ .../vendor/python/python_2/engineio/socket.py | 247 ++++++ .../python/python_2/engineio/static_files.py | 55 ++ .../python/python_2/socketio/__init__.py | 35 + .../vendor/python/python_2/socketio/asgi.py | 36 + .../python_2/socketio/asyncio_client.py | 445 +++++++++++ .../python_2/socketio/asyncio_manager.py | 58 ++ .../python_2/socketio/asyncio_namespace.py | 204 +++++ .../socketio/asyncio_pubsub_manager.py | 163 ++++ .../socketio/asyncio_redis_manager.py | 107 +++ .../python_2/socketio/asyncio_server.py | 515 +++++++++++++ .../python/python_2/socketio/base_manager.py | 178 +++++ .../vendor/python/python_2/socketio/client.py | 590 ++++++++++++++ .../python/python_2/socketio/exceptions.py | 26 + .../python/python_2/socketio/kombu_manager.py | 105 +++ .../python/python_2/socketio/middleware.py | 42 + .../python/python_2/socketio/namespace.py | 191 +++++ .../vendor/python/python_2/socketio/packet.py | 179 +++++ .../python_2/socketio/pubsub_manager.py | 154 ++++ .../python/python_2/socketio/redis_manager.py | 111 +++ .../vendor/python/python_2/socketio/server.py | 719 ++++++++++++++++++ .../python/python_2/socketio/tornado.py | 11 + .../python/python_2/socketio/zmq_manager.py | 111 +++ .../python/python_2/websocket/__init__.py | 28 + .../vendor/python/python_2/websocket/_abnf.py | 458 +++++++++++ .../vendor/python/python_2/websocket/_app.py | 399 ++++++++++ .../python/python_2/websocket/_cookiejar.py | 78 ++ .../vendor/python/python_2/websocket/_core.py | 595 +++++++++++++++ .../python/python_2/websocket/_exceptions.py | 86 +++ .../python/python_2/websocket/_handshake.py | 212 ++++++ .../vendor/python/python_2/websocket/_http.py | 335 ++++++++ .../python/python_2/websocket/_logging.py | 92 +++ .../python/python_2/websocket/_socket.py | 176 +++++ .../python/python_2/websocket/_ssl_compat.py | 53 ++ .../vendor/python/python_2/websocket/_url.py | 178 +++++ .../python/python_2/websocket/_utils.py | 110 +++ .../python_2/websocket/tests/__init__.py | 0 .../websocket/tests/data/header01.txt | 6 + .../websocket/tests/data/header02.txt | 6 + .../websocket/tests/data/header03.txt | 6 + .../python_2/websocket/tests/test_abnf.py | 77 ++ .../python_2/websocket/tests/test_app.py | 137 ++++ .../websocket/tests/test_cookiejar.py | 117 +++ .../python_2/websocket/tests/test_http.py | 109 +++ .../python_2/websocket/tests/test_url.py | 309 ++++++++ .../websocket/tests/test_websocket.py | 433 +++++++++++ 72 files changed, 12949 insertions(+) create mode 100644 openpype/vendor/python/python_2/engineio/__init__.py create mode 100644 openpype/vendor/python/python_2/engineio/async_aiohttp.py create mode 100644 openpype/vendor/python/python_2/engineio/async_asgi.py create mode 100644 openpype/vendor/python/python_2/engineio/async_drivers/__init__.py create mode 100644 openpype/vendor/python/python_2/engineio/async_drivers/aiohttp.py create mode 100644 openpype/vendor/python/python_2/engineio/async_drivers/asgi.py create mode 100644 openpype/vendor/python/python_2/engineio/async_drivers/eventlet.py create mode 100644 openpype/vendor/python/python_2/engineio/async_drivers/gevent.py create mode 100644 openpype/vendor/python/python_2/engineio/async_drivers/gevent_uwsgi.py create mode 100644 openpype/vendor/python/python_2/engineio/async_drivers/sanic.py create mode 100644 openpype/vendor/python/python_2/engineio/async_drivers/threading.py create mode 100644 openpype/vendor/python/python_2/engineio/async_drivers/tornado.py create mode 100644 openpype/vendor/python/python_2/engineio/async_eventlet.py create mode 100644 openpype/vendor/python/python_2/engineio/async_gevent.py create mode 100644 openpype/vendor/python/python_2/engineio/async_gevent_uwsgi.py create mode 100644 openpype/vendor/python/python_2/engineio/async_sanic.py create mode 100644 openpype/vendor/python/python_2/engineio/async_threading.py create mode 100644 openpype/vendor/python/python_2/engineio/async_tornado.py create mode 100644 openpype/vendor/python/python_2/engineio/asyncio_client.py create mode 100644 openpype/vendor/python/python_2/engineio/asyncio_server.py create mode 100644 openpype/vendor/python/python_2/engineio/asyncio_socket.py create mode 100644 openpype/vendor/python/python_2/engineio/client.py create mode 100644 openpype/vendor/python/python_2/engineio/exceptions.py create mode 100644 openpype/vendor/python/python_2/engineio/middleware.py create mode 100644 openpype/vendor/python/python_2/engineio/packet.py create mode 100644 openpype/vendor/python/python_2/engineio/payload.py create mode 100644 openpype/vendor/python/python_2/engineio/server.py create mode 100644 openpype/vendor/python/python_2/engineio/socket.py create mode 100644 openpype/vendor/python/python_2/engineio/static_files.py create mode 100644 openpype/vendor/python/python_2/socketio/__init__.py create mode 100644 openpype/vendor/python/python_2/socketio/asgi.py create mode 100644 openpype/vendor/python/python_2/socketio/asyncio_client.py create mode 100644 openpype/vendor/python/python_2/socketio/asyncio_manager.py create mode 100644 openpype/vendor/python/python_2/socketio/asyncio_namespace.py create mode 100644 openpype/vendor/python/python_2/socketio/asyncio_pubsub_manager.py create mode 100644 openpype/vendor/python/python_2/socketio/asyncio_redis_manager.py create mode 100644 openpype/vendor/python/python_2/socketio/asyncio_server.py create mode 100644 openpype/vendor/python/python_2/socketio/base_manager.py create mode 100644 openpype/vendor/python/python_2/socketio/client.py create mode 100644 openpype/vendor/python/python_2/socketio/exceptions.py create mode 100644 openpype/vendor/python/python_2/socketio/kombu_manager.py create mode 100644 openpype/vendor/python/python_2/socketio/middleware.py create mode 100644 openpype/vendor/python/python_2/socketio/namespace.py create mode 100644 openpype/vendor/python/python_2/socketio/packet.py create mode 100644 openpype/vendor/python/python_2/socketio/pubsub_manager.py create mode 100644 openpype/vendor/python/python_2/socketio/redis_manager.py create mode 100644 openpype/vendor/python/python_2/socketio/server.py create mode 100644 openpype/vendor/python/python_2/socketio/tornado.py create mode 100644 openpype/vendor/python/python_2/socketio/zmq_manager.py create mode 100644 openpype/vendor/python/python_2/websocket/__init__.py create mode 100644 openpype/vendor/python/python_2/websocket/_abnf.py create mode 100644 openpype/vendor/python/python_2/websocket/_app.py create mode 100644 openpype/vendor/python/python_2/websocket/_cookiejar.py create mode 100644 openpype/vendor/python/python_2/websocket/_core.py create mode 100644 openpype/vendor/python/python_2/websocket/_exceptions.py create mode 100644 openpype/vendor/python/python_2/websocket/_handshake.py create mode 100644 openpype/vendor/python/python_2/websocket/_http.py create mode 100644 openpype/vendor/python/python_2/websocket/_logging.py create mode 100644 openpype/vendor/python/python_2/websocket/_socket.py create mode 100644 openpype/vendor/python/python_2/websocket/_ssl_compat.py create mode 100644 openpype/vendor/python/python_2/websocket/_url.py create mode 100644 openpype/vendor/python/python_2/websocket/_utils.py create mode 100644 openpype/vendor/python/python_2/websocket/tests/__init__.py create mode 100644 openpype/vendor/python/python_2/websocket/tests/data/header01.txt create mode 100644 openpype/vendor/python/python_2/websocket/tests/data/header02.txt create mode 100644 openpype/vendor/python/python_2/websocket/tests/data/header03.txt create mode 100644 openpype/vendor/python/python_2/websocket/tests/test_abnf.py create mode 100644 openpype/vendor/python/python_2/websocket/tests/test_app.py create mode 100644 openpype/vendor/python/python_2/websocket/tests/test_cookiejar.py create mode 100644 openpype/vendor/python/python_2/websocket/tests/test_http.py create mode 100644 openpype/vendor/python/python_2/websocket/tests/test_url.py create mode 100644 openpype/vendor/python/python_2/websocket/tests/test_websocket.py diff --git a/openpype/vendor/python/python_2/engineio/__init__.py b/openpype/vendor/python/python_2/engineio/__init__.py new file mode 100644 index 0000000000..888bf40190 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/__init__.py @@ -0,0 +1,25 @@ +import sys + +from .client import Client +from .middleware import WSGIApp, Middleware +from .server import Server +if sys.version_info >= (3, 5): # pragma: no cover + from .asyncio_server import AsyncServer + from .asyncio_client import AsyncClient + from .async_drivers.asgi import ASGIApp + try: + from .async_drivers.tornado import get_tornado_handler + except ImportError: + get_tornado_handler = None +else: # pragma: no cover + AsyncServer = None + AsyncClient = None + get_tornado_handler = None + ASGIApp = None + +__version__ = '3.8.2.post1' + +__all__ = ['__version__', 'Server', 'WSGIApp', 'Middleware', 'Client'] +if AsyncServer is not None: # pragma: no cover + __all__ += ['AsyncServer', 'ASGIApp', 'get_tornado_handler', + 'AsyncClient'], diff --git a/openpype/vendor/python/python_2/engineio/async_aiohttp.py b/openpype/vendor/python/python_2/engineio/async_aiohttp.py new file mode 100644 index 0000000000..ad0252dff9 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/async_aiohttp.py @@ -0,0 +1,129 @@ +import asyncio +import sys +from urllib.parse import urlsplit + +from aiohttp.web import Response, WebSocketResponse +import six + + +def create_route(app, engineio_server, engineio_endpoint): + """This function sets up the engine.io endpoint as a route for the + application. + + Note that both GET and POST requests must be hooked up on the engine.io + endpoint. + """ + app.router.add_get(engineio_endpoint, engineio_server.handle_request) + app.router.add_post(engineio_endpoint, engineio_server.handle_request) + app.router.add_route('OPTIONS', engineio_endpoint, + engineio_server.handle_request) + + +def translate_request(request): + """This function takes the arguments passed to the request handler and + uses them to generate a WSGI compatible environ dictionary. + """ + message = request._message + payload = request._payload + + uri_parts = urlsplit(message.path) + environ = { + 'wsgi.input': payload, + 'wsgi.errors': sys.stderr, + 'wsgi.version': (1, 0), + 'wsgi.async': True, + 'wsgi.multithread': False, + 'wsgi.multiprocess': False, + 'wsgi.run_once': False, + 'SERVER_SOFTWARE': 'aiohttp', + 'REQUEST_METHOD': message.method, + 'QUERY_STRING': uri_parts.query or '', + 'RAW_URI': message.path, + 'SERVER_PROTOCOL': 'HTTP/%s.%s' % message.version, + 'REMOTE_ADDR': '127.0.0.1', + 'REMOTE_PORT': '0', + 'SERVER_NAME': 'aiohttp', + 'SERVER_PORT': '0', + 'aiohttp.request': request + } + + for hdr_name, hdr_value in message.headers.items(): + hdr_name = hdr_name.upper() + if hdr_name == 'CONTENT-TYPE': + environ['CONTENT_TYPE'] = hdr_value + continue + elif hdr_name == 'CONTENT-LENGTH': + environ['CONTENT_LENGTH'] = hdr_value + continue + + key = 'HTTP_%s' % hdr_name.replace('-', '_') + if key in environ: + hdr_value = '%s,%s' % (environ[key], hdr_value) + + environ[key] = hdr_value + + environ['wsgi.url_scheme'] = environ.get('HTTP_X_FORWARDED_PROTO', 'http') + + path_info = uri_parts.path + + environ['PATH_INFO'] = path_info + environ['SCRIPT_NAME'] = '' + + return environ + + +def make_response(status, headers, payload, environ): + """This function generates an appropriate response object for this async + mode. + """ + return Response(body=payload, status=int(status.split()[0]), + headers=headers) + + +class WebSocket(object): # pragma: no cover + """ + This wrapper class provides a aiohttp WebSocket interface that is + somewhat compatible with eventlet's implementation. + """ + def __init__(self, handler): + self.handler = handler + self._sock = None + + async def __call__(self, environ): + request = environ['aiohttp.request'] + self._sock = WebSocketResponse() + await self._sock.prepare(request) + + self.environ = environ + await self.handler(self) + return self._sock + + async def close(self): + await self._sock.close() + + async def send(self, message): + if isinstance(message, bytes): + f = self._sock.send_bytes + else: + f = self._sock.send_str + if asyncio.iscoroutinefunction(f): + await f(message) + else: + f(message) + + async def wait(self): + msg = await self._sock.receive() + if not isinstance(msg.data, six.binary_type) and \ + not isinstance(msg.data, six.text_type): + raise IOError() + return msg.data + + +_async = { + 'asyncio': True, + 'create_route': create_route, + 'translate_request': translate_request, + 'make_response': make_response, + 'websocket': sys.modules[__name__], + 'websocket_class': 'WebSocket' +} diff --git a/openpype/vendor/python/python_2/engineio/async_asgi.py b/openpype/vendor/python/python_2/engineio/async_asgi.py new file mode 100644 index 0000000000..d216f31c77 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/async_asgi.py @@ -0,0 +1,223 @@ +import sys + + +class ASGIApp: + """ASGI application middleware for Engine.IO. + + This middleware dispatches traffic to an Engine.IO application. It can + also serve a list of static files to the client, or forward unrelated + HTTP traffic to another ASGI application. + + :param engineio_server: The Engine.IO server. Must be an instance of the + ``engineio.AsyncServer`` class. + :param static_files: A dictionary where the keys are URLs that should be + served as static files. For each URL, the value is + a dictionary with ``content_type`` and ``filename`` + keys. This option is intended to be used for serving + client files during development. + :param other_asgi_app: A separate ASGI app that receives all other traffic. + :param engineio_path: The endpoint where the Engine.IO application should + be installed. The default value is appropriate for + most cases. + + Example usage:: + + import engineio + import uvicorn + + eio = engineio.AsyncServer() + app = engineio.ASGIApp(eio, static_files={ + '/': {'content_type': 'text/html', 'filename': 'index.html'}, + '/index.html': {'content_type': 'text/html', + 'filename': 'index.html'}, + }) + uvicorn.run(app, '127.0.0.1', 5000) + """ + def __init__(self, engineio_server, other_asgi_app=None, + static_files=None, engineio_path='engine.io'): + self.engineio_server = engineio_server + self.other_asgi_app = other_asgi_app + self.engineio_path = engineio_path.strip('/') + self.static_files = static_files or {} + + def __call__(self, scope): + if scope['type'] in ['http', 'websocket'] and \ + scope['path'].startswith('/{0}/'.format(self.engineio_path)): + return self.engineio_asgi_app(scope) + elif scope['type'] == 'http' and scope['path'] in self.static_files: + return self.serve_static_file(scope) + elif self.other_asgi_app is not None: + return self.other_asgi_app(scope) + elif scope['type'] == 'lifespan': + return self.lifespan + else: + return self.not_found + + def engineio_asgi_app(self, scope): + async def _app(receive, send): + await self.engineio_server.handle_request(scope, receive, send) + return _app + + def serve_static_file(self, scope): + async def _send_static_file(receive, send): # pragma: no cover + event = await receive() + if event['type'] == 'http.request': + if scope['path'] in self.static_files: + content_type = self.static_files[scope['path']][ + 'content_type'].encode('utf-8') + filename = self.static_files[scope['path']]['filename'] + status_code = 200 + with open(filename, 'rb') as f: + payload = f.read() + else: + content_type = b'text/plain' + status_code = 404 + payload = b'not found' + await send({'type': 'http.response.start', + 'status': status_code, + 'headers': [(b'Content-Type', content_type)]}) + await send({'type': 'http.response.body', + 'body': payload}) + return _send_static_file + + async def lifespan(self, receive, send): + event = await receive() + if event['type'] == 'lifespan.startup': + await send({'type': 'lifespan.startup.complete'}) + elif event['type'] == 'lifespan.shutdown': + await send({'type': 'lifespan.shutdown.complete'}) + + async def not_found(self, receive, send): + """Return a 404 Not Found error to the client.""" + await send({'type': 'http.response.start', + 'status': 404, + 'headers': [(b'Content-Type', b'text/plain')]}) + await send({'type': 'http.response.body', + 'body': b'not found'}) + + +async def translate_request(scope, receive, send): + class AwaitablePayload(object): # pragma: no cover + def __init__(self, payload): + self.payload = payload or b'' + + async def read(self, length=None): + if length is None: + r = self.payload + self.payload = b'' + else: + r = self.payload[:length] + self.payload = self.payload[length:] + return r + + event = await receive() + payload = b'' + if event['type'] == 'http.request': + payload += event.get('body') or b'' + while event.get('more_body'): + event = await receive() + if event['type'] == 'http.request': + payload += event.get('body') or b'' + elif event['type'] == 'websocket.connect': + await send({'type': 'websocket.accept'}) + else: + return {} + + raw_uri = scope['path'].encode('utf-8') + if 'query_string' in scope and scope['query_string']: + raw_uri += b'?' + scope['query_string'] + environ = { + 'wsgi.input': AwaitablePayload(payload), + 'wsgi.errors': sys.stderr, + 'wsgi.version': (1, 0), + 'wsgi.async': True, + 'wsgi.multithread': False, + 'wsgi.multiprocess': False, + 'wsgi.run_once': False, + 'SERVER_SOFTWARE': 'asgi', + 'REQUEST_METHOD': scope.get('method', 'GET'), + 'PATH_INFO': scope['path'], + 'QUERY_STRING': scope.get('query_string', b'').decode('utf-8'), + 'RAW_URI': raw_uri.decode('utf-8'), + 'SCRIPT_NAME': '', + 'SERVER_PROTOCOL': 'HTTP/1.1', + 'REMOTE_ADDR': '127.0.0.1', + 'REMOTE_PORT': '0', + 'SERVER_NAME': 'asgi', + 'SERVER_PORT': '0', + 'asgi.receive': receive, + 'asgi.send': send, + } + + for hdr_name, hdr_value in scope['headers']: + hdr_name = hdr_name.upper().decode('utf-8') + hdr_value = hdr_value.decode('utf-8') + if hdr_name == 'CONTENT-TYPE': + environ['CONTENT_TYPE'] = hdr_value + continue + elif hdr_name == 'CONTENT-LENGTH': + environ['CONTENT_LENGTH'] = hdr_value + continue + + key = 'HTTP_%s' % hdr_name.replace('-', '_') + if key in environ: + hdr_value = '%s,%s' % (environ[key], hdr_value) + + environ[key] = hdr_value + + environ['wsgi.url_scheme'] = environ.get('HTTP_X_FORWARDED_PROTO', 'http') + return environ + + +async def make_response(status, headers, payload, environ): + headers = [(h[0].encode('utf-8'), h[1].encode('utf-8')) for h in headers] + await environ['asgi.send']({'type': 'http.response.start', + 'status': int(status.split(' ')[0]), + 'headers': headers}) + await environ['asgi.send']({'type': 'http.response.body', + 'body': payload}) + + +class WebSocket(object): # pragma: no cover + """ + This wrapper class provides an asgi WebSocket interface that is + somewhat compatible with eventlet's implementation. + """ + def __init__(self, handler): + self.handler = handler + self.asgi_receive = None + self.asgi_send = None + + async def __call__(self, environ): + self.asgi_receive = environ['asgi.receive'] + self.asgi_send = environ['asgi.send'] + await self.handler(self) + + async def close(self): + await self.asgi_send({'type': 'websocket.close'}) + + async def send(self, message): + msg_bytes = None + msg_text = None + if isinstance(message, bytes): + msg_bytes = message + else: + msg_text = message + await self.asgi_send({'type': 'websocket.send', + 'bytes': msg_bytes, + 'text': msg_text}) + + async def wait(self): + event = await self.asgi_receive() + if event['type'] != 'websocket.receive': + raise IOError() + return event.get('bytes') or event.get('text') + + +_async = { + 'asyncio': True, + 'translate_request': translate_request, + 'make_response': make_response, + 'websocket': sys.modules[__name__], + 'websocket_class': 'WebSocket' +} diff --git a/openpype/vendor/python/python_2/engineio/async_drivers/__init__.py b/openpype/vendor/python/python_2/engineio/async_drivers/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openpype/vendor/python/python_2/engineio/async_drivers/aiohttp.py b/openpype/vendor/python/python_2/engineio/async_drivers/aiohttp.py new file mode 100644 index 0000000000..ad6987649d --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/async_drivers/aiohttp.py @@ -0,0 +1,128 @@ +import asyncio +import sys +from urllib.parse import urlsplit + +from aiohttp.web import Response, WebSocketResponse +import six + + +def create_route(app, engineio_server, engineio_endpoint): + """This function sets up the engine.io endpoint as a route for the + application. + + Note that both GET and POST requests must be hooked up on the engine.io + endpoint. + """ + app.router.add_get(engineio_endpoint, engineio_server.handle_request) + app.router.add_post(engineio_endpoint, engineio_server.handle_request) + app.router.add_route('OPTIONS', engineio_endpoint, + engineio_server.handle_request) + + +def translate_request(request): + """This function takes the arguments passed to the request handler and + uses them to generate a WSGI compatible environ dictionary. + """ + message = request._message + payload = request._payload + + uri_parts = urlsplit(message.path) + environ = { + 'wsgi.input': payload, + 'wsgi.errors': sys.stderr, + 'wsgi.version': (1, 0), + 'wsgi.async': True, + 'wsgi.multithread': False, + 'wsgi.multiprocess': False, + 'wsgi.run_once': False, + 'SERVER_SOFTWARE': 'aiohttp', + 'REQUEST_METHOD': message.method, + 'QUERY_STRING': uri_parts.query or '', + 'RAW_URI': message.path, + 'SERVER_PROTOCOL': 'HTTP/%s.%s' % message.version, + 'REMOTE_ADDR': '127.0.0.1', + 'REMOTE_PORT': '0', + 'SERVER_NAME': 'aiohttp', + 'SERVER_PORT': '0', + 'aiohttp.request': request + } + + for hdr_name, hdr_value in message.headers.items(): + hdr_name = hdr_name.upper() + if hdr_name == 'CONTENT-TYPE': + environ['CONTENT_TYPE'] = hdr_value + continue + elif hdr_name == 'CONTENT-LENGTH': + environ['CONTENT_LENGTH'] = hdr_value + continue + + key = 'HTTP_%s' % hdr_name.replace('-', '_') + if key in environ: + hdr_value = '%s,%s' % (environ[key], hdr_value) + + environ[key] = hdr_value + + environ['wsgi.url_scheme'] = environ.get('HTTP_X_FORWARDED_PROTO', 'http') + + path_info = uri_parts.path + + environ['PATH_INFO'] = path_info + environ['SCRIPT_NAME'] = '' + + return environ + + +def make_response(status, headers, payload, environ): + """This function generates an appropriate response object for this async + mode. + """ + return Response(body=payload, status=int(status.split()[0]), + headers=headers) + + +class WebSocket(object): # pragma: no cover + """ + This wrapper class provides a aiohttp WebSocket interface that is + somewhat compatible with eventlet's implementation. + """ + def __init__(self, handler): + self.handler = handler + self._sock = None + + async def __call__(self, environ): + request = environ['aiohttp.request'] + self._sock = WebSocketResponse() + await self._sock.prepare(request) + + self.environ = environ + await self.handler(self) + return self._sock + + async def close(self): + await self._sock.close() + + async def send(self, message): + if isinstance(message, bytes): + f = self._sock.send_bytes + else: + f = self._sock.send_str + if asyncio.iscoroutinefunction(f): + await f(message) + else: + f(message) + + async def wait(self): + msg = await self._sock.receive() + if not isinstance(msg.data, six.binary_type) and \ + not isinstance(msg.data, six.text_type): + raise IOError() + return msg.data + + +_async = { + 'asyncio': True, + 'create_route': create_route, + 'translate_request': translate_request, + 'make_response': make_response, + 'websocket': WebSocket, +} diff --git a/openpype/vendor/python/python_2/engineio/async_drivers/asgi.py b/openpype/vendor/python/python_2/engineio/async_drivers/asgi.py new file mode 100644 index 0000000000..9f14ef05ff --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/async_drivers/asgi.py @@ -0,0 +1,214 @@ +import os +import sys + +from engineio.static_files import get_static_file + + +class ASGIApp: + """ASGI application middleware for Engine.IO. + + This middleware dispatches traffic to an Engine.IO application. It can + also serve a list of static files to the client, or forward unrelated + HTTP traffic to another ASGI application. + + :param engineio_server: The Engine.IO server. Must be an instance of the + ``engineio.AsyncServer`` class. + :param static_files: A dictionary with static file mapping rules. See the + documentation for details on this argument. + :param other_asgi_app: A separate ASGI app that receives all other traffic. + :param engineio_path: The endpoint where the Engine.IO application should + be installed. The default value is appropriate for + most cases. + + Example usage:: + + import engineio + import uvicorn + + eio = engineio.AsyncServer() + app = engineio.ASGIApp(eio, static_files={ + '/': {'content_type': 'text/html', 'filename': 'index.html'}, + '/index.html': {'content_type': 'text/html', + 'filename': 'index.html'}, + }) + uvicorn.run(app, '127.0.0.1', 5000) + """ + def __init__(self, engineio_server, other_asgi_app=None, + static_files=None, engineio_path='engine.io'): + self.engineio_server = engineio_server + self.other_asgi_app = other_asgi_app + self.engineio_path = engineio_path.strip('/') + self.static_files = static_files or {} + + async def __call__(self, scope, receive, send): + if scope['type'] in ['http', 'websocket'] and \ + scope['path'].startswith('/{0}/'.format(self.engineio_path)): + await self.engineio_server.handle_request(scope, receive, send) + else: + static_file = get_static_file(scope['path'], self.static_files) \ + if scope['type'] == 'http' and self.static_files else None + if static_file: + await self.serve_static_file(static_file, receive, send) + elif self.other_asgi_app is not None: + await self.other_asgi_app(scope, receive, send) + elif scope['type'] == 'lifespan': + await self.lifespan(receive, send) + else: + await self.not_found(receive, send) + + async def serve_static_file(self, static_file, receive, + send): # pragma: no cover + event = await receive() + if event['type'] == 'http.request': + if os.path.exists(static_file['filename']): + with open(static_file['filename'], 'rb') as f: + payload = f.read() + await send({'type': 'http.response.start', + 'status': 200, + 'headers': [(b'Content-Type', static_file[ + 'content_type'].encode('utf-8'))]}) + await send({'type': 'http.response.body', + 'body': payload}) + else: + await self.not_found(receive, send) + + async def lifespan(self, receive, send): + event = await receive() + if event['type'] == 'lifespan.startup': + await send({'type': 'lifespan.startup.complete'}) + elif event['type'] == 'lifespan.shutdown': + await send({'type': 'lifespan.shutdown.complete'}) + + async def not_found(self, receive, send): + """Return a 404 Not Found error to the client.""" + await send({'type': 'http.response.start', + 'status': 404, + 'headers': [(b'Content-Type', b'text/plain')]}) + await send({'type': 'http.response.body', + 'body': b'Not Found'}) + + +async def translate_request(scope, receive, send): + class AwaitablePayload(object): # pragma: no cover + def __init__(self, payload): + self.payload = payload or b'' + + async def read(self, length=None): + if length is None: + r = self.payload + self.payload = b'' + else: + r = self.payload[:length] + self.payload = self.payload[length:] + return r + + event = await receive() + payload = b'' + if event['type'] == 'http.request': + payload += event.get('body') or b'' + while event.get('more_body'): + event = await receive() + if event['type'] == 'http.request': + payload += event.get('body') or b'' + elif event['type'] == 'websocket.connect': + await send({'type': 'websocket.accept'}) + else: + return {} + + raw_uri = scope['path'].encode('utf-8') + if 'query_string' in scope and scope['query_string']: + raw_uri += b'?' + scope['query_string'] + environ = { + 'wsgi.input': AwaitablePayload(payload), + 'wsgi.errors': sys.stderr, + 'wsgi.version': (1, 0), + 'wsgi.async': True, + 'wsgi.multithread': False, + 'wsgi.multiprocess': False, + 'wsgi.run_once': False, + 'SERVER_SOFTWARE': 'asgi', + 'REQUEST_METHOD': scope.get('method', 'GET'), + 'PATH_INFO': scope['path'], + 'QUERY_STRING': scope.get('query_string', b'').decode('utf-8'), + 'RAW_URI': raw_uri.decode('utf-8'), + 'SCRIPT_NAME': '', + 'SERVER_PROTOCOL': 'HTTP/1.1', + 'REMOTE_ADDR': '127.0.0.1', + 'REMOTE_PORT': '0', + 'SERVER_NAME': 'asgi', + 'SERVER_PORT': '0', + 'asgi.receive': receive, + 'asgi.send': send, + } + + for hdr_name, hdr_value in scope['headers']: + hdr_name = hdr_name.upper().decode('utf-8') + hdr_value = hdr_value.decode('utf-8') + if hdr_name == 'CONTENT-TYPE': + environ['CONTENT_TYPE'] = hdr_value + continue + elif hdr_name == 'CONTENT-LENGTH': + environ['CONTENT_LENGTH'] = hdr_value + continue + + key = 'HTTP_%s' % hdr_name.replace('-', '_') + if key in environ: + hdr_value = '%s,%s' % (environ[key], hdr_value) + + environ[key] = hdr_value + + environ['wsgi.url_scheme'] = environ.get('HTTP_X_FORWARDED_PROTO', 'http') + return environ + + +async def make_response(status, headers, payload, environ): + headers = [(h[0].encode('utf-8'), h[1].encode('utf-8')) for h in headers] + await environ['asgi.send']({'type': 'http.response.start', + 'status': int(status.split(' ')[0]), + 'headers': headers}) + await environ['asgi.send']({'type': 'http.response.body', + 'body': payload}) + + +class WebSocket(object): # pragma: no cover + """ + This wrapper class provides an asgi WebSocket interface that is + somewhat compatible with eventlet's implementation. + """ + def __init__(self, handler): + self.handler = handler + self.asgi_receive = None + self.asgi_send = None + + async def __call__(self, environ): + self.asgi_receive = environ['asgi.receive'] + self.asgi_send = environ['asgi.send'] + await self.handler(self) + + async def close(self): + await self.asgi_send({'type': 'websocket.close'}) + + async def send(self, message): + msg_bytes = None + msg_text = None + if isinstance(message, bytes): + msg_bytes = message + else: + msg_text = message + await self.asgi_send({'type': 'websocket.send', + 'bytes': msg_bytes, + 'text': msg_text}) + + async def wait(self): + event = await self.asgi_receive() + if event['type'] != 'websocket.receive': + raise IOError() + return event.get('bytes') or event.get('text') + + +_async = { + 'asyncio': True, + 'translate_request': translate_request, + 'make_response': make_response, + 'websocket': WebSocket, +} diff --git a/openpype/vendor/python/python_2/engineio/async_drivers/eventlet.py b/openpype/vendor/python/python_2/engineio/async_drivers/eventlet.py new file mode 100644 index 0000000000..9be3797cd8 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/async_drivers/eventlet.py @@ -0,0 +1,30 @@ +from __future__ import absolute_import + +from eventlet.green.threading import Thread, Event +from eventlet import queue +from eventlet import sleep +from eventlet.websocket import WebSocketWSGI as _WebSocketWSGI + + +class WebSocketWSGI(_WebSocketWSGI): + def __init__(self, *args, **kwargs): + super(WebSocketWSGI, self).__init__(*args, **kwargs) + self._sock = None + + def __call__(self, environ, start_response): + if 'eventlet.input' not in environ: + raise RuntimeError('You need to use the eventlet server. ' + 'See the Deployment section of the ' + 'documentation for more information.') + self._sock = environ['eventlet.input'].get_socket() + return super(WebSocketWSGI, self).__call__(environ, start_response) + + +_async = { + 'thread': Thread, + 'queue': queue.Queue, + 'queue_empty': queue.Empty, + 'event': Event, + 'websocket': WebSocketWSGI, + 'sleep': sleep, +} diff --git a/openpype/vendor/python/python_2/engineio/async_drivers/gevent.py b/openpype/vendor/python/python_2/engineio/async_drivers/gevent.py new file mode 100644 index 0000000000..024dd0aad5 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/async_drivers/gevent.py @@ -0,0 +1,63 @@ +from __future__ import absolute_import + +import gevent +from gevent import queue +from gevent.event import Event +try: + import geventwebsocket # noqa + _websocket_available = True +except ImportError: + _websocket_available = False + + +class Thread(gevent.Greenlet): # pragma: no cover + """ + This wrapper class provides gevent Greenlet interface that is compatible + with the standard library's Thread class. + """ + def __init__(self, target, args=[], kwargs={}): + super(Thread, self).__init__(target, *args, **kwargs) + + def _run(self): + return self.run() + + +class WebSocketWSGI(object): # pragma: no cover + """ + This wrapper class provides a gevent WebSocket interface that is + compatible with eventlet's implementation. + """ + def __init__(self, app): + self.app = app + + def __call__(self, environ, start_response): + if 'wsgi.websocket' not in environ: + raise RuntimeError('You need to use the gevent-websocket server. ' + 'See the Deployment section of the ' + 'documentation for more information.') + self._sock = environ['wsgi.websocket'] + self.environ = environ + self.version = self._sock.version + self.path = self._sock.path + self.origin = self._sock.origin + self.protocol = self._sock.protocol + return self.app(self) + + def close(self): + return self._sock.close() + + def send(self, message): + return self._sock.send(message) + + def wait(self): + return self._sock.receive() + + +_async = { + 'thread': Thread, + 'queue': queue.JoinableQueue, + 'queue_empty': queue.Empty, + 'event': Event, + 'websocket': WebSocketWSGI if _websocket_available else None, + 'sleep': gevent.sleep, +} diff --git a/openpype/vendor/python/python_2/engineio/async_drivers/gevent_uwsgi.py b/openpype/vendor/python/python_2/engineio/async_drivers/gevent_uwsgi.py new file mode 100644 index 0000000000..07fa2a79df --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/async_drivers/gevent_uwsgi.py @@ -0,0 +1,156 @@ +from __future__ import absolute_import + +import six + +import gevent +from gevent import queue +from gevent.event import Event +import uwsgi +_websocket_available = hasattr(uwsgi, 'websocket_handshake') + + +class Thread(gevent.Greenlet): # pragma: no cover + """ + This wrapper class provides gevent Greenlet interface that is compatible + with the standard library's Thread class. + """ + def __init__(self, target, args=[], kwargs={}): + super(Thread, self).__init__(target, *args, **kwargs) + + def _run(self): + return self.run() + + +class uWSGIWebSocket(object): # pragma: no cover + """ + This wrapper class provides a uWSGI WebSocket interface that is + compatible with eventlet's implementation. + """ + def __init__(self, app): + self.app = app + self._sock = None + + def __call__(self, environ, start_response): + self._sock = uwsgi.connection_fd() + self.environ = environ + + uwsgi.websocket_handshake() + + self._req_ctx = None + if hasattr(uwsgi, 'request_context'): + # uWSGI >= 2.1.x with support for api access across-greenlets + self._req_ctx = uwsgi.request_context() + else: + # use event and queue for sending messages + from gevent.event import Event + from gevent.queue import Queue + from gevent.select import select + self._event = Event() + self._send_queue = Queue() + + # spawn a select greenlet + def select_greenlet_runner(fd, event): + """Sets event when data becomes available to read on fd.""" + while True: + event.set() + try: + select([fd], [], [])[0] + except ValueError: + break + self._select_greenlet = gevent.spawn( + select_greenlet_runner, + self._sock, + self._event) + + self.app(self) + + def close(self): + """Disconnects uWSGI from the client.""" + uwsgi.disconnect() + if self._req_ctx is None: + # better kill it here in case wait() is not called again + self._select_greenlet.kill() + self._event.set() + + def _send(self, msg): + """Transmits message either in binary or UTF-8 text mode, + depending on its type.""" + if isinstance(msg, six.binary_type): + method = uwsgi.websocket_send_binary + else: + method = uwsgi.websocket_send + if self._req_ctx is not None: + method(msg, request_context=self._req_ctx) + else: + method(msg) + + def _decode_received(self, msg): + """Returns either bytes or str, depending on message type.""" + if not isinstance(msg, six.binary_type): + # already decoded - do nothing + return msg + # only decode from utf-8 if message is not binary data + type = six.byte2int(msg[0:1]) + if type >= 48: # no binary + return msg.decode('utf-8') + # binary message, don't try to decode + return msg + + def send(self, msg): + """Queues a message for sending. Real transmission is done in + wait method. + Sends directly if uWSGI version is new enough.""" + if self._req_ctx is not None: + self._send(msg) + else: + self._send_queue.put(msg) + self._event.set() + + def wait(self): + """Waits and returns received messages. + If running in compatibility mode for older uWSGI versions, + it also sends messages that have been queued by send(). + A return value of None means that connection was closed. + This must be called repeatedly. For uWSGI < 2.1.x it must + be called from the main greenlet.""" + while True: + if self._req_ctx is not None: + try: + msg = uwsgi.websocket_recv(request_context=self._req_ctx) + except IOError: # connection closed + return None + return self._decode_received(msg) + else: + # we wake up at least every 3 seconds to let uWSGI + # do its ping/ponging + event_set = self._event.wait(timeout=3) + if event_set: + self._event.clear() + # maybe there is something to send + msgs = [] + while True: + try: + msgs.append(self._send_queue.get(block=False)) + except gevent.queue.Empty: + break + for msg in msgs: + self._send(msg) + # maybe there is something to receive, if not, at least + # ensure uWSGI does its ping/ponging + try: + msg = uwsgi.websocket_recv_nb() + except IOError: # connection closed + self._select_greenlet.kill() + return None + if msg: # message available + return self._decode_received(msg) + + +_async = { + 'thread': Thread, + 'queue': queue.JoinableQueue, + 'queue_empty': queue.Empty, + 'event': Event, + 'websocket': uWSGIWebSocket if _websocket_available else None, + 'sleep': gevent.sleep, +} diff --git a/openpype/vendor/python/python_2/engineio/async_drivers/sanic.py b/openpype/vendor/python/python_2/engineio/async_drivers/sanic.py new file mode 100644 index 0000000000..6929654b92 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/async_drivers/sanic.py @@ -0,0 +1,144 @@ +import sys +from urllib.parse import urlsplit + +from sanic.response import HTTPResponse +try: + from sanic.websocket import WebSocketProtocol +except ImportError: + # the installed version of sanic does not have websocket support + WebSocketProtocol = None +import six + + +def create_route(app, engineio_server, engineio_endpoint): + """This function sets up the engine.io endpoint as a route for the + application. + + Note that both GET and POST requests must be hooked up on the engine.io + endpoint. + """ + app.add_route(engineio_server.handle_request, engineio_endpoint, + methods=['GET', 'POST', 'OPTIONS']) + try: + app.enable_websocket() + except AttributeError: + # ignore, this version does not support websocket + pass + + +def translate_request(request): + """This function takes the arguments passed to the request handler and + uses them to generate a WSGI compatible environ dictionary. + """ + class AwaitablePayload(object): + def __init__(self, payload): + self.payload = payload or b'' + + async def read(self, length=None): + if length is None: + r = self.payload + self.payload = b'' + else: + r = self.payload[:length] + self.payload = self.payload[length:] + return r + + uri_parts = urlsplit(request.url) + environ = { + 'wsgi.input': AwaitablePayload(request.body), + 'wsgi.errors': sys.stderr, + 'wsgi.version': (1, 0), + 'wsgi.async': True, + 'wsgi.multithread': False, + 'wsgi.multiprocess': False, + 'wsgi.run_once': False, + 'SERVER_SOFTWARE': 'sanic', + 'REQUEST_METHOD': request.method, + 'QUERY_STRING': uri_parts.query or '', + 'RAW_URI': request.url, + 'SERVER_PROTOCOL': 'HTTP/' + request.version, + 'REMOTE_ADDR': '127.0.0.1', + 'REMOTE_PORT': '0', + 'SERVER_NAME': 'sanic', + 'SERVER_PORT': '0', + 'sanic.request': request + } + + for hdr_name, hdr_value in request.headers.items(): + hdr_name = hdr_name.upper() + if hdr_name == 'CONTENT-TYPE': + environ['CONTENT_TYPE'] = hdr_value + continue + elif hdr_name == 'CONTENT-LENGTH': + environ['CONTENT_LENGTH'] = hdr_value + continue + + key = 'HTTP_%s' % hdr_name.replace('-', '_') + if key in environ: + hdr_value = '%s,%s' % (environ[key], hdr_value) + + environ[key] = hdr_value + + environ['wsgi.url_scheme'] = environ.get('HTTP_X_FORWARDED_PROTO', 'http') + + path_info = uri_parts.path + + environ['PATH_INFO'] = path_info + environ['SCRIPT_NAME'] = '' + + return environ + + +def make_response(status, headers, payload, environ): + """This function generates an appropriate response object for this async + mode. + """ + headers_dict = {} + content_type = None + for h in headers: + if h[0].lower() == 'content-type': + content_type = h[1] + else: + headers_dict[h[0]] = h[1] + return HTTPResponse(body_bytes=payload, content_type=content_type, + status=int(status.split()[0]), headers=headers_dict) + + +class WebSocket(object): # pragma: no cover + """ + This wrapper class provides a sanic WebSocket interface that is + somewhat compatible with eventlet's implementation. + """ + def __init__(self, handler): + self.handler = handler + self._sock = None + + async def __call__(self, environ): + request = environ['sanic.request'] + protocol = request.transport.get_protocol() + self._sock = await protocol.websocket_handshake(request) + + self.environ = environ + await self.handler(self) + + async def close(self): + await self._sock.close() + + async def send(self, message): + await self._sock.send(message) + + async def wait(self): + data = await self._sock.recv() + if not isinstance(data, six.binary_type) and \ + not isinstance(data, six.text_type): + raise IOError() + return data + + +_async = { + 'asyncio': True, + 'create_route': create_route, + 'translate_request': translate_request, + 'make_response': make_response, + 'websocket': WebSocket if WebSocketProtocol else None, +} diff --git a/openpype/vendor/python/python_2/engineio/async_drivers/threading.py b/openpype/vendor/python/python_2/engineio/async_drivers/threading.py new file mode 100644 index 0000000000..9b53756681 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/async_drivers/threading.py @@ -0,0 +1,17 @@ +from __future__ import absolute_import +import threading +import time + +try: + import queue +except ImportError: # pragma: no cover + import Queue as queue + +_async = { + 'thread': threading.Thread, + 'queue': queue.Queue, + 'queue_empty': queue.Empty, + 'event': threading.Event, + 'websocket': None, + 'sleep': time.sleep, +} diff --git a/openpype/vendor/python/python_2/engineio/async_drivers/tornado.py b/openpype/vendor/python/python_2/engineio/async_drivers/tornado.py new file mode 100644 index 0000000000..adfe18f5a2 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/async_drivers/tornado.py @@ -0,0 +1,184 @@ +import asyncio +import sys +from urllib.parse import urlsplit +from .. import exceptions + +import tornado.web +import tornado.websocket +import six + + +def get_tornado_handler(engineio_server): + class Handler(tornado.websocket.WebSocketHandler): # pragma: no cover + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if isinstance(engineio_server.cors_allowed_origins, + six.string_types): + if engineio_server.cors_allowed_origins == '*': + self.allowed_origins = None + else: + self.allowed_origins = [ + engineio_server.cors_allowed_origins] + else: + self.allowed_origins = engineio_server.cors_allowed_origins + self.receive_queue = asyncio.Queue() + + async def get(self, *args, **kwargs): + if self.request.headers.get('Upgrade', '').lower() == 'websocket': + ret = super().get(*args, **kwargs) + if asyncio.iscoroutine(ret): + await ret + else: + await engineio_server.handle_request(self) + + async def open(self, *args, **kwargs): + # this is the handler for the websocket request + asyncio.ensure_future(engineio_server.handle_request(self)) + + async def post(self, *args, **kwargs): + await engineio_server.handle_request(self) + + async def options(self, *args, **kwargs): + await engineio_server.handle_request(self) + + async def on_message(self, message): + await self.receive_queue.put(message) + + async def get_next_message(self): + return await self.receive_queue.get() + + def on_close(self): + self.receive_queue.put_nowait(None) + + def check_origin(self, origin): + if self.allowed_origins is None or origin in self.allowed_origins: + return True + return super().check_origin(origin) + + def get_compression_options(self): + # enable compression + return {} + + return Handler + + +def translate_request(handler): + """This function takes the arguments passed to the request handler and + uses them to generate a WSGI compatible environ dictionary. + """ + class AwaitablePayload(object): + def __init__(self, payload): + self.payload = payload or b'' + + async def read(self, length=None): + if length is None: + r = self.payload + self.payload = b'' + else: + r = self.payload[:length] + self.payload = self.payload[length:] + return r + + payload = handler.request.body + + uri_parts = urlsplit(handler.request.path) + full_uri = handler.request.path + if handler.request.query: # pragma: no cover + full_uri += '?' + handler.request.query + environ = { + 'wsgi.input': AwaitablePayload(payload), + 'wsgi.errors': sys.stderr, + 'wsgi.version': (1, 0), + 'wsgi.async': True, + 'wsgi.multithread': False, + 'wsgi.multiprocess': False, + 'wsgi.run_once': False, + 'SERVER_SOFTWARE': 'aiohttp', + 'REQUEST_METHOD': handler.request.method, + 'QUERY_STRING': handler.request.query or '', + 'RAW_URI': full_uri, + 'SERVER_PROTOCOL': 'HTTP/%s' % handler.request.version, + 'REMOTE_ADDR': '127.0.0.1', + 'REMOTE_PORT': '0', + 'SERVER_NAME': 'aiohttp', + 'SERVER_PORT': '0', + 'tornado.handler': handler + } + + for hdr_name, hdr_value in handler.request.headers.items(): + hdr_name = hdr_name.upper() + if hdr_name == 'CONTENT-TYPE': + environ['CONTENT_TYPE'] = hdr_value + continue + elif hdr_name == 'CONTENT-LENGTH': + environ['CONTENT_LENGTH'] = hdr_value + continue + + key = 'HTTP_%s' % hdr_name.replace('-', '_') + environ[key] = hdr_value + + environ['wsgi.url_scheme'] = environ.get('HTTP_X_FORWARDED_PROTO', 'http') + + path_info = uri_parts.path + + environ['PATH_INFO'] = path_info + environ['SCRIPT_NAME'] = '' + + return environ + + +def make_response(status, headers, payload, environ): + """This function generates an appropriate response object for this async + mode. + """ + tornado_handler = environ['tornado.handler'] + try: + tornado_handler.set_status(int(status.split()[0])) + except RuntimeError: # pragma: no cover + # for websocket connections Tornado does not accept a response, since + # it already emitted the 101 status code + return + for header, value in headers: + tornado_handler.set_header(header, value) + tornado_handler.write(payload) + tornado_handler.finish() + + +class WebSocket(object): # pragma: no cover + """ + This wrapper class provides a tornado WebSocket interface that is + somewhat compatible with eventlet's implementation. + """ + def __init__(self, handler): + self.handler = handler + self.tornado_handler = None + + async def __call__(self, environ): + self.tornado_handler = environ['tornado.handler'] + self.environ = environ + await self.handler(self) + + async def close(self): + self.tornado_handler.close() + + async def send(self, message): + try: + self.tornado_handler.write_message( + message, binary=isinstance(message, bytes)) + except tornado.websocket.WebSocketClosedError: + raise exceptions.EngineIOError() + + async def wait(self): + msg = await self.tornado_handler.get_next_message() + if not isinstance(msg, six.binary_type) and \ + not isinstance(msg, six.text_type): + raise IOError() + return msg + + +_async = { + 'asyncio': True, + 'translate_request': translate_request, + 'make_response': make_response, + 'websocket': WebSocket, +} diff --git a/openpype/vendor/python/python_2/engineio/async_eventlet.py b/openpype/vendor/python/python_2/engineio/async_eventlet.py new file mode 100644 index 0000000000..042a67499b --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/async_eventlet.py @@ -0,0 +1,30 @@ +import importlib +import sys + +from eventlet import sleep +from eventlet.websocket import WebSocketWSGI as _WebSocketWSGI + + +class WebSocketWSGI(_WebSocketWSGI): + def __init__(self, *args, **kwargs): + super(WebSocketWSGI, self).__init__(*args, **kwargs) + self._sock = None + + def __call__(self, environ, start_response): + if 'eventlet.input' not in environ: + raise RuntimeError('You need to use the eventlet server. ' + 'See the Deployment section of the ' + 'documentation for more information.') + self._sock = environ['eventlet.input'].get_socket() + return super(WebSocketWSGI, self).__call__(environ, start_response) + + +_async = { + 'threading': importlib.import_module('eventlet.green.threading'), + 'thread_class': 'Thread', + 'queue': importlib.import_module('eventlet.queue'), + 'queue_class': 'Queue', + 'websocket': sys.modules[__name__], + 'websocket_class': 'WebSocketWSGI', + 'sleep': sleep +} diff --git a/openpype/vendor/python/python_2/engineio/async_gevent.py b/openpype/vendor/python/python_2/engineio/async_gevent.py new file mode 100644 index 0000000000..34a9e43ce3 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/async_gevent.py @@ -0,0 +1,63 @@ +import importlib +import sys + +import gevent +try: + import geventwebsocket # noqa + _websocket_available = True +except ImportError: + _websocket_available = False + + +class Thread(gevent.Greenlet): # pragma: no cover + """ + This wrapper class provides gevent Greenlet interface that is compatible + with the standard library's Thread class. + """ + def __init__(self, target, args=[], kwargs={}): + super(Thread, self).__init__(target, *args, **kwargs) + + def _run(self): + return self.run() + + +class WebSocketWSGI(object): # pragma: no cover + """ + This wrapper class provides a gevent WebSocket interface that is + compatible with eventlet's implementation. + """ + def __init__(self, app): + self.app = app + + def __call__(self, environ, start_response): + if 'wsgi.websocket' not in environ: + raise RuntimeError('You need to use the gevent-websocket server. ' + 'See the Deployment section of the ' + 'documentation for more information.') + self._sock = environ['wsgi.websocket'] + self.environ = environ + self.version = self._sock.version + self.path = self._sock.path + self.origin = self._sock.origin + self.protocol = self._sock.protocol + return self.app(self) + + def close(self): + return self._sock.close() + + def send(self, message): + return self._sock.send(message) + + def wait(self): + return self._sock.receive() + + +_async = { + 'threading': sys.modules[__name__], + 'thread_class': 'Thread', + 'queue': importlib.import_module('gevent.queue'), + 'queue_class': 'JoinableQueue', + 'websocket': sys.modules[__name__] if _websocket_available else None, + 'websocket_class': 'WebSocketWSGI' if _websocket_available else None, + 'sleep': gevent.sleep +} diff --git a/openpype/vendor/python/python_2/engineio/async_gevent_uwsgi.py b/openpype/vendor/python/python_2/engineio/async_gevent_uwsgi.py new file mode 100644 index 0000000000..d2d6983893 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/async_gevent_uwsgi.py @@ -0,0 +1,155 @@ +import importlib +import sys +import six + +import gevent +import uwsgi +_websocket_available = hasattr(uwsgi, 'websocket_handshake') + + +class Thread(gevent.Greenlet): # pragma: no cover + """ + This wrapper class provides gevent Greenlet interface that is compatible + with the standard library's Thread class. + """ + def __init__(self, target, args=[], kwargs={}): + super(Thread, self).__init__(target, *args, **kwargs) + + def _run(self): + return self.run() + + +class uWSGIWebSocket(object): # pragma: no cover + """ + This wrapper class provides a uWSGI WebSocket interface that is + compatible with eventlet's implementation. + """ + def __init__(self, app): + self.app = app + self._sock = None + + def __call__(self, environ, start_response): + self._sock = uwsgi.connection_fd() + self.environ = environ + + uwsgi.websocket_handshake() + + self._req_ctx = None + if hasattr(uwsgi, 'request_context'): + # uWSGI >= 2.1.x with support for api access across-greenlets + self._req_ctx = uwsgi.request_context() + else: + # use event and queue for sending messages + from gevent.event import Event + from gevent.queue import Queue + from gevent.select import select + self._event = Event() + self._send_queue = Queue() + + # spawn a select greenlet + def select_greenlet_runner(fd, event): + """Sets event when data becomes available to read on fd.""" + while True: + event.set() + try: + select([fd], [], [])[0] + except ValueError: + break + self._select_greenlet = gevent.spawn( + select_greenlet_runner, + self._sock, + self._event) + + self.app(self) + + def close(self): + """Disconnects uWSGI from the client.""" + uwsgi.disconnect() + if self._req_ctx is None: + # better kill it here in case wait() is not called again + self._select_greenlet.kill() + self._event.set() + + def _send(self, msg): + """Transmits message either in binary or UTF-8 text mode, + depending on its type.""" + if isinstance(msg, six.binary_type): + method = uwsgi.websocket_send_binary + else: + method = uwsgi.websocket_send + if self._req_ctx is not None: + method(msg, request_context=self._req_ctx) + else: + method(msg) + + def _decode_received(self, msg): + """Returns either bytes or str, depending on message type.""" + if not isinstance(msg, six.binary_type): + # already decoded - do nothing + return msg + # only decode from utf-8 if message is not binary data + type = six.byte2int(msg[0:1]) + if type >= 48: # no binary + return msg.decode('utf-8') + # binary message, don't try to decode + return msg + + def send(self, msg): + """Queues a message for sending. Real transmission is done in + wait method. + Sends directly if uWSGI version is new enough.""" + if self._req_ctx is not None: + self._send(msg) + else: + self._send_queue.put(msg) + self._event.set() + + def wait(self): + """Waits and returns received messages. + If running in compatibility mode for older uWSGI versions, + it also sends messages that have been queued by send(). + A return value of None means that connection was closed. + This must be called repeatedly. For uWSGI < 2.1.x it must + be called from the main greenlet.""" + while True: + if self._req_ctx is not None: + try: + msg = uwsgi.websocket_recv(request_context=self._req_ctx) + except IOError: # connection closed + return None + return self._decode_received(msg) + else: + # we wake up at least every 3 seconds to let uWSGI + # do its ping/ponging + event_set = self._event.wait(timeout=3) + if event_set: + self._event.clear() + # maybe there is something to send + msgs = [] + while True: + try: + msgs.append(self._send_queue.get(block=False)) + except gevent.queue.Empty: + break + for msg in msgs: + self._send(msg) + # maybe there is something to receive, if not, at least + # ensure uWSGI does its ping/ponging + try: + msg = uwsgi.websocket_recv_nb() + except IOError: # connection closed + self._select_greenlet.kill() + return None + if msg: # message available + return self._decode_received(msg) + + +_async = { + 'threading': sys.modules[__name__], + 'thread_class': 'Thread', + 'queue': importlib.import_module('gevent.queue'), + 'queue_class': 'JoinableQueue', + 'websocket': sys.modules[__name__] if _websocket_available else None, + 'websocket_class': 'uWSGIWebSocket' if _websocket_available else None, + 'sleep': gevent.sleep +} diff --git a/openpype/vendor/python/python_2/engineio/async_sanic.py b/openpype/vendor/python/python_2/engineio/async_sanic.py new file mode 100644 index 0000000000..d150aac0e6 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/async_sanic.py @@ -0,0 +1,145 @@ +import sys +from urllib.parse import urlsplit + +from sanic.response import HTTPResponse +try: + from sanic.websocket import WebSocketProtocol +except ImportError: + # the installed version of sanic does not have websocket support + WebSocketProtocol = None +import six + + +def create_route(app, engineio_server, engineio_endpoint): + """This function sets up the engine.io endpoint as a route for the + application. + + Note that both GET and POST requests must be hooked up on the engine.io + endpoint. + """ + app.add_route(engineio_server.handle_request, engineio_endpoint, + methods=['GET', 'POST', 'OPTIONS']) + try: + app.enable_websocket() + except AttributeError: + # ignore, this version does not support websocket + pass + + +def translate_request(request): + """This function takes the arguments passed to the request handler and + uses them to generate a WSGI compatible environ dictionary. + """ + class AwaitablePayload(object): + def __init__(self, payload): + self.payload = payload or b'' + + async def read(self, length=None): + if length is None: + r = self.payload + self.payload = b'' + else: + r = self.payload[:length] + self.payload = self.payload[length:] + return r + + uri_parts = urlsplit(request.url) + environ = { + 'wsgi.input': AwaitablePayload(request.body), + 'wsgi.errors': sys.stderr, + 'wsgi.version': (1, 0), + 'wsgi.async': True, + 'wsgi.multithread': False, + 'wsgi.multiprocess': False, + 'wsgi.run_once': False, + 'SERVER_SOFTWARE': 'sanic', + 'REQUEST_METHOD': request.method, + 'QUERY_STRING': uri_parts.query or '', + 'RAW_URI': request.url, + 'SERVER_PROTOCOL': 'HTTP/' + request.version, + 'REMOTE_ADDR': '127.0.0.1', + 'REMOTE_PORT': '0', + 'SERVER_NAME': 'sanic', + 'SERVER_PORT': '0', + 'sanic.request': request + } + + for hdr_name, hdr_value in request.headers.items(): + hdr_name = hdr_name.upper() + if hdr_name == 'CONTENT-TYPE': + environ['CONTENT_TYPE'] = hdr_value + continue + elif hdr_name == 'CONTENT-LENGTH': + environ['CONTENT_LENGTH'] = hdr_value + continue + + key = 'HTTP_%s' % hdr_name.replace('-', '_') + if key in environ: + hdr_value = '%s,%s' % (environ[key], hdr_value) + + environ[key] = hdr_value + + environ['wsgi.url_scheme'] = environ.get('HTTP_X_FORWARDED_PROTO', 'http') + + path_info = uri_parts.path + + environ['PATH_INFO'] = path_info + environ['SCRIPT_NAME'] = '' + + return environ + + +def make_response(status, headers, payload, environ): + """This function generates an appropriate response object for this async + mode. + """ + headers_dict = {} + content_type = None + for h in headers: + if h[0].lower() == 'content-type': + content_type = h[1] + else: + headers_dict[h[0]] = h[1] + return HTTPResponse(body_bytes=payload, content_type=content_type, + status=int(status.split()[0]), headers=headers_dict) + + +class WebSocket(object): # pragma: no cover + """ + This wrapper class provides a sanic WebSocket interface that is + somewhat compatible with eventlet's implementation. + """ + def __init__(self, handler): + self.handler = handler + self._sock = None + + async def __call__(self, environ): + request = environ['sanic.request'] + protocol = request.transport.get_protocol() + self._sock = await protocol.websocket_handshake(request) + + self.environ = environ + await self.handler(self) + + async def close(self): + await self._sock.close() + + async def send(self, message): + await self._sock.send(message) + + async def wait(self): + data = await self._sock.recv() + if not isinstance(data, six.binary_type) and \ + not isinstance(data, six.text_type): + raise IOError() + return data + + +_async = { + 'asyncio': True, + 'create_route': create_route, + 'translate_request': translate_request, + 'make_response': make_response, + 'websocket': sys.modules[__name__] if WebSocketProtocol else None, + 'websocket_class': 'WebSocket' if WebSocketProtocol else None +} diff --git a/openpype/vendor/python/python_2/engineio/async_threading.py b/openpype/vendor/python/python_2/engineio/async_threading.py new file mode 100644 index 0000000000..fb458b07af --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/async_threading.py @@ -0,0 +1,17 @@ +import importlib +import time + +try: + queue = importlib.import_module('queue') +except ImportError: # pragma: no cover + queue = importlib.import_module('Queue') # pragma: no cover + +_async = { + 'threading': importlib.import_module('threading'), + 'thread_class': 'Thread', + 'queue': queue, + 'queue_class': 'Queue', + 'websocket': None, + 'websocket_class': None, + 'sleep': time.sleep +} diff --git a/openpype/vendor/python/python_2/engineio/async_tornado.py b/openpype/vendor/python/python_2/engineio/async_tornado.py new file mode 100644 index 0000000000..4b4f9c7572 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/async_tornado.py @@ -0,0 +1,154 @@ +import asyncio +import sys +from urllib.parse import urlsplit + +try: + import tornado.web + import tornado.websocket +except ImportError: # pragma: no cover + pass +import six + + +def get_tornado_handler(engineio_server): + class Handler(tornado.websocket.WebSocketHandler): # pragma: no cover + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.receive_queue = asyncio.Queue() + + async def get(self): + if self.request.headers.get('Upgrade', '').lower() == 'websocket': + super().get() + await engineio_server.handle_request(self) + + async def post(self): + await engineio_server.handle_request(self) + + async def options(self): + await engineio_server.handle_request(self) + + async def on_message(self, message): + await self.receive_queue.put(message) + + async def get_next_message(self): + return await self.receive_queue.get() + + def on_close(self): + self.receive_queue.put_nowait(None) + + return Handler + + +def translate_request(handler): + """This function takes the arguments passed to the request handler and + uses them to generate a WSGI compatible environ dictionary. + """ + class AwaitablePayload(object): + def __init__(self, payload): + self.payload = payload or b'' + + async def read(self, length=None): + if length is None: + r = self.payload + self.payload = b'' + else: + r = self.payload[:length] + self.payload = self.payload[length:] + return r + + payload = handler.request.body + + uri_parts = urlsplit(handler.request.path) + full_uri = handler.request.path + if handler.request.query: # pragma: no cover + full_uri += '?' + handler.request.query + environ = { + 'wsgi.input': AwaitablePayload(payload), + 'wsgi.errors': sys.stderr, + 'wsgi.version': (1, 0), + 'wsgi.async': True, + 'wsgi.multithread': False, + 'wsgi.multiprocess': False, + 'wsgi.run_once': False, + 'SERVER_SOFTWARE': 'aiohttp', + 'REQUEST_METHOD': handler.request.method, + 'QUERY_STRING': handler.request.query or '', + 'RAW_URI': full_uri, + 'SERVER_PROTOCOL': 'HTTP/%s' % handler.request.version, + 'REMOTE_ADDR': '127.0.0.1', + 'REMOTE_PORT': '0', + 'SERVER_NAME': 'aiohttp', + 'SERVER_PORT': '0', + 'tornado.handler': handler + } + + for hdr_name, hdr_value in handler.request.headers.items(): + hdr_name = hdr_name.upper() + if hdr_name == 'CONTENT-TYPE': + environ['CONTENT_TYPE'] = hdr_value + continue + elif hdr_name == 'CONTENT-LENGTH': + environ['CONTENT_LENGTH'] = hdr_value + continue + + key = 'HTTP_%s' % hdr_name.replace('-', '_') + environ[key] = hdr_value + + environ['wsgi.url_scheme'] = environ.get('HTTP_X_FORWARDED_PROTO', 'http') + + path_info = uri_parts.path + + environ['PATH_INFO'] = path_info + environ['SCRIPT_NAME'] = '' + + return environ + + +def make_response(status, headers, payload, environ): + """This function generates an appropriate response object for this async + mode. + """ + tornado_handler = environ['tornado.handler'] + tornado_handler.set_status(int(status.split()[0])) + for header, value in headers: + tornado_handler.set_header(header, value) + tornado_handler.write(payload) + tornado_handler.finish() + + +class WebSocket(object): # pragma: no cover + """ + This wrapper class provides a tornado WebSocket interface that is + somewhat compatible with eventlet's implementation. + """ + def __init__(self, handler): + self.handler = handler + self.tornado_handler = None + + async def __call__(self, environ): + self.tornado_handler = environ['tornado.handler'] + self.environ = environ + await self.handler(self) + + async def close(self): + self.tornado_handler.close() + + async def send(self, message): + self.tornado_handler.write_message( + message, binary=isinstance(message, bytes)) + + async def wait(self): + msg = await self.tornado_handler.get_next_message() + if not isinstance(msg, six.binary_type) and \ + not isinstance(msg, six.text_type): + raise IOError() + return msg + + +_async = { + 'asyncio': True, + 'translate_request': translate_request, + 'make_response': make_response, + 'websocket': sys.modules[__name__], + 'websocket_class': 'WebSocket' +} diff --git a/openpype/vendor/python/python_2/engineio/asyncio_client.py b/openpype/vendor/python/python_2/engineio/asyncio_client.py new file mode 100644 index 0000000000..340cf278b7 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/asyncio_client.py @@ -0,0 +1,556 @@ +import asyncio + +try: + import aiohttp +except ImportError: # pragma: no cover + aiohttp = None +import six +try: + import websockets +except ImportError: # pragma: no cover + websockets = None + +from . import client +from . import exceptions +from . import packet +from . import payload + + +class AsyncClient(client.Client): + """An Engine.IO client for asyncio. + + This class implements a fully compliant Engine.IO web client with support + for websocket and long-polling transports, compatible with the asyncio + framework on Python 3.5 or newer. + + :param logger: To enable logging set to ``True`` or pass a logger object to + use. To disable logging set to ``False``. The default is + ``False``. + :param json: An alternative json module to use for encoding and decoding + packets. Custom json modules must have ``dumps`` and ``loads`` + functions that are compatible with the standard library + versions. + """ + def is_asyncio_based(self): + return True + + async def connect(self, url, headers={}, transports=None, + engineio_path='engine.io'): + """Connect to an Engine.IO server. + + :param url: The URL of the Engine.IO server. It can include custom + query string parameters if required by the server. + :param headers: A dictionary with custom headers to send with the + connection request. + :param transports: The list of allowed transports. Valid transports + are ``'polling'`` and ``'websocket'``. If not + given, the polling transport is connected first, + then an upgrade to websocket is attempted. + :param engineio_path: The endpoint where the Engine.IO server is + installed. The default value is appropriate for + most cases. + + Note: this method is a coroutine. + + Example usage:: + + eio = engineio.Client() + await eio.connect('http://localhost:5000') + """ + if self.state != 'disconnected': + raise ValueError('Client is not in a disconnected state') + valid_transports = ['polling', 'websocket'] + if transports is not None: + if isinstance(transports, six.text_type): + transports = [transports] + transports = [transport for transport in transports + if transport in valid_transports] + if not transports: + raise ValueError('No valid transports provided') + self.transports = transports or valid_transports + self.queue = self.create_queue() + return await getattr(self, '_connect_' + self.transports[0])( + url, headers, engineio_path) + + async def wait(self): + """Wait until the connection with the server ends. + + Client applications can use this function to block the main thread + during the life of the connection. + + Note: this method is a coroutine. + """ + if self.read_loop_task: + await self.read_loop_task + + async def send(self, data, binary=None): + """Send a message to a client. + + :param data: The data to send to the client. Data can be of type + ``str``, ``bytes``, ``list`` or ``dict``. If a ``list`` + or ``dict``, the data will be serialized as JSON. + :param binary: ``True`` to send packet as binary, ``False`` to send + as text. If not given, unicode (Python 2) and str + (Python 3) are sent as text, and str (Python 2) and + bytes (Python 3) are sent as binary. + + Note: this method is a coroutine. + """ + await self._send_packet(packet.Packet(packet.MESSAGE, data=data, + binary=binary)) + + async def disconnect(self, abort=False): + """Disconnect from the server. + + :param abort: If set to ``True``, do not wait for background tasks + associated with the connection to end. + + Note: this method is a coroutine. + """ + if self.state == 'connected': + await self._send_packet(packet.Packet(packet.CLOSE)) + await self.queue.put(None) + self.state = 'disconnecting' + await self._trigger_event('disconnect', run_async=False) + if self.current_transport == 'websocket': + await self.ws.close() + if not abort: + await self.read_loop_task + self.state = 'disconnected' + try: + client.connected_clients.remove(self) + except ValueError: # pragma: no cover + pass + self._reset() + + def start_background_task(self, target, *args, **kwargs): + """Start a background task. + + This is a utility function that applications can use to start a + background task. + + :param target: the target function to execute. + :param args: arguments to pass to the function. + :param kwargs: keyword arguments to pass to the function. + + This function returns an object compatible with the `Thread` class in + the Python standard library. The `start()` method on this object is + already called by this function. + + Note: this method is a coroutine. + """ + return asyncio.ensure_future(target(*args, **kwargs)) + + async def sleep(self, seconds=0): + """Sleep for the requested amount of time. + + Note: this method is a coroutine. + """ + return await asyncio.sleep(seconds) + + def create_queue(self): + """Create a queue object.""" + q = asyncio.Queue() + q.Empty = asyncio.QueueEmpty + return q + + def create_event(self): + """Create an event object.""" + return asyncio.Event() + + def _reset(self): + if self.http: # pragma: no cover + asyncio.ensure_future(self.http.close()) + super()._reset() + + async def _connect_polling(self, url, headers, engineio_path): + """Establish a long-polling connection to the Engine.IO server.""" + if aiohttp is None: # pragma: no cover + self.logger.error('aiohttp not installed -- cannot make HTTP ' + 'requests!') + return + self.base_url = self._get_engineio_url(url, engineio_path, 'polling') + self.logger.info('Attempting polling connection to ' + self.base_url) + r = await self._send_request( + 'GET', self.base_url + self._get_url_timestamp(), headers=headers) + if r is None: + self._reset() + raise exceptions.ConnectionError( + 'Connection refused by the server') + if r.status != 200: + raise exceptions.ConnectionError( + 'Unexpected status code {} in server response'.format( + r.status)) + try: + p = payload.Payload(encoded_payload=await r.read()) + except ValueError: + six.raise_from(exceptions.ConnectionError( + 'Unexpected response from server'), None) + open_packet = p.packets[0] + if open_packet.packet_type != packet.OPEN: + raise exceptions.ConnectionError( + 'OPEN packet not returned by server') + self.logger.info( + 'Polling connection accepted with ' + str(open_packet.data)) + self.sid = open_packet.data['sid'] + self.upgrades = open_packet.data['upgrades'] + self.ping_interval = open_packet.data['pingInterval'] / 1000.0 + self.ping_timeout = open_packet.data['pingTimeout'] / 1000.0 + self.current_transport = 'polling' + self.base_url += '&sid=' + self.sid + + self.state = 'connected' + client.connected_clients.append(self) + await self._trigger_event('connect', run_async=False) + + for pkt in p.packets[1:]: + await self._receive_packet(pkt) + + if 'websocket' in self.upgrades and 'websocket' in self.transports: + # attempt to upgrade to websocket + if await self._connect_websocket(url, headers, engineio_path): + # upgrade to websocket succeeded, we're done here + return + + self.ping_loop_task = self.start_background_task(self._ping_loop) + self.write_loop_task = self.start_background_task(self._write_loop) + self.read_loop_task = self.start_background_task( + self._read_loop_polling) + + async def _connect_websocket(self, url, headers, engineio_path): + """Establish or upgrade to a WebSocket connection with the server.""" + if websockets is None: # pragma: no cover + self.logger.error('websockets package not installed') + return False + websocket_url = self._get_engineio_url(url, engineio_path, + 'websocket') + if self.sid: + self.logger.info( + 'Attempting WebSocket upgrade to ' + websocket_url) + upgrade = True + websocket_url += '&sid=' + self.sid + else: + upgrade = False + self.base_url = websocket_url + self.logger.info( + 'Attempting WebSocket connection to ' + websocket_url) + + # get the cookies from the long-polling connection so that they can + # also be sent the the WebSocket route + cookies = None + if self.http: + cookies = '; '.join(["{}={}".format(cookie.key, cookie.value) + for cookie in self.http._cookie_jar]) + headers = headers.copy() + headers['Cookie'] = cookies + + try: + ws = await websockets.connect( + websocket_url + self._get_url_timestamp(), + extra_headers=headers) + except (websockets.exceptions.InvalidURI, + websockets.exceptions.InvalidHandshake): + if upgrade: + self.logger.warning( + 'WebSocket upgrade failed: connection error') + return False + else: + raise exceptions.ConnectionError('Connection error') + if upgrade: + p = packet.Packet(packet.PING, data='probe').encode( + always_bytes=False) + try: + await ws.send(p) + except Exception as e: # pragma: no cover + self.logger.warning( + 'WebSocket upgrade failed: unexpected send exception: %s', + str(e)) + return False + try: + p = await ws.recv() + except Exception as e: # pragma: no cover + self.logger.warning( + 'WebSocket upgrade failed: unexpected recv exception: %s', + str(e)) + return False + pkt = packet.Packet(encoded_packet=p) + if pkt.packet_type != packet.PONG or pkt.data != 'probe': + self.logger.warning( + 'WebSocket upgrade failed: no PONG packet') + return False + p = packet.Packet(packet.UPGRADE).encode(always_bytes=False) + try: + await ws.send(p) + except Exception as e: # pragma: no cover + self.logger.warning( + 'WebSocket upgrade failed: unexpected send exception: %s', + str(e)) + return False + self.current_transport = 'websocket' + if self.http: # pragma: no cover + await self.http.close() + self.logger.info('WebSocket upgrade was successful') + else: + try: + p = await ws.recv() + except Exception as e: # pragma: no cover + raise exceptions.ConnectionError( + 'Unexpected recv exception: ' + str(e)) + open_packet = packet.Packet(encoded_packet=p) + if open_packet.packet_type != packet.OPEN: + raise exceptions.ConnectionError('no OPEN packet') + self.logger.info( + 'WebSocket connection accepted with ' + str(open_packet.data)) + self.sid = open_packet.data['sid'] + self.upgrades = open_packet.data['upgrades'] + self.ping_interval = open_packet.data['pingInterval'] / 1000.0 + self.ping_timeout = open_packet.data['pingTimeout'] / 1000.0 + self.current_transport = 'websocket' + + self.state = 'connected' + client.connected_clients.append(self) + await self._trigger_event('connect', run_async=False) + + self.ws = ws + self.ping_loop_task = self.start_background_task(self._ping_loop) + self.write_loop_task = self.start_background_task(self._write_loop) + self.read_loop_task = self.start_background_task( + self._read_loop_websocket) + return True + + async def _receive_packet(self, pkt): + """Handle incoming packets from the server.""" + packet_name = packet.packet_names[pkt.packet_type] \ + if pkt.packet_type < len(packet.packet_names) else 'UNKNOWN' + self.logger.info( + 'Received packet %s data %s', packet_name, + pkt.data if not isinstance(pkt.data, bytes) else '') + if pkt.packet_type == packet.MESSAGE: + await self._trigger_event('message', pkt.data, run_async=True) + elif pkt.packet_type == packet.PONG: + self.pong_received = True + elif pkt.packet_type == packet.CLOSE: + await self.disconnect(abort=True) + elif pkt.packet_type == packet.NOOP: + pass + else: + self.logger.error('Received unexpected packet of type %s', + pkt.packet_type) + + async def _send_packet(self, pkt): + """Queue a packet to be sent to the server.""" + if self.state != 'connected': + return + await self.queue.put(pkt) + self.logger.info( + 'Sending packet %s data %s', + packet.packet_names[pkt.packet_type], + pkt.data if not isinstance(pkt.data, bytes) else '') + + async def _send_request( + self, method, url, headers=None, body=None): # pragma: no cover + if self.http is None or self.http.closed: + self.http = aiohttp.ClientSession() + method = getattr(self.http, method.lower()) + try: + return await method(url, headers=headers, data=body) + except aiohttp.ClientError: + return + + async def _trigger_event(self, event, *args, **kwargs): + """Invoke an event handler.""" + run_async = kwargs.pop('run_async', False) + ret = None + if event in self.handlers: + if asyncio.iscoroutinefunction(self.handlers[event]) is True: + if run_async: + return self.start_background_task(self.handlers[event], + *args) + else: + try: + ret = await self.handlers[event](*args) + except asyncio.CancelledError: # pragma: no cover + pass + except: + self.logger.exception(event + ' async handler error') + if event == 'connect': + # if connect handler raised error we reject the + # connection + return False + else: + if run_async: + async def async_handler(): + return self.handlers[event](*args) + + return self.start_background_task(async_handler) + else: + try: + ret = self.handlers[event](*args) + except: + self.logger.exception(event + ' handler error') + if event == 'connect': + # if connect handler raised error we reject the + # connection + return False + return ret + + async def _ping_loop(self): + """This background task sends a PING to the server at the requested + interval. + """ + self.pong_received = True + self.ping_loop_event.clear() + while self.state == 'connected': + if not self.pong_received: + self.logger.info( + 'PONG response has not been received, aborting') + if self.ws: + await self.ws.close() + await self.queue.put(None) + break + self.pong_received = False + await self._send_packet(packet.Packet(packet.PING)) + try: + await asyncio.wait_for(self.ping_loop_event.wait(), + self.ping_interval) + except (asyncio.TimeoutError, + asyncio.CancelledError): # pragma: no cover + pass + self.logger.info('Exiting ping task') + + async def _read_loop_polling(self): + """Read packets by polling the Engine.IO server.""" + while self.state == 'connected': + self.logger.info( + 'Sending polling GET request to ' + self.base_url) + r = await self._send_request( + 'GET', self.base_url + self._get_url_timestamp()) + if r is None: + self.logger.warning( + 'Connection refused by the server, aborting') + await self.queue.put(None) + break + if r.status != 200: + self.logger.warning('Unexpected status code %s in server ' + 'response, aborting', r.status) + await self.queue.put(None) + break + try: + p = payload.Payload(encoded_payload=await r.read()) + except ValueError: + self.logger.warning( + 'Unexpected packet from server, aborting') + await self.queue.put(None) + break + for pkt in p.packets: + await self._receive_packet(pkt) + + self.logger.info('Waiting for write loop task to end') + await self.write_loop_task + self.logger.info('Waiting for ping loop task to end') + self.ping_loop_event.set() + await self.ping_loop_task + if self.state == 'connected': + await self._trigger_event('disconnect', run_async=False) + try: + client.connected_clients.remove(self) + except ValueError: # pragma: no cover + pass + self._reset() + self.logger.info('Exiting read loop task') + + async def _read_loop_websocket(self): + """Read packets from the Engine.IO WebSocket connection.""" + while self.state == 'connected': + p = None + try: + p = await self.ws.recv() + except websockets.exceptions.ConnectionClosed: + self.logger.info( + 'Read loop: WebSocket connection was closed, aborting') + await self.queue.put(None) + break + except Exception as e: + self.logger.info( + 'Unexpected error "%s", aborting', str(e)) + await self.queue.put(None) + break + if isinstance(p, six.text_type): # pragma: no cover + p = p.encode('utf-8') + pkt = packet.Packet(encoded_packet=p) + await self._receive_packet(pkt) + + self.logger.info('Waiting for write loop task to end') + await self.write_loop_task + self.logger.info('Waiting for ping loop task to end') + self.ping_loop_event.set() + await self.ping_loop_task + if self.state == 'connected': + await self._trigger_event('disconnect', run_async=False) + try: + client.connected_clients.remove(self) + except ValueError: # pragma: no cover + pass + self._reset() + self.logger.info('Exiting read loop task') + + async def _write_loop(self): + """This background task sends packages to the server as they are + pushed to the send queue. + """ + while self.state == 'connected': + # to simplify the timeout handling, use the maximum of the + # ping interval and ping timeout as timeout, with an extra 5 + # seconds grace period + timeout = max(self.ping_interval, self.ping_timeout) + 5 + packets = None + try: + packets = [await asyncio.wait_for(self.queue.get(), timeout)] + except (self.queue.Empty, asyncio.TimeoutError, + asyncio.CancelledError): + self.logger.error('packet queue is empty, aborting') + break + if packets == [None]: + self.queue.task_done() + packets = [] + else: + while True: + try: + packets.append(self.queue.get_nowait()) + except self.queue.Empty: + break + if packets[-1] is None: + packets = packets[:-1] + self.queue.task_done() + break + if not packets: + # empty packet list returned -> connection closed + break + if self.current_transport == 'polling': + p = payload.Payload(packets=packets) + r = await self._send_request( + 'POST', self.base_url, body=p.encode(), + headers={'Content-Type': 'application/octet-stream'}) + for pkt in packets: + self.queue.task_done() + if r is None: + self.logger.warning( + 'Connection refused by the server, aborting') + break + if r.status != 200: + self.logger.warning('Unexpected status code %s in server ' + 'response, aborting', r.status) + self._reset() + break + else: + # websocket + try: + for pkt in packets: + await self.ws.send(pkt.encode(always_bytes=False)) + self.queue.task_done() + except websockets.exceptions.ConnectionClosed: + self.logger.info( + 'Write loop: WebSocket connection was closed, ' + 'aborting') + break + self.logger.info('Exiting write loop task') diff --git a/openpype/vendor/python/python_2/engineio/asyncio_server.py b/openpype/vendor/python/python_2/engineio/asyncio_server.py new file mode 100644 index 0000000000..cc5ed8007c --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/asyncio_server.py @@ -0,0 +1,444 @@ +import asyncio + +import six +from six.moves import urllib + +from . import exceptions +from . import packet +from . import server +from . import asyncio_socket + + +class AsyncServer(server.Server): + """An Engine.IO server for asyncio. + + This class implements a fully compliant Engine.IO web server with support + for websocket and long-polling transports, compatible with the asyncio + framework on Python 3.5 or newer. + + :param async_mode: The asynchronous model to use. See the Deployment + section in the documentation for a description of the + available options. Valid async modes are "aiohttp", + "sanic", "tornado" and "asgi". If this argument is not + given, "aiohttp" is tried first, followed by "sanic", + "tornado", and finally "asgi". The first async mode that + has all its dependencies installed is the one that is + chosen. + :param ping_timeout: The time in seconds that the client waits for the + server to respond before disconnecting. + :param ping_interval: The interval in seconds at which the client pings + the server. + :param max_http_buffer_size: The maximum size of a message when using the + polling transport. + :param allow_upgrades: Whether to allow transport upgrades or not. + :param http_compression: Whether to compress packages when using the + polling transport. + :param compression_threshold: Only compress messages when their byte size + is greater than this value. + :param cookie: Name of the HTTP cookie that contains the client session + id. If set to ``None``, a cookie is not sent to the client. + :param cors_allowed_origins: List of origins that are allowed to connect + to this server. All origins are allowed by + default. + :param cors_credentials: Whether credentials (cookies, authentication) are + allowed in requests to this server. + :param logger: To enable logging set to ``True`` or pass a logger object to + use. To disable logging set to ``False``. + :param json: An alternative json module to use for encoding and decoding + packets. Custom json modules must have ``dumps`` and ``loads`` + functions that are compatible with the standard library + versions. + :param async_handlers: If set to ``True``, run message event handlers in + non-blocking threads. To run handlers synchronously, + set to ``False``. The default is ``True``. + :param kwargs: Reserved for future extensions, any additional parameters + given as keyword arguments will be silently ignored. + """ + def is_asyncio_based(self): + return True + + def async_modes(self): + return ['aiohttp', 'sanic', 'tornado', 'asgi'] + + def attach(self, app, engineio_path='engine.io'): + """Attach the Engine.IO server to an application.""" + engineio_path = engineio_path.strip('/') + self._async['create_route'](app, self, '/{}/'.format(engineio_path)) + + async def send(self, sid, data, binary=None): + """Send a message to a client. + + :param sid: The session id of the recipient client. + :param data: The data to send to the client. Data can be of type + ``str``, ``bytes``, ``list`` or ``dict``. If a ``list`` + or ``dict``, the data will be serialized as JSON. + :param binary: ``True`` to send packet as binary, ``False`` to send + as text. If not given, unicode (Python 2) and str + (Python 3) are sent as text, and str (Python 2) and + bytes (Python 3) are sent as binary. + + Note: this method is a coroutine. + """ + try: + socket = self._get_socket(sid) + except KeyError: + # the socket is not available + self.logger.warning('Cannot send to sid %s', sid) + return + await socket.send(packet.Packet(packet.MESSAGE, data=data, + binary=binary)) + + async def get_session(self, sid): + """Return the user session for a client. + + :param sid: The session id of the client. + + The return value is a dictionary. Modifications made to this + dictionary are not guaranteed to be preserved. If you want to modify + the user session, use the ``session`` context manager instead. + """ + socket = self._get_socket(sid) + return socket.session + + async def save_session(self, sid, session): + """Store the user session for a client. + + :param sid: The session id of the client. + :param session: The session dictionary. + """ + socket = self._get_socket(sid) + socket.session = session + + def session(self, sid): + """Return the user session for a client with context manager syntax. + + :param sid: The session id of the client. + + This is a context manager that returns the user session dictionary for + the client. Any changes that are made to this dictionary inside the + context manager block are saved back to the session. Example usage:: + + @eio.on('connect') + def on_connect(sid, environ): + username = authenticate_user(environ) + if not username: + return False + with eio.session(sid) as session: + session['username'] = username + + @eio.on('message') + def on_message(sid, msg): + async with eio.session(sid) as session: + print('received message from ', session['username']) + """ + class _session_context_manager(object): + def __init__(self, server, sid): + self.server = server + self.sid = sid + self.session = None + + async def __aenter__(self): + self.session = await self.server.get_session(sid) + return self.session + + async def __aexit__(self, *args): + await self.server.save_session(sid, self.session) + + return _session_context_manager(self, sid) + + async def disconnect(self, sid=None): + """Disconnect a client. + + :param sid: The session id of the client to close. If this parameter + is not given, then all clients are closed. + + Note: this method is a coroutine. + """ + if sid is not None: + try: + socket = self._get_socket(sid) + except KeyError: # pragma: no cover + # the socket was already closed or gone + pass + else: + await socket.close() + del self.sockets[sid] + else: + await asyncio.wait([client.close() + for client in six.itervalues(self.sockets)]) + self.sockets = {} + + async def handle_request(self, *args, **kwargs): + """Handle an HTTP request from the client. + + This is the entry point of the Engine.IO application. This function + returns the HTTP response to deliver to the client. + + Note: this method is a coroutine. + """ + translate_request = self._async['translate_request'] + if asyncio.iscoroutinefunction(translate_request): + environ = await translate_request(*args, **kwargs) + else: + environ = translate_request(*args, **kwargs) + method = environ['REQUEST_METHOD'] + query = urllib.parse.parse_qs(environ.get('QUERY_STRING', '')) + + sid = query['sid'][0] if 'sid' in query else None + b64 = False + jsonp = False + jsonp_index = None + + if 'b64' in query: + if query['b64'][0] == "1" or query['b64'][0].lower() == "true": + b64 = True + if 'j' in query: + jsonp = True + try: + jsonp_index = int(query['j'][0]) + except (ValueError, KeyError, IndexError): + # Invalid JSONP index number + pass + + if jsonp and jsonp_index is None: + self.logger.warning('Invalid JSONP index number') + r = self._bad_request() + elif method == 'GET': + if sid is None: + transport = query.get('transport', ['polling'])[0] + if transport != 'polling' and transport != 'websocket': + self.logger.warning('Invalid transport %s', transport) + r = self._bad_request() + else: + r = await self._handle_connect(environ, transport, + b64, jsonp_index) + else: + if sid not in self.sockets: + self.logger.warning('Invalid session %s', sid) + r = self._bad_request() + else: + socket = self._get_socket(sid) + try: + packets = await socket.handle_get_request(environ) + if isinstance(packets, list): + r = self._ok(packets, b64=b64, + jsonp_index=jsonp_index) + else: + r = packets + except exceptions.EngineIOError: + if sid in self.sockets: # pragma: no cover + await self.disconnect(sid) + r = self._bad_request() + if sid in self.sockets and self.sockets[sid].closed: + del self.sockets[sid] + elif method == 'POST': + if sid is None or sid not in self.sockets: + self.logger.warning('Invalid session %s', sid) + r = self._bad_request() + else: + socket = self._get_socket(sid) + try: + await socket.handle_post_request(environ) + r = self._ok(jsonp_index=jsonp_index) + except exceptions.EngineIOError: + if sid in self.sockets: # pragma: no cover + await self.disconnect(sid) + r = self._bad_request() + except: # pragma: no cover + # for any other unexpected errors, we log the error + # and keep going + self.logger.exception('post request handler error') + r = self._ok(jsonp_index=jsonp_index) + elif method == 'OPTIONS': + r = self._ok() + else: + self.logger.warning('Method %s not supported', method) + r = self._method_not_found() + if not isinstance(r, dict): + return r + if self.http_compression and \ + len(r['response']) >= self.compression_threshold: + encodings = [e.split(';')[0].strip() for e in + environ.get('HTTP_ACCEPT_ENCODING', '').split(',')] + for encoding in encodings: + if encoding in self.compression_methods: + r['response'] = \ + getattr(self, '_' + encoding)(r['response']) + r['headers'] += [('Content-Encoding', encoding)] + break + cors_headers = self._cors_headers(environ) + make_response = self._async['make_response'] + if asyncio.iscoroutinefunction(make_response): + response = await make_response(r['status'], + r['headers'] + cors_headers, + r['response'], environ) + else: + response = make_response(r['status'], r['headers'] + cors_headers, + r['response'], environ) + return response + + def start_background_task(self, target, *args, **kwargs): + """Start a background task using the appropriate async model. + + This is a utility function that applications can use to start a + background task using the method that is compatible with the + selected async mode. + + :param target: the target function to execute. + :param args: arguments to pass to the function. + :param kwargs: keyword arguments to pass to the function. + + The return value is a ``asyncio.Task`` object. + """ + return asyncio.ensure_future(target(*args, **kwargs)) + + async def sleep(self, seconds=0): + """Sleep for the requested amount of time using the appropriate async + model. + + This is a utility function that applications can use to put a task to + sleep without having to worry about using the correct call for the + selected async mode. + + Note: this method is a coroutine. + """ + return await asyncio.sleep(seconds) + + def create_queue(self, *args, **kwargs): + """Create a queue object using the appropriate async model. + + This is a utility function that applications can use to create a queue + without having to worry about using the correct call for the selected + async mode. For asyncio based async modes, this returns an instance of + ``asyncio.Queue``. + """ + return asyncio.Queue(*args, **kwargs) + + def get_queue_empty_exception(self): + """Return the queue empty exception for the appropriate async model. + + This is a utility function that applications can use to work with a + queue without having to worry about using the correct call for the + selected async mode. For asyncio based async modes, this returns an + instance of ``asyncio.QueueEmpty``. + """ + return asyncio.QueueEmpty + + def create_event(self, *args, **kwargs): + """Create an event object using the appropriate async model. + + This is a utility function that applications can use to create an + event without having to worry about using the correct call for the + selected async mode. For asyncio based async modes, this returns + an instance of ``asyncio.Event``. + """ + return asyncio.Event(*args, **kwargs) + + async def _handle_connect(self, environ, transport, b64=False, + jsonp_index=None): + """Handle a client connection request.""" + if self.start_service_task: + # start the service task to monitor connected clients + self.start_service_task = False + self.start_background_task(self._service_task) + + sid = self._generate_id() + s = asyncio_socket.AsyncSocket(self, sid) + self.sockets[sid] = s + + pkt = packet.Packet( + packet.OPEN, {'sid': sid, + 'upgrades': self._upgrades(sid, transport), + 'pingTimeout': int(self.ping_timeout * 1000), + 'pingInterval': int(self.ping_interval * 1000)}) + await s.send(pkt) + + ret = await self._trigger_event('connect', sid, environ, + run_async=False) + if ret is False: + del self.sockets[sid] + self.logger.warning('Application rejected connection') + return self._unauthorized() + + if transport == 'websocket': + ret = await s.handle_get_request(environ) + if s.closed: + # websocket connection ended, so we are done + del self.sockets[sid] + return ret + else: + s.connected = True + headers = None + if self.cookie: + headers = [('Set-Cookie', self.cookie + '=' + sid)] + try: + return self._ok(await s.poll(), headers=headers, b64=b64, + jsonp_index=jsonp_index) + except exceptions.QueueEmpty: + return self._bad_request() + + async def _trigger_event(self, event, *args, **kwargs): + """Invoke an event handler.""" + run_async = kwargs.pop('run_async', False) + ret = None + if event in self.handlers: + if asyncio.iscoroutinefunction(self.handlers[event]) is True: + if run_async: + return self.start_background_task(self.handlers[event], + *args) + else: + try: + ret = await self.handlers[event](*args) + except asyncio.CancelledError: # pragma: no cover + pass + except: + self.logger.exception(event + ' async handler error') + if event == 'connect': + # if connect handler raised error we reject the + # connection + return False + else: + if run_async: + async def async_handler(): + return self.handlers[event](*args) + + return self.start_background_task(async_handler) + else: + try: + ret = self.handlers[event](*args) + except: + self.logger.exception(event + ' handler error') + if event == 'connect': + # if connect handler raised error we reject the + # connection + return False + return ret + + async def _service_task(self): # pragma: no cover + """Monitor connected clients and clean up those that time out.""" + while True: + if len(self.sockets) == 0: + # nothing to do + await self.sleep(self.ping_timeout) + continue + + # go through the entire client list in a ping interval cycle + sleep_interval = self.ping_timeout / len(self.sockets) + + try: + # iterate over the current clients + for socket in self.sockets.copy().values(): + if not socket.closing and not socket.closed: + await socket.check_ping_timeout() + await self.sleep(sleep_interval) + except (SystemExit, KeyboardInterrupt, asyncio.CancelledError): + self.logger.info('service task canceled') + break + except: + if asyncio.get_event_loop().is_closed(): + self.logger.info('event loop is closed, exiting service ' + 'task') + break + + # an unexpected exception has occurred, log it and continue + self.logger.exception('service task exception') diff --git a/openpype/vendor/python/python_2/engineio/asyncio_socket.py b/openpype/vendor/python/python_2/engineio/asyncio_socket.py new file mode 100644 index 0000000000..c4afcfe309 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/asyncio_socket.py @@ -0,0 +1,235 @@ +import asyncio +import six +import sys +import time + +from . import exceptions +from . import packet +from . import payload +from . import socket + + +class AsyncSocket(socket.Socket): + async def poll(self): + """Wait for packets to send to the client.""" + try: + packets = [await asyncio.wait_for(self.queue.get(), + self.server.ping_timeout)] + self.queue.task_done() + except (asyncio.TimeoutError, asyncio.CancelledError): + raise exceptions.QueueEmpty() + if packets == [None]: + return [] + try: + packets.append(self.queue.get_nowait()) + self.queue.task_done() + except asyncio.QueueEmpty: + pass + return packets + + async def receive(self, pkt): + """Receive packet from the client.""" + self.server.logger.info('%s: Received packet %s data %s', + self.sid, packet.packet_names[pkt.packet_type], + pkt.data if not isinstance(pkt.data, bytes) + else '') + if pkt.packet_type == packet.PING: + self.last_ping = time.time() + await self.send(packet.Packet(packet.PONG, pkt.data)) + elif pkt.packet_type == packet.MESSAGE: + await self.server._trigger_event( + 'message', self.sid, pkt.data, + run_async=self.server.async_handlers) + elif pkt.packet_type == packet.UPGRADE: + await self.send(packet.Packet(packet.NOOP)) + elif pkt.packet_type == packet.CLOSE: + await self.close(wait=False, abort=True) + else: + raise exceptions.UnknownPacketError() + + async def check_ping_timeout(self): + """Make sure the client is still sending pings. + + This helps detect disconnections for long-polling clients. + """ + if self.closed: + raise exceptions.SocketIsClosedError() + if time.time() - self.last_ping > self.server.ping_interval + 5: + self.server.logger.info('%s: Client is gone, closing socket', + self.sid) + # Passing abort=False here will cause close() to write a + # CLOSE packet. This has the effect of updating half-open sockets + # to their correct state of disconnected + await self.close(wait=False, abort=False) + return False + return True + + async def send(self, pkt): + """Send a packet to the client.""" + if not await self.check_ping_timeout(): + return + if self.upgrading: + self.packet_backlog.append(pkt) + else: + await self.queue.put(pkt) + self.server.logger.info('%s: Sending packet %s data %s', + self.sid, packet.packet_names[pkt.packet_type], + pkt.data if not isinstance(pkt.data, bytes) + else '') + + async def handle_get_request(self, environ): + """Handle a long-polling GET request from the client.""" + connections = [ + s.strip() + for s in environ.get('HTTP_CONNECTION', '').lower().split(',')] + transport = environ.get('HTTP_UPGRADE', '').lower() + if 'upgrade' in connections and transport in self.upgrade_protocols: + self.server.logger.info('%s: Received request to upgrade to %s', + self.sid, transport) + return await getattr(self, '_upgrade_' + transport)(environ) + try: + packets = await self.poll() + except exceptions.QueueEmpty: + exc = sys.exc_info() + await self.close(wait=False) + six.reraise(*exc) + return packets + + async def handle_post_request(self, environ): + """Handle a long-polling POST request from the client.""" + length = int(environ.get('CONTENT_LENGTH', '0')) + if length > self.server.max_http_buffer_size: + raise exceptions.ContentTooLongError() + else: + body = await environ['wsgi.input'].read(length) + p = payload.Payload(encoded_payload=body) + for pkt in p.packets: + await self.receive(pkt) + + async def close(self, wait=True, abort=False): + """Close the socket connection.""" + if not self.closed and not self.closing: + self.closing = True + await self.server._trigger_event('disconnect', self.sid) + if not abort: + await self.send(packet.Packet(packet.CLOSE)) + self.closed = True + if wait: + await self.queue.join() + + async def _upgrade_websocket(self, environ): + """Upgrade the connection from polling to websocket.""" + if self.upgraded: + raise IOError('Socket has been upgraded already') + if self.server._async['websocket'] is None: + # the selected async mode does not support websocket + return self.server._bad_request() + ws = self.server._async['websocket'](self._websocket_handler) + return await ws(environ) + + async def _websocket_handler(self, ws): + """Engine.IO handler for websocket transport.""" + if self.connected: + # the socket was already connected, so this is an upgrade + self.upgrading = True # hold packet sends during the upgrade + + try: + pkt = await ws.wait() + except IOError: # pragma: no cover + return + decoded_pkt = packet.Packet(encoded_packet=pkt) + if decoded_pkt.packet_type != packet.PING or \ + decoded_pkt.data != 'probe': + self.server.logger.info( + '%s: Failed websocket upgrade, no PING packet', self.sid) + return + await ws.send(packet.Packet( + packet.PONG, + data=six.text_type('probe')).encode(always_bytes=False)) + await self.queue.put(packet.Packet(packet.NOOP)) # end poll + + try: + pkt = await ws.wait() + except IOError: # pragma: no cover + return + decoded_pkt = packet.Packet(encoded_packet=pkt) + if decoded_pkt.packet_type != packet.UPGRADE: + self.upgraded = False + self.server.logger.info( + ('%s: Failed websocket upgrade, expected UPGRADE packet, ' + 'received %s instead.'), + self.sid, pkt) + return + self.upgraded = True + + # flush any packets that were sent during the upgrade + for pkt in self.packet_backlog: + await self.queue.put(pkt) + self.packet_backlog = [] + self.upgrading = False + else: + self.connected = True + self.upgraded = True + + # start separate writer thread + async def writer(): + while True: + packets = None + try: + packets = await self.poll() + except exceptions.QueueEmpty: + break + if not packets: + # empty packet list returned -> connection closed + break + try: + for pkt in packets: + await ws.send(pkt.encode(always_bytes=False)) + except: + break + writer_task = asyncio.ensure_future(writer()) + + self.server.logger.info( + '%s: Upgrade to websocket successful', self.sid) + + while True: + p = None + wait_task = asyncio.ensure_future(ws.wait()) + try: + p = await asyncio.wait_for(wait_task, self.server.ping_timeout) + except asyncio.CancelledError: # pragma: no cover + # there is a bug (https://bugs.python.org/issue30508) in + # asyncio that causes a "Task exception never retrieved" error + # to appear when wait_task raises an exception before it gets + # cancelled. Calling wait_task.exception() prevents the error + # from being issued in Python 3.6, but causes other errors in + # other versions, so we run it with all errors suppressed and + # hope for the best. + try: + wait_task.exception() + except: + pass + break + except: + break + if p is None: + # connection closed by client + break + if isinstance(p, six.text_type): # pragma: no cover + p = p.encode('utf-8') + pkt = packet.Packet(encoded_packet=p) + try: + await self.receive(pkt) + except exceptions.UnknownPacketError: # pragma: no cover + pass + except exceptions.SocketIsClosedError: # pragma: no cover + self.server.logger.info('Receive error -- socket is closed') + break + except: # pragma: no cover + # if we get an unexpected exception we log the error and exit + # the connection properly + self.server.logger.exception('Unknown receive error') + + await self.queue.put(None) # unlock the writer task so it can exit + await asyncio.wait_for(writer_task, timeout=None) + await self.close(wait=False, abort=True) diff --git a/openpype/vendor/python/python_2/engineio/client.py b/openpype/vendor/python/python_2/engineio/client.py new file mode 100644 index 0000000000..16dcc94e63 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/client.py @@ -0,0 +1,641 @@ +import logging +try: + import queue +except ImportError: # pragma: no cover + import Queue as queue +import signal +import threading +import time + +import six +from six.moves import urllib +try: + import requests +except ImportError: # pragma: no cover + requests = None +try: + import websocket +except ImportError: # pragma: no cover + websocket = None +from . import exceptions +from . import packet +from . import payload + +default_logger = logging.getLogger('engineio.client') +connected_clients = [] + +if six.PY2: # pragma: no cover + ConnectionError = OSError + + +def signal_handler(sig, frame): + """SIGINT handler. + + Disconnect all active clients and then invoke the original signal handler. + """ + for client in connected_clients[:]: + if client.is_asyncio_based(): + client.start_background_task(client.disconnect, abort=True) + else: + client.disconnect(abort=True) + return original_signal_handler(sig, frame) + + +original_signal_handler = signal.signal(signal.SIGINT, signal_handler) + + +class Client(object): + """An Engine.IO client. + + This class implements a fully compliant Engine.IO web client with support + for websocket and long-polling transports. + + :param logger: To enable logging set to ``True`` or pass a logger object to + use. To disable logging set to ``False``. The default is + ``False``. + :param json: An alternative json module to use for encoding and decoding + packets. Custom json modules must have ``dumps`` and ``loads`` + functions that are compatible with the standard library + versions. + """ + event_names = ['connect', 'disconnect', 'message'] + + def __init__(self, logger=False, json=None): + self.handlers = {} + self.base_url = None + self.transports = None + self.current_transport = None + self.sid = None + self.upgrades = None + self.ping_interval = None + self.ping_timeout = None + self.pong_received = True + self.http = None + self.ws = None + self.read_loop_task = None + self.write_loop_task = None + self.ping_loop_task = None + self.ping_loop_event = self.create_event() + self.queue = None + self.state = 'disconnected' + + if json is not None: + packet.Packet.json = json + if not isinstance(logger, bool): + self.logger = logger + else: + self.logger = default_logger + if not logging.root.handlers and \ + self.logger.level == logging.NOTSET: + if logger: + self.logger.setLevel(logging.INFO) + else: + self.logger.setLevel(logging.ERROR) + self.logger.addHandler(logging.StreamHandler()) + + def is_asyncio_based(self): + return False + + def on(self, event, handler=None): + """Register an event handler. + + :param event: The event name. Can be ``'connect'``, ``'message'`` or + ``'disconnect'``. + :param handler: The function that should be invoked to handle the + event. When this parameter is not given, the method + acts as a decorator for the handler function. + + Example usage:: + + # as a decorator: + @eio.on('connect') + def connect_handler(): + print('Connection request') + + # as a method: + def message_handler(msg): + print('Received message: ', msg) + eio.send('response') + eio.on('message', message_handler) + """ + if event not in self.event_names: + raise ValueError('Invalid event') + + def set_handler(handler): + self.handlers[event] = handler + return handler + + if handler is None: + return set_handler + set_handler(handler) + + def connect(self, url, headers={}, transports=None, + engineio_path='engine.io'): + """Connect to an Engine.IO server. + + :param url: The URL of the Engine.IO server. It can include custom + query string parameters if required by the server. + :param headers: A dictionary with custom headers to send with the + connection request. + :param transports: The list of allowed transports. Valid transports + are ``'polling'`` and ``'websocket'``. If not + given, the polling transport is connected first, + then an upgrade to websocket is attempted. + :param engineio_path: The endpoint where the Engine.IO server is + installed. The default value is appropriate for + most cases. + + Example usage:: + + eio = engineio.Client() + eio.connect('http://localhost:5000') + """ + if self.state != 'disconnected': + raise ValueError('Client is not in a disconnected state') + valid_transports = ['polling', 'websocket'] + if transports is not None: + if isinstance(transports, six.string_types): + transports = [transports] + transports = [transport for transport in transports + if transport in valid_transports] + if not transports: + raise ValueError('No valid transports provided') + self.transports = transports or valid_transports + self.queue = self.create_queue() + return getattr(self, '_connect_' + self.transports[0])( + url, headers, engineio_path) + + def wait(self): + """Wait until the connection with the server ends. + + Client applications can use this function to block the main thread + during the life of the connection. + """ + if self.read_loop_task: + self.read_loop_task.join() + + def send(self, data, binary=None): + """Send a message to a client. + + :param data: The data to send to the client. Data can be of type + ``str``, ``bytes``, ``list`` or ``dict``. If a ``list`` + or ``dict``, the data will be serialized as JSON. + :param binary: ``True`` to send packet as binary, ``False`` to send + as text. If not given, unicode (Python 2) and str + (Python 3) are sent as text, and str (Python 2) and + bytes (Python 3) are sent as binary. + """ + self._send_packet(packet.Packet(packet.MESSAGE, data=data, + binary=binary)) + + def disconnect(self, abort=False): + """Disconnect from the server. + + :param abort: If set to ``True``, do not wait for background tasks + associated with the connection to end. + """ + if self.state == 'connected': + self._send_packet(packet.Packet(packet.CLOSE)) + self.queue.put(None) + self.state = 'disconnecting' + self._trigger_event('disconnect', run_async=False) + if self.current_transport == 'websocket': + self.ws.close() + if not abort: + self.read_loop_task.join() + self.state = 'disconnected' + try: + connected_clients.remove(self) + except ValueError: # pragma: no cover + pass + self._reset() + + def transport(self): + """Return the name of the transport currently in use. + + The possible values returned by this function are ``'polling'`` and + ``'websocket'``. + """ + return self.current_transport + + def start_background_task(self, target, *args, **kwargs): + """Start a background task. + + This is a utility function that applications can use to start a + background task. + + :param target: the target function to execute. + :param args: arguments to pass to the function. + :param kwargs: keyword arguments to pass to the function. + + This function returns an object compatible with the `Thread` class in + the Python standard library. The `start()` method on this object is + already called by this function. + """ + th = threading.Thread(target=target, args=args, kwargs=kwargs) + th.start() + return th + + def sleep(self, seconds=0): + """Sleep for the requested amount of time.""" + return time.sleep(seconds) + + def create_queue(self, *args, **kwargs): + """Create a queue object.""" + q = queue.Queue(*args, **kwargs) + q.Empty = queue.Empty + return q + + def create_event(self, *args, **kwargs): + """Create an event object.""" + return threading.Event(*args, **kwargs) + + def _reset(self): + self.state = 'disconnected' + self.sid = None + + def _connect_polling(self, url, headers, engineio_path): + """Establish a long-polling connection to the Engine.IO server.""" + if requests is None: # pragma: no cover + # not installed + self.logger.error('requests package is not installed -- cannot ' + 'send HTTP requests!') + return + self.base_url = self._get_engineio_url(url, engineio_path, 'polling') + self.logger.info('Attempting polling connection to ' + self.base_url) + r = self._send_request( + 'GET', self.base_url + self._get_url_timestamp(), headers=headers) + if r is None: + self._reset() + raise exceptions.ConnectionError( + 'Connection refused by the server') + if r.status_code != 200: + raise exceptions.ConnectionError( + 'Unexpected status code {} in server response'.format( + r.status_code)) + try: + p = payload.Payload(encoded_payload=r.content) + except ValueError: + six.raise_from(exceptions.ConnectionError( + 'Unexpected response from server'), None) + open_packet = p.packets[0] + if open_packet.packet_type != packet.OPEN: + raise exceptions.ConnectionError( + 'OPEN packet not returned by server') + self.logger.info( + 'Polling connection accepted with ' + str(open_packet.data)) + self.sid = open_packet.data['sid'] + self.upgrades = open_packet.data['upgrades'] + self.ping_interval = open_packet.data['pingInterval'] / 1000.0 + self.ping_timeout = open_packet.data['pingTimeout'] / 1000.0 + self.current_transport = 'polling' + self.base_url += '&sid=' + self.sid + + self.state = 'connected' + connected_clients.append(self) + self._trigger_event('connect', run_async=False) + + for pkt in p.packets[1:]: + self._receive_packet(pkt) + + if 'websocket' in self.upgrades and 'websocket' in self.transports: + # attempt to upgrade to websocket + if self._connect_websocket(url, headers, engineio_path): + # upgrade to websocket succeeded, we're done here + return + + # start background tasks associated with this client + self.ping_loop_task = self.start_background_task(self._ping_loop) + self.write_loop_task = self.start_background_task(self._write_loop) + self.read_loop_task = self.start_background_task( + self._read_loop_polling) + + def _connect_websocket(self, url, headers, engineio_path): + """Establish or upgrade to a WebSocket connection with the server.""" + if websocket is None: # pragma: no cover + # not installed + self.logger.warning('websocket-client package not installed, only ' + 'polling transport is available') + return False + websocket_url = self._get_engineio_url(url, engineio_path, 'websocket') + if self.sid: + self.logger.info( + 'Attempting WebSocket upgrade to ' + websocket_url) + upgrade = True + websocket_url += '&sid=' + self.sid + else: + upgrade = False + self.base_url = websocket_url + self.logger.info( + 'Attempting WebSocket connection to ' + websocket_url) + + # get the cookies from the long-polling connection so that they can + # also be sent the the WebSocket route + cookies = None + if self.http: + cookies = '; '.join(["{}={}".format(cookie.name, cookie.value) + for cookie in self.http.cookies]) + try: + ws = websocket.create_connection( + websocket_url + self._get_url_timestamp(), header=headers, + cookie=cookies) + except ConnectionError: + if upgrade: + self.logger.warning( + 'WebSocket upgrade failed: connection error') + return False + else: + raise exceptions.ConnectionError('Connection error') + if upgrade: + p = packet.Packet(packet.PING, + data=six.text_type('probe')).encode() + try: + ws.send(p) + except Exception as e: # pragma: no cover + self.logger.warning( + 'WebSocket upgrade failed: unexpected send exception: %s', + str(e)) + return False + try: + p = ws.recv() + except Exception as e: # pragma: no cover + self.logger.warning( + 'WebSocket upgrade failed: unexpected recv exception: %s', + str(e)) + return False + pkt = packet.Packet(encoded_packet=p) + if pkt.packet_type != packet.PONG or pkt.data != 'probe': + self.logger.warning( + 'WebSocket upgrade failed: no PONG packet') + return False + p = packet.Packet(packet.UPGRADE).encode() + try: + ws.send(p) + except Exception as e: # pragma: no cover + self.logger.warning( + 'WebSocket upgrade failed: unexpected send exception: %s', + str(e)) + return False + self.current_transport = 'websocket' + self.logger.info('WebSocket upgrade was successful') + else: + try: + p = ws.recv() + except Exception as e: # pragma: no cover + raise exceptions.ConnectionError( + 'Unexpected recv exception: ' + str(e)) + open_packet = packet.Packet(encoded_packet=p) + if open_packet.packet_type != packet.OPEN: + raise exceptions.ConnectionError('no OPEN packet') + self.logger.info( + 'WebSocket connection accepted with ' + str(open_packet.data)) + self.sid = open_packet.data['sid'] + self.upgrades = open_packet.data['upgrades'] + self.ping_interval = open_packet.data['pingInterval'] / 1000.0 + self.ping_timeout = open_packet.data['pingTimeout'] / 1000.0 + self.current_transport = 'websocket' + + self.state = 'connected' + connected_clients.append(self) + self._trigger_event('connect', run_async=False) + self.ws = ws + + # start background tasks associated with this client + self.ping_loop_task = self.start_background_task(self._ping_loop) + self.write_loop_task = self.start_background_task(self._write_loop) + self.read_loop_task = self.start_background_task( + self._read_loop_websocket) + return True + + def _receive_packet(self, pkt): + """Handle incoming packets from the server.""" + packet_name = packet.packet_names[pkt.packet_type] \ + if pkt.packet_type < len(packet.packet_names) else 'UNKNOWN' + self.logger.info( + 'Received packet %s data %s', packet_name, + pkt.data if not isinstance(pkt.data, bytes) else '') + if pkt.packet_type == packet.MESSAGE: + self._trigger_event('message', pkt.data, run_async=True) + elif pkt.packet_type == packet.PONG: + self.pong_received = True + elif pkt.packet_type == packet.CLOSE: + self.disconnect(abort=True) + elif pkt.packet_type == packet.NOOP: + pass + else: + self.logger.error('Received unexpected packet of type %s', + pkt.packet_type) + + def _send_packet(self, pkt): + """Queue a packet to be sent to the server.""" + if self.state != 'connected': + return + self.queue.put(pkt) + self.logger.info( + 'Sending packet %s data %s', + packet.packet_names[pkt.packet_type], + pkt.data if not isinstance(pkt.data, bytes) else '') + + def _send_request( + self, method, url, headers=None, body=None): # pragma: no cover + if self.http is None: + self.http = requests.Session() + try: + return self.http.request(method, url, headers=headers, data=body) + except requests.exceptions.RequestException: + pass + + def _trigger_event(self, event, *args, **kwargs): + """Invoke an event handler.""" + run_async = kwargs.pop('run_async', False) + if event in self.handlers: + if run_async: + return self.start_background_task(self.handlers[event], *args) + else: + try: + return self.handlers[event](*args) + except: + self.logger.exception(event + ' handler error') + + def _get_engineio_url(self, url, engineio_path, transport): + """Generate the Engine.IO connection URL.""" + engineio_path = engineio_path.strip('/') + parsed_url = urllib.parse.urlparse(url) + + if transport == 'polling': + scheme = 'http' + elif transport == 'websocket': + scheme = 'ws' + else: # pragma: no cover + raise ValueError('invalid transport') + if parsed_url.scheme in ['https', 'wss']: + scheme += 's' + + return ('{scheme}://{netloc}/{path}/?{query}' + '{sep}transport={transport}&EIO=3').format( + scheme=scheme, netloc=parsed_url.netloc, + path=engineio_path, query=parsed_url.query, + sep='&' if parsed_url.query else '', + transport=transport) + + def _get_url_timestamp(self): + """Generate the Engine.IO query string timestamp.""" + return '&t=' + str(time.time()) + + def _ping_loop(self): + """This background task sends a PING to the server at the requested + interval. + """ + self.pong_received = True + self.ping_loop_event.clear() + while self.state == 'connected': + if not self.pong_received: + self.logger.info( + 'PONG response has not been received, aborting') + if self.ws: + self.ws.close() + self.queue.put(None) + break + self.pong_received = False + self._send_packet(packet.Packet(packet.PING)) + self.ping_loop_event.wait(timeout=self.ping_interval) + self.logger.info('Exiting ping task') + + def _read_loop_polling(self): + """Read packets by polling the Engine.IO server.""" + while self.state == 'connected': + self.logger.info( + 'Sending polling GET request to ' + self.base_url) + r = self._send_request( + 'GET', self.base_url + self._get_url_timestamp()) + if r is None: + self.logger.warning( + 'Connection refused by the server, aborting') + self.queue.put(None) + break + if r.status_code != 200: + self.logger.warning('Unexpected status code %s in server ' + 'response, aborting', r.status_code) + self.queue.put(None) + break + try: + p = payload.Payload(encoded_payload=r.content) + except ValueError: + self.logger.warning( + 'Unexpected packet from server, aborting') + self.queue.put(None) + break + for pkt in p.packets: + self._receive_packet(pkt) + + self.logger.info('Waiting for write loop task to end') + self.write_loop_task.join() + self.logger.info('Waiting for ping loop task to end') + self.ping_loop_event.set() + self.ping_loop_task.join() + if self.state == 'connected': + self._trigger_event('disconnect', run_async=False) + try: + connected_clients.remove(self) + except ValueError: # pragma: no cover + pass + self._reset() + self.logger.info('Exiting read loop task') + + def _read_loop_websocket(self): + """Read packets from the Engine.IO WebSocket connection.""" + while self.state == 'connected': + p = None + try: + p = self.ws.recv() + except websocket.WebSocketConnectionClosedException: + self.logger.warning( + 'WebSocket connection was closed, aborting') + self.queue.put(None) + break + except Exception as e: + self.logger.info( + 'Unexpected error "%s", aborting', str(e)) + self.queue.put(None) + break + if isinstance(p, six.text_type): # pragma: no cover + p = p.encode('utf-8') + pkt = packet.Packet(encoded_packet=p) + self._receive_packet(pkt) + + self.logger.info('Waiting for write loop task to end') + self.write_loop_task.join() + self.logger.info('Waiting for ping loop task to end') + self.ping_loop_event.set() + self.ping_loop_task.join() + if self.state == 'connected': + self._trigger_event('disconnect', run_async=False) + try: + connected_clients.remove(self) + except ValueError: # pragma: no cover + pass + self._reset() + self.logger.info('Exiting read loop task') + + def _write_loop(self): + """This background task sends packages to the server as they are + pushed to the send queue. + """ + while self.state == 'connected': + # to simplify the timeout handling, use the maximum of the + # ping interval and ping timeout as timeout, with an extra 5 + # seconds grace period + timeout = max(self.ping_interval, self.ping_timeout) + 5 + packets = None + try: + packets = [self.queue.get(timeout=timeout)] + except self.queue.Empty: + self.logger.error('packet queue is empty, aborting') + break + if packets == [None]: + self.queue.task_done() + packets = [] + else: + while True: + try: + packets.append(self.queue.get(block=False)) + except self.queue.Empty: + break + if packets[-1] is None: + packets = packets[:-1] + self.queue.task_done() + break + if not packets: + # empty packet list returned -> connection closed + break + if self.current_transport == 'polling': + p = payload.Payload(packets=packets) + r = self._send_request( + 'POST', self.base_url, body=p.encode(), + headers={'Content-Type': 'application/octet-stream'}) + for pkt in packets: + self.queue.task_done() + if r is None: + self.logger.warning( + 'Connection refused by the server, aborting') + break + if r.status_code != 200: + self.logger.warning('Unexpected status code %s in server ' + 'response, aborting', r.status_code) + self._reset() + break + else: + # websocket + try: + for pkt in packets: + encoded_packet = pkt.encode(always_bytes=False) + if pkt.binary: + self.ws.send_binary(encoded_packet) + else: + self.ws.send(encoded_packet) + self.queue.task_done() + except websocket.WebSocketConnectionClosedException: + self.logger.warning( + 'WebSocket connection was closed, aborting') + break + self.logger.info('Exiting write loop task') diff --git a/openpype/vendor/python/python_2/engineio/exceptions.py b/openpype/vendor/python/python_2/engineio/exceptions.py new file mode 100644 index 0000000000..fb0b3e057c --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/exceptions.py @@ -0,0 +1,22 @@ +class EngineIOError(Exception): + pass + + +class ContentTooLongError(EngineIOError): + pass + + +class UnknownPacketError(EngineIOError): + pass + + +class QueueEmpty(EngineIOError): + pass + + +class SocketIsClosedError(EngineIOError): + pass + + +class ConnectionError(EngineIOError): + pass diff --git a/openpype/vendor/python/python_2/engineio/middleware.py b/openpype/vendor/python/python_2/engineio/middleware.py new file mode 100644 index 0000000000..d0bdcc7476 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/middleware.py @@ -0,0 +1,87 @@ +import os +from engineio.static_files import get_static_file + + +class WSGIApp(object): + """WSGI application middleware for Engine.IO. + + This middleware dispatches traffic to an Engine.IO application. It can + also serve a list of static files to the client, or forward unrelated + HTTP traffic to another WSGI application. + + :param engineio_app: The Engine.IO server. Must be an instance of the + ``engineio.Server`` class. + :param wsgi_app: The WSGI app that receives all other traffic. + :param static_files: A dictionary with static file mapping rules. See the + documentation for details on this argument. + :param engineio_path: The endpoint where the Engine.IO application should + be installed. The default value is appropriate for + most cases. + + Example usage:: + + import engineio + import eventlet + + eio = engineio.Server() + app = engineio.WSGIApp(eio, static_files={ + '/': {'content_type': 'text/html', 'filename': 'index.html'}, + '/index.html': {'content_type': 'text/html', + 'filename': 'index.html'}, + }) + eventlet.wsgi.server(eventlet.listen(('', 8000)), app) + """ + def __init__(self, engineio_app, wsgi_app=None, static_files=None, + engineio_path='engine.io'): + self.engineio_app = engineio_app + self.wsgi_app = wsgi_app + self.engineio_path = engineio_path.strip('/') + self.static_files = static_files or {} + + def __call__(self, environ, start_response): + if 'gunicorn.socket' in environ: + # gunicorn saves the socket under environ['gunicorn.socket'], while + # eventlet saves it under environ['eventlet.input']. Eventlet also + # stores the socket inside a wrapper class, while gunicon writes it + # directly into the environment. To give eventlet's WebSocket + # module access to this socket when running under gunicorn, here we + # copy the socket to the eventlet format. + class Input(object): + def __init__(self, socket): + self.socket = socket + + def get_socket(self): + return self.socket + + environ['eventlet.input'] = Input(environ['gunicorn.socket']) + path = environ['PATH_INFO'] + if path is not None and \ + path.startswith('/{0}/'.format(self.engineio_path)): + return self.engineio_app.handle_request(environ, start_response) + else: + static_file = get_static_file(path, self.static_files) \ + if self.static_files else None + if static_file: + if os.path.exists(static_file['filename']): + start_response( + '200 OK', + [('Content-Type', static_file['content_type'])]) + with open(static_file['filename'], 'rb') as f: + return [f.read()] + else: + return self.not_found(start_response) + elif self.wsgi_app is not None: + return self.wsgi_app(environ, start_response) + return self.not_found(start_response) + + def not_found(self, start_response): + start_response("404 Not Found", [('Content-Type', 'text/plain')]) + return [b'Not Found'] + + +class Middleware(WSGIApp): + """This class has been renamed to ``WSGIApp`` and is now deprecated.""" + def __init__(self, engineio_app, wsgi_app=None, + engineio_path='engine.io'): + super(Middleware, self).__init__(engineio_app, wsgi_app, + engineio_path=engineio_path) diff --git a/openpype/vendor/python/python_2/engineio/packet.py b/openpype/vendor/python/python_2/engineio/packet.py new file mode 100644 index 0000000000..a3aa6d4761 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/packet.py @@ -0,0 +1,92 @@ +import base64 +import json as _json + +import six + +(OPEN, CLOSE, PING, PONG, MESSAGE, UPGRADE, NOOP) = (0, 1, 2, 3, 4, 5, 6) +packet_names = ['OPEN', 'CLOSE', 'PING', 'PONG', 'MESSAGE', 'UPGRADE', 'NOOP'] + +binary_types = (six.binary_type, bytearray) + + +class Packet(object): + """Engine.IO packet.""" + + json = _json + + def __init__(self, packet_type=NOOP, data=None, binary=None, + encoded_packet=None): + self.packet_type = packet_type + self.data = data + if binary is not None: + self.binary = binary + elif isinstance(data, six.text_type): + self.binary = False + elif isinstance(data, binary_types): + self.binary = True + else: + self.binary = False + if encoded_packet: + self.decode(encoded_packet) + + def encode(self, b64=False, always_bytes=True): + """Encode the packet for transmission.""" + if self.binary and not b64: + encoded_packet = six.int2byte(self.packet_type) + else: + encoded_packet = six.text_type(self.packet_type) + if self.binary and b64: + encoded_packet = 'b' + encoded_packet + if self.binary: + if b64: + encoded_packet += base64.b64encode(self.data).decode('utf-8') + else: + encoded_packet += self.data + elif isinstance(self.data, six.string_types): + encoded_packet += self.data + elif isinstance(self.data, dict) or isinstance(self.data, list): + encoded_packet += self.json.dumps(self.data, + separators=(',', ':')) + elif self.data is not None: + encoded_packet += str(self.data) + if always_bytes and not isinstance(encoded_packet, binary_types): + encoded_packet = encoded_packet.encode('utf-8') + return encoded_packet + + def decode(self, encoded_packet): + """Decode a transmitted package.""" + b64 = False + if not isinstance(encoded_packet, binary_types): + encoded_packet = encoded_packet.encode('utf-8') + elif not isinstance(encoded_packet, bytes): + encoded_packet = bytes(encoded_packet) + self.packet_type = six.byte2int(encoded_packet[0:1]) + if self.packet_type == 98: # 'b' --> binary base64 encoded packet + self.binary = True + encoded_packet = encoded_packet[1:] + self.packet_type = six.byte2int(encoded_packet[0:1]) + self.packet_type -= 48 + b64 = True + elif self.packet_type >= 48: + self.packet_type -= 48 + self.binary = False + else: + self.binary = True + self.data = None + if len(encoded_packet) > 1: + if self.binary: + if b64: + self.data = base64.b64decode(encoded_packet[1:]) + else: + self.data = encoded_packet[1:] + else: + try: + self.data = self.json.loads( + encoded_packet[1:].decode('utf-8')) + if isinstance(self.data, int): + # do not allow integer payloads, see + # github.com/miguelgrinberg/python-engineio/issues/75 + # for background on this decision + raise ValueError + except ValueError: + self.data = encoded_packet[1:].decode('utf-8') diff --git a/openpype/vendor/python/python_2/engineio/payload.py b/openpype/vendor/python/python_2/engineio/payload.py new file mode 100644 index 0000000000..cfff557f5b --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/payload.py @@ -0,0 +1,80 @@ +import six + +from . import packet + +from six.moves import urllib + + +class Payload(object): + """Engine.IO payload.""" + def __init__(self, packets=None, encoded_payload=None): + self.packets = packets or [] + if encoded_payload is not None: + self.decode(encoded_payload) + + def encode(self, b64=False, jsonp_index=None): + """Encode the payload for transmission.""" + encoded_payload = b'' + for pkt in self.packets: + encoded_packet = pkt.encode(b64=b64) + packet_len = len(encoded_packet) + if b64: + encoded_payload += str(packet_len).encode('utf-8') + b':' + \ + encoded_packet + else: + binary_len = b'' + while packet_len != 0: + binary_len = six.int2byte(packet_len % 10) + binary_len + packet_len = int(packet_len / 10) + if not pkt.binary: + encoded_payload += b'\0' + else: + encoded_payload += b'\1' + encoded_payload += binary_len + b'\xff' + encoded_packet + if jsonp_index is not None: + encoded_payload = b'___eio[' + \ + str(jsonp_index).encode() + \ + b']("' + \ + encoded_payload.replace(b'"', b'\\"') + \ + b'");' + return encoded_payload + + def decode(self, encoded_payload): + """Decode a transmitted payload.""" + self.packets = [] + while encoded_payload: + # JSONP POST payload starts with 'd=' + if encoded_payload.startswith(b'd='): + encoded_payload = urllib.parse.parse_qs( + encoded_payload)[b'd'][0] + + if six.byte2int(encoded_payload[0:1]) <= 1: + packet_len = 0 + i = 1 + while six.byte2int(encoded_payload[i:i + 1]) != 255: + packet_len = packet_len * 10 + six.byte2int( + encoded_payload[i:i + 1]) + i += 1 + self.packets.append(packet.Packet( + encoded_packet=encoded_payload[i + 1:i + 1 + packet_len])) + else: + i = encoded_payload.find(b':') + if i == -1: + raise ValueError('invalid payload') + + # extracting the packet out of the payload is extremely + # inefficient, because the payload needs to be treated as + # binary, but the non-binary packets have to be parsed as + # unicode. Luckily this complication only applies to long + # polling, as the websocket transport sends packets + # individually wrapped. + packet_len = int(encoded_payload[0:i]) + pkt = encoded_payload.decode('utf-8', errors='ignore')[ + i + 1: i + 1 + packet_len].encode('utf-8') + self.packets.append(packet.Packet(encoded_packet=pkt)) + + # the engine.io protocol sends the packet length in + # utf-8 characters, but we need it in bytes to be able to + # jump to the next packet in the payload + packet_len = len(pkt) + encoded_payload = encoded_payload[i + 1 + packet_len:] diff --git a/openpype/vendor/python/python_2/engineio/server.py b/openpype/vendor/python/python_2/engineio/server.py new file mode 100644 index 0000000000..a2ba7d16b4 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/server.py @@ -0,0 +1,633 @@ +import gzip +import importlib +import logging +import uuid +import zlib + +import six +from six.moves import urllib + +from . import exceptions +from . import packet +from . import payload +from . import socket + +default_logger = logging.getLogger('engineio.server') + + +class Server(object): + """An Engine.IO server. + + This class implements a fully compliant Engine.IO web server with support + for websocket and long-polling transports. + + :param async_mode: The asynchronous model to use. See the Deployment + section in the documentation for a description of the + available options. Valid async modes are "threading", + "eventlet", "gevent" and "gevent_uwsgi". If this + argument is not given, "eventlet" is tried first, then + "gevent_uwsgi", then "gevent", and finally "threading". + The first async mode that has all its dependencies + installed is the one that is chosen. + :param ping_timeout: The time in seconds that the client waits for the + server to respond before disconnecting. The default + is 60 seconds. + :param ping_interval: The interval in seconds at which the client pings + the server. The default is 25 seconds. + :param max_http_buffer_size: The maximum size of a message when using the + polling transport. The default is 100,000,000 + bytes. + :param allow_upgrades: Whether to allow transport upgrades or not. The + default is ``True``. + :param http_compression: Whether to compress packages when using the + polling transport. The default is ``True``. + :param compression_threshold: Only compress messages when their byte size + is greater than this value. The default is + 1024 bytes. + :param cookie: Name of the HTTP cookie that contains the client session + id. If set to ``None``, a cookie is not sent to the client. + The default is ``'io'``. + :param cors_allowed_origins: Origin or list of origins that are allowed to + connect to this server. All origins are + allowed by default, which is equivalent to + setting this argument to ``'*'``. + :param cors_credentials: Whether credentials (cookies, authentication) are + allowed in requests to this server. The default + is ``True``. + :param logger: To enable logging set to ``True`` or pass a logger object to + use. To disable logging set to ``False``. The default is + ``False``. + :param json: An alternative json module to use for encoding and decoding + packets. Custom json modules must have ``dumps`` and ``loads`` + functions that are compatible with the standard library + versions. + :param async_handlers: If set to ``True``, run message event handlers in + non-blocking threads. To run handlers synchronously, + set to ``False``. The default is ``True``. + :param monitor_clients: If set to ``True``, a background task will ensure + inactive clients are closed. Set to ``False`` to + disable the monitoring task (not recommended). The + default is ``True``. + :param kwargs: Reserved for future extensions, any additional parameters + given as keyword arguments will be silently ignored. + """ + compression_methods = ['gzip', 'deflate'] + event_names = ['connect', 'disconnect', 'message'] + _default_monitor_clients = True + + def __init__(self, async_mode=None, ping_timeout=60, ping_interval=25, + max_http_buffer_size=100000000, allow_upgrades=True, + http_compression=True, compression_threshold=1024, + cookie='io', cors_allowed_origins=None, + cors_credentials=True, logger=False, json=None, + async_handlers=True, monitor_clients=None, **kwargs): + self.ping_timeout = ping_timeout + self.ping_interval = ping_interval + self.max_http_buffer_size = max_http_buffer_size + self.allow_upgrades = allow_upgrades + self.http_compression = http_compression + self.compression_threshold = compression_threshold + self.cookie = cookie + self.cors_allowed_origins = cors_allowed_origins + self.cors_credentials = cors_credentials + self.async_handlers = async_handlers + self.sockets = {} + self.handlers = {} + self.start_service_task = monitor_clients \ + if monitor_clients is not None else self._default_monitor_clients + if json is not None: + packet.Packet.json = json + if not isinstance(logger, bool): + self.logger = logger + else: + self.logger = default_logger + if not logging.root.handlers and \ + self.logger.level == logging.NOTSET: + if logger: + self.logger.setLevel(logging.INFO) + else: + self.logger.setLevel(logging.ERROR) + self.logger.addHandler(logging.StreamHandler()) + modes = self.async_modes() + if async_mode is not None: + modes = [async_mode] if async_mode in modes else [] + self._async = None + self.async_mode = None + for mode in modes: + try: + self._async = importlib.import_module( + 'engineio.async_drivers.' + mode)._async + asyncio_based = self._async['asyncio'] \ + if 'asyncio' in self._async else False + if asyncio_based != self.is_asyncio_based(): + continue # pragma: no cover + self.async_mode = mode + break + except ImportError: + pass + if self.async_mode is None: + raise ValueError('Invalid async_mode specified') + if self.is_asyncio_based() and \ + ('asyncio' not in self._async or not + self._async['asyncio']): # pragma: no cover + raise ValueError('The selected async_mode is not asyncio ' + 'compatible') + if not self.is_asyncio_based() and 'asyncio' in self._async and \ + self._async['asyncio']: # pragma: no cover + raise ValueError('The selected async_mode requires asyncio and ' + 'must use the AsyncServer class') + self.logger.info('Server initialized for %s.', self.async_mode) + + def is_asyncio_based(self): + return False + + def async_modes(self): + return ['eventlet', 'gevent_uwsgi', 'gevent', 'threading'] + + def on(self, event, handler=None): + """Register an event handler. + + :param event: The event name. Can be ``'connect'``, ``'message'`` or + ``'disconnect'``. + :param handler: The function that should be invoked to handle the + event. When this parameter is not given, the method + acts as a decorator for the handler function. + + Example usage:: + + # as a decorator: + @eio.on('connect') + def connect_handler(sid, environ): + print('Connection request') + if environ['REMOTE_ADDR'] in blacklisted: + return False # reject + + # as a method: + def message_handler(sid, msg): + print('Received message: ', msg) + eio.send(sid, 'response') + eio.on('message', message_handler) + + The handler function receives the ``sid`` (session ID) for the + client as first argument. The ``'connect'`` event handler receives the + WSGI environment as a second argument, and can return ``False`` to + reject the connection. The ``'message'`` handler receives the message + payload as a second argument. The ``'disconnect'`` handler does not + take a second argument. + """ + if event not in self.event_names: + raise ValueError('Invalid event') + + def set_handler(handler): + self.handlers[event] = handler + return handler + + if handler is None: + return set_handler + set_handler(handler) + + def send(self, sid, data, binary=None): + """Send a message to a client. + + :param sid: The session id of the recipient client. + :param data: The data to send to the client. Data can be of type + ``str``, ``bytes``, ``list`` or ``dict``. If a ``list`` + or ``dict``, the data will be serialized as JSON. + :param binary: ``True`` to send packet as binary, ``False`` to send + as text. If not given, unicode (Python 2) and str + (Python 3) are sent as text, and str (Python 2) and + bytes (Python 3) are sent as binary. + """ + try: + socket = self._get_socket(sid) + except KeyError: + # the socket is not available + self.logger.warning('Cannot send to sid %s', sid) + return + socket.send(packet.Packet(packet.MESSAGE, data=data, binary=binary)) + + def get_session(self, sid): + """Return the user session for a client. + + :param sid: The session id of the client. + + The return value is a dictionary. Modifications made to this + dictionary are not guaranteed to be preserved unless + ``save_session()`` is called, or when the ``session`` context manager + is used. + """ + socket = self._get_socket(sid) + return socket.session + + def save_session(self, sid, session): + """Store the user session for a client. + + :param sid: The session id of the client. + :param session: The session dictionary. + """ + socket = self._get_socket(sid) + socket.session = session + + def session(self, sid): + """Return the user session for a client with context manager syntax. + + :param sid: The session id of the client. + + This is a context manager that returns the user session dictionary for + the client. Any changes that are made to this dictionary inside the + context manager block are saved back to the session. Example usage:: + + @eio.on('connect') + def on_connect(sid, environ): + username = authenticate_user(environ) + if not username: + return False + with eio.session(sid) as session: + session['username'] = username + + @eio.on('message') + def on_message(sid, msg): + with eio.session(sid) as session: + print('received message from ', session['username']) + """ + class _session_context_manager(object): + def __init__(self, server, sid): + self.server = server + self.sid = sid + self.session = None + + def __enter__(self): + self.session = self.server.get_session(sid) + return self.session + + def __exit__(self, *args): + self.server.save_session(sid, self.session) + + return _session_context_manager(self, sid) + + def disconnect(self, sid=None): + """Disconnect a client. + + :param sid: The session id of the client to close. If this parameter + is not given, then all clients are closed. + """ + if sid is not None: + try: + socket = self._get_socket(sid) + except KeyError: # pragma: no cover + # the socket was already closed or gone + pass + else: + socket.close() + del self.sockets[sid] + else: + for client in six.itervalues(self.sockets): + client.close() + self.sockets = {} + + def transport(self, sid): + """Return the name of the transport used by the client. + + The two possible values returned by this function are ``'polling'`` + and ``'websocket'``. + + :param sid: The session of the client. + """ + return 'websocket' if self._get_socket(sid).upgraded else 'polling' + + def handle_request(self, environ, start_response): + """Handle an HTTP request from the client. + + This is the entry point of the Engine.IO application, using the same + interface as a WSGI application. For the typical usage, this function + is invoked by the :class:`Middleware` instance, but it can be invoked + directly when the middleware is not used. + + :param environ: The WSGI environment. + :param start_response: The WSGI ``start_response`` function. + + This function returns the HTTP response body to deliver to the client + as a byte sequence. + """ + method = environ['REQUEST_METHOD'] + query = urllib.parse.parse_qs(environ.get('QUERY_STRING', '')) + + sid = query['sid'][0] if 'sid' in query else None + b64 = False + jsonp = False + jsonp_index = None + + if 'b64' in query: + if query['b64'][0] == "1" or query['b64'][0].lower() == "true": + b64 = True + if 'j' in query: + jsonp = True + try: + jsonp_index = int(query['j'][0]) + except (ValueError, KeyError, IndexError): + # Invalid JSONP index number + pass + + if jsonp and jsonp_index is None: + self.logger.warning('Invalid JSONP index number') + r = self._bad_request() + elif method == 'GET': + if sid is None: + transport = query.get('transport', ['polling'])[0] + if transport != 'polling' and transport != 'websocket': + self.logger.warning('Invalid transport %s', transport) + r = self._bad_request() + else: + r = self._handle_connect(environ, start_response, + transport, b64, jsonp_index) + else: + if sid not in self.sockets: + self.logger.warning('Invalid session %s', sid) + r = self._bad_request() + else: + socket = self._get_socket(sid) + try: + packets = socket.handle_get_request( + environ, start_response) + if isinstance(packets, list): + r = self._ok(packets, b64=b64, + jsonp_index=jsonp_index) + else: + r = packets + except exceptions.EngineIOError: + if sid in self.sockets: # pragma: no cover + self.disconnect(sid) + r = self._bad_request() + if sid in self.sockets and self.sockets[sid].closed: + del self.sockets[sid] + elif method == 'POST': + if sid is None or sid not in self.sockets: + self.logger.warning('Invalid session %s', sid) + r = self._bad_request() + else: + socket = self._get_socket(sid) + try: + socket.handle_post_request(environ) + r = self._ok(jsonp_index=jsonp_index) + except exceptions.EngineIOError: + if sid in self.sockets: # pragma: no cover + self.disconnect(sid) + r = self._bad_request() + except: # pragma: no cover + # for any other unexpected errors, we log the error + # and keep going + self.logger.exception('post request handler error') + r = self._ok(jsonp_index=jsonp_index) + elif method == 'OPTIONS': + r = self._ok() + else: + self.logger.warning('Method %s not supported', method) + r = self._method_not_found() + + if not isinstance(r, dict): + return r or [] + if self.http_compression and \ + len(r['response']) >= self.compression_threshold: + encodings = [e.split(';')[0].strip() for e in + environ.get('HTTP_ACCEPT_ENCODING', '').split(',')] + for encoding in encodings: + if encoding in self.compression_methods: + r['response'] = \ + getattr(self, '_' + encoding)(r['response']) + r['headers'] += [('Content-Encoding', encoding)] + break + cors_headers = self._cors_headers(environ) + start_response(r['status'], r['headers'] + cors_headers) + return [r['response']] + + def start_background_task(self, target, *args, **kwargs): + """Start a background task using the appropriate async model. + + This is a utility function that applications can use to start a + background task using the method that is compatible with the + selected async mode. + + :param target: the target function to execute. + :param args: arguments to pass to the function. + :param kwargs: keyword arguments to pass to the function. + + This function returns an object compatible with the `Thread` class in + the Python standard library. The `start()` method on this object is + already called by this function. + """ + th = self._async['thread'](target=target, args=args, kwargs=kwargs) + th.start() + return th # pragma: no cover + + def sleep(self, seconds=0): + """Sleep for the requested amount of time using the appropriate async + model. + + This is a utility function that applications can use to put a task to + sleep without having to worry about using the correct call for the + selected async mode. + """ + return self._async['sleep'](seconds) + + def create_queue(self, *args, **kwargs): + """Create a queue object using the appropriate async model. + + This is a utility function that applications can use to create a queue + without having to worry about using the correct call for the selected + async mode. + """ + return self._async['queue'](*args, **kwargs) + + def get_queue_empty_exception(self): + """Return the queue empty exception for the appropriate async model. + + This is a utility function that applications can use to work with a + queue without having to worry about using the correct call for the + selected async mode. + """ + return self._async['queue_empty'] + + def create_event(self, *args, **kwargs): + """Create an event object using the appropriate async model. + + This is a utility function that applications can use to create an + event without having to worry about using the correct call for the + selected async mode. + """ + return self._async['event'](*args, **kwargs) + + def _generate_id(self): + """Generate a unique session id.""" + return uuid.uuid4().hex + + def _handle_connect(self, environ, start_response, transport, b64=False, + jsonp_index=None): + """Handle a client connection request.""" + if self.start_service_task: + # start the service task to monitor connected clients + self.start_service_task = False + self.start_background_task(self._service_task) + + sid = self._generate_id() + s = socket.Socket(self, sid) + self.sockets[sid] = s + + pkt = packet.Packet( + packet.OPEN, {'sid': sid, + 'upgrades': self._upgrades(sid, transport), + 'pingTimeout': int(self.ping_timeout * 1000), + 'pingInterval': int(self.ping_interval * 1000)}) + s.send(pkt) + + ret = self._trigger_event('connect', sid, environ, run_async=False) + if ret is False: + del self.sockets[sid] + self.logger.warning('Application rejected connection') + return self._unauthorized() + + if transport == 'websocket': + ret = s.handle_get_request(environ, start_response) + if s.closed: + # websocket connection ended, so we are done + del self.sockets[sid] + return ret + else: + s.connected = True + headers = None + if self.cookie: + headers = [('Set-Cookie', self.cookie + '=' + sid)] + try: + return self._ok(s.poll(), headers=headers, b64=b64, + jsonp_index=jsonp_index) + except exceptions.QueueEmpty: + return self._bad_request() + + def _upgrades(self, sid, transport): + """Return the list of possible upgrades for a client connection.""" + if not self.allow_upgrades or self._get_socket(sid).upgraded or \ + self._async['websocket'] is None or transport == 'websocket': + return [] + return ['websocket'] + + def _trigger_event(self, event, *args, **kwargs): + """Invoke an event handler.""" + run_async = kwargs.pop('run_async', False) + if event in self.handlers: + if run_async: + return self.start_background_task(self.handlers[event], *args) + else: + try: + return self.handlers[event](*args) + except: + self.logger.exception(event + ' handler error') + if event == 'connect': + # if connect handler raised error we reject the + # connection + return False + + def _get_socket(self, sid): + """Return the socket object for a given session.""" + try: + s = self.sockets[sid] + except KeyError: + raise KeyError('Session not found') + if s.closed: + del self.sockets[sid] + raise KeyError('Session is disconnected') + return s + + def _ok(self, packets=None, headers=None, b64=False, jsonp_index=None): + """Generate a successful HTTP response.""" + if packets is not None: + if headers is None: + headers = [] + if b64: + headers += [('Content-Type', 'text/plain; charset=UTF-8')] + else: + headers += [('Content-Type', 'application/octet-stream')] + return {'status': '200 OK', + 'headers': headers, + 'response': payload.Payload(packets=packets).encode( + b64=b64, jsonp_index=jsonp_index)} + else: + return {'status': '200 OK', + 'headers': [('Content-Type', 'text/plain')], + 'response': b'OK'} + + def _bad_request(self): + """Generate a bad request HTTP error response.""" + return {'status': '400 BAD REQUEST', + 'headers': [('Content-Type', 'text/plain')], + 'response': b'Bad Request'} + + def _method_not_found(self): + """Generate a method not found HTTP error response.""" + return {'status': '405 METHOD NOT FOUND', + 'headers': [('Content-Type', 'text/plain')], + 'response': b'Method Not Found'} + + def _unauthorized(self): + """Generate a unauthorized HTTP error response.""" + return {'status': '401 UNAUTHORIZED', + 'headers': [('Content-Type', 'text/plain')], + 'response': b'Unauthorized'} + + def _cors_headers(self, environ): + """Return the cross-origin-resource-sharing headers.""" + if isinstance(self.cors_allowed_origins, six.string_types): + if self.cors_allowed_origins == '*': + allowed_origins = None + else: + allowed_origins = [self.cors_allowed_origins] + else: + allowed_origins = self.cors_allowed_origins + if allowed_origins is not None and \ + environ.get('HTTP_ORIGIN', '') not in allowed_origins: + return [] + if 'HTTP_ORIGIN' in environ: + headers = [('Access-Control-Allow-Origin', environ['HTTP_ORIGIN'])] + else: + headers = [('Access-Control-Allow-Origin', '*')] + if environ['REQUEST_METHOD'] == 'OPTIONS': + headers += [('Access-Control-Allow-Methods', 'OPTIONS, GET, POST')] + if 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' in environ: + headers += [('Access-Control-Allow-Headers', + environ['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])] + if self.cors_credentials: + headers += [('Access-Control-Allow-Credentials', 'true')] + return headers + + def _gzip(self, response): + """Apply gzip compression to a response.""" + bytesio = six.BytesIO() + with gzip.GzipFile(fileobj=bytesio, mode='w') as gz: + gz.write(response) + return bytesio.getvalue() + + def _deflate(self, response): + """Apply deflate compression to a response.""" + return zlib.compress(response) + + def _service_task(self): # pragma: no cover + """Monitor connected clients and clean up those that time out.""" + while True: + if len(self.sockets) == 0: + # nothing to do + self.sleep(self.ping_timeout) + continue + + # go through the entire client list in a ping interval cycle + sleep_interval = self.ping_timeout / len(self.sockets) + + try: + # iterate over the current clients + for s in self.sockets.copy().values(): + if not s.closing and not s.closed: + s.check_ping_timeout() + self.sleep(sleep_interval) + except (SystemExit, KeyboardInterrupt): + self.logger.info('service task canceled') + break + except: + # an unexpected exception has occurred, log it and continue + self.logger.exception('service task exception') diff --git a/openpype/vendor/python/python_2/engineio/socket.py b/openpype/vendor/python/python_2/engineio/socket.py new file mode 100644 index 0000000000..495088ae3e --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/socket.py @@ -0,0 +1,247 @@ +import six +import sys +import time + +from . import exceptions +from . import packet +from . import payload + + +class Socket(object): + """An Engine.IO socket.""" + upgrade_protocols = ['websocket'] + + def __init__(self, server, sid): + self.server = server + self.sid = sid + self.queue = self.server.create_queue() + self.last_ping = time.time() + self.connected = False + self.upgrading = False + self.upgraded = False + self.packet_backlog = [] + self.closing = False + self.closed = False + self.session = {} + + def poll(self): + """Wait for packets to send to the client.""" + queue_empty = self.server.get_queue_empty_exception() + try: + packets = [self.queue.get(timeout=self.server.ping_timeout)] + self.queue.task_done() + except queue_empty: + raise exceptions.QueueEmpty() + if packets == [None]: + return [] + while True: + try: + packets.append(self.queue.get(block=False)) + self.queue.task_done() + except queue_empty: + break + return packets + + def receive(self, pkt): + """Receive packet from the client.""" + packet_name = packet.packet_names[pkt.packet_type] \ + if pkt.packet_type < len(packet.packet_names) else 'UNKNOWN' + self.server.logger.info('%s: Received packet %s data %s', + self.sid, packet_name, + pkt.data if not isinstance(pkt.data, bytes) + else '') + if pkt.packet_type == packet.PING: + self.last_ping = time.time() + self.send(packet.Packet(packet.PONG, pkt.data)) + elif pkt.packet_type == packet.MESSAGE: + self.server._trigger_event('message', self.sid, pkt.data, + run_async=self.server.async_handlers) + elif pkt.packet_type == packet.UPGRADE: + self.send(packet.Packet(packet.NOOP)) + elif pkt.packet_type == packet.CLOSE: + self.close(wait=False, abort=True) + else: + raise exceptions.UnknownPacketError() + + def check_ping_timeout(self): + """Make sure the client is still sending pings. + + This helps detect disconnections for long-polling clients. + """ + if self.closed: + raise exceptions.SocketIsClosedError() + if time.time() - self.last_ping > self.server.ping_interval + 5: + self.server.logger.info('%s: Client is gone, closing socket', + self.sid) + # Passing abort=False here will cause close() to write a + # CLOSE packet. This has the effect of updating half-open sockets + # to their correct state of disconnected + self.close(wait=False, abort=False) + return False + return True + + def send(self, pkt): + """Send a packet to the client.""" + if not self.check_ping_timeout(): + return + if self.upgrading: + self.packet_backlog.append(pkt) + else: + self.queue.put(pkt) + self.server.logger.info('%s: Sending packet %s data %s', + self.sid, packet.packet_names[pkt.packet_type], + pkt.data if not isinstance(pkt.data, bytes) + else '') + + def handle_get_request(self, environ, start_response): + """Handle a long-polling GET request from the client.""" + connections = [ + s.strip() + for s in environ.get('HTTP_CONNECTION', '').lower().split(',')] + transport = environ.get('HTTP_UPGRADE', '').lower() + if 'upgrade' in connections and transport in self.upgrade_protocols: + self.server.logger.info('%s: Received request to upgrade to %s', + self.sid, transport) + return getattr(self, '_upgrade_' + transport)(environ, + start_response) + try: + packets = self.poll() + except exceptions.QueueEmpty: + exc = sys.exc_info() + self.close(wait=False) + six.reraise(*exc) + return packets + + def handle_post_request(self, environ): + """Handle a long-polling POST request from the client.""" + length = int(environ.get('CONTENT_LENGTH', '0')) + if length > self.server.max_http_buffer_size: + raise exceptions.ContentTooLongError() + else: + body = environ['wsgi.input'].read(length) + p = payload.Payload(encoded_payload=body) + for pkt in p.packets: + self.receive(pkt) + + def close(self, wait=True, abort=False): + """Close the socket connection.""" + if not self.closed and not self.closing: + self.closing = True + self.server._trigger_event('disconnect', self.sid, run_async=False) + if not abort: + self.send(packet.Packet(packet.CLOSE)) + self.closed = True + self.queue.put(None) + if wait: + self.queue.join() + + def _upgrade_websocket(self, environ, start_response): + """Upgrade the connection from polling to websocket.""" + if self.upgraded: + raise IOError('Socket has been upgraded already') + if self.server._async['websocket'] is None: + # the selected async mode does not support websocket + return self.server._bad_request() + ws = self.server._async['websocket'](self._websocket_handler) + return ws(environ, start_response) + + def _websocket_handler(self, ws): + """Engine.IO handler for websocket transport.""" + # try to set a socket timeout matching the configured ping interval + for attr in ['_sock', 'socket']: # pragma: no cover + if hasattr(ws, attr) and hasattr(getattr(ws, attr), 'settimeout'): + getattr(ws, attr).settimeout(self.server.ping_timeout) + + if self.connected: + # the socket was already connected, so this is an upgrade + self.upgrading = True # hold packet sends during the upgrade + + pkt = ws.wait() + decoded_pkt = packet.Packet(encoded_packet=pkt) + if decoded_pkt.packet_type != packet.PING or \ + decoded_pkt.data != 'probe': + self.server.logger.info( + '%s: Failed websocket upgrade, no PING packet', self.sid) + return [] + ws.send(packet.Packet( + packet.PONG, + data=six.text_type('probe')).encode(always_bytes=False)) + self.queue.put(packet.Packet(packet.NOOP)) # end poll + + pkt = ws.wait() + decoded_pkt = packet.Packet(encoded_packet=pkt) + if decoded_pkt.packet_type != packet.UPGRADE: + self.upgraded = False + self.server.logger.info( + ('%s: Failed websocket upgrade, expected UPGRADE packet, ' + 'received %s instead.'), + self.sid, pkt) + return [] + self.upgraded = True + + # flush any packets that were sent during the upgrade + for pkt in self.packet_backlog: + self.queue.put(pkt) + self.packet_backlog = [] + self.upgrading = False + else: + self.connected = True + self.upgraded = True + + # start separate writer thread + def writer(): + while True: + packets = None + try: + packets = self.poll() + except exceptions.QueueEmpty: + break + if not packets: + # empty packet list returned -> connection closed + break + try: + for pkt in packets: + ws.send(pkt.encode(always_bytes=False)) + except: + break + writer_task = self.server.start_background_task(writer) + + self.server.logger.info( + '%s: Upgrade to websocket successful', self.sid) + + while True: + p = None + try: + p = ws.wait() + except Exception as e: + # if the socket is already closed, we can assume this is a + # downstream error of that + if not self.closed: # pragma: no cover + self.server.logger.info( + '%s: Unexpected error "%s", closing connection', + self.sid, str(e)) + break + if p is None: + # connection closed by client + break + if isinstance(p, six.text_type): # pragma: no cover + p = p.encode('utf-8') + pkt = packet.Packet(encoded_packet=p) + try: + self.receive(pkt) + except exceptions.UnknownPacketError: # pragma: no cover + pass + except exceptions.SocketIsClosedError: # pragma: no cover + self.server.logger.info('Receive error -- socket is closed') + break + except: # pragma: no cover + # if we get an unexpected exception we log the error and exit + # the connection properly + self.server.logger.exception('Unknown receive error') + break + + self.queue.put(None) # unlock the writer task so that it can exit + writer_task.join() + self.close(wait=False, abort=True) + + return [] diff --git a/openpype/vendor/python/python_2/engineio/static_files.py b/openpype/vendor/python/python_2/engineio/static_files.py new file mode 100644 index 0000000000..3058f6ea42 --- /dev/null +++ b/openpype/vendor/python/python_2/engineio/static_files.py @@ -0,0 +1,55 @@ +content_types = { + 'css': 'text/css', + 'gif': 'image/gif', + 'html': 'text/html', + 'jpg': 'image/jpeg', + 'js': 'application/javascript', + 'json': 'application/json', + 'png': 'image/png', + 'txt': 'text/plain', +} + + +def get_static_file(path, static_files): + """Return the local filename and content type for the requested static + file URL. + + :param path: the path portion of the requested URL. + :param static_files: a static file configuration dictionary. + + This function returns a dictionary with two keys, "filename" and + "content_type". If the requested URL does not match any static file, the + return value is None. + """ + if path in static_files: + f = static_files[path] + else: + f = None + rest = '' + while path != '': + path, last = path.rsplit('/', 1) + rest = '/' + last + rest + if path in static_files: + f = static_files[path] + rest + break + elif path + '/' in static_files: + f = static_files[path + '/'] + rest[1:] + break + if f: + if isinstance(f, str): + f = {'filename': f} + if f['filename'].endswith('/'): + if '' in static_files: + if isinstance(static_files[''], str): + f['filename'] += static_files[''] + else: + f['filename'] += static_files['']['filename'] + if 'content_type' in static_files['']: + f['content_type'] = static_files['']['content_type'] + else: + f['filename'] += 'index.html' + if 'content_type' not in f: + ext = f['filename'].rsplit('.')[-1] + f['content_type'] = content_types.get( + ext, 'application/octet-stream') + return f diff --git a/openpype/vendor/python/python_2/socketio/__init__.py b/openpype/vendor/python/python_2/socketio/__init__.py new file mode 100644 index 0000000000..f0a9541820 --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/__init__.py @@ -0,0 +1,35 @@ +import sys + +from .client import Client +from .base_manager import BaseManager +from .pubsub_manager import PubSubManager +from .kombu_manager import KombuManager +from .redis_manager import RedisManager +from .zmq_manager import ZmqManager +from .server import Server +from .namespace import Namespace, ClientNamespace +from .middleware import WSGIApp, Middleware +from .tornado import get_tornado_handler +if sys.version_info >= (3, 5): # pragma: no cover + from .asyncio_client import AsyncClient + from .asyncio_server import AsyncServer + from .asyncio_manager import AsyncManager + from .asyncio_namespace import AsyncNamespace, AsyncClientNamespace + from .asyncio_redis_manager import AsyncRedisManager + from .asgi import ASGIApp +else: # pragma: no cover + AsyncClient = None + AsyncServer = None + AsyncManager = None + AsyncNamespace = None + AsyncRedisManager = None + +__version__ = '4.2.1' + +__all__ = ['__version__', 'Client', 'Server', 'BaseManager', 'PubSubManager', + 'KombuManager', 'RedisManager', 'ZmqManager', 'Namespace', + 'ClientNamespace', 'WSGIApp', 'Middleware'] +if AsyncServer is not None: # pragma: no cover + __all__ += ['AsyncClient', 'AsyncServer', 'AsyncNamespace', + 'AsyncClientNamespace', 'AsyncManager', 'AsyncRedisManager', + 'ASGIApp', 'get_tornado_handler'] diff --git a/openpype/vendor/python/python_2/socketio/asgi.py b/openpype/vendor/python/python_2/socketio/asgi.py new file mode 100644 index 0000000000..9bcdd03bac --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/asgi.py @@ -0,0 +1,36 @@ +import engineio + + +class ASGIApp(engineio.ASGIApp): # pragma: no cover + """ASGI application middleware for Socket.IO. + + This middleware dispatches traffic to an Socket.IO application. It can + also serve a list of static files to the client, or forward unrelated + HTTP traffic to another ASGI application. + + :param socketio_server: The Socket.IO server. Must be an instance of the + ``socketio.AsyncServer`` class. + :param static_files: A dictionary with static file mapping rules. See the + documentation for details on this argument. + :param other_asgi_app: A separate ASGI app that receives all other traffic. + :param socketio_path: The endpoint where the Socket.IO application should + be installed. The default value is appropriate for + most cases. + + Example usage:: + + import socketio + import uvicorn + + sio = socketio.AsyncServer() + app = engineio.ASGIApp(sio, static_files={ + '/': 'index.html', + '/static': './public', + }) + uvicorn.run(app, host='127.0.0.1', port=5000) + """ + def __init__(self, socketio_server, other_asgi_app=None, + static_files=None, socketio_path='socket.io'): + super().__init__(socketio_server, other_asgi_app, + static_files=static_files, + engineio_path=socketio_path) diff --git a/openpype/vendor/python/python_2/socketio/asyncio_client.py b/openpype/vendor/python/python_2/socketio/asyncio_client.py new file mode 100644 index 0000000000..d71ccecfaa --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/asyncio_client.py @@ -0,0 +1,445 @@ +import asyncio +import logging +import random + +import engineio +import six + +from . import client +from . import exceptions +from . import packet + +default_logger = logging.getLogger('socketio.client') + + +class AsyncClient(client.Client): + """A Socket.IO client for asyncio. + + This class implements a fully compliant Socket.IO web client with support + for websocket and long-polling transports. + + :param reconnection: ``True`` if the client should automatically attempt to + reconnect to the server after an interruption, or + ``False`` to not reconnect. The default is ``True``. + :param reconnection_attempts: How many reconnection attempts to issue + before giving up, or 0 for infinity attempts. + The default is 0. + :param reconnection_delay: How long to wait in seconds before the first + reconnection attempt. Each successive attempt + doubles this delay. + :param reconnection_delay_max: The maximum delay between reconnection + attempts. + :param randomization_factor: Randomization amount for each delay between + reconnection attempts. The default is 0.5, + which means that each delay is randomly + adjusted by +/- 50%. + :param logger: To enable logging set to ``True`` or pass a logger object to + use. To disable logging set to ``False``. The default is + ``False``. + :param binary: ``True`` to support binary payloads, ``False`` to treat all + payloads as text. On Python 2, if this is set to ``True``, + ``unicode`` values are treated as text, and ``str`` and + ``bytes`` values are treated as binary. This option has no + effect on Python 3, where text and binary payloads are + always automatically discovered. + :param json: An alternative json module to use for encoding and decoding + packets. Custom json modules must have ``dumps`` and ``loads`` + functions that are compatible with the standard library + versions. + + The Engine.IO configuration supports the following settings: + + :param engineio_logger: To enable Engine.IO logging set to ``True`` or pass + a logger object to use. To disable logging set to + ``False``. The default is ``False``. + """ + def is_asyncio_based(self): + return True + + async def connect(self, url, headers={}, transports=None, + namespaces=None, socketio_path='socket.io'): + """Connect to a Socket.IO server. + + :param url: The URL of the Socket.IO server. It can include custom + query string parameters if required by the server. + :param headers: A dictionary with custom headers to send with the + connection request. + :param transports: The list of allowed transports. Valid transports + are ``'polling'`` and ``'websocket'``. If not + given, the polling transport is connected first, + then an upgrade to websocket is attempted. + :param namespaces: The list of custom namespaces to connect, in + addition to the default namespace. If not given, + the namespace list is obtained from the registered + event handlers. + :param socketio_path: The endpoint where the Socket.IO server is + installed. The default value is appropriate for + most cases. + + Note: this method is a coroutine. + + Example usage:: + + sio = socketio.Client() + sio.connect('http://localhost:5000') + """ + self.connection_url = url + self.connection_headers = headers + self.connection_transports = transports + self.connection_namespaces = namespaces + self.socketio_path = socketio_path + + if namespaces is None: + namespaces = set(self.handlers.keys()).union( + set(self.namespace_handlers.keys())) + elif isinstance(namespaces, six.string_types): + namespaces = [namespaces] + self.connection_namespaces = namespaces + self.namespaces = [n for n in namespaces if n != '/'] + try: + await self.eio.connect(url, headers=headers, + transports=transports, + engineio_path=socketio_path) + except engineio.exceptions.ConnectionError as exc: + six.raise_from(exceptions.ConnectionError(exc.args[0]), None) + + async def wait(self): + """Wait until the connection with the server ends. + + Client applications can use this function to block the main thread + during the life of the connection. + + Note: this method is a coroutine. + """ + while True: + await self.eio.wait() + await self.sleep(1) # give the reconnect task time to start up + if not self._reconnect_task: + break + await self._reconnect_task + if self.eio.state != 'connected': + break + + async def emit(self, event, data=None, namespace=None, callback=None): + """Emit a custom event to one or more connected clients. + + :param event: The event name. It can be any string. The event names + ``'connect'``, ``'message'`` and ``'disconnect'`` are + reserved and should not be used. + :param data: The data to send to the client or clients. Data can be of + type ``str``, ``bytes``, ``list`` or ``dict``. If a + ``list`` or ``dict``, the data will be serialized as JSON. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the event is emitted to the + default namespace. + :param callback: If given, this function will be called to acknowledge + the the client has received the message. The arguments + that will be passed to the function are those provided + by the client. Callback functions can only be used + when addressing an individual client. + + Note: this method is a coroutine. + """ + namespace = namespace or '/' + self.logger.info('Emitting event "%s" [%s]', event, namespace) + if callback is not None: + id = self._generate_ack_id(namespace, callback) + else: + id = None + if six.PY2 and not self.binary: + binary = False # pragma: nocover + else: + binary = None + # tuples are expanded to multiple arguments, everything else is sent + # as a single argument + if isinstance(data, tuple): + data = list(data) + elif data is not None: + data = [data] + else: + data = [] + await self._send_packet(packet.Packet( + packet.EVENT, namespace=namespace, data=[event] + data, id=id, + binary=binary)) + + async def send(self, data, namespace=None, callback=None): + """Send a message to one or more connected clients. + + This function emits an event with the name ``'message'``. Use + :func:`emit` to issue custom event names. + + :param data: The data to send to the client or clients. Data can be of + type ``str``, ``bytes``, ``list`` or ``dict``. If a + ``list`` or ``dict``, the data will be serialized as JSON. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the event is emitted to the + default namespace. + :param callback: If given, this function will be called to acknowledge + the the client has received the message. The arguments + that will be passed to the function are those provided + by the client. Callback functions can only be used + when addressing an individual client. + + Note: this method is a coroutine. + """ + await self.emit('message', data=data, namespace=namespace, + callback=callback) + + async def call(self, event, data=None, namespace=None, timeout=60): + """Emit a custom event to a client and wait for the response. + + :param event: The event name. It can be any string. The event names + ``'connect'``, ``'message'`` and ``'disconnect'`` are + reserved and should not be used. + :param data: The data to send to the client or clients. Data can be of + type ``str``, ``bytes``, ``list`` or ``dict``. If a + ``list`` or ``dict``, the data will be serialized as JSON. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the event is emitted to the + default namespace. + :param timeout: The waiting timeout. If the timeout is reached before + the client acknowledges the event, then a + ``TimeoutError`` exception is raised. + + Note: this method is a coroutine. + """ + callback_event = self.eio.create_event() + callback_args = [] + + def event_callback(*args): + callback_args.append(args) + callback_event.set() + + await self.emit(event, data=data, namespace=namespace, + callback=event_callback) + try: + await asyncio.wait_for(callback_event.wait(), timeout) + except asyncio.TimeoutError: + six.raise_from(exceptions.TimeoutError(), None) + return callback_args[0] if len(callback_args[0]) > 1 \ + else callback_args[0][0] if len(callback_args[0]) == 1 \ + else None + + async def disconnect(self): + """Disconnect from the server. + + Note: this method is a coroutine. + """ + # here we just request the disconnection + # later in _handle_eio_disconnect we invoke the disconnect handler + for n in self.namespaces: + await self._send_packet(packet.Packet(packet.DISCONNECT, + namespace=n)) + await self._send_packet(packet.Packet( + packet.DISCONNECT, namespace='/')) + await self.eio.disconnect(abort=True) + + def start_background_task(self, target, *args, **kwargs): + """Start a background task using the appropriate async model. + + This is a utility function that applications can use to start a + background task using the method that is compatible with the + selected async mode. + + :param target: the target function to execute. + :param args: arguments to pass to the function. + :param kwargs: keyword arguments to pass to the function. + + This function returns an object compatible with the `Thread` class in + the Python standard library. The `start()` method on this object is + already called by this function. + """ + return self.eio.start_background_task(target, *args, **kwargs) + + async def sleep(self, seconds=0): + """Sleep for the requested amount of time using the appropriate async + model. + + This is a utility function that applications can use to put a task to + sleep without having to worry about using the correct call for the + selected async mode. + + Note: this method is a coroutine. + """ + return await self.eio.sleep(seconds) + + async def _send_packet(self, pkt): + """Send a Socket.IO packet to the server.""" + encoded_packet = pkt.encode() + if isinstance(encoded_packet, list): + binary = False + for ep in encoded_packet: + await self.eio.send(ep, binary=binary) + binary = True + else: + await self.eio.send(encoded_packet, binary=False) + + async def _handle_connect(self, namespace): + namespace = namespace or '/' + self.logger.info('Namespace {} is connected'.format(namespace)) + await self._trigger_event('connect', namespace=namespace) + if namespace == '/': + for n in self.namespaces: + await self._send_packet(packet.Packet(packet.CONNECT, + namespace=n)) + elif namespace not in self.namespaces: + self.namespaces.append(namespace) + + async def _handle_disconnect(self, namespace): + namespace = namespace or '/' + await self._trigger_event('disconnect', namespace=namespace) + if namespace in self.namespaces: + self.namespaces.remove(namespace) + + async def _handle_event(self, namespace, id, data): + namespace = namespace or '/' + self.logger.info('Received event "%s" [%s]', data[0], namespace) + r = await self._trigger_event(data[0], namespace, *data[1:]) + if id is not None: + # send ACK packet with the response returned by the handler + # tuples are expanded as multiple arguments + if r is None: + data = [] + elif isinstance(r, tuple): + data = list(r) + else: + data = [r] + if six.PY2 and not self.binary: + binary = False # pragma: nocover + else: + binary = None + await self._send_packet(packet.Packet( + packet.ACK, namespace=namespace, id=id, data=data, + binary=binary)) + + async def _handle_ack(self, namespace, id, data): + namespace = namespace or '/' + self.logger.info('Received ack [%s]', namespace) + callback = None + try: + callback = self.callbacks[namespace][id] + except KeyError: + # if we get an unknown callback we just ignore it + self.logger.warning('Unknown callback received, ignoring.') + else: + del self.callbacks[namespace][id] + if callback is not None: + if asyncio.iscoroutinefunction(callback): + await callback(*data) + else: + callback(*data) + + def _handle_error(self, namespace): + namespace = namespace or '/' + self.logger.info('Connection to namespace {} was rejected'.format( + namespace)) + if namespace in self.namespaces: + self.namespaces.remove(namespace) + + async def _trigger_event(self, event, namespace, *args): + """Invoke an application event handler.""" + # first see if we have an explicit handler for the event + if namespace in self.handlers and event in self.handlers[namespace]: + if asyncio.iscoroutinefunction(self.handlers[namespace][event]): + try: + ret = await self.handlers[namespace][event](*args) + except asyncio.CancelledError: # pragma: no cover + ret = None + else: + ret = self.handlers[namespace][event](*args) + return ret + + # or else, forward the event to a namepsace handler if one exists + elif namespace in self.namespace_handlers: + return await self.namespace_handlers[namespace].trigger_event( + event, *args) + + async def _handle_reconnect(self): + self._reconnect_abort.clear() + client.reconnecting_clients.append(self) + attempt_count = 0 + current_delay = self.reconnection_delay + while True: + delay = current_delay + current_delay *= 2 + if delay > self.reconnection_delay_max: + delay = self.reconnection_delay_max + delay += self.randomization_factor * (2 * random.random() - 1) + self.logger.info( + 'Connection failed, new attempt in {:.02f} seconds'.format( + delay)) + try: + await asyncio.wait_for(self._reconnect_abort.wait(), delay) + self.logger.info('Reconnect task aborted') + break + except (asyncio.TimeoutError, asyncio.CancelledError): + pass + attempt_count += 1 + try: + await self.connect(self.connection_url, + headers=self.connection_headers, + transports=self.connection_transports, + namespaces=self.connection_namespaces, + socketio_path=self.socketio_path) + except (exceptions.ConnectionError, ValueError): + pass + else: + self.logger.info('Reconnection successful') + self._reconnect_task = None + break + if self.reconnection_attempts and \ + attempt_count >= self.reconnection_attempts: + self.logger.info( + 'Maximum reconnection attempts reached, giving up') + break + client.reconnecting_clients.remove(self) + + def _handle_eio_connect(self): + """Handle the Engine.IO connection event.""" + self.logger.info('Engine.IO connection established') + self.sid = self.eio.sid + + async def _handle_eio_message(self, data): + """Dispatch Engine.IO messages.""" + if self._binary_packet: + pkt = self._binary_packet + if pkt.add_attachment(data): + self._binary_packet = None + if pkt.packet_type == packet.BINARY_EVENT: + await self._handle_event(pkt.namespace, pkt.id, pkt.data) + else: + await self._handle_ack(pkt.namespace, pkt.id, pkt.data) + else: + pkt = packet.Packet(encoded_packet=data) + if pkt.packet_type == packet.CONNECT: + await self._handle_connect(pkt.namespace) + elif pkt.packet_type == packet.DISCONNECT: + await self._handle_disconnect(pkt.namespace) + elif pkt.packet_type == packet.EVENT: + await self._handle_event(pkt.namespace, pkt.id, pkt.data) + elif pkt.packet_type == packet.ACK: + await self._handle_ack(pkt.namespace, pkt.id, pkt.data) + elif pkt.packet_type == packet.BINARY_EVENT or \ + pkt.packet_type == packet.BINARY_ACK: + self._binary_packet = pkt + elif pkt.packet_type == packet.ERROR: + self._handle_error(pkt.namespace) + else: + raise ValueError('Unknown packet type.') + + async def _handle_eio_disconnect(self): + """Handle the Engine.IO disconnection event.""" + self.logger.info('Engine.IO connection dropped') + self._reconnect_abort.set() + for n in self.namespaces: + await self._trigger_event('disconnect', namespace=n) + await self._trigger_event('disconnect', namespace='/') + self.callbacks = {} + self._binary_packet = None + self.sid = None + if self.eio.state == 'connected' and self.reconnection: + self._reconnect_task = self.start_background_task( + self._handle_reconnect) + + def _engineio_client_class(self): + return engineio.AsyncClient diff --git a/openpype/vendor/python/python_2/socketio/asyncio_manager.py b/openpype/vendor/python/python_2/socketio/asyncio_manager.py new file mode 100644 index 0000000000..f4496ec7f4 --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/asyncio_manager.py @@ -0,0 +1,58 @@ +import asyncio + +from .base_manager import BaseManager + + +class AsyncManager(BaseManager): + """Manage a client list for an asyncio server.""" + async def emit(self, event, data, namespace, room=None, skip_sid=None, + callback=None, **kwargs): + """Emit a message to a single client, a room, or all the clients + connected to the namespace. + + Note: this method is a coroutine. + """ + if namespace not in self.rooms or room not in self.rooms[namespace]: + return + tasks = [] + if not isinstance(skip_sid, list): + skip_sid = [skip_sid] + for sid in self.get_participants(namespace, room): + if sid not in skip_sid: + if callback is not None: + id = self._generate_ack_id(sid, namespace, callback) + else: + id = None + tasks.append(self.server._emit_internal(sid, event, data, + namespace, id)) + if tasks == []: # pragma: no cover + return + await asyncio.wait(tasks) + + async def close_room(self, room, namespace): + """Remove all participants from a room. + + Note: this method is a coroutine. + """ + return super().close_room(room, namespace) + + async def trigger_callback(self, sid, namespace, id, data): + """Invoke an application callback. + + Note: this method is a coroutine. + """ + callback = None + try: + callback = self.callbacks[sid][namespace][id] + except KeyError: + # if we get an unknown callback we just ignore it + self._get_logger().warning('Unknown callback received, ignoring.') + else: + del self.callbacks[sid][namespace][id] + if callback is not None: + ret = callback(*data) + if asyncio.iscoroutine(ret): + try: + await ret + except asyncio.CancelledError: # pragma: no cover + pass diff --git a/openpype/vendor/python/python_2/socketio/asyncio_namespace.py b/openpype/vendor/python/python_2/socketio/asyncio_namespace.py new file mode 100644 index 0000000000..12e9c0fe62 --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/asyncio_namespace.py @@ -0,0 +1,204 @@ +import asyncio + +from socketio import namespace + + +class AsyncNamespace(namespace.Namespace): + """Base class for asyncio server-side class-based namespaces. + + A class-based namespace is a class that contains all the event handlers + for a Socket.IO namespace. The event handlers are methods of the class + with the prefix ``on_``, such as ``on_connect``, ``on_disconnect``, + ``on_message``, ``on_json``, and so on. These can be regular functions or + coroutines. + + :param namespace: The Socket.IO namespace to be used with all the event + handlers defined in this class. If this argument is + omitted, the default namespace is used. + """ + def is_asyncio_based(self): + return True + + async def trigger_event(self, event, *args): + """Dispatch an event to the proper handler method. + + In the most common usage, this method is not overloaded by subclasses, + as it performs the routing of events to methods. However, this + method can be overriden if special dispatching rules are needed, or if + having a single method that catches all events is desired. + + Note: this method is a coroutine. + """ + handler_name = 'on_' + event + if hasattr(self, handler_name): + handler = getattr(self, handler_name) + if asyncio.iscoroutinefunction(handler) is True: + try: + ret = await handler(*args) + except asyncio.CancelledError: # pragma: no cover + ret = None + else: + ret = handler(*args) + return ret + + async def emit(self, event, data=None, room=None, skip_sid=None, + namespace=None, callback=None): + """Emit a custom event to one or more connected clients. + + The only difference with the :func:`socketio.Server.emit` method is + that when the ``namespace`` argument is not given the namespace + associated with the class is used. + + Note: this method is a coroutine. + """ + return await self.server.emit(event, data=data, room=room, + skip_sid=skip_sid, + namespace=namespace or self.namespace, + callback=callback) + + async def send(self, data, room=None, skip_sid=None, namespace=None, + callback=None): + """Send a message to one or more connected clients. + + The only difference with the :func:`socketio.Server.send` method is + that when the ``namespace`` argument is not given the namespace + associated with the class is used. + + Note: this method is a coroutine. + """ + return await self.server.send(data, room=room, skip_sid=skip_sid, + namespace=namespace or self.namespace, + callback=callback) + + async def close_room(self, room, namespace=None): + """Close a room. + + The only difference with the :func:`socketio.Server.close_room` method + is that when the ``namespace`` argument is not given the namespace + associated with the class is used. + + Note: this method is a coroutine. + """ + return await self.server.close_room( + room, namespace=namespace or self.namespace) + + async def get_session(self, sid, namespace=None): + """Return the user session for a client. + + The only difference with the :func:`socketio.Server.get_session` + method is that when the ``namespace`` argument is not given the + namespace associated with the class is used. + + Note: this method is a coroutine. + """ + return await self.server.get_session( + sid, namespace=namespace or self.namespace) + + async def save_session(self, sid, session, namespace=None): + """Store the user session for a client. + + The only difference with the :func:`socketio.Server.save_session` + method is that when the ``namespace`` argument is not given the + namespace associated with the class is used. + + Note: this method is a coroutine. + """ + return await self.server.save_session( + sid, session, namespace=namespace or self.namespace) + + def session(self, sid, namespace=None): + """Return the user session for a client with context manager syntax. + + The only difference with the :func:`socketio.Server.session` method is + that when the ``namespace`` argument is not given the namespace + associated with the class is used. + """ + return self.server.session(sid, namespace=namespace or self.namespace) + + async def disconnect(self, sid, namespace=None): + """Disconnect a client. + + The only difference with the :func:`socketio.Server.disconnect` method + is that when the ``namespace`` argument is not given the namespace + associated with the class is used. + + Note: this method is a coroutine. + """ + return await self.server.disconnect( + sid, namespace=namespace or self.namespace) + + +class AsyncClientNamespace(namespace.ClientNamespace): + """Base class for asyncio client-side class-based namespaces. + + A class-based namespace is a class that contains all the event handlers + for a Socket.IO namespace. The event handlers are methods of the class + with the prefix ``on_``, such as ``on_connect``, ``on_disconnect``, + ``on_message``, ``on_json``, and so on. These can be regular functions or + coroutines. + + :param namespace: The Socket.IO namespace to be used with all the event + handlers defined in this class. If this argument is + omitted, the default namespace is used. + """ + def is_asyncio_based(self): + return True + + async def trigger_event(self, event, *args): + """Dispatch an event to the proper handler method. + + In the most common usage, this method is not overloaded by subclasses, + as it performs the routing of events to methods. However, this + method can be overriden if special dispatching rules are needed, or if + having a single method that catches all events is desired. + + Note: this method is a coroutine. + """ + handler_name = 'on_' + event + if hasattr(self, handler_name): + handler = getattr(self, handler_name) + if asyncio.iscoroutinefunction(handler) is True: + try: + ret = await handler(*args) + except asyncio.CancelledError: # pragma: no cover + ret = None + else: + ret = handler(*args) + return ret + + async def emit(self, event, data=None, namespace=None, callback=None): + """Emit a custom event to the server. + + The only difference with the :func:`socketio.Client.emit` method is + that when the ``namespace`` argument is not given the namespace + associated with the class is used. + + Note: this method is a coroutine. + """ + return await self.client.emit(event, data=data, + namespace=namespace or self.namespace, + callback=callback) + + async def send(self, data, namespace=None, callback=None): + """Send a message to the server. + + The only difference with the :func:`socketio.Client.send` method is + that when the ``namespace`` argument is not given the namespace + associated with the class is used. + + Note: this method is a coroutine. + """ + return await self.client.send(data, + namespace=namespace or self.namespace, + callback=callback) + + async def disconnect(self): + """Disconnect a client. + + The only difference with the :func:`socketio.Client.disconnect` method + is that when the ``namespace`` argument is not given the namespace + associated with the class is used. + + Note: this method is a coroutine. + """ + return await self.client.disconnect() diff --git a/openpype/vendor/python/python_2/socketio/asyncio_pubsub_manager.py b/openpype/vendor/python/python_2/socketio/asyncio_pubsub_manager.py new file mode 100644 index 0000000000..6fdba6d0ce --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/asyncio_pubsub_manager.py @@ -0,0 +1,163 @@ +from functools import partial +import uuid + +import json +import pickle +import six + +from .asyncio_manager import AsyncManager + + +class AsyncPubSubManager(AsyncManager): + """Manage a client list attached to a pub/sub backend under asyncio. + + This is a base class that enables multiple servers to share the list of + clients, with the servers communicating events through a pub/sub backend. + The use of a pub/sub backend also allows any client connected to the + backend to emit events addressed to Socket.IO clients. + + The actual backends must be implemented by subclasses, this class only + provides a pub/sub generic framework for asyncio applications. + + :param channel: The channel name on which the server sends and receives + notifications. + """ + name = 'asyncpubsub' + + def __init__(self, channel='socketio', write_only=False, logger=None): + super().__init__() + self.channel = channel + self.write_only = write_only + self.host_id = uuid.uuid4().hex + self.logger = logger + + def initialize(self): + super().initialize() + if not self.write_only: + self.thread = self.server.start_background_task(self._thread) + self._get_logger().info(self.name + ' backend initialized.') + + async def emit(self, event, data, namespace=None, room=None, skip_sid=None, + callback=None, **kwargs): + """Emit a message to a single client, a room, or all the clients + connected to the namespace. + + This method takes care or propagating the message to all the servers + that are connected through the message queue. + + The parameters are the same as in :meth:`.Server.emit`. + + Note: this method is a coroutine. + """ + if kwargs.get('ignore_queue'): + return await super().emit( + event, data, namespace=namespace, room=room, skip_sid=skip_sid, + callback=callback) + namespace = namespace or '/' + if callback is not None: + if self.server is None: + raise RuntimeError('Callbacks can only be issued from the ' + 'context of a server.') + if room is None: + raise ValueError('Cannot use callback without a room set.') + id = self._generate_ack_id(room, namespace, callback) + callback = (room, namespace, id) + else: + callback = None + await self._publish({'method': 'emit', 'event': event, 'data': data, + 'namespace': namespace, 'room': room, + 'skip_sid': skip_sid, 'callback': callback, + 'host_id': self.host_id}) + + async def close_room(self, room, namespace=None): + await self._publish({'method': 'close_room', 'room': room, + 'namespace': namespace or '/'}) + + async def _publish(self, data): + """Publish a message on the Socket.IO channel. + + This method needs to be implemented by the different subclasses that + support pub/sub backends. + """ + raise NotImplementedError('This method must be implemented in a ' + 'subclass.') # pragma: no cover + + async def _listen(self): + """Return the next message published on the Socket.IO channel, + blocking until a message is available. + + This method needs to be implemented by the different subclasses that + support pub/sub backends. + """ + raise NotImplementedError('This method must be implemented in a ' + 'subclass.') # pragma: no cover + + async def _handle_emit(self, message): + # Events with callbacks are very tricky to handle across hosts + # Here in the receiving end we set up a local callback that preserves + # the callback host and id from the sender + remote_callback = message.get('callback') + remote_host_id = message.get('host_id') + if remote_callback is not None and len(remote_callback) == 3: + callback = partial(self._return_callback, remote_host_id, + *remote_callback) + else: + callback = None + await super().emit(message['event'], message['data'], + namespace=message.get('namespace'), + room=message.get('room'), + skip_sid=message.get('skip_sid'), + callback=callback) + + async def _handle_callback(self, message): + if self.host_id == message.get('host_id'): + try: + sid = message['sid'] + namespace = message['namespace'] + id = message['id'] + args = message['args'] + except KeyError: + return + await self.trigger_callback(sid, namespace, id, args) + + async def _return_callback(self, host_id, sid, namespace, callback_id, + *args): + # When an event callback is received, the callback is returned back + # the sender, which is identified by the host_id + await self._publish({'method': 'callback', 'host_id': host_id, + 'sid': sid, 'namespace': namespace, + 'id': callback_id, 'args': args}) + + async def _handle_close_room(self, message): + await super().close_room( + room=message.get('room'), namespace=message.get('namespace')) + + async def _thread(self): + while True: + try: + message = await self._listen() + except: + import traceback + traceback.print_exc() + break + data = None + if isinstance(message, dict): + data = message + else: + if isinstance(message, six.binary_type): # pragma: no cover + try: + data = pickle.loads(message) + except: + pass + if data is None: + try: + data = json.loads(message) + except: + pass + if data and 'method' in data: + if data['method'] == 'emit': + await self._handle_emit(data) + elif data['method'] == 'callback': + await self._handle_callback(data) + elif data['method'] == 'close_room': + await self._handle_close_room(data) diff --git a/openpype/vendor/python/python_2/socketio/asyncio_redis_manager.py b/openpype/vendor/python/python_2/socketio/asyncio_redis_manager.py new file mode 100644 index 0000000000..21499c26c5 --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/asyncio_redis_manager.py @@ -0,0 +1,107 @@ +import asyncio +import pickle +from urllib.parse import urlparse + +try: + import aioredis +except ImportError: + aioredis = None + +from .asyncio_pubsub_manager import AsyncPubSubManager + + +def _parse_redis_url(url): + p = urlparse(url) + if p.scheme not in {'redis', 'rediss'}: + raise ValueError('Invalid redis url') + ssl = p.scheme == 'rediss' + host = p.hostname or 'localhost' + port = p.port or 6379 + password = p.password + if p.path: + db = int(p.path[1:]) + else: + db = 0 + return host, port, password, db, ssl + + +class AsyncRedisManager(AsyncPubSubManager): # pragma: no cover + """Redis based client manager for asyncio servers. + + This class implements a Redis backend for event sharing across multiple + processes. Only kept here as one more example of how to build a custom + backend, since the kombu backend is perfectly adequate to support a Redis + message queue. + + To use a Redis backend, initialize the :class:`Server` instance as + follows:: + + server = socketio.Server(client_manager=socketio.AsyncRedisManager( + 'redis://hostname:port/0')) + + :param url: The connection URL for the Redis server. For a default Redis + store running on the same host, use ``redis://``. To use an + SSL connection, use ``rediss://``. + :param channel: The channel name on which the server sends and receives + notifications. Must be the same in all the servers. + :param write_only: If set ot ``True``, only initialize to emit events. The + default of ``False`` initializes the class for emitting + and receiving. + """ + name = 'aioredis' + + def __init__(self, url='redis://localhost:6379/0', channel='socketio', + write_only=False, logger=None): + if aioredis is None: + raise RuntimeError('Redis package is not installed ' + '(Run "pip install aioredis" in your ' + 'virtualenv).') + ( + self.host, self.port, self.password, self.db, self.ssl + ) = _parse_redis_url(url) + self.pub = None + self.sub = None + super().__init__(channel=channel, write_only=write_only, logger=logger) + + async def _publish(self, data): + retry = True + while True: + try: + if self.pub is None: + self.pub = await aioredis.create_redis( + (self.host, self.port), db=self.db, + password=self.password, ssl=self.ssl + ) + return await self.pub.publish(self.channel, + pickle.dumps(data)) + except (aioredis.RedisError, OSError): + if retry: + self._get_logger().error('Cannot publish to redis... ' + 'retrying') + self.pub = None + retry = False + else: + self._get_logger().error('Cannot publish to redis... ' + 'giving up') + break + + async def _listen(self): + retry_sleep = 1 + while True: + try: + if self.sub is None: + self.sub = await aioredis.create_redis( + (self.host, self.port), db=self.db, + password=self.password, ssl=self.ssl + ) + self.ch = (await self.sub.subscribe(self.channel))[0] + return await self.ch.get() + except (aioredis.RedisError, OSError): + self._get_logger().error('Cannot receive from redis... ' + 'retrying in ' + '{} secs'.format(retry_sleep)) + self.sub = None + await asyncio.sleep(retry_sleep) + retry_sleep *= 2 + if retry_sleep > 60: + retry_sleep = 60 diff --git a/openpype/vendor/python/python_2/socketio/asyncio_server.py b/openpype/vendor/python/python_2/socketio/asyncio_server.py new file mode 100644 index 0000000000..45f5d86bba --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/asyncio_server.py @@ -0,0 +1,515 @@ +import asyncio + +import engineio +import six + +from . import asyncio_manager +from . import exceptions +from . import packet +from . import server + + +class AsyncServer(server.Server): + """A Socket.IO server for asyncio. + + This class implements a fully compliant Socket.IO web server with support + for websocket and long-polling transports, compatible with the asyncio + framework on Python 3.5 or newer. + + :param client_manager: The client manager instance that will manage the + client list. When this is omitted, the client list + is stored in an in-memory structure, so the use of + multiple connected servers is not possible. + :param logger: To enable logging set to ``True`` or pass a logger object to + use. To disable logging set to ``False``. + :param json: An alternative json module to use for encoding and decoding + packets. Custom json modules must have ``dumps`` and ``loads`` + functions that are compatible with the standard library + versions. + :param async_handlers: If set to ``True``, event handlers are executed in + separate threads. To run handlers synchronously, + set to ``False``. The default is ``True``. + :param kwargs: Connection parameters for the underlying Engine.IO server. + + The Engine.IO configuration supports the following settings: + + :param async_mode: The asynchronous model to use. See the Deployment + section in the documentation for a description of the + available options. Valid async modes are "aiohttp". If + this argument is not given, an async mode is chosen + based on the installed packages. + :param ping_timeout: The time in seconds that the client waits for the + server to respond before disconnecting. + :param ping_interval: The interval in seconds at which the client pings + the server. + :param max_http_buffer_size: The maximum size of a message when using the + polling transport. + :param allow_upgrades: Whether to allow transport upgrades or not. + :param http_compression: Whether to compress packages when using the + polling transport. + :param compression_threshold: Only compress messages when their byte size + is greater than this value. + :param cookie: Name of the HTTP cookie that contains the client session + id. If set to ``None``, a cookie is not sent to the client. + :param cors_allowed_origins: List of origins that are allowed to connect + to this server. All origins are allowed by + default. + :param cors_credentials: Whether credentials (cookies, authentication) are + allowed in requests to this server. + :param engineio_logger: To enable Engine.IO logging set to ``True`` or pass + a logger object to use. To disable logging set to + ``False``. + """ + def __init__(self, client_manager=None, logger=False, json=None, + async_handlers=True, **kwargs): + if client_manager is None: + client_manager = asyncio_manager.AsyncManager() + super().__init__(client_manager=client_manager, logger=logger, + binary=False, json=json, + async_handlers=async_handlers, **kwargs) + + def is_asyncio_based(self): + return True + + def attach(self, app, socketio_path='socket.io'): + """Attach the Socket.IO server to an application.""" + self.eio.attach(app, socketio_path) + + async def emit(self, event, data=None, to=None, room=None, skip_sid=None, + namespace=None, callback=None, **kwargs): + """Emit a custom event to one or more connected clients. + + :param event: The event name. It can be any string. The event names + ``'connect'``, ``'message'`` and ``'disconnect'`` are + reserved and should not be used. + :param data: The data to send to the client or clients. Data can be of + type ``str``, ``bytes``, ``list`` or ``dict``. If a + ``list`` or ``dict``, the data will be serialized as JSON. + :param to: The recipient of the message. This can be set to the + session ID of a client to address only that client, or to + to any custom room created by the application to address all + the clients in that room, If this argument is omitted the + event is broadcasted to all connected clients. + :param room: Alias for the ``to`` parameter. + :param skip_sid: The session ID of a client to skip when broadcasting + to a room or to all clients. This can be used to + prevent a message from being sent to the sender. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the event is emitted to the + default namespace. + :param callback: If given, this function will be called to acknowledge + the the client has received the message. The arguments + that will be passed to the function are those provided + by the client. Callback functions can only be used + when addressing an individual client. + :param ignore_queue: Only used when a message queue is configured. If + set to ``True``, the event is emitted to the + clients directly, without going through the queue. + This is more efficient, but only works when a + single server process is used. It is recommended + to always leave this parameter with its default + value of ``False``. + + Note: this method is a coroutine. + """ + namespace = namespace or '/' + room = to or room + self.logger.info('emitting event "%s" to %s [%s]', event, + room or 'all', namespace) + await self.manager.emit(event, data, namespace, room=room, + skip_sid=skip_sid, callback=callback, + **kwargs) + + async def send(self, data, to=None, room=None, skip_sid=None, + namespace=None, callback=None, **kwargs): + """Send a message to one or more connected clients. + + This function emits an event with the name ``'message'``. Use + :func:`emit` to issue custom event names. + + :param data: The data to send to the client or clients. Data can be of + type ``str``, ``bytes``, ``list`` or ``dict``. If a + ``list`` or ``dict``, the data will be serialized as JSON. + :param to: The recipient of the message. This can be set to the + session ID of a client to address only that client, or to + to any custom room created by the application to address all + the clients in that room, If this argument is omitted the + event is broadcasted to all connected clients. + :param room: Alias for the ``to`` parameter. + :param skip_sid: The session ID of a client to skip when broadcasting + to a room or to all clients. This can be used to + prevent a message from being sent to the sender. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the event is emitted to the + default namespace. + :param callback: If given, this function will be called to acknowledge + the the client has received the message. The arguments + that will be passed to the function are those provided + by the client. Callback functions can only be used + when addressing an individual client. + :param ignore_queue: Only used when a message queue is configured. If + set to ``True``, the event is emitted to the + clients directly, without going through the queue. + This is more efficient, but only works when a + single server process is used. It is recommended + to always leave this parameter with its default + value of ``False``. + + Note: this method is a coroutine. + """ + await self.emit('message', data=data, to=to, room=room, + skip_sid=skip_sid, namespace=namespace, + callback=callback, **kwargs) + + async def call(self, event, data=None, to=None, sid=None, namespace=None, + timeout=60, **kwargs): + """Emit a custom event to a client and wait for the response. + + :param event: The event name. It can be any string. The event names + ``'connect'``, ``'message'`` and ``'disconnect'`` are + reserved and should not be used. + :param data: The data to send to the client or clients. Data can be of + type ``str``, ``bytes``, ``list`` or ``dict``. If a + ``list`` or ``dict``, the data will be serialized as JSON. + :param to: The session ID of the recipient client. + :param sid: Alias for the ``to`` parameter. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the event is emitted to the + default namespace. + :param timeout: The waiting timeout. If the timeout is reached before + the client acknowledges the event, then a + ``TimeoutError`` exception is raised. + :param ignore_queue: Only used when a message queue is configured. If + set to ``True``, the event is emitted to the + client directly, without going through the queue. + This is more efficient, but only works when a + single server process is used. It is recommended + to always leave this parameter with its default + value of ``False``. + """ + if not self.async_handlers: + raise RuntimeError( + 'Cannot use call() when async_handlers is False.') + callback_event = self.eio.create_event() + callback_args = [] + + def event_callback(*args): + callback_args.append(args) + callback_event.set() + + await self.emit(event, data=data, room=to or sid, namespace=namespace, + callback=event_callback, **kwargs) + try: + await asyncio.wait_for(callback_event.wait(), timeout) + except asyncio.TimeoutError: + six.raise_from(exceptions.TimeoutError(), None) + return callback_args[0] if len(callback_args[0]) > 1 \ + else callback_args[0][0] if len(callback_args[0]) == 1 \ + else None + + async def close_room(self, room, namespace=None): + """Close a room. + + This function removes all the clients from the given room. + + :param room: Room name. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the default namespace is used. + + Note: this method is a coroutine. + """ + namespace = namespace or '/' + self.logger.info('room %s is closing [%s]', room, namespace) + await self.manager.close_room(room, namespace) + + async def get_session(self, sid, namespace=None): + """Return the user session for a client. + + :param sid: The session id of the client. + :param namespace: The Socket.IO namespace. If this argument is omitted + the default namespace is used. + + The return value is a dictionary. Modifications made to this + dictionary are not guaranteed to be preserved. If you want to modify + the user session, use the ``session`` context manager instead. + """ + namespace = namespace or '/' + eio_session = await self.eio.get_session(sid) + return eio_session.setdefault(namespace, {}) + + async def save_session(self, sid, session, namespace=None): + """Store the user session for a client. + + :param sid: The session id of the client. + :param session: The session dictionary. + :param namespace: The Socket.IO namespace. If this argument is omitted + the default namespace is used. + """ + namespace = namespace or '/' + eio_session = await self.eio.get_session(sid) + eio_session[namespace] = session + + def session(self, sid, namespace=None): + """Return the user session for a client with context manager syntax. + + :param sid: The session id of the client. + + This is a context manager that returns the user session dictionary for + the client. Any changes that are made to this dictionary inside the + context manager block are saved back to the session. Example usage:: + + @eio.on('connect') + def on_connect(sid, environ): + username = authenticate_user(environ) + if not username: + return False + with eio.session(sid) as session: + session['username'] = username + + @eio.on('message') + def on_message(sid, msg): + async with eio.session(sid) as session: + print('received message from ', session['username']) + """ + class _session_context_manager(object): + def __init__(self, server, sid, namespace): + self.server = server + self.sid = sid + self.namespace = namespace + self.session = None + + async def __aenter__(self): + self.session = await self.server.get_session( + sid, namespace=self.namespace) + return self.session + + async def __aexit__(self, *args): + await self.server.save_session(sid, self.session, + namespace=self.namespace) + + return _session_context_manager(self, sid, namespace) + + async def disconnect(self, sid, namespace=None): + """Disconnect a client. + + :param sid: Session ID of the client. + :param namespace: The Socket.IO namespace to disconnect. If this + argument is omitted the default namespace is used. + + Note: this method is a coroutine. + """ + namespace = namespace or '/' + if self.manager.is_connected(sid, namespace=namespace): + self.logger.info('Disconnecting %s [%s]', sid, namespace) + self.manager.pre_disconnect(sid, namespace=namespace) + await self._send_packet(sid, packet.Packet(packet.DISCONNECT, + namespace=namespace)) + await self._trigger_event('disconnect', namespace, sid) + self.manager.disconnect(sid, namespace=namespace) + + async def handle_request(self, *args, **kwargs): + """Handle an HTTP request from the client. + + This is the entry point of the Socket.IO application. This function + returns the HTTP response body to deliver to the client. + + Note: this method is a coroutine. + """ + return await self.eio.handle_request(*args, **kwargs) + + def start_background_task(self, target, *args, **kwargs): + """Start a background task using the appropriate async model. + + This is a utility function that applications can use to start a + background task using the method that is compatible with the + selected async mode. + + :param target: the target function to execute. Must be a coroutine. + :param args: arguments to pass to the function. + :param kwargs: keyword arguments to pass to the function. + + The return value is a ``asyncio.Task`` object. + + Note: this method is a coroutine. + """ + return self.eio.start_background_task(target, *args, **kwargs) + + async def sleep(self, seconds=0): + """Sleep for the requested amount of time using the appropriate async + model. + + This is a utility function that applications can use to put a task to + sleep without having to worry about using the correct call for the + selected async mode. + + Note: this method is a coroutine. + """ + return await self.eio.sleep(seconds) + + async def _emit_internal(self, sid, event, data, namespace=None, id=None): + """Send a message to a client.""" + # tuples are expanded to multiple arguments, everything else is sent + # as a single argument + if isinstance(data, tuple): + data = list(data) + else: + data = [data] + await self._send_packet(sid, packet.Packet( + packet.EVENT, namespace=namespace, data=[event] + data, id=id, + binary=None)) + + async def _send_packet(self, sid, pkt): + """Send a Socket.IO packet to a client.""" + encoded_packet = pkt.encode() + if isinstance(encoded_packet, list): + binary = False + for ep in encoded_packet: + await self.eio.send(sid, ep, binary=binary) + binary = True + else: + await self.eio.send(sid, encoded_packet, binary=False) + + async def _handle_connect(self, sid, namespace): + """Handle a client connection request.""" + namespace = namespace or '/' + self.manager.connect(sid, namespace) + if self.always_connect: + await self._send_packet(sid, packet.Packet(packet.CONNECT, + namespace=namespace)) + fail_reason = None + try: + success = await self._trigger_event('connect', namespace, sid, + self.environ[sid]) + except exceptions.ConnectionRefusedError as exc: + fail_reason = exc.error_args + success = False + + if success is False: + if self.always_connect: + self.manager.pre_disconnect(sid, namespace) + await self._send_packet(sid, packet.Packet( + packet.DISCONNECT, data=fail_reason, namespace=namespace)) + self.manager.disconnect(sid, namespace) + if not self.always_connect: + await self._send_packet(sid, packet.Packet( + packet.ERROR, data=fail_reason, namespace=namespace)) + if sid in self.environ: # pragma: no cover + del self.environ[sid] + return False + elif not self.always_connect: + await self._send_packet(sid, packet.Packet(packet.CONNECT, + namespace=namespace)) + + async def _handle_disconnect(self, sid, namespace): + """Handle a client disconnect.""" + namespace = namespace or '/' + if namespace == '/': + namespace_list = list(self.manager.get_namespaces()) + else: + namespace_list = [namespace] + for n in namespace_list: + if n != '/' and self.manager.is_connected(sid, n): + await self._trigger_event('disconnect', n, sid) + self.manager.disconnect(sid, n) + if namespace == '/' and self.manager.is_connected(sid, namespace): + await self._trigger_event('disconnect', '/', sid) + self.manager.disconnect(sid, '/') + + async def _handle_event(self, sid, namespace, id, data): + """Handle an incoming client event.""" + namespace = namespace or '/' + self.logger.info('received event "%s" from %s [%s]', data[0], sid, + namespace) + if self.async_handlers: + self.start_background_task(self._handle_event_internal, self, sid, + data, namespace, id) + else: + await self._handle_event_internal(self, sid, data, namespace, id) + + async def _handle_event_internal(self, server, sid, data, namespace, id): + r = await server._trigger_event(data[0], namespace, sid, *data[1:]) + if id is not None: + # send ACK packet with the response returned by the handler + # tuples are expanded as multiple arguments + if r is None: + data = [] + elif isinstance(r, tuple): + data = list(r) + else: + data = [r] + await server._send_packet(sid, packet.Packet(packet.ACK, + namespace=namespace, + id=id, data=data, + binary=None)) + + async def _handle_ack(self, sid, namespace, id, data): + """Handle ACK packets from the client.""" + namespace = namespace or '/' + self.logger.info('received ack from %s [%s]', sid, namespace) + await self.manager.trigger_callback(sid, namespace, id, data) + + async def _trigger_event(self, event, namespace, *args): + """Invoke an application event handler.""" + # first see if we have an explicit handler for the event + if namespace in self.handlers and event in self.handlers[namespace]: + if asyncio.iscoroutinefunction(self.handlers[namespace][event]) \ + is True: + try: + ret = await self.handlers[namespace][event](*args) + except asyncio.CancelledError: # pragma: no cover + ret = None + else: + ret = self.handlers[namespace][event](*args) + return ret + + # or else, forward the event to a namepsace handler if one exists + elif namespace in self.namespace_handlers: + return await self.namespace_handlers[namespace].trigger_event( + event, *args) + + async def _handle_eio_connect(self, sid, environ): + """Handle the Engine.IO connection event.""" + if not self.manager_initialized: + self.manager_initialized = True + self.manager.initialize() + self.environ[sid] = environ + return await self._handle_connect(sid, '/') + + async def _handle_eio_message(self, sid, data): + """Dispatch Engine.IO messages.""" + if sid in self._binary_packet: + pkt = self._binary_packet[sid] + if pkt.add_attachment(data): + del self._binary_packet[sid] + if pkt.packet_type == packet.BINARY_EVENT: + await self._handle_event(sid, pkt.namespace, pkt.id, + pkt.data) + else: + await self._handle_ack(sid, pkt.namespace, pkt.id, + pkt.data) + else: + pkt = packet.Packet(encoded_packet=data) + if pkt.packet_type == packet.CONNECT: + await self._handle_connect(sid, pkt.namespace) + elif pkt.packet_type == packet.DISCONNECT: + await self._handle_disconnect(sid, pkt.namespace) + elif pkt.packet_type == packet.EVENT: + await self._handle_event(sid, pkt.namespace, pkt.id, pkt.data) + elif pkt.packet_type == packet.ACK: + await self._handle_ack(sid, pkt.namespace, pkt.id, pkt.data) + elif pkt.packet_type == packet.BINARY_EVENT or \ + pkt.packet_type == packet.BINARY_ACK: + self._binary_packet[sid] = pkt + elif pkt.packet_type == packet.ERROR: + raise ValueError('Unexpected ERROR packet.') + else: + raise ValueError('Unknown packet type.') + + async def _handle_eio_disconnect(self, sid): + """Handle Engine.IO disconnect event.""" + await self._handle_disconnect(sid, '/') + if sid in self.environ: + del self.environ[sid] + + def _engineio_server_class(self): + return engineio.AsyncServer diff --git a/openpype/vendor/python/python_2/socketio/base_manager.py b/openpype/vendor/python/python_2/socketio/base_manager.py new file mode 100644 index 0000000000..3cccb85690 --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/base_manager.py @@ -0,0 +1,178 @@ +import itertools +import logging + +import six + +default_logger = logging.getLogger('socketio') + + +class BaseManager(object): + """Manage client connections. + + This class keeps track of all the clients and the rooms they are in, to + support the broadcasting of messages. The data used by this class is + stored in a memory structure, making it appropriate only for single process + services. More sophisticated storage backends can be implemented by + subclasses. + """ + def __init__(self): + self.logger = None + self.server = None + self.rooms = {} + self.callbacks = {} + self.pending_disconnect = {} + + def set_server(self, server): + self.server = server + + def initialize(self): + """Invoked before the first request is received. Subclasses can add + their initialization code here. + """ + pass + + def get_namespaces(self): + """Return an iterable with the active namespace names.""" + return six.iterkeys(self.rooms) + + def get_participants(self, namespace, room): + """Return an iterable with the active participants in a room.""" + for sid, active in six.iteritems(self.rooms[namespace][room].copy()): + yield sid + + def connect(self, sid, namespace): + """Register a client connection to a namespace.""" + self.enter_room(sid, namespace, None) + self.enter_room(sid, namespace, sid) + + def is_connected(self, sid, namespace): + if namespace in self.pending_disconnect and \ + sid in self.pending_disconnect[namespace]: + # the client is in the process of being disconnected + return False + try: + return self.rooms[namespace][None][sid] + except KeyError: + pass + + def pre_disconnect(self, sid, namespace): + """Put the client in the to-be-disconnected list. + + This allows the client data structures to be present while the + disconnect handler is invoked, but still recognize the fact that the + client is soon going away. + """ + if namespace not in self.pending_disconnect: + self.pending_disconnect[namespace] = [] + self.pending_disconnect[namespace].append(sid) + + def disconnect(self, sid, namespace): + """Register a client disconnect from a namespace.""" + if namespace not in self.rooms: + return + rooms = [] + for room_name, room in six.iteritems(self.rooms[namespace].copy()): + if sid in room: + rooms.append(room_name) + for room in rooms: + self.leave_room(sid, namespace, room) + if sid in self.callbacks and namespace in self.callbacks[sid]: + del self.callbacks[sid][namespace] + if len(self.callbacks[sid]) == 0: + del self.callbacks[sid] + if namespace in self.pending_disconnect and \ + sid in self.pending_disconnect[namespace]: + self.pending_disconnect[namespace].remove(sid) + if len(self.pending_disconnect[namespace]) == 0: + del self.pending_disconnect[namespace] + + def enter_room(self, sid, namespace, room): + """Add a client to a room.""" + if namespace not in self.rooms: + self.rooms[namespace] = {} + if room not in self.rooms[namespace]: + self.rooms[namespace][room] = {} + self.rooms[namespace][room][sid] = True + + def leave_room(self, sid, namespace, room): + """Remove a client from a room.""" + try: + del self.rooms[namespace][room][sid] + if len(self.rooms[namespace][room]) == 0: + del self.rooms[namespace][room] + if len(self.rooms[namespace]) == 0: + del self.rooms[namespace] + except KeyError: + pass + + def close_room(self, room, namespace): + """Remove all participants from a room.""" + try: + for sid in self.get_participants(namespace, room): + self.leave_room(sid, namespace, room) + except KeyError: + pass + + def get_rooms(self, sid, namespace): + """Return the rooms a client is in.""" + r = [] + try: + for room_name, room in six.iteritems(self.rooms[namespace]): + if room_name is not None and sid in room and room[sid]: + r.append(room_name) + except KeyError: + pass + return r + + def emit(self, event, data, namespace, room=None, skip_sid=None, + callback=None, **kwargs): + """Emit a message to a single client, a room, or all the clients + connected to the namespace.""" + if namespace not in self.rooms or room not in self.rooms[namespace]: + return + if not isinstance(skip_sid, list): + skip_sid = [skip_sid] + for sid in self.get_participants(namespace, room): + if sid not in skip_sid: + if callback is not None: + id = self._generate_ack_id(sid, namespace, callback) + else: + id = None + self.server._emit_internal(sid, event, data, namespace, id) + + def trigger_callback(self, sid, namespace, id, data): + """Invoke an application callback.""" + callback = None + try: + callback = self.callbacks[sid][namespace][id] + except KeyError: + # if we get an unknown callback we just ignore it + self._get_logger().warning('Unknown callback received, ignoring.') + else: + del self.callbacks[sid][namespace][id] + if callback is not None: + callback(*data) + + def _generate_ack_id(self, sid, namespace, callback): + """Generate a unique identifier for an ACK packet.""" + namespace = namespace or '/' + if sid not in self.callbacks: + self.callbacks[sid] = {} + if namespace not in self.callbacks[sid]: + self.callbacks[sid][namespace] = {0: itertools.count(1)} + id = six.next(self.callbacks[sid][namespace][0]) + self.callbacks[sid][namespace][id] = callback + return id + + def _get_logger(self): + """Get the appropriate logger + + Prevents uninitialized servers in write-only mode from failing. + """ + + if self.logger: + return self.logger + elif self.server: + return self.server.logger + else: + return default_logger diff --git a/openpype/vendor/python/python_2/socketio/client.py b/openpype/vendor/python/python_2/socketio/client.py new file mode 100644 index 0000000000..c0bdc1ab13 --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/client.py @@ -0,0 +1,590 @@ +import itertools +import logging +import random +import signal + +import engineio +import six + +from . import exceptions +from . import namespace +from . import packet + +default_logger = logging.getLogger('socketio.client') +reconnecting_clients = [] + + +def signal_handler(sig, frame): # pragma: no cover + """SIGINT handler. + + Notify any clients that are in a reconnect loop to abort. Other + disconnection tasks are handled at the engine.io level. + """ + for client in reconnecting_clients[:]: + client._reconnect_abort.set() + return original_signal_handler(sig, frame) + + +original_signal_handler = signal.signal(signal.SIGINT, signal_handler) + + +class Client(object): + """A Socket.IO client. + + This class implements a fully compliant Socket.IO web client with support + for websocket and long-polling transports. + + :param reconnection: ``True`` if the client should automatically attempt to + reconnect to the server after an interruption, or + ``False`` to not reconnect. The default is ``True``. + :param reconnection_attempts: How many reconnection attempts to issue + before giving up, or 0 for infinity attempts. + The default is 0. + :param reconnection_delay: How long to wait in seconds before the first + reconnection attempt. Each successive attempt + doubles this delay. + :param reconnection_delay_max: The maximum delay between reconnection + attempts. + :param randomization_factor: Randomization amount for each delay between + reconnection attempts. The default is 0.5, + which means that each delay is randomly + adjusted by +/- 50%. + :param logger: To enable logging set to ``True`` or pass a logger object to + use. To disable logging set to ``False``. The default is + ``False``. + :param binary: ``True`` to support binary payloads, ``False`` to treat all + payloads as text. On Python 2, if this is set to ``True``, + ``unicode`` values are treated as text, and ``str`` and + ``bytes`` values are treated as binary. This option has no + effect on Python 3, where text and binary payloads are + always automatically discovered. + :param json: An alternative json module to use for encoding and decoding + packets. Custom json modules must have ``dumps`` and ``loads`` + functions that are compatible with the standard library + versions. + + The Engine.IO configuration supports the following settings: + + :param engineio_logger: To enable Engine.IO logging set to ``True`` or pass + a logger object to use. To disable logging set to + ``False``. The default is ``False``. + """ + def __init__(self, reconnection=True, reconnection_attempts=0, + reconnection_delay=1, reconnection_delay_max=5, + randomization_factor=0.5, logger=False, binary=False, + json=None, **kwargs): + self.reconnection = reconnection + self.reconnection_attempts = reconnection_attempts + self.reconnection_delay = reconnection_delay + self.reconnection_delay_max = reconnection_delay_max + self.randomization_factor = randomization_factor + self.binary = binary + + engineio_options = kwargs + engineio_logger = engineio_options.pop('engineio_logger', None) + if engineio_logger is not None: + engineio_options['logger'] = engineio_logger + if json is not None: + packet.Packet.json = json + engineio_options['json'] = json + + self.eio = self._engineio_client_class()(**engineio_options) + self.eio.on('connect', self._handle_eio_connect) + self.eio.on('message', self._handle_eio_message) + self.eio.on('disconnect', self._handle_eio_disconnect) + + if not isinstance(logger, bool): + self.logger = logger + else: + self.logger = default_logger + if not logging.root.handlers and \ + self.logger.level == logging.NOTSET: + if logger: + self.logger.setLevel(logging.INFO) + else: + self.logger.setLevel(logging.ERROR) + self.logger.addHandler(logging.StreamHandler()) + + self.connection_url = None + self.connection_headers = None + self.connection_transports = None + self.connection_namespaces = None + self.socketio_path = None + self.sid = None + + self.namespaces = [] + self.handlers = {} + self.namespace_handlers = {} + self.callbacks = {} + self._binary_packet = None + self._reconnect_task = None + self._reconnect_abort = self.eio.create_event() + + def is_asyncio_based(self): + return False + + def on(self, event, handler=None, namespace=None): + """Register an event handler. + + :param event: The event name. It can be any string. The event names + ``'connect'``, ``'message'`` and ``'disconnect'`` are + reserved and should not be used. + :param handler: The function that should be invoked to handle the + event. When this parameter is not given, the method + acts as a decorator for the handler function. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the handler is associated with + the default namespace. + + Example usage:: + + # as a decorator: + @sio.on('connect') + def connect_handler(): + print('Connected!') + + # as a method: + def message_handler(msg): + print('Received message: ', msg) + sio.send( 'response') + sio.on('message', message_handler) + + The ``'connect'`` event handler receives no arguments. The + ``'message'`` handler and handlers for custom event names receive the + message payload as only argument. Any values returned from a message + handler will be passed to the client's acknowledgement callback + function if it exists. The ``'disconnect'`` handler does not take + arguments. + """ + namespace = namespace or '/' + + def set_handler(handler): + if namespace not in self.handlers: + self.handlers[namespace] = {} + self.handlers[namespace][event] = handler + return handler + + if handler is None: + return set_handler + set_handler(handler) + + def event(self, *args, **kwargs): + """Decorator to register an event handler. + + This is a simplified version of the ``on()`` method that takes the + event name from the decorated function. + + Example usage:: + + @sio.event + def my_event(data): + print('Received data: ', data) + + The above example is equivalent to:: + + @sio.on('my_event') + def my_event(data): + print('Received data: ', data) + + A custom namespace can be given as an argument to the decorator:: + + @sio.event(namespace='/test') + def my_event(data): + print('Received data: ', data) + """ + if len(args) == 1 and len(kwargs) == 0 and callable(args[0]): + # the decorator was invoked without arguments + # args[0] is the decorated function + return self.on(args[0].__name__)(args[0]) + else: + # the decorator was invoked with arguments + def set_handler(handler): + return self.on(handler.__name__, *args, **kwargs)(handler) + + return set_handler + + def register_namespace(self, namespace_handler): + """Register a namespace handler object. + + :param namespace_handler: An instance of a :class:`Namespace` + subclass that handles all the event traffic + for a namespace. + """ + if not isinstance(namespace_handler, namespace.ClientNamespace): + raise ValueError('Not a namespace instance') + if self.is_asyncio_based() != namespace_handler.is_asyncio_based(): + raise ValueError('Not a valid namespace class for this client') + namespace_handler._set_client(self) + self.namespace_handlers[namespace_handler.namespace] = \ + namespace_handler + + def connect(self, url, headers={}, transports=None, + namespaces=None, socketio_path='socket.io'): + """Connect to a Socket.IO server. + + :param url: The URL of the Socket.IO server. It can include custom + query string parameters if required by the server. + :param headers: A dictionary with custom headers to send with the + connection request. + :param transports: The list of allowed transports. Valid transports + are ``'polling'`` and ``'websocket'``. If not + given, the polling transport is connected first, + then an upgrade to websocket is attempted. + :param namespaces: The list of custom namespaces to connect, in + addition to the default namespace. If not given, + the namespace list is obtained from the registered + event handlers. + :param socketio_path: The endpoint where the Socket.IO server is + installed. The default value is appropriate for + most cases. + + Example usage:: + + sio = socketio.Client() + sio.connect('http://localhost:5000') + """ + self.connection_url = url + self.connection_headers = headers + self.connection_transports = transports + self.connection_namespaces = namespaces + self.socketio_path = socketio_path + + if namespaces is None: + namespaces = set(self.handlers.keys()).union( + set(self.namespace_handlers.keys())) + elif isinstance(namespaces, six.string_types): + namespaces = [namespaces] + self.connection_namespaces = namespaces + self.namespaces = [n for n in namespaces if n != '/'] + try: + self.eio.connect(url, headers=headers, transports=transports, + engineio_path=socketio_path) + except engineio.exceptions.ConnectionError as exc: + six.raise_from(exceptions.ConnectionError(exc.args[0]), None) + + def wait(self): + """Wait until the connection with the server ends. + + Client applications can use this function to block the main thread + during the life of the connection. + """ + while True: + self.eio.wait() + self.sleep(1) # give the reconnect task time to start up + if not self._reconnect_task: + break + self._reconnect_task.join() + if self.eio.state != 'connected': + break + + def emit(self, event, data=None, namespace=None, callback=None): + """Emit a custom event to one or more connected clients. + + :param event: The event name. It can be any string. The event names + ``'connect'``, ``'message'`` and ``'disconnect'`` are + reserved and should not be used. + :param data: The data to send to the client or clients. Data can be of + type ``str``, ``bytes``, ``list`` or ``dict``. If a + ``list`` or ``dict``, the data will be serialized as JSON. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the event is emitted to the + default namespace. + :param callback: If given, this function will be called to acknowledge + the the client has received the message. The arguments + that will be passed to the function are those provided + by the client. Callback functions can only be used + when addressing an individual client. + """ + namespace = namespace or '/' + self.logger.info('Emitting event "%s" [%s]', event, namespace) + if callback is not None: + id = self._generate_ack_id(namespace, callback) + else: + id = None + if six.PY2 and not self.binary: + binary = False # pragma: nocover + else: + binary = None + # tuples are expanded to multiple arguments, everything else is sent + # as a single argument + if isinstance(data, tuple): + data = list(data) + elif data is not None: + data = [data] + else: + data = [] + self._send_packet(packet.Packet(packet.EVENT, namespace=namespace, + data=[event] + data, id=id, + binary=binary)) + + def send(self, data, namespace=None, callback=None): + """Send a message to one or more connected clients. + + This function emits an event with the name ``'message'``. Use + :func:`emit` to issue custom event names. + + :param data: The data to send to the client or clients. Data can be of + type ``str``, ``bytes``, ``list`` or ``dict``. If a + ``list`` or ``dict``, the data will be serialized as JSON. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the event is emitted to the + default namespace. + :param callback: If given, this function will be called to acknowledge + the the client has received the message. The arguments + that will be passed to the function are those provided + by the client. Callback functions can only be used + when addressing an individual client. + """ + self.emit('message', data=data, namespace=namespace, + callback=callback) + + def call(self, event, data=None, namespace=None, timeout=60): + """Emit a custom event to a client and wait for the response. + + :param event: The event name. It can be any string. The event names + ``'connect'``, ``'message'`` and ``'disconnect'`` are + reserved and should not be used. + :param data: The data to send to the client or clients. Data can be of + type ``str``, ``bytes``, ``list`` or ``dict``. If a + ``list`` or ``dict``, the data will be serialized as JSON. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the event is emitted to the + default namespace. + :param timeout: The waiting timeout. If the timeout is reached before + the client acknowledges the event, then a + ``TimeoutError`` exception is raised. + """ + callback_event = self.eio.create_event() + callback_args = [] + + def event_callback(*args): + callback_args.append(args) + callback_event.set() + + self.emit(event, data=data, namespace=namespace, + callback=event_callback) + if not callback_event.wait(timeout=timeout): + raise exceptions.TimeoutError() + return callback_args[0] if len(callback_args[0]) > 1 \ + else callback_args[0][0] if len(callback_args[0]) == 1 \ + else None + + def disconnect(self): + """Disconnect from the server.""" + # here we just request the disconnection + # later in _handle_eio_disconnect we invoke the disconnect handler + for n in self.namespaces: + self._send_packet(packet.Packet(packet.DISCONNECT, namespace=n)) + self._send_packet(packet.Packet( + packet.DISCONNECT, namespace='/')) + self.eio.disconnect(abort=True) + + def transport(self): + """Return the name of the transport used by the client. + + The two possible values returned by this function are ``'polling'`` + and ``'websocket'``. + """ + return self.eio.transport() + + def start_background_task(self, target, *args, **kwargs): + """Start a background task using the appropriate async model. + + This is a utility function that applications can use to start a + background task using the method that is compatible with the + selected async mode. + + :param target: the target function to execute. + :param args: arguments to pass to the function. + :param kwargs: keyword arguments to pass to the function. + + This function returns an object compatible with the `Thread` class in + the Python standard library. The `start()` method on this object is + already called by this function. + """ + return self.eio.start_background_task(target, *args, **kwargs) + + def sleep(self, seconds=0): + """Sleep for the requested amount of time using the appropriate async + model. + + This is a utility function that applications can use to put a task to + sleep without having to worry about using the correct call for the + selected async mode. + """ + return self.eio.sleep(seconds) + + def _send_packet(self, pkt): + """Send a Socket.IO packet to the server.""" + encoded_packet = pkt.encode() + if isinstance(encoded_packet, list): + binary = False + for ep in encoded_packet: + self.eio.send(ep, binary=binary) + binary = True + else: + self.eio.send(encoded_packet, binary=False) + + def _generate_ack_id(self, namespace, callback): + """Generate a unique identifier for an ACK packet.""" + namespace = namespace or '/' + if namespace not in self.callbacks: + self.callbacks[namespace] = {0: itertools.count(1)} + id = six.next(self.callbacks[namespace][0]) + self.callbacks[namespace][id] = callback + return id + + def _handle_connect(self, namespace): + namespace = namespace or '/' + self.logger.info('Namespace {} is connected'.format(namespace)) + self._trigger_event('connect', namespace=namespace) + if namespace == '/': + for n in self.namespaces: + self._send_packet(packet.Packet(packet.CONNECT, namespace=n)) + elif namespace not in self.namespaces: + self.namespaces.append(namespace) + + def _handle_disconnect(self, namespace): + namespace = namespace or '/' + self._trigger_event('disconnect', namespace=namespace) + if namespace in self.namespaces: + self.namespaces.remove(namespace) + + def _handle_event(self, namespace, id, data): + namespace = namespace or '/' + self.logger.info('Received event "%s" [%s]', data[0], namespace) + r = self._trigger_event(data[0], namespace, *data[1:]) + if id is not None: + # send ACK packet with the response returned by the handler + # tuples are expanded as multiple arguments + if r is None: + data = [] + elif isinstance(r, tuple): + data = list(r) + else: + data = [r] + if six.PY2 and not self.binary: + binary = False # pragma: nocover + else: + binary = None + self._send_packet(packet.Packet(packet.ACK, namespace=namespace, + id=id, data=data, binary=binary)) + + def _handle_ack(self, namespace, id, data): + namespace = namespace or '/' + self.logger.info('Received ack [%s]', namespace) + callback = None + try: + callback = self.callbacks[namespace][id] + except KeyError: + # if we get an unknown callback we just ignore it + self.logger.warning('Unknown callback received, ignoring.') + else: + del self.callbacks[namespace][id] + if callback is not None: + callback(*data) + + def _handle_error(self, namespace): + namespace = namespace or '/' + self.logger.info('Connection to namespace {} was rejected'.format( + namespace)) + if namespace in self.namespaces: + self.namespaces.remove(namespace) + + def _trigger_event(self, event, namespace, *args): + """Invoke an application event handler.""" + # first see if we have an explicit handler for the event + if namespace in self.handlers and event in self.handlers[namespace]: + return self.handlers[namespace][event](*args) + + # or else, forward the event to a namespace handler if one exists + elif namespace in self.namespace_handlers: + return self.namespace_handlers[namespace].trigger_event( + event, *args) + + def _handle_reconnect(self): + self._reconnect_abort.clear() + reconnecting_clients.append(self) + attempt_count = 0 + current_delay = self.reconnection_delay + while True: + delay = current_delay + current_delay *= 2 + if delay > self.reconnection_delay_max: + delay = self.reconnection_delay_max + delay += self.randomization_factor * (2 * random.random() - 1) + self.logger.info( + 'Connection failed, new attempt in {:.02f} seconds'.format( + delay)) + print('***', self._reconnect_abort.wait) + if self._reconnect_abort.wait(delay): + self.logger.info('Reconnect task aborted') + break + attempt_count += 1 + try: + self.connect(self.connection_url, + headers=self.connection_headers, + transports=self.connection_transports, + namespaces=self.connection_namespaces, + socketio_path=self.socketio_path) + except (exceptions.ConnectionError, ValueError): + pass + else: + self.logger.info('Reconnection successful') + self._reconnect_task = None + break + if self.reconnection_attempts and \ + attempt_count >= self.reconnection_attempts: + self.logger.info( + 'Maximum reconnection attempts reached, giving up') + break + reconnecting_clients.remove(self) + + def _handle_eio_connect(self): + """Handle the Engine.IO connection event.""" + self.logger.info('Engine.IO connection established') + self.sid = self.eio.sid + + def _handle_eio_message(self, data): + """Dispatch Engine.IO messages.""" + if self._binary_packet: + pkt = self._binary_packet + if pkt.add_attachment(data): + self._binary_packet = None + if pkt.packet_type == packet.BINARY_EVENT: + self._handle_event(pkt.namespace, pkt.id, pkt.data) + else: + self._handle_ack(pkt.namespace, pkt.id, pkt.data) + else: + pkt = packet.Packet(encoded_packet=data) + if pkt.packet_type == packet.CONNECT: + self._handle_connect(pkt.namespace) + elif pkt.packet_type == packet.DISCONNECT: + self._handle_disconnect(pkt.namespace) + elif pkt.packet_type == packet.EVENT: + self._handle_event(pkt.namespace, pkt.id, pkt.data) + elif pkt.packet_type == packet.ACK: + self._handle_ack(pkt.namespace, pkt.id, pkt.data) + elif pkt.packet_type == packet.BINARY_EVENT or \ + pkt.packet_type == packet.BINARY_ACK: + self._binary_packet = pkt + elif pkt.packet_type == packet.ERROR: + self._handle_error(pkt.namespace) + else: + raise ValueError('Unknown packet type.') + + def _handle_eio_disconnect(self): + """Handle the Engine.IO disconnection event.""" + self.logger.info('Engine.IO connection dropped') + for n in self.namespaces: + self._trigger_event('disconnect', namespace=n) + self._trigger_event('disconnect', namespace='/') + self.callbacks = {} + self._binary_packet = None + self.sid = None + if self.eio.state == 'connected' and self.reconnection: + self._reconnect_task = self.start_background_task( + self._handle_reconnect) + + def _engineio_client_class(self): + return engineio.Client diff --git a/openpype/vendor/python/python_2/socketio/exceptions.py b/openpype/vendor/python/python_2/socketio/exceptions.py new file mode 100644 index 0000000000..344aabb569 --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/exceptions.py @@ -0,0 +1,26 @@ +class SocketIOError(Exception): + pass + + +class ConnectionError(SocketIOError): + pass + + +class ConnectionRefusedError(ConnectionError): + """Connection refused exception. + + This exception can be raised from a connect handler when the connection + is not accepted. The positional arguments provided with the exception are + returned with the error packet to the client. + """ + def __init__(self, *args): + if len(args) == 0: + self.error_args = None + elif len(args) == 1: + self.error_args = args[0] + else: + self.error_args = args + + +class TimeoutError(SocketIOError): + pass diff --git a/openpype/vendor/python/python_2/socketio/kombu_manager.py b/openpype/vendor/python/python_2/socketio/kombu_manager.py new file mode 100644 index 0000000000..4394a6d3ea --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/kombu_manager.py @@ -0,0 +1,105 @@ +import pickle +import uuid + +try: + import kombu +except ImportError: + kombu = None + +from .pubsub_manager import PubSubManager + + +class KombuManager(PubSubManager): # pragma: no cover + """Client manager that uses kombu for inter-process messaging. + + This class implements a client manager backend for event sharing across + multiple processes, using RabbitMQ, Redis or any other messaging mechanism + supported by `kombu `_. + + To use a kombu backend, initialize the :class:`Server` instance as + follows:: + + url = 'amqp://user:password@hostname:port//' + server = socketio.Server(client_manager=socketio.KombuManager(url)) + + :param url: The connection URL for the backend messaging queue. Example + connection URLs are ``'amqp://guest:guest@localhost:5672//'`` + and ``'redis://localhost:6379/'`` for RabbitMQ and Redis + respectively. Consult the `kombu documentation + `_ for more on how to construct + connection URLs. + :param channel: The channel name on which the server sends and receives + notifications. Must be the same in all the servers. + :param write_only: If set ot ``True``, only initialize to emit events. The + default of ``False`` initializes the class for emitting + and receiving. + """ + name = 'kombu' + + def __init__(self, url='amqp://guest:guest@localhost:5672//', + channel='socketio', write_only=False, logger=None): + if kombu is None: + raise RuntimeError('Kombu package is not installed ' + '(Run "pip install kombu" in your ' + 'virtualenv).') + super(KombuManager, self).__init__(channel=channel, + write_only=write_only, + logger=logger) + self.url = url + self.producer = self._producer() + + def initialize(self): + super(KombuManager, self).initialize() + + monkey_patched = True + if self.server.async_mode == 'eventlet': + from eventlet.patcher import is_monkey_patched + monkey_patched = is_monkey_patched('socket') + elif 'gevent' in self.server.async_mode: + from gevent.monkey import is_module_patched + monkey_patched = is_module_patched('socket') + if not monkey_patched: + raise RuntimeError( + 'Kombu requires a monkey patched socket library to work ' + 'with ' + self.server.async_mode) + + def _connection(self): + return kombu.Connection(self.url) + + def _exchange(self): + return kombu.Exchange(self.channel, type='fanout', durable=False) + + def _queue(self): + queue_name = 'flask-socketio.' + str(uuid.uuid4()) + return kombu.Queue(queue_name, self._exchange(), + durable=False, + queue_arguments={'x-expires': 300000}) + + def _producer(self): + return self._connection().Producer(exchange=self._exchange()) + + def __error_callback(self, exception, interval): + self._get_logger().exception('Sleeping {}s'.format(interval)) + + def _publish(self, data): + connection = self._connection() + publish = connection.ensure(self.producer, self.producer.publish, + errback=self.__error_callback) + publish(pickle.dumps(data)) + + def _listen(self): + reader_queue = self._queue() + + while True: + connection = self._connection().ensure_connection( + errback=self.__error_callback) + try: + with connection.SimpleQueue(reader_queue) as queue: + while True: + message = queue.get(block=True) + message.ack() + yield message.payload + except connection.connection_errors: + self._get_logger().exception("Connection error " + "while reading from queue") diff --git a/openpype/vendor/python/python_2/socketio/middleware.py b/openpype/vendor/python/python_2/socketio/middleware.py new file mode 100644 index 0000000000..1a69740857 --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/middleware.py @@ -0,0 +1,42 @@ +import engineio + + +class WSGIApp(engineio.WSGIApp): + """WSGI middleware for Socket.IO. + + This middleware dispatches traffic to a Socket.IO application. It can also + serve a list of static files to the client, or forward unrelated HTTP + traffic to another WSGI application. + + :param socketio_app: The Socket.IO server. Must be an instance of the + ``socketio.Server`` class. + :param wsgi_app: The WSGI app that receives all other traffic. + :param static_files: A dictionary with static file mapping rules. See the + documentation for details on this argument. + :param socketio_path: The endpoint where the Socket.IO application should + be installed. The default value is appropriate for + most cases. + + Example usage:: + + import socketio + import eventlet + from . import wsgi_app + + sio = socketio.Server() + app = socketio.WSGIApp(sio, wsgi_app) + eventlet.wsgi.server(eventlet.listen(('', 8000)), app) + """ + def __init__(self, socketio_app, wsgi_app=None, static_files=None, + socketio_path='socket.io'): + super(WSGIApp, self).__init__(socketio_app, wsgi_app, + static_files=static_files, + engineio_path=socketio_path) + + +class Middleware(WSGIApp): + """This class has been renamed to WSGIApp and is now deprecated.""" + def __init__(self, socketio_app, wsgi_app=None, + socketio_path='socket.io'): + super(Middleware, self).__init__(socketio_app, wsgi_app, + socketio_path=socketio_path) diff --git a/openpype/vendor/python/python_2/socketio/namespace.py b/openpype/vendor/python/python_2/socketio/namespace.py new file mode 100644 index 0000000000..418615ff8e --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/namespace.py @@ -0,0 +1,191 @@ +class BaseNamespace(object): + def __init__(self, namespace=None): + self.namespace = namespace or '/' + + def is_asyncio_based(self): + return False + + def trigger_event(self, event, *args): + """Dispatch an event to the proper handler method. + + In the most common usage, this method is not overloaded by subclasses, + as it performs the routing of events to methods. However, this + method can be overriden if special dispatching rules are needed, or if + having a single method that catches all events is desired. + """ + handler_name = 'on_' + event + if hasattr(self, handler_name): + return getattr(self, handler_name)(*args) + + +class Namespace(BaseNamespace): + """Base class for server-side class-based namespaces. + + A class-based namespace is a class that contains all the event handlers + for a Socket.IO namespace. The event handlers are methods of the class + with the prefix ``on_``, such as ``on_connect``, ``on_disconnect``, + ``on_message``, ``on_json``, and so on. + + :param namespace: The Socket.IO namespace to be used with all the event + handlers defined in this class. If this argument is + omitted, the default namespace is used. + """ + def __init__(self, namespace=None): + super(Namespace, self).__init__(namespace=namespace) + self.server = None + + def _set_server(self, server): + self.server = server + + def emit(self, event, data=None, room=None, skip_sid=None, namespace=None, + callback=None): + """Emit a custom event to one or more connected clients. + + The only difference with the :func:`socketio.Server.emit` method is + that when the ``namespace`` argument is not given the namespace + associated with the class is used. + """ + return self.server.emit(event, data=data, room=room, skip_sid=skip_sid, + namespace=namespace or self.namespace, + callback=callback) + + def send(self, data, room=None, skip_sid=None, namespace=None, + callback=None): + """Send a message to one or more connected clients. + + The only difference with the :func:`socketio.Server.send` method is + that when the ``namespace`` argument is not given the namespace + associated with the class is used. + """ + return self.server.send(data, room=room, skip_sid=skip_sid, + namespace=namespace or self.namespace, + callback=callback) + + def enter_room(self, sid, room, namespace=None): + """Enter a room. + + The only difference with the :func:`socketio.Server.enter_room` method + is that when the ``namespace`` argument is not given the namespace + associated with the class is used. + """ + return self.server.enter_room(sid, room, + namespace=namespace or self.namespace) + + def leave_room(self, sid, room, namespace=None): + """Leave a room. + + The only difference with the :func:`socketio.Server.leave_room` method + is that when the ``namespace`` argument is not given the namespace + associated with the class is used. + """ + return self.server.leave_room(sid, room, + namespace=namespace or self.namespace) + + def close_room(self, room, namespace=None): + """Close a room. + + The only difference with the :func:`socketio.Server.close_room` method + is that when the ``namespace`` argument is not given the namespace + associated with the class is used. + """ + return self.server.close_room(room, + namespace=namespace or self.namespace) + + def rooms(self, sid, namespace=None): + """Return the rooms a client is in. + + The only difference with the :func:`socketio.Server.rooms` method is + that when the ``namespace`` argument is not given the namespace + associated with the class is used. + """ + return self.server.rooms(sid, namespace=namespace or self.namespace) + + def get_session(self, sid, namespace=None): + """Return the user session for a client. + + The only difference with the :func:`socketio.Server.get_session` + method is that when the ``namespace`` argument is not given the + namespace associated with the class is used. + """ + return self.server.get_session( + sid, namespace=namespace or self.namespace) + + def save_session(self, sid, session, namespace=None): + """Store the user session for a client. + + The only difference with the :func:`socketio.Server.save_session` + method is that when the ``namespace`` argument is not given the + namespace associated with the class is used. + """ + return self.server.save_session( + sid, session, namespace=namespace or self.namespace) + + def session(self, sid, namespace=None): + """Return the user session for a client with context manager syntax. + + The only difference with the :func:`socketio.Server.session` method is + that when the ``namespace`` argument is not given the namespace + associated with the class is used. + """ + return self.server.session(sid, namespace=namespace or self.namespace) + + def disconnect(self, sid, namespace=None): + """Disconnect a client. + + The only difference with the :func:`socketio.Server.disconnect` method + is that when the ``namespace`` argument is not given the namespace + associated with the class is used. + """ + return self.server.disconnect(sid, + namespace=namespace or self.namespace) + + +class ClientNamespace(BaseNamespace): + """Base class for client-side class-based namespaces. + + A class-based namespace is a class that contains all the event handlers + for a Socket.IO namespace. The event handlers are methods of the class + with the prefix ``on_``, such as ``on_connect``, ``on_disconnect``, + ``on_message``, ``on_json``, and so on. + + :param namespace: The Socket.IO namespace to be used with all the event + handlers defined in this class. If this argument is + omitted, the default namespace is used. + """ + def __init__(self, namespace=None): + super(ClientNamespace, self).__init__(namespace=namespace) + self.client = None + + def _set_client(self, client): + self.client = client + + def emit(self, event, data=None, namespace=None, callback=None): + """Emit a custom event to the server. + + The only difference with the :func:`socketio.Client.emit` method is + that when the ``namespace`` argument is not given the namespace + associated with the class is used. + """ + return self.client.emit(event, data=data, + namespace=namespace or self.namespace, + callback=callback) + + def send(self, data, room=None, skip_sid=None, namespace=None, + callback=None): + """Send a message to the server. + + The only difference with the :func:`socketio.Client.send` method is + that when the ``namespace`` argument is not given the namespace + associated with the class is used. + """ + return self.client.send(data, namespace=namespace or self.namespace, + callback=callback) + + def disconnect(self): + """Disconnect from the server. + + The only difference with the :func:`socketio.Client.disconnect` method + is that when the ``namespace`` argument is not given the namespace + associated with the class is used. + """ + return self.client.disconnect() diff --git a/openpype/vendor/python/python_2/socketio/packet.py b/openpype/vendor/python/python_2/socketio/packet.py new file mode 100644 index 0000000000..73b469d6d2 --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/packet.py @@ -0,0 +1,179 @@ +import functools +import json as _json + +import six + +(CONNECT, DISCONNECT, EVENT, ACK, ERROR, BINARY_EVENT, BINARY_ACK) = \ + (0, 1, 2, 3, 4, 5, 6) +packet_names = ['CONNECT', 'DISCONNECT', 'EVENT', 'ACK', 'ERROR', + 'BINARY_EVENT', 'BINARY_ACK'] + + +class Packet(object): + """Socket.IO packet.""" + + # the format of the Socket.IO packet is as follows: + # + # packet type: 1 byte, values 0-6 + # num_attachments: ASCII encoded, only if num_attachments != 0 + # '-': only if num_attachments != 0 + # namespace: only if namespace != '/' + # ',': only if namespace and one of id and data are defined in this packet + # id: ASCII encoded, only if id is not None + # data: JSON dump of data payload + + json = _json + + def __init__(self, packet_type=EVENT, data=None, namespace=None, id=None, + binary=None, encoded_packet=None): + self.packet_type = packet_type + self.data = data + self.namespace = namespace + self.id = id + if binary or (binary is None and self._data_is_binary(self.data)): + if self.packet_type == EVENT: + self.packet_type = BINARY_EVENT + elif self.packet_type == ACK: + self.packet_type = BINARY_ACK + else: + raise ValueError('Packet does not support binary payload.') + self.attachment_count = 0 + self.attachments = [] + if encoded_packet: + self.attachment_count = self.decode(encoded_packet) + + def encode(self): + """Encode the packet for transmission. + + If the packet contains binary elements, this function returns a list + of packets where the first is the original packet with placeholders for + the binary components and the remaining ones the binary attachments. + """ + encoded_packet = six.text_type(self.packet_type) + if self.packet_type == BINARY_EVENT or self.packet_type == BINARY_ACK: + data, attachments = self._deconstruct_binary(self.data) + encoded_packet += six.text_type(len(attachments)) + '-' + else: + data = self.data + attachments = None + needs_comma = False + if self.namespace is not None and self.namespace != '/': + encoded_packet += self.namespace + needs_comma = True + if self.id is not None: + if needs_comma: + encoded_packet += ',' + needs_comma = False + encoded_packet += six.text_type(self.id) + if data is not None: + if needs_comma: + encoded_packet += ',' + encoded_packet += self.json.dumps(data, separators=(',', ':')) + if attachments is not None: + encoded_packet = [encoded_packet] + attachments + return encoded_packet + + def decode(self, encoded_packet): + """Decode a transmitted package. + + The return value indicates how many binary attachment packets are + necessary to fully decode the packet. + """ + ep = encoded_packet + try: + self.packet_type = int(ep[0:1]) + except TypeError: + self.packet_type = ep + ep = '' + self.namespace = None + self.data = None + ep = ep[1:] + dash = ep.find('-') + attachment_count = 0 + if dash > 0 and ep[0:dash].isdigit(): + attachment_count = int(ep[0:dash]) + ep = ep[dash + 1:] + if ep and ep[0:1] == '/': + sep = ep.find(',') + if sep == -1: + self.namespace = ep + ep = '' + else: + self.namespace = ep[0:sep] + ep = ep[sep + 1:] + q = self.namespace.find('?') + if q != -1: + self.namespace = self.namespace[0:q] + if ep and ep[0].isdigit(): + self.id = 0 + while ep and ep[0].isdigit(): + self.id = self.id * 10 + int(ep[0]) + ep = ep[1:] + if ep: + self.data = self.json.loads(ep) + return attachment_count + + def add_attachment(self, attachment): + if self.attachment_count <= len(self.attachments): + raise ValueError('Unexpected binary attachment') + self.attachments.append(attachment) + if self.attachment_count == len(self.attachments): + self.reconstruct_binary(self.attachments) + return True + return False + + def reconstruct_binary(self, attachments): + """Reconstruct a decoded packet using the given list of binary + attachments. + """ + self.data = self._reconstruct_binary_internal(self.data, + self.attachments) + + def _reconstruct_binary_internal(self, data, attachments): + if isinstance(data, list): + return [self._reconstruct_binary_internal(item, attachments) + for item in data] + elif isinstance(data, dict): + if data.get('_placeholder') and 'num' in data: + return attachments[data['num']] + else: + return {key: self._reconstruct_binary_internal(value, + attachments) + for key, value in six.iteritems(data)} + else: + return data + + def _deconstruct_binary(self, data): + """Extract binary components in the packet.""" + attachments = [] + data = self._deconstruct_binary_internal(data, attachments) + return data, attachments + + def _deconstruct_binary_internal(self, data, attachments): + if isinstance(data, six.binary_type): + attachments.append(data) + return {'_placeholder': True, 'num': len(attachments) - 1} + elif isinstance(data, list): + return [self._deconstruct_binary_internal(item, attachments) + for item in data] + elif isinstance(data, dict): + return {key: self._deconstruct_binary_internal(value, attachments) + for key, value in six.iteritems(data)} + else: + return data + + def _data_is_binary(self, data): + """Check if the data contains binary components.""" + if isinstance(data, six.binary_type): + return True + elif isinstance(data, list): + return functools.reduce( + lambda a, b: a or b, [self._data_is_binary(item) + for item in data], False) + elif isinstance(data, dict): + return functools.reduce( + lambda a, b: a or b, [self._data_is_binary(item) + for item in six.itervalues(data)], + False) + else: + return False diff --git a/openpype/vendor/python/python_2/socketio/pubsub_manager.py b/openpype/vendor/python/python_2/socketio/pubsub_manager.py new file mode 100644 index 0000000000..2905b2c325 --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/pubsub_manager.py @@ -0,0 +1,154 @@ +from functools import partial +import uuid + +import json +import pickle +import six + +from .base_manager import BaseManager + + +class PubSubManager(BaseManager): + """Manage a client list attached to a pub/sub backend. + + This is a base class that enables multiple servers to share the list of + clients, with the servers communicating events through a pub/sub backend. + The use of a pub/sub backend also allows any client connected to the + backend to emit events addressed to Socket.IO clients. + + The actual backends must be implemented by subclasses, this class only + provides a pub/sub generic framework. + + :param channel: The channel name on which the server sends and receives + notifications. + """ + name = 'pubsub' + + def __init__(self, channel='socketio', write_only=False, logger=None): + super(PubSubManager, self).__init__() + self.channel = channel + self.write_only = write_only + self.host_id = uuid.uuid4().hex + self.logger = logger + + def initialize(self): + super(PubSubManager, self).initialize() + if not self.write_only: + self.thread = self.server.start_background_task(self._thread) + self._get_logger().info(self.name + ' backend initialized.') + + def emit(self, event, data, namespace=None, room=None, skip_sid=None, + callback=None, **kwargs): + """Emit a message to a single client, a room, or all the clients + connected to the namespace. + + This method takes care or propagating the message to all the servers + that are connected through the message queue. + + The parameters are the same as in :meth:`.Server.emit`. + """ + if kwargs.get('ignore_queue'): + return super(PubSubManager, self).emit( + event, data, namespace=namespace, room=room, skip_sid=skip_sid, + callback=callback) + namespace = namespace or '/' + if callback is not None: + if self.server is None: + raise RuntimeError('Callbacks can only be issued from the ' + 'context of a server.') + if room is None: + raise ValueError('Cannot use callback without a room set.') + id = self._generate_ack_id(room, namespace, callback) + callback = (room, namespace, id) + else: + callback = None + self._publish({'method': 'emit', 'event': event, 'data': data, + 'namespace': namespace, 'room': room, + 'skip_sid': skip_sid, 'callback': callback, + 'host_id': self.host_id}) + + def close_room(self, room, namespace=None): + self._publish({'method': 'close_room', 'room': room, + 'namespace': namespace or '/'}) + + def _publish(self, data): + """Publish a message on the Socket.IO channel. + + This method needs to be implemented by the different subclasses that + support pub/sub backends. + """ + raise NotImplementedError('This method must be implemented in a ' + 'subclass.') # pragma: no cover + + def _listen(self): + """Return the next message published on the Socket.IO channel, + blocking until a message is available. + + This method needs to be implemented by the different subclasses that + support pub/sub backends. + """ + raise NotImplementedError('This method must be implemented in a ' + 'subclass.') # pragma: no cover + + def _handle_emit(self, message): + # Events with callbacks are very tricky to handle across hosts + # Here in the receiving end we set up a local callback that preserves + # the callback host and id from the sender + remote_callback = message.get('callback') + remote_host_id = message.get('host_id') + if remote_callback is not None and len(remote_callback) == 3: + callback = partial(self._return_callback, remote_host_id, + *remote_callback) + else: + callback = None + super(PubSubManager, self).emit(message['event'], message['data'], + namespace=message.get('namespace'), + room=message.get('room'), + skip_sid=message.get('skip_sid'), + callback=callback) + + def _handle_callback(self, message): + if self.host_id == message.get('host_id'): + try: + sid = message['sid'] + namespace = message['namespace'] + id = message['id'] + args = message['args'] + except KeyError: + return + self.trigger_callback(sid, namespace, id, args) + + def _return_callback(self, host_id, sid, namespace, callback_id, *args): + # When an event callback is received, the callback is returned back + # the sender, which is identified by the host_id + self._publish({'method': 'callback', 'host_id': host_id, + 'sid': sid, 'namespace': namespace, 'id': callback_id, + 'args': args}) + + def _handle_close_room(self, message): + super(PubSubManager, self).close_room( + room=message.get('room'), namespace=message.get('namespace')) + + def _thread(self): + for message in self._listen(): + data = None + if isinstance(message, dict): + data = message + else: + if isinstance(message, six.binary_type): # pragma: no cover + try: + data = pickle.loads(message) + except: + pass + if data is None: + try: + data = json.loads(message) + except: + pass + if data and 'method' in data: + if data['method'] == 'emit': + self._handle_emit(data) + elif data['method'] == 'callback': + self._handle_callback(data) + elif data['method'] == 'close_room': + self._handle_close_room(data) diff --git a/openpype/vendor/python/python_2/socketio/redis_manager.py b/openpype/vendor/python/python_2/socketio/redis_manager.py new file mode 100644 index 0000000000..69be586fca --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/redis_manager.py @@ -0,0 +1,111 @@ +import logging +import pickle +import time + +try: + import redis +except ImportError: + redis = None + +from .pubsub_manager import PubSubManager + +logger = logging.getLogger('socketio') + + +class RedisManager(PubSubManager): # pragma: no cover + """Redis based client manager. + + This class implements a Redis backend for event sharing across multiple + processes. Only kept here as one more example of how to build a custom + backend, since the kombu backend is perfectly adequate to support a Redis + message queue. + + To use a Redis backend, initialize the :class:`Server` instance as + follows:: + + url = 'redis://hostname:port/0' + server = socketio.Server(client_manager=socketio.RedisManager(url)) + + :param url: The connection URL for the Redis server. For a default Redis + store running on the same host, use ``redis://``. + :param channel: The channel name on which the server sends and receives + notifications. Must be the same in all the servers. + :param write_only: If set ot ``True``, only initialize to emit events. The + default of ``False`` initializes the class for emitting + and receiving. + """ + name = 'redis' + + def __init__(self, url='redis://localhost:6379/0', channel='socketio', + write_only=False, logger=None): + if redis is None: + raise RuntimeError('Redis package is not installed ' + '(Run "pip install redis" in your ' + 'virtualenv).') + self.redis_url = url + self._redis_connect() + super(RedisManager, self).__init__(channel=channel, + write_only=write_only, + logger=logger) + + def initialize(self): + super(RedisManager, self).initialize() + + monkey_patched = True + if self.server.async_mode == 'eventlet': + from eventlet.patcher import is_monkey_patched + monkey_patched = is_monkey_patched('socket') + elif 'gevent' in self.server.async_mode: + from gevent.monkey import is_module_patched + monkey_patched = is_module_patched('socket') + if not monkey_patched: + raise RuntimeError( + 'Redis requires a monkey patched socket library to work ' + 'with ' + self.server.async_mode) + + def _redis_connect(self): + self.redis = redis.Redis.from_url(self.redis_url) + self.pubsub = self.redis.pubsub() + + def _publish(self, data): + retry = True + while True: + try: + if not retry: + self._redis_connect() + return self.redis.publish(self.channel, pickle.dumps(data)) + except redis.exceptions.ConnectionError: + if retry: + logger.error('Cannot publish to redis... retrying') + retry = False + else: + logger.error('Cannot publish to redis... giving up') + break + + def _redis_listen_with_retries(self): + retry_sleep = 1 + connect = False + while True: + try: + if connect: + self._redis_connect() + self.pubsub.subscribe(self.channel) + for message in self.pubsub.listen(): + yield message + except redis.exceptions.ConnectionError: + logger.error('Cannot receive from redis... ' + 'retrying in {} secs'.format(retry_sleep)) + connect = True + time.sleep(retry_sleep) + retry_sleep *= 2 + if retry_sleep > 60: + retry_sleep = 60 + + def _listen(self): + channel = self.channel.encode('utf-8') + self.pubsub.subscribe(self.channel) + for message in self._redis_listen_with_retries(): + if message['channel'] == channel and \ + message['type'] == 'message' and 'data' in message: + yield message['data'] + self.pubsub.unsubscribe(self.channel) diff --git a/openpype/vendor/python/python_2/socketio/server.py b/openpype/vendor/python/python_2/socketio/server.py new file mode 100644 index 0000000000..f9a74dc51b --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/server.py @@ -0,0 +1,719 @@ +import logging + +import engineio +import six + +from . import base_manager +from . import exceptions +from . import namespace +from . import packet + +default_logger = logging.getLogger('socketio.server') + + +class Server(object): + """A Socket.IO server. + + This class implements a fully compliant Socket.IO web server with support + for websocket and long-polling transports. + + :param client_manager: The client manager instance that will manage the + client list. When this is omitted, the client list + is stored in an in-memory structure, so the use of + multiple connected servers is not possible. + :param logger: To enable logging set to ``True`` or pass a logger object to + use. To disable logging set to ``False``. The default is + ``False``. + :param binary: ``True`` to support binary payloads, ``False`` to treat all + payloads as text. On Python 2, if this is set to ``True``, + ``unicode`` values are treated as text, and ``str`` and + ``bytes`` values are treated as binary. This option has no + effect on Python 3, where text and binary payloads are + always automatically discovered. + :param json: An alternative json module to use for encoding and decoding + packets. Custom json modules must have ``dumps`` and ``loads`` + functions that are compatible with the standard library + versions. + :param async_handlers: If set to ``True``, event handlers for a client are + executed in separate threads. To run handlers for a + client synchronously, set to ``False``. The default + is ``True``. + :param always_connect: When set to ``False``, new connections are + provisory until the connect handler returns + something other than ``False``, at which point they + are accepted. When set to ``True``, connections are + immediately accepted, and then if the connect + handler returns ``False`` a disconnect is issued. + Set to ``True`` if you need to emit events from the + connect handler and your client is confused when it + receives events before the connection acceptance. + In any other case use the default of ``False``. + :param kwargs: Connection parameters for the underlying Engine.IO server. + + The Engine.IO configuration supports the following settings: + + :param async_mode: The asynchronous model to use. See the Deployment + section in the documentation for a description of the + available options. Valid async modes are "threading", + "eventlet", "gevent" and "gevent_uwsgi". If this + argument is not given, "eventlet" is tried first, then + "gevent_uwsgi", then "gevent", and finally "threading". + The first async mode that has all its dependencies + installed is then one that is chosen. + :param ping_timeout: The time in seconds that the client waits for the + server to respond before disconnecting. The default + is 60 seconds. + :param ping_interval: The interval in seconds at which the client pings + the server. The default is 25 seconds. + :param max_http_buffer_size: The maximum size of a message when using the + polling transport. The default is 100,000,000 + bytes. + :param allow_upgrades: Whether to allow transport upgrades or not. The + default is ``True``. + :param http_compression: Whether to compress packages when using the + polling transport. The default is ``True``. + :param compression_threshold: Only compress messages when their byte size + is greater than this value. The default is + 1024 bytes. + :param cookie: Name of the HTTP cookie that contains the client session + id. If set to ``None``, a cookie is not sent to the client. + The default is ``'io'``. + :param cors_allowed_origins: List of origins that are allowed to connect + to this server. All origins are allowed by + default. + :param cors_credentials: Whether credentials (cookies, authentication) are + allowed in requests to this server. The default is + ``True``. + :param engineio_logger: To enable Engine.IO logging set to ``True`` or pass + a logger object to use. To disable logging set to + ``False``. The default is ``False``. + """ + def __init__(self, client_manager=None, logger=False, binary=False, + json=None, async_handlers=True, always_connect=False, + **kwargs): + engineio_options = kwargs + engineio_logger = engineio_options.pop('engineio_logger', None) + if engineio_logger is not None: + engineio_options['logger'] = engineio_logger + if json is not None: + packet.Packet.json = json + engineio_options['json'] = json + engineio_options['async_handlers'] = False + self.eio = self._engineio_server_class()(**engineio_options) + self.eio.on('connect', self._handle_eio_connect) + self.eio.on('message', self._handle_eio_message) + self.eio.on('disconnect', self._handle_eio_disconnect) + self.binary = binary + + self.environ = {} + self.handlers = {} + self.namespace_handlers = {} + + self._binary_packet = {} + + if not isinstance(logger, bool): + self.logger = logger + else: + self.logger = default_logger + if not logging.root.handlers and \ + self.logger.level == logging.NOTSET: + if logger: + self.logger.setLevel(logging.INFO) + else: + self.logger.setLevel(logging.ERROR) + self.logger.addHandler(logging.StreamHandler()) + + if client_manager is None: + client_manager = base_manager.BaseManager() + self.manager = client_manager + self.manager.set_server(self) + self.manager_initialized = False + + self.async_handlers = async_handlers + self.always_connect = always_connect + + self.async_mode = self.eio.async_mode + + def is_asyncio_based(self): + return False + + def on(self, event, handler=None, namespace=None): + """Register an event handler. + + :param event: The event name. It can be any string. The event names + ``'connect'``, ``'message'`` and ``'disconnect'`` are + reserved and should not be used. + :param handler: The function that should be invoked to handle the + event. When this parameter is not given, the method + acts as a decorator for the handler function. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the handler is associated with + the default namespace. + + Example usage:: + + # as a decorator: + @socket_io.on('connect', namespace='/chat') + def connect_handler(sid, environ): + print('Connection request') + if environ['REMOTE_ADDR'] in blacklisted: + return False # reject + + # as a method: + def message_handler(sid, msg): + print('Received message: ', msg) + eio.send(sid, 'response') + socket_io.on('message', namespace='/chat', message_handler) + + The handler function receives the ``sid`` (session ID) for the + client as first argument. The ``'connect'`` event handler receives the + WSGI environment as a second argument, and can return ``False`` to + reject the connection. The ``'message'`` handler and handlers for + custom event names receive the message payload as a second argument. + Any values returned from a message handler will be passed to the + client's acknowledgement callback function if it exists. The + ``'disconnect'`` handler does not take a second argument. + """ + namespace = namespace or '/' + + def set_handler(handler): + if namespace not in self.handlers: + self.handlers[namespace] = {} + self.handlers[namespace][event] = handler + return handler + + if handler is None: + return set_handler + set_handler(handler) + + def event(self, *args, **kwargs): + """Decorator to register an event handler. + + This is a simplified version of the ``on()`` method that takes the + event name from the decorated function. + + Example usage:: + + @sio.event + def my_event(data): + print('Received data: ', data) + + The above example is equivalent to:: + + @sio.on('my_event') + def my_event(data): + print('Received data: ', data) + + A custom namespace can be given as an argument to the decorator:: + + @sio.event(namespace='/test') + def my_event(data): + print('Received data: ', data) + """ + if len(args) == 1 and len(kwargs) == 0 and callable(args[0]): + # the decorator was invoked without arguments + # args[0] is the decorated function + return self.on(args[0].__name__)(args[0]) + else: + # the decorator was invoked with arguments + def set_handler(handler): + return self.on(handler.__name__, *args, **kwargs)(handler) + + return set_handler + + def register_namespace(self, namespace_handler): + """Register a namespace handler object. + + :param namespace_handler: An instance of a :class:`Namespace` + subclass that handles all the event traffic + for a namespace. + """ + if not isinstance(namespace_handler, namespace.Namespace): + raise ValueError('Not a namespace instance') + if self.is_asyncio_based() != namespace_handler.is_asyncio_based(): + raise ValueError('Not a valid namespace class for this server') + namespace_handler._set_server(self) + self.namespace_handlers[namespace_handler.namespace] = \ + namespace_handler + + def emit(self, event, data=None, to=None, room=None, skip_sid=None, + namespace=None, callback=None, **kwargs): + """Emit a custom event to one or more connected clients. + + :param event: The event name. It can be any string. The event names + ``'connect'``, ``'message'`` and ``'disconnect'`` are + reserved and should not be used. + :param data: The data to send to the client or clients. Data can be of + type ``str``, ``bytes``, ``list`` or ``dict``. If a + ``list`` or ``dict``, the data will be serialized as JSON. + :param to: The recipient of the message. This can be set to the + session ID of a client to address only that client, or to + to any custom room created by the application to address all + the clients in that room, If this argument is omitted the + event is broadcasted to all connected clients. + :param room: Alias for the ``to`` parameter. + :param skip_sid: The session ID of a client to skip when broadcasting + to a room or to all clients. This can be used to + prevent a message from being sent to the sender. To + skip multiple sids, pass a list. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the event is emitted to the + default namespace. + :param callback: If given, this function will be called to acknowledge + the the client has received the message. The arguments + that will be passed to the function are those provided + by the client. Callback functions can only be used + when addressing an individual client. + :param ignore_queue: Only used when a message queue is configured. If + set to ``True``, the event is emitted to the + clients directly, without going through the queue. + This is more efficient, but only works when a + single server process is used. It is recommended + to always leave this parameter with its default + value of ``False``. + """ + namespace = namespace or '/' + room = to or room + self.logger.info('emitting event "%s" to %s [%s]', event, + room or 'all', namespace) + self.manager.emit(event, data, namespace, room=room, + skip_sid=skip_sid, callback=callback, **kwargs) + + def send(self, data, to=None, room=None, skip_sid=None, namespace=None, + callback=None, **kwargs): + """Send a message to one or more connected clients. + + This function emits an event with the name ``'message'``. Use + :func:`emit` to issue custom event names. + + :param data: The data to send to the client or clients. Data can be of + type ``str``, ``bytes``, ``list`` or ``dict``. If a + ``list`` or ``dict``, the data will be serialized as JSON. + :param to: The recipient of the message. This can be set to the + session ID of a client to address only that client, or to + to any custom room created by the application to address all + the clients in that room, If this argument is omitted the + event is broadcasted to all connected clients. + :param room: Alias for the ``to`` parameter. + :param skip_sid: The session ID of a client to skip when broadcasting + to a room or to all clients. This can be used to + prevent a message from being sent to the sender. To + skip multiple sids, pass a list. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the event is emitted to the + default namespace. + :param callback: If given, this function will be called to acknowledge + the the client has received the message. The arguments + that will be passed to the function are those provided + by the client. Callback functions can only be used + when addressing an individual client. + :param ignore_queue: Only used when a message queue is configured. If + set to ``True``, the event is emitted to the + clients directly, without going through the queue. + This is more efficient, but only works when a + single server process is used. It is recommended + to always leave this parameter with its default + value of ``False``. + """ + self.emit('message', data=data, to=to, room=room, skip_sid=skip_sid, + namespace=namespace, callback=callback, **kwargs) + + def call(self, event, data=None, to=None, sid=None, namespace=None, + timeout=60, **kwargs): + """Emit a custom event to a client and wait for the response. + + :param event: The event name. It can be any string. The event names + ``'connect'``, ``'message'`` and ``'disconnect'`` are + reserved and should not be used. + :param data: The data to send to the client or clients. Data can be of + type ``str``, ``bytes``, ``list`` or ``dict``. If a + ``list`` or ``dict``, the data will be serialized as JSON. + :param to: The session ID of the recipient client. + :param sid: Alias for the ``to`` parameter. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the event is emitted to the + default namespace. + :param timeout: The waiting timeout. If the timeout is reached before + the client acknowledges the event, then a + ``TimeoutError`` exception is raised. + :param ignore_queue: Only used when a message queue is configured. If + set to ``True``, the event is emitted to the + client directly, without going through the queue. + This is more efficient, but only works when a + single server process is used. It is recommended + to always leave this parameter with its default + value of ``False``. + """ + if not self.async_handlers: + raise RuntimeError( + 'Cannot use call() when async_handlers is False.') + callback_event = self.eio.create_event() + callback_args = [] + + def event_callback(*args): + callback_args.append(args) + callback_event.set() + + self.emit(event, data=data, room=to or sid, namespace=namespace, + callback=event_callback, **kwargs) + if not callback_event.wait(timeout=timeout): + raise exceptions.TimeoutError() + return callback_args[0] if len(callback_args[0]) > 1 \ + else callback_args[0][0] if len(callback_args[0]) == 1 \ + else None + + def enter_room(self, sid, room, namespace=None): + """Enter a room. + + This function adds the client to a room. The :func:`emit` and + :func:`send` functions can optionally broadcast events to all the + clients in a room. + + :param sid: Session ID of the client. + :param room: Room name. If the room does not exist it is created. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the default namespace is used. + """ + namespace = namespace or '/' + self.logger.info('%s is entering room %s [%s]', sid, room, namespace) + self.manager.enter_room(sid, namespace, room) + + def leave_room(self, sid, room, namespace=None): + """Leave a room. + + This function removes the client from a room. + + :param sid: Session ID of the client. + :param room: Room name. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the default namespace is used. + """ + namespace = namespace or '/' + self.logger.info('%s is leaving room %s [%s]', sid, room, namespace) + self.manager.leave_room(sid, namespace, room) + + def close_room(self, room, namespace=None): + """Close a room. + + This function removes all the clients from the given room. + + :param room: Room name. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the default namespace is used. + """ + namespace = namespace or '/' + self.logger.info('room %s is closing [%s]', room, namespace) + self.manager.close_room(room, namespace) + + def rooms(self, sid, namespace=None): + """Return the rooms a client is in. + + :param sid: Session ID of the client. + :param namespace: The Socket.IO namespace for the event. If this + argument is omitted the default namespace is used. + """ + namespace = namespace or '/' + return self.manager.get_rooms(sid, namespace) + + def get_session(self, sid, namespace=None): + """Return the user session for a client. + + :param sid: The session id of the client. + :param namespace: The Socket.IO namespace. If this argument is omitted + the default namespace is used. + + The return value is a dictionary. Modifications made to this + dictionary are not guaranteed to be preserved unless + ``save_session()`` is called, or when the ``session`` context manager + is used. + """ + namespace = namespace or '/' + eio_session = self.eio.get_session(sid) + return eio_session.setdefault(namespace, {}) + + def save_session(self, sid, session, namespace=None): + """Store the user session for a client. + + :param sid: The session id of the client. + :param session: The session dictionary. + :param namespace: The Socket.IO namespace. If this argument is omitted + the default namespace is used. + """ + namespace = namespace or '/' + eio_session = self.eio.get_session(sid) + eio_session[namespace] = session + + def session(self, sid, namespace=None): + """Return the user session for a client with context manager syntax. + + :param sid: The session id of the client. + + This is a context manager that returns the user session dictionary for + the client. Any changes that are made to this dictionary inside the + context manager block are saved back to the session. Example usage:: + + @sio.on('connect') + def on_connect(sid, environ): + username = authenticate_user(environ) + if not username: + return False + with sio.session(sid) as session: + session['username'] = username + + @sio.on('message') + def on_message(sid, msg): + with sio.session(sid) as session: + print('received message from ', session['username']) + """ + class _session_context_manager(object): + def __init__(self, server, sid, namespace): + self.server = server + self.sid = sid + self.namespace = namespace + self.session = None + + def __enter__(self): + self.session = self.server.get_session(sid, + namespace=namespace) + return self.session + + def __exit__(self, *args): + self.server.save_session(sid, self.session, + namespace=namespace) + + return _session_context_manager(self, sid, namespace) + + def disconnect(self, sid, namespace=None): + """Disconnect a client. + + :param sid: Session ID of the client. + :param namespace: The Socket.IO namespace to disconnect. If this + argument is omitted the default namespace is used. + """ + namespace = namespace or '/' + if self.manager.is_connected(sid, namespace=namespace): + self.logger.info('Disconnecting %s [%s]', sid, namespace) + self.manager.pre_disconnect(sid, namespace=namespace) + self._send_packet(sid, packet.Packet(packet.DISCONNECT, + namespace=namespace)) + self._trigger_event('disconnect', namespace, sid) + self.manager.disconnect(sid, namespace=namespace) + + def transport(self, sid): + """Return the name of the transport used by the client. + + The two possible values returned by this function are ``'polling'`` + and ``'websocket'``. + + :param sid: The session of the client. + """ + return self.eio.transport(sid) + + def handle_request(self, environ, start_response): + """Handle an HTTP request from the client. + + This is the entry point of the Socket.IO application, using the same + interface as a WSGI application. For the typical usage, this function + is invoked by the :class:`Middleware` instance, but it can be invoked + directly when the middleware is not used. + + :param environ: The WSGI environment. + :param start_response: The WSGI ``start_response`` function. + + This function returns the HTTP response body to deliver to the client + as a byte sequence. + """ + return self.eio.handle_request(environ, start_response) + + def start_background_task(self, target, *args, **kwargs): + """Start a background task using the appropriate async model. + + This is a utility function that applications can use to start a + background task using the method that is compatible with the + selected async mode. + + :param target: the target function to execute. + :param args: arguments to pass to the function. + :param kwargs: keyword arguments to pass to the function. + + This function returns an object compatible with the `Thread` class in + the Python standard library. The `start()` method on this object is + already called by this function. + """ + return self.eio.start_background_task(target, *args, **kwargs) + + def sleep(self, seconds=0): + """Sleep for the requested amount of time using the appropriate async + model. + + This is a utility function that applications can use to put a task to + sleep without having to worry about using the correct call for the + selected async mode. + """ + return self.eio.sleep(seconds) + + def _emit_internal(self, sid, event, data, namespace=None, id=None): + """Send a message to a client.""" + if six.PY2 and not self.binary: + binary = False # pragma: nocover + else: + binary = None + # tuples are expanded to multiple arguments, everything else is sent + # as a single argument + if isinstance(data, tuple): + data = list(data) + else: + data = [data] + self._send_packet(sid, packet.Packet(packet.EVENT, namespace=namespace, + data=[event] + data, id=id, + binary=binary)) + + def _send_packet(self, sid, pkt): + """Send a Socket.IO packet to a client.""" + encoded_packet = pkt.encode() + if isinstance(encoded_packet, list): + binary = False + for ep in encoded_packet: + self.eio.send(sid, ep, binary=binary) + binary = True + else: + self.eio.send(sid, encoded_packet, binary=False) + + def _handle_connect(self, sid, namespace): + """Handle a client connection request.""" + namespace = namespace or '/' + self.manager.connect(sid, namespace) + if self.always_connect: + self._send_packet(sid, packet.Packet(packet.CONNECT, + namespace=namespace)) + fail_reason = None + try: + success = self._trigger_event('connect', namespace, sid, + self.environ[sid]) + except exceptions.ConnectionRefusedError as exc: + fail_reason = exc.error_args + success = False + + if success is False: + if self.always_connect: + self.manager.pre_disconnect(sid, namespace) + self._send_packet(sid, packet.Packet( + packet.DISCONNECT, data=fail_reason, namespace=namespace)) + self.manager.disconnect(sid, namespace) + if not self.always_connect: + self._send_packet(sid, packet.Packet( + packet.ERROR, data=fail_reason, namespace=namespace)) + if sid in self.environ: # pragma: no cover + del self.environ[sid] + return False + elif not self.always_connect: + self._send_packet(sid, packet.Packet(packet.CONNECT, + namespace=namespace)) + + def _handle_disconnect(self, sid, namespace): + """Handle a client disconnect.""" + namespace = namespace or '/' + if namespace == '/': + namespace_list = list(self.manager.get_namespaces()) + else: + namespace_list = [namespace] + for n in namespace_list: + if n != '/' and self.manager.is_connected(sid, n): + self._trigger_event('disconnect', n, sid) + self.manager.disconnect(sid, n) + if namespace == '/' and self.manager.is_connected(sid, namespace): + self._trigger_event('disconnect', '/', sid) + self.manager.disconnect(sid, '/') + + def _handle_event(self, sid, namespace, id, data): + """Handle an incoming client event.""" + namespace = namespace or '/' + self.logger.info('received event "%s" from %s [%s]', data[0], sid, + namespace) + if self.async_handlers: + self.start_background_task(self._handle_event_internal, self, sid, + data, namespace, id) + else: + self._handle_event_internal(self, sid, data, namespace, id) + + def _handle_event_internal(self, server, sid, data, namespace, id): + r = server._trigger_event(data[0], namespace, sid, *data[1:]) + if id is not None: + # send ACK packet with the response returned by the handler + # tuples are expanded as multiple arguments + if r is None: + data = [] + elif isinstance(r, tuple): + data = list(r) + else: + data = [r] + if six.PY2 and not self.binary: + binary = False # pragma: nocover + else: + binary = None + server._send_packet(sid, packet.Packet(packet.ACK, + namespace=namespace, + id=id, data=data, + binary=binary)) + + def _handle_ack(self, sid, namespace, id, data): + """Handle ACK packets from the client.""" + namespace = namespace or '/' + self.logger.info('received ack from %s [%s]', sid, namespace) + self.manager.trigger_callback(sid, namespace, id, data) + + def _trigger_event(self, event, namespace, *args): + """Invoke an application event handler.""" + # first see if we have an explicit handler for the event + if namespace in self.handlers and event in self.handlers[namespace]: + return self.handlers[namespace][event](*args) + + # or else, forward the event to a namespace handler if one exists + elif namespace in self.namespace_handlers: + return self.namespace_handlers[namespace].trigger_event( + event, *args) + + def _handle_eio_connect(self, sid, environ): + """Handle the Engine.IO connection event.""" + if not self.manager_initialized: + self.manager_initialized = True + self.manager.initialize() + self.environ[sid] = environ + return self._handle_connect(sid, '/') + + def _handle_eio_message(self, sid, data): + """Dispatch Engine.IO messages.""" + if sid in self._binary_packet: + pkt = self._binary_packet[sid] + if pkt.add_attachment(data): + del self._binary_packet[sid] + if pkt.packet_type == packet.BINARY_EVENT: + self._handle_event(sid, pkt.namespace, pkt.id, pkt.data) + else: + self._handle_ack(sid, pkt.namespace, pkt.id, pkt.data) + else: + pkt = packet.Packet(encoded_packet=data) + if pkt.packet_type == packet.CONNECT: + self._handle_connect(sid, pkt.namespace) + elif pkt.packet_type == packet.DISCONNECT: + self._handle_disconnect(sid, pkt.namespace) + elif pkt.packet_type == packet.EVENT: + self._handle_event(sid, pkt.namespace, pkt.id, pkt.data) + elif pkt.packet_type == packet.ACK: + self._handle_ack(sid, pkt.namespace, pkt.id, pkt.data) + elif pkt.packet_type == packet.BINARY_EVENT or \ + pkt.packet_type == packet.BINARY_ACK: + self._binary_packet[sid] = pkt + elif pkt.packet_type == packet.ERROR: + raise ValueError('Unexpected ERROR packet.') + else: + raise ValueError('Unknown packet type.') + + def _handle_eio_disconnect(self, sid): + """Handle Engine.IO disconnect event.""" + self._handle_disconnect(sid, '/') + if sid in self.environ: + del self.environ[sid] + + def _engineio_server_class(self): + return engineio.Server diff --git a/openpype/vendor/python/python_2/socketio/tornado.py b/openpype/vendor/python/python_2/socketio/tornado.py new file mode 100644 index 0000000000..5b2e6f684f --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/tornado.py @@ -0,0 +1,11 @@ +import sys +if sys.version_info >= (3, 5): + try: + from engineio.async_drivers.tornado import get_tornado_handler as \ + get_engineio_handler + except ImportError: # pragma: no cover + get_engineio_handler = None + + +def get_tornado_handler(socketio_server): # pragma: no cover + return get_engineio_handler(socketio_server.eio) diff --git a/openpype/vendor/python/python_2/socketio/zmq_manager.py b/openpype/vendor/python/python_2/socketio/zmq_manager.py new file mode 100644 index 0000000000..f2a2ae5dc6 --- /dev/null +++ b/openpype/vendor/python/python_2/socketio/zmq_manager.py @@ -0,0 +1,111 @@ +import pickle +import re + +try: + import eventlet.green.zmq as zmq +except ImportError: + zmq = None +import six + +from .pubsub_manager import PubSubManager + + +class ZmqManager(PubSubManager): # pragma: no cover + """zmq based client manager. + + NOTE: this zmq implementation should be considered experimental at this + time. At this time, eventlet is required to use zmq. + + This class implements a zmq backend for event sharing across multiple + processes. To use a zmq backend, initialize the :class:`Server` instance as + follows:: + + url = 'zmq+tcp://hostname:port1+port2' + server = socketio.Server(client_manager=socketio.ZmqManager(url)) + + :param url: The connection URL for the zmq message broker, + which will need to be provided and running. + :param channel: The channel name on which the server sends and receives + notifications. Must be the same in all the servers. + :param write_only: If set to ``True``, only initialize to emit events. The + default of ``False`` initializes the class for emitting + and receiving. + + A zmq message broker must be running for the zmq_manager to work. + you can write your own or adapt one from the following simple broker + below:: + + import zmq + + receiver = zmq.Context().socket(zmq.PULL) + receiver.bind("tcp://*:5555") + + publisher = zmq.Context().socket(zmq.PUB) + publisher.bind("tcp://*:5556") + + while True: + publisher.send(receiver.recv()) + """ + name = 'zmq' + + def __init__(self, url='zmq+tcp://localhost:5555+5556', + channel='socketio', + write_only=False, + logger=None): + if zmq is None: + raise RuntimeError('zmq package is not installed ' + '(Run "pip install pyzmq" in your ' + 'virtualenv).') + + r = re.compile(r':\d+\+\d+$') + if not (url.startswith('zmq+tcp://') and r.search(url)): + raise RuntimeError('unexpected connection string: ' + url) + + url = url.replace('zmq+', '') + (sink_url, sub_port) = url.split('+') + sink_port = sink_url.split(':')[-1] + sub_url = sink_url.replace(sink_port, sub_port) + + sink = zmq.Context().socket(zmq.PUSH) + sink.connect(sink_url) + + sub = zmq.Context().socket(zmq.SUB) + sub.setsockopt_string(zmq.SUBSCRIBE, u'') + sub.connect(sub_url) + + self.sink = sink + self.sub = sub + self.channel = channel + super(ZmqManager, self).__init__(channel=channel, + write_only=write_only, + logger=logger) + + def _publish(self, data): + pickled_data = pickle.dumps( + { + 'type': 'message', + 'channel': self.channel, + 'data': data + } + ) + return self.sink.send(pickled_data) + + def zmq_listen(self): + while True: + response = self.sub.recv() + if response is not None: + yield response + + def _listen(self): + for message in self.zmq_listen(): + if isinstance(message, six.binary_type): + try: + message = pickle.loads(message) + except Exception: + pass + if isinstance(message, dict) and \ + message['type'] == 'message' and \ + message['channel'] == self.channel and \ + 'data' in message: + yield message['data'] + return diff --git a/openpype/vendor/python/python_2/websocket/__init__.py b/openpype/vendor/python/python_2/websocket/__init__.py new file mode 100644 index 0000000000..f2c7b44c17 --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/__init__.py @@ -0,0 +1,28 @@ +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" +from ._abnf import * +from ._app import WebSocketApp +from ._core import * +from ._exceptions import * +from ._logging import * +from ._socket import * + +__version__ = "0.59.0" diff --git a/openpype/vendor/python/python_2/websocket/_abnf.py b/openpype/vendor/python/python_2/websocket/_abnf.py new file mode 100644 index 0000000000..80fbe1f9b9 --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/_abnf.py @@ -0,0 +1,458 @@ +""" + +""" + +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" +import array +import os +import struct + +import six + +from ._exceptions import * +from ._utils import validate_utf8 +from threading import Lock + +try: + if six.PY3: + import numpy + else: + numpy = None +except ImportError: + numpy = None + +try: + # If wsaccel is available we use compiled routines to mask data. + if not numpy: + from wsaccel.xormask import XorMaskerSimple + + def _mask(_m, _d): + return XorMaskerSimple(_m).process(_d) +except ImportError: + # wsaccel is not available, we rely on python implementations. + def _mask(_m, _d): + for i in range(len(_d)): + _d[i] ^= _m[i % 4] + + if six.PY3: + return _d.tobytes() + else: + return _d.tostring() + + +__all__ = [ + 'ABNF', 'continuous_frame', 'frame_buffer', + 'STATUS_NORMAL', + 'STATUS_GOING_AWAY', + 'STATUS_PROTOCOL_ERROR', + 'STATUS_UNSUPPORTED_DATA_TYPE', + 'STATUS_STATUS_NOT_AVAILABLE', + 'STATUS_ABNORMAL_CLOSED', + 'STATUS_INVALID_PAYLOAD', + 'STATUS_POLICY_VIOLATION', + 'STATUS_MESSAGE_TOO_BIG', + 'STATUS_INVALID_EXTENSION', + 'STATUS_UNEXPECTED_CONDITION', + 'STATUS_BAD_GATEWAY', + 'STATUS_TLS_HANDSHAKE_ERROR', +] + +# closing frame status codes. +STATUS_NORMAL = 1000 +STATUS_GOING_AWAY = 1001 +STATUS_PROTOCOL_ERROR = 1002 +STATUS_UNSUPPORTED_DATA_TYPE = 1003 +STATUS_STATUS_NOT_AVAILABLE = 1005 +STATUS_ABNORMAL_CLOSED = 1006 +STATUS_INVALID_PAYLOAD = 1007 +STATUS_POLICY_VIOLATION = 1008 +STATUS_MESSAGE_TOO_BIG = 1009 +STATUS_INVALID_EXTENSION = 1010 +STATUS_UNEXPECTED_CONDITION = 1011 +STATUS_BAD_GATEWAY = 1014 +STATUS_TLS_HANDSHAKE_ERROR = 1015 + +VALID_CLOSE_STATUS = ( + STATUS_NORMAL, + STATUS_GOING_AWAY, + STATUS_PROTOCOL_ERROR, + STATUS_UNSUPPORTED_DATA_TYPE, + STATUS_INVALID_PAYLOAD, + STATUS_POLICY_VIOLATION, + STATUS_MESSAGE_TOO_BIG, + STATUS_INVALID_EXTENSION, + STATUS_UNEXPECTED_CONDITION, + STATUS_BAD_GATEWAY, +) + + +class ABNF(object): + """ + ABNF frame class. + See http://tools.ietf.org/html/rfc5234 + and http://tools.ietf.org/html/rfc6455#section-5.2 + """ + + # operation code values. + OPCODE_CONT = 0x0 + OPCODE_TEXT = 0x1 + OPCODE_BINARY = 0x2 + OPCODE_CLOSE = 0x8 + OPCODE_PING = 0x9 + OPCODE_PONG = 0xa + + # available operation code value tuple + OPCODES = (OPCODE_CONT, OPCODE_TEXT, OPCODE_BINARY, OPCODE_CLOSE, + OPCODE_PING, OPCODE_PONG) + + # opcode human readable string + OPCODE_MAP = { + OPCODE_CONT: "cont", + OPCODE_TEXT: "text", + OPCODE_BINARY: "binary", + OPCODE_CLOSE: "close", + OPCODE_PING: "ping", + OPCODE_PONG: "pong" + } + + # data length threshold. + LENGTH_7 = 0x7e + LENGTH_16 = 1 << 16 + LENGTH_63 = 1 << 63 + + def __init__(self, fin=0, rsv1=0, rsv2=0, rsv3=0, + opcode=OPCODE_TEXT, mask=1, data=""): + """ + Constructor for ABNF. Please check RFC for arguments. + """ + self.fin = fin + self.rsv1 = rsv1 + self.rsv2 = rsv2 + self.rsv3 = rsv3 + self.opcode = opcode + self.mask = mask + if data is None: + data = "" + self.data = data + self.get_mask_key = os.urandom + + def validate(self, skip_utf8_validation=False): + """ + Validate the ABNF frame. + + Parameters + ---------- + skip_utf8_validation: skip utf8 validation. + """ + if self.rsv1 or self.rsv2 or self.rsv3: + raise WebSocketProtocolException("rsv is not implemented, yet") + + if self.opcode not in ABNF.OPCODES: + raise WebSocketProtocolException("Invalid opcode %r", self.opcode) + + if self.opcode == ABNF.OPCODE_PING and not self.fin: + raise WebSocketProtocolException("Invalid ping frame.") + + if self.opcode == ABNF.OPCODE_CLOSE: + l = len(self.data) + if not l: + return + if l == 1 or l >= 126: + raise WebSocketProtocolException("Invalid close frame.") + if l > 2 and not skip_utf8_validation and not validate_utf8(self.data[2:]): + raise WebSocketProtocolException("Invalid close frame.") + + code = 256 * \ + six.byte2int(self.data[0:1]) + six.byte2int(self.data[1:2]) + if not self._is_valid_close_status(code): + raise WebSocketProtocolException("Invalid close opcode.") + + @staticmethod + def _is_valid_close_status(code): + return code in VALID_CLOSE_STATUS or (3000 <= code < 5000) + + def __str__(self): + return "fin=" + str(self.fin) \ + + " opcode=" + str(self.opcode) \ + + " data=" + str(self.data) + + @staticmethod + def create_frame(data, opcode, fin=1): + """ + Create frame to send text, binary and other data. + + Parameters + ---------- + data: + data to send. This is string value(byte array). + If opcode is OPCODE_TEXT and this value is unicode, + data value is converted into unicode string, automatically. + opcode: + operation code. please see OPCODE_XXX. + fin: + fin flag. if set to 0, create continue fragmentation. + """ + if opcode == ABNF.OPCODE_TEXT and isinstance(data, six.text_type): + data = data.encode("utf-8") + # mask must be set if send data from client + return ABNF(fin, 0, 0, 0, opcode, 1, data) + + def format(self): + """ + Format this object to string(byte array) to send data to server. + """ + if any(x not in (0, 1) for x in [self.fin, self.rsv1, self.rsv2, self.rsv3]): + raise ValueError("not 0 or 1") + if self.opcode not in ABNF.OPCODES: + raise ValueError("Invalid OPCODE") + length = len(self.data) + if length >= ABNF.LENGTH_63: + raise ValueError("data is too long") + + frame_header = chr(self.fin << 7 | + self.rsv1 << 6 | self.rsv2 << 5 | self.rsv3 << 4 | + self.opcode) + if length < ABNF.LENGTH_7: + frame_header += chr(self.mask << 7 | length) + frame_header = six.b(frame_header) + elif length < ABNF.LENGTH_16: + frame_header += chr(self.mask << 7 | 0x7e) + frame_header = six.b(frame_header) + frame_header += struct.pack("!H", length) + else: + frame_header += chr(self.mask << 7 | 0x7f) + frame_header = six.b(frame_header) + frame_header += struct.pack("!Q", length) + + if not self.mask: + return frame_header + self.data + else: + mask_key = self.get_mask_key(4) + return frame_header + self._get_masked(mask_key) + + def _get_masked(self, mask_key): + s = ABNF.mask(mask_key, self.data) + + if isinstance(mask_key, six.text_type): + mask_key = mask_key.encode('utf-8') + + return mask_key + s + + @staticmethod + def mask(mask_key, data): + """ + Mask or unmask data. Just do xor for each byte + + Parameters + ---------- + mask_key: + 4 byte string(byte). + data: + data to mask/unmask. + """ + if data is None: + data = "" + + if isinstance(mask_key, six.text_type): + mask_key = six.b(mask_key) + + if isinstance(data, six.text_type): + data = six.b(data) + + if numpy: + origlen = len(data) + _mask_key = mask_key[3] << 24 | mask_key[2] << 16 | mask_key[1] << 8 | mask_key[0] + + # We need data to be a multiple of four... + data += bytes(" " * (4 - (len(data) % 4)), "us-ascii") + a = numpy.frombuffer(data, dtype="uint32") + masked = numpy.bitwise_xor(a, [_mask_key]).astype("uint32") + if len(data) > origlen: + return masked.tobytes()[:origlen] + return masked.tobytes() + else: + _m = array.array("B", mask_key) + _d = array.array("B", data) + return _mask(_m, _d) + + +class frame_buffer(object): + _HEADER_MASK_INDEX = 5 + _HEADER_LENGTH_INDEX = 6 + + def __init__(self, recv_fn, skip_utf8_validation): + self.recv = recv_fn + self.skip_utf8_validation = skip_utf8_validation + # Buffers over the packets from the layer beneath until desired amount + # bytes of bytes are received. + self.recv_buffer = [] + self.clear() + self.lock = Lock() + + def clear(self): + self.header = None + self.length = None + self.mask = None + + def has_received_header(self): + return self.header is None + + def recv_header(self): + header = self.recv_strict(2) + b1 = header[0] + + if six.PY2: + b1 = ord(b1) + + fin = b1 >> 7 & 1 + rsv1 = b1 >> 6 & 1 + rsv2 = b1 >> 5 & 1 + rsv3 = b1 >> 4 & 1 + opcode = b1 & 0xf + b2 = header[1] + + if six.PY2: + b2 = ord(b2) + + has_mask = b2 >> 7 & 1 + length_bits = b2 & 0x7f + + self.header = (fin, rsv1, rsv2, rsv3, opcode, has_mask, length_bits) + + def has_mask(self): + if not self.header: + return False + return self.header[frame_buffer._HEADER_MASK_INDEX] + + def has_received_length(self): + return self.length is None + + def recv_length(self): + bits = self.header[frame_buffer._HEADER_LENGTH_INDEX] + length_bits = bits & 0x7f + if length_bits == 0x7e: + v = self.recv_strict(2) + self.length = struct.unpack("!H", v)[0] + elif length_bits == 0x7f: + v = self.recv_strict(8) + self.length = struct.unpack("!Q", v)[0] + else: + self.length = length_bits + + def has_received_mask(self): + return self.mask is None + + def recv_mask(self): + self.mask = self.recv_strict(4) if self.has_mask() else "" + + def recv_frame(self): + + with self.lock: + # Header + if self.has_received_header(): + self.recv_header() + (fin, rsv1, rsv2, rsv3, opcode, has_mask, _) = self.header + + # Frame length + if self.has_received_length(): + self.recv_length() + length = self.length + + # Mask + if self.has_received_mask(): + self.recv_mask() + mask = self.mask + + # Payload + payload = self.recv_strict(length) + if has_mask: + payload = ABNF.mask(mask, payload) + + # Reset for next frame + self.clear() + + frame = ABNF(fin, rsv1, rsv2, rsv3, opcode, has_mask, payload) + frame.validate(self.skip_utf8_validation) + + return frame + + def recv_strict(self, bufsize): + shortage = bufsize - sum(len(x) for x in self.recv_buffer) + while shortage > 0: + # Limit buffer size that we pass to socket.recv() to avoid + # fragmenting the heap -- the number of bytes recv() actually + # reads is limited by socket buffer and is relatively small, + # yet passing large numbers repeatedly causes lots of large + # buffers allocated and then shrunk, which results in + # fragmentation. + bytes_ = self.recv(min(16384, shortage)) + self.recv_buffer.append(bytes_) + shortage -= len(bytes_) + + unified = six.b("").join(self.recv_buffer) + + if shortage == 0: + self.recv_buffer = [] + return unified + else: + self.recv_buffer = [unified[bufsize:]] + return unified[:bufsize] + + +class continuous_frame(object): + + def __init__(self, fire_cont_frame, skip_utf8_validation): + self.fire_cont_frame = fire_cont_frame + self.skip_utf8_validation = skip_utf8_validation + self.cont_data = None + self.recving_frames = None + + def validate(self, frame): + if not self.recving_frames and frame.opcode == ABNF.OPCODE_CONT: + raise WebSocketProtocolException("Illegal frame") + if self.recving_frames and \ + frame.opcode in (ABNF.OPCODE_TEXT, ABNF.OPCODE_BINARY): + raise WebSocketProtocolException("Illegal frame") + + def add(self, frame): + if self.cont_data: + self.cont_data[1] += frame.data + else: + if frame.opcode in (ABNF.OPCODE_TEXT, ABNF.OPCODE_BINARY): + self.recving_frames = frame.opcode + self.cont_data = [frame.opcode, frame.data] + + if frame.fin: + self.recving_frames = None + + def is_fire(self, frame): + return frame.fin or self.fire_cont_frame + + def extract(self, frame): + data = self.cont_data + self.cont_data = None + frame.data = data[1] + if not self.fire_cont_frame and data[0] == ABNF.OPCODE_TEXT and not self.skip_utf8_validation and not validate_utf8(frame.data): + raise WebSocketPayloadException( + "cannot decode: " + repr(frame.data)) + + return [data[0], frame] diff --git a/openpype/vendor/python/python_2/websocket/_app.py b/openpype/vendor/python/python_2/websocket/_app.py new file mode 100644 index 0000000000..a3f91a38a3 --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/_app.py @@ -0,0 +1,399 @@ +""" + +""" + +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" +import inspect +import select +import sys +import threading +import time +import traceback + +import six + +from ._abnf import ABNF +from ._core import WebSocket, getdefaulttimeout +from ._exceptions import * +from . import _logging + + +__all__ = ["WebSocketApp"] + + +class Dispatcher: + """ + Dispatcher + """ + def __init__(self, app, ping_timeout): + self.app = app + self.ping_timeout = ping_timeout + + def read(self, sock, read_callback, check_callback): + while self.app.keep_running: + r, w, e = select.select( + (self.app.sock.sock, ), (), (), self.ping_timeout) + if r: + if not read_callback(): + break + check_callback() + + +class SSLDispatcher: + """ + SSLDispatcher + """ + def __init__(self, app, ping_timeout): + self.app = app + self.ping_timeout = ping_timeout + + def read(self, sock, read_callback, check_callback): + while self.app.keep_running: + r = self.select() + if r: + if not read_callback(): + break + check_callback() + + def select(self): + sock = self.app.sock.sock + if sock.pending(): + return [sock,] + + r, w, e = select.select((sock, ), (), (), self.ping_timeout) + return r + + +class WebSocketApp(object): + """ + Higher level of APIs are provided. The interface is like JavaScript WebSocket object. + """ + + def __init__(self, url, header=None, + on_open=None, on_message=None, on_error=None, + on_close=None, on_ping=None, on_pong=None, + on_cont_message=None, + keep_running=True, get_mask_key=None, cookie=None, + subprotocols=None, + on_data=None): + """ + WebSocketApp initialization + + Parameters + ---------- + url: + websocket url. + header: list or dict + custom header for websocket handshake. + on_open: + callable object which is called at opening websocket. + this function has one argument. The argument is this class object. + on_message: + callable object which is called when received data. + on_message has 2 arguments. + The 1st argument is this class object. + The 2nd argument is utf-8 string which we get from the server. + on_error: + callable object which is called when we get error. + on_error has 2 arguments. + The 1st argument is this class object. + The 2nd argument is exception object. + on_close: + callable object which is called when closed the connection. + this function has one argument. The argument is this class object. + on_cont_message: + callback object which is called when receive continued + frame data. + on_cont_message has 3 arguments. + The 1st argument is this class object. + The 2nd argument is utf-8 string which we get from the server. + The 3rd argument is continue flag. if 0, the data continue + to next frame data + on_data: + callback object which is called when a message received. + This is called before on_message or on_cont_message, + and then on_message or on_cont_message is called. + on_data has 4 argument. + The 1st argument is this class object. + The 2nd argument is utf-8 string which we get from the server. + The 3rd argument is data type. ABNF.OPCODE_TEXT or ABNF.OPCODE_BINARY will be came. + The 4th argument is continue flag. if 0, the data continue + keep_running: + this parameter is obsolete and ignored. + get_mask_key: func + a callable to produce new mask keys, + see the WebSocket.set_mask_key's docstring for more information + cookie: str + cookie value. + subprotocols: + array of available sub protocols. default is None. + """ + self.url = url + self.header = header if header is not None else [] + self.cookie = cookie + + self.on_open = on_open + self.on_message = on_message + self.on_data = on_data + self.on_error = on_error + self.on_close = on_close + self.on_ping = on_ping + self.on_pong = on_pong + self.on_cont_message = on_cont_message + self.keep_running = False + self.get_mask_key = get_mask_key + self.sock = None + self.last_ping_tm = 0 + self.last_pong_tm = 0 + self.subprotocols = subprotocols + + def send(self, data, opcode=ABNF.OPCODE_TEXT): + """ + send message + + Parameters + ---------- + data: + Message to send. If you set opcode to OPCODE_TEXT, + data must be utf-8 string or unicode. + opcode: + Operation code of data. default is OPCODE_TEXT. + """ + + if not self.sock or self.sock.send(data, opcode) == 0: + raise WebSocketConnectionClosedException( + "Connection is already closed.") + + def close(self, **kwargs): + """ + Close websocket connection. + """ + self.keep_running = False + if self.sock: + self.sock.close(**kwargs) + self.sock = None + + def _send_ping(self, interval, event, payload): + while not event.wait(interval): + self.last_ping_tm = time.time() + if self.sock: + try: + self.sock.ping(payload) + except Exception as ex: + _logging.warning("send_ping routine terminated: {}".format(ex)) + break + + def run_forever(self, sockopt=None, sslopt=None, + ping_interval=0, ping_timeout=None, + ping_payload="", + http_proxy_host=None, http_proxy_port=None, + http_no_proxy=None, http_proxy_auth=None, + skip_utf8_validation=False, + host=None, origin=None, dispatcher=None, + suppress_origin=False, proxy_type=None): + """ + Run event loop for WebSocket framework. + + This loop is an infinite loop and is alive while websocket is available. + + Parameters + ---------- + sockopt: tuple + values for socket.setsockopt. + sockopt must be tuple + and each element is argument of sock.setsockopt. + sslopt: dict + optional dict object for ssl socket option. + ping_interval: int or float + automatically send "ping" command + every specified period (in seconds) + if set to 0, not send automatically. + ping_timeout: int or float + timeout (in seconds) if the pong message is not received. + ping_payload: str + payload message to send with each ping. + http_proxy_host: + http proxy host name. + http_proxy_port: + http proxy port. If not set, set to 80. + http_no_proxy: + host names, which doesn't use proxy. + skip_utf8_validation: bool + skip utf8 validation. + host: str + update host header. + origin: str + update origin header. + dispatcher: + customize reading data from socket. + suppress_origin: bool + suppress outputting origin header. + + Returns + ------- + teardown: bool + False if caught KeyboardInterrupt, True if other exception was raised during a loop + """ + + if ping_timeout is not None and ping_timeout <= 0: + ping_timeout = None + if ping_timeout and ping_interval and ping_interval <= ping_timeout: + raise WebSocketException("Ensure ping_interval > ping_timeout") + if not sockopt: + sockopt = [] + if not sslopt: + sslopt = {} + if self.sock: + raise WebSocketException("socket is already opened") + thread = None + self.keep_running = True + self.last_ping_tm = 0 + self.last_pong_tm = 0 + + def teardown(close_frame=None): + """ + Tears down the connection. + + If close_frame is set, we will invoke the on_close handler with the + statusCode and reason from there. + """ + if thread and thread.is_alive(): + event.set() + thread.join() + self.keep_running = False + if self.sock: + self.sock.close() + close_args = self._get_close_args( + close_frame.data if close_frame else None) + self._callback(self.on_close, *close_args) + self.sock = None + + try: + self.sock = WebSocket( + self.get_mask_key, sockopt=sockopt, sslopt=sslopt, + fire_cont_frame=self.on_cont_message is not None, + skip_utf8_validation=skip_utf8_validation, + enable_multithread=True if ping_interval else False) + self.sock.settimeout(getdefaulttimeout()) + self.sock.connect( + self.url, header=self.header, cookie=self.cookie, + http_proxy_host=http_proxy_host, + http_proxy_port=http_proxy_port, http_no_proxy=http_no_proxy, + http_proxy_auth=http_proxy_auth, subprotocols=self.subprotocols, + host=host, origin=origin, suppress_origin=suppress_origin, + proxy_type=proxy_type) + if not dispatcher: + dispatcher = self.create_dispatcher(ping_timeout) + + self._callback(self.on_open) + + if ping_interval: + event = threading.Event() + thread = threading.Thread( + target=self._send_ping, args=(ping_interval, event, ping_payload)) + thread.daemon = True + thread.start() + + def read(): + if not self.keep_running: + return teardown() + + op_code, frame = self.sock.recv_data_frame(True) + if op_code == ABNF.OPCODE_CLOSE: + return teardown(frame) + elif op_code == ABNF.OPCODE_PING: + self._callback(self.on_ping, frame.data) + elif op_code == ABNF.OPCODE_PONG: + self.last_pong_tm = time.time() + self._callback(self.on_pong, frame.data) + elif op_code == ABNF.OPCODE_CONT and self.on_cont_message: + self._callback(self.on_data, frame.data, + frame.opcode, frame.fin) + self._callback(self.on_cont_message, + frame.data, frame.fin) + else: + data = frame.data + if six.PY3 and op_code == ABNF.OPCODE_TEXT: + data = data.decode("utf-8") + self._callback(self.on_data, data, frame.opcode, True) + self._callback(self.on_message, data) + + return True + + def check(): + if (ping_timeout): + has_timeout_expired = time.time() - self.last_ping_tm > ping_timeout + has_pong_not_arrived_after_last_ping = self.last_pong_tm - self.last_ping_tm < 0 + has_pong_arrived_too_late = self.last_pong_tm - self.last_ping_tm > ping_timeout + + if (self.last_ping_tm and + has_timeout_expired and + (has_pong_not_arrived_after_last_ping or has_pong_arrived_too_late)): + raise WebSocketTimeoutException("ping/pong timed out") + return True + + dispatcher.read(self.sock.sock, read, check) + except (Exception, KeyboardInterrupt, SystemExit) as e: + self._callback(self.on_error, e) + if isinstance(e, SystemExit): + # propagate SystemExit further + raise + teardown() + return not isinstance(e, KeyboardInterrupt) + + def create_dispatcher(self, ping_timeout): + timeout = ping_timeout or 10 + if self.sock.is_ssl(): + return SSLDispatcher(self, timeout) + + return Dispatcher(self, timeout) + + def _get_close_args(self, data): + """ + _get_close_args extracts the code, reason from the close body + if they exists, and if the self.on_close except three arguments + """ + # if the on_close callback is "old", just return empty list + if sys.version_info < (3, 0): + if not self.on_close or len(inspect.getargspec(self.on_close).args) != 3: + return [] + else: + if not self.on_close or len(inspect.getfullargspec(self.on_close).args) != 3: + return [] + + if data and len(data) >= 2: + code = 256 * six.byte2int(data[0:1]) + six.byte2int(data[1:2]) + reason = data[2:].decode('utf-8') + return [code, reason] + + return [None, None] + + def _callback(self, callback, *args): + if callback: + try: + callback(self, *args) + + except Exception as e: + _logging.error("error from callback {}: {}".format(callback, e)) + if _logging.isEnabledForDebug(): + _, _, tb = sys.exc_info() + traceback.print_tb(tb) diff --git a/openpype/vendor/python/python_2/websocket/_cookiejar.py b/openpype/vendor/python/python_2/websocket/_cookiejar.py new file mode 100644 index 0000000000..bc2891a650 --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/_cookiejar.py @@ -0,0 +1,78 @@ +""" + +""" + +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" +try: + import Cookie +except: + import http.cookies as Cookie + + +class SimpleCookieJar(object): + def __init__(self): + self.jar = dict() + + def add(self, set_cookie): + if set_cookie: + try: + simpleCookie = Cookie.SimpleCookie(set_cookie) + except: + simpleCookie = Cookie.SimpleCookie(set_cookie.encode('ascii', 'ignore')) + + for k, v in simpleCookie.items(): + domain = v.get("domain") + if domain: + if not domain.startswith("."): + domain = "." + domain + cookie = self.jar.get(domain) if self.jar.get(domain) else Cookie.SimpleCookie() + cookie.update(simpleCookie) + self.jar[domain.lower()] = cookie + + def set(self, set_cookie): + if set_cookie: + try: + simpleCookie = Cookie.SimpleCookie(set_cookie) + except: + simpleCookie = Cookie.SimpleCookie(set_cookie.encode('ascii', 'ignore')) + + for k, v in simpleCookie.items(): + domain = v.get("domain") + if domain: + if not domain.startswith("."): + domain = "." + domain + self.jar[domain.lower()] = simpleCookie + + def get(self, host): + if not host: + return "" + + cookies = [] + for domain, simpleCookie in self.jar.items(): + host = host.lower() + if host.endswith(domain) or host == domain[1:]: + cookies.append(self.jar.get(domain)) + + return "; ".join(filter( + None, sorted( + ["%s=%s" % (k, v.value) for cookie in filter(None, cookies) for k, v in cookie.items()] + ))) diff --git a/openpype/vendor/python/python_2/websocket/_core.py b/openpype/vendor/python/python_2/websocket/_core.py new file mode 100644 index 0000000000..1ff80f05d7 --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/_core.py @@ -0,0 +1,595 @@ +from __future__ import print_function +""" +_core.py +==================================== +WebSocket Python client +""" + +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" +import socket +import struct +import threading +import time + +import six + +# websocket modules +from ._abnf import * +from ._exceptions import * +from ._handshake import * +from ._http import * +from ._logging import * +from ._socket import * +from ._ssl_compat import * +from ._utils import * + +__all__ = ['WebSocket', 'create_connection'] + + +class WebSocket(object): + """ + Low level WebSocket interface. + + This class is based on the WebSocket protocol `draft-hixie-thewebsocketprotocol-76 `_ + + We can connect to the websocket server and send/receive data. + The following example is an echo client. + + >>> import websocket + >>> ws = websocket.WebSocket() + >>> ws.connect("ws://echo.websocket.org") + >>> ws.send("Hello, Server") + >>> ws.recv() + 'Hello, Server' + >>> ws.close() + + Parameters + ---------- + get_mask_key: func + a callable to produce new mask keys, see the set_mask_key + function's docstring for more details + sockopt: tuple + values for socket.setsockopt. + sockopt must be tuple and each element is argument of sock.setsockopt. + sslopt: dict + optional dict object for ssl socket option. + fire_cont_frame: bool + fire recv event for each cont frame. default is False + enable_multithread: bool + if set to True, lock send method. + skip_utf8_validation: bool + skip utf8 validation. + """ + + def __init__(self, get_mask_key=None, sockopt=None, sslopt=None, + fire_cont_frame=False, enable_multithread=False, + skip_utf8_validation=False, **_): + """ + Initialize WebSocket object. + + Parameters + ---------- + sslopt: specify ssl certification verification options + """ + self.sock_opt = sock_opt(sockopt, sslopt) + self.handshake_response = None + self.sock = None + + self.connected = False + self.get_mask_key = get_mask_key + # These buffer over the build-up of a single frame. + self.frame_buffer = frame_buffer(self._recv, skip_utf8_validation) + self.cont_frame = continuous_frame( + fire_cont_frame, skip_utf8_validation) + + if enable_multithread: + self.lock = threading.Lock() + self.readlock = threading.Lock() + else: + self.lock = NoLock() + self.readlock = NoLock() + + def __iter__(self): + """ + Allow iteration over websocket, implying sequential `recv` executions. + """ + while True: + yield self.recv() + + def __next__(self): + return self.recv() + + def next(self): + return self.__next__() + + def fileno(self): + return self.sock.fileno() + + def set_mask_key(self, func): + """ + Set function to create mask key. You can customize mask key generator. + Mainly, this is for testing purpose. + + Parameters + ---------- + func: func + callable object. the func takes 1 argument as integer. + The argument means length of mask key. + This func must return string(byte array), + which length is argument specified. + """ + self.get_mask_key = func + + def gettimeout(self): + """ + Get the websocket timeout (in seconds) as an int or float + + Returns + ---------- + timeout: int or float + returns timeout value (in seconds). This value could be either float/integer. + """ + return self.sock_opt.timeout + + def settimeout(self, timeout): + """ + Set the timeout to the websocket. + + Parameters + ---------- + timeout: int or float + timeout time (in seconds). This value could be either float/integer. + """ + self.sock_opt.timeout = timeout + if self.sock: + self.sock.settimeout(timeout) + + timeout = property(gettimeout, settimeout) + + def getsubprotocol(self): + """ + Get subprotocol + """ + if self.handshake_response: + return self.handshake_response.subprotocol + else: + return None + + subprotocol = property(getsubprotocol) + + def getstatus(self): + """ + Get handshake status + """ + if self.handshake_response: + return self.handshake_response.status + else: + return None + + status = property(getstatus) + + def getheaders(self): + """ + Get handshake response header + """ + if self.handshake_response: + return self.handshake_response.headers + else: + return None + + def is_ssl(self): + return isinstance(self.sock, ssl.SSLSocket) + + headers = property(getheaders) + + def connect(self, url, **options): + """ + Connect to url. url is websocket url scheme. + ie. ws://host:port/resource + You can customize using 'options'. + If you set "header" list object, you can set your own custom header. + + >>> ws = WebSocket() + >>> ws.connect("ws://echo.websocket.org/", + ... header=["User-Agent: MyProgram", + ... "x-custom: header"]) + + timeout: + socket timeout time. This value is an integer or float. + if you set None for this value, it means "use default_timeout value" + + Parameters + ---------- + options: + - header: list or dict + custom http header list or dict. + - cookie: str + cookie value. + - origin: str + custom origin url. + - suppress_origin: bool + suppress outputting origin header. + - host: str + custom host header string. + - http_proxy_host: + http proxy host name. + - http_proxy_port: + http proxy port. If not set, set to 80. + - http_no_proxy: + host names, which doesn't use proxy. + - http_proxy_auth: + http proxy auth information. tuple of username and password. default is None + - redirect_limit: + number of redirects to follow. + - subprotocols: + array of available sub protocols. default is None. + - socket: + pre-initialized stream socket. + """ + self.sock_opt.timeout = options.get('timeout', self.sock_opt.timeout) + self.sock, addrs = connect(url, self.sock_opt, proxy_info(**options), + options.pop('socket', None)) + + try: + self.handshake_response = handshake(self.sock, *addrs, **options) + for attempt in range(options.pop('redirect_limit', 3)): + if self.handshake_response.status in SUPPORTED_REDIRECT_STATUSES: + url = self.handshake_response.headers['location'] + self.sock.close() + self.sock, addrs = connect(url, self.sock_opt, proxy_info(**options), + options.pop('socket', None)) + self.handshake_response = handshake(self.sock, *addrs, **options) + self.connected = True + except: + if self.sock: + self.sock.close() + self.sock = None + raise + + def send(self, payload, opcode=ABNF.OPCODE_TEXT): + """ + Send the data as string. + + Parameters + ---------- + payload: + Payload must be utf-8 string or unicode, + if the opcode is OPCODE_TEXT. + Otherwise, it must be string(byte array) + opcode: + operation code to send. Please see OPCODE_XXX. + """ + + frame = ABNF.create_frame(payload, opcode) + return self.send_frame(frame) + + def send_frame(self, frame): + """ + Send the data frame. + + >>> ws = create_connection("ws://echo.websocket.org/") + >>> frame = ABNF.create_frame("Hello", ABNF.OPCODE_TEXT) + >>> ws.send_frame(frame) + >>> cont_frame = ABNF.create_frame("My name is ", ABNF.OPCODE_CONT, 0) + >>> ws.send_frame(frame) + >>> cont_frame = ABNF.create_frame("Foo Bar", ABNF.OPCODE_CONT, 1) + >>> ws.send_frame(frame) + + Parameters + ---------- + frame: + frame data created by ABNF.create_frame + """ + if self.get_mask_key: + frame.get_mask_key = self.get_mask_key + data = frame.format() + length = len(data) + if (isEnabledForTrace()): + trace("send: " + repr(data)) + + with self.lock: + while data: + l = self._send(data) + data = data[l:] + + return length + + def send_binary(self, payload): + return self.send(payload, ABNF.OPCODE_BINARY) + + def ping(self, payload=""): + """ + Send ping data. + + Parameters + ---------- + payload: + data payload to send server. + """ + if isinstance(payload, six.text_type): + payload = payload.encode("utf-8") + self.send(payload, ABNF.OPCODE_PING) + + def pong(self, payload=""): + """ + Send pong data. + + Parameters + ---------- + payload: + data payload to send server. + """ + if isinstance(payload, six.text_type): + payload = payload.encode("utf-8") + self.send(payload, ABNF.OPCODE_PONG) + + def recv(self): + """ + Receive string data(byte array) from the server. + + Returns + ---------- + data: string (byte array) value. + """ + with self.readlock: + opcode, data = self.recv_data() + if six.PY3 and opcode == ABNF.OPCODE_TEXT: + return data.decode("utf-8") + elif opcode == ABNF.OPCODE_TEXT or opcode == ABNF.OPCODE_BINARY: + return data + else: + return '' + + def recv_data(self, control_frame=False): + """ + Receive data with operation code. + + Parameters + ---------- + control_frame: bool + a boolean flag indicating whether to return control frame + data, defaults to False + + Returns + ------- + opcode, frame.data: tuple + tuple of operation code and string(byte array) value. + """ + opcode, frame = self.recv_data_frame(control_frame) + return opcode, frame.data + + def recv_data_frame(self, control_frame=False): + """ + Receive data with operation code. + + Parameters + ---------- + control_frame: bool + a boolean flag indicating whether to return control frame + data, defaults to False + + Returns + ------- + frame.opcode, frame: tuple + tuple of operation code and string(byte array) value. + """ + while True: + frame = self.recv_frame() + if not frame: + # handle error: + # 'NoneType' object has no attribute 'opcode' + raise WebSocketProtocolException( + "Not a valid frame %s" % frame) + elif frame.opcode in (ABNF.OPCODE_TEXT, ABNF.OPCODE_BINARY, ABNF.OPCODE_CONT): + self.cont_frame.validate(frame) + self.cont_frame.add(frame) + + if self.cont_frame.is_fire(frame): + return self.cont_frame.extract(frame) + + elif frame.opcode == ABNF.OPCODE_CLOSE: + self.send_close() + return frame.opcode, frame + elif frame.opcode == ABNF.OPCODE_PING: + if len(frame.data) < 126: + self.pong(frame.data) + else: + raise WebSocketProtocolException( + "Ping message is too long") + if control_frame: + return frame.opcode, frame + elif frame.opcode == ABNF.OPCODE_PONG: + if control_frame: + return frame.opcode, frame + + def recv_frame(self): + """ + Receive data as frame from server. + + Returns + ------- + self.frame_buffer.recv_frame(): ABNF frame object + """ + return self.frame_buffer.recv_frame() + + def send_close(self, status=STATUS_NORMAL, reason=six.b("")): + """ + Send close data to the server. + + Parameters + ---------- + status: + status code to send. see STATUS_XXX. + reason: str or bytes + the reason to close. This must be string or bytes. + """ + if status < 0 or status >= ABNF.LENGTH_16: + raise ValueError("code is invalid range") + self.connected = False + self.send(struct.pack('!H', status) + reason, ABNF.OPCODE_CLOSE) + + def close(self, status=STATUS_NORMAL, reason=six.b(""), timeout=3): + """ + Close Websocket object + + Parameters + ---------- + status: + status code to send. see STATUS_XXX. + reason: + the reason to close. This must be string. + timeout: int or float + timeout until receive a close frame. + If None, it will wait forever until receive a close frame. + """ + if self.connected: + if status < 0 or status >= ABNF.LENGTH_16: + raise ValueError("code is invalid range") + + try: + self.connected = False + self.send(struct.pack('!H', status) + reason, ABNF.OPCODE_CLOSE) + sock_timeout = self.sock.gettimeout() + self.sock.settimeout(timeout) + start_time = time.time() + while timeout is None or time.time() - start_time < timeout: + try: + frame = self.recv_frame() + if frame.opcode != ABNF.OPCODE_CLOSE: + continue + if isEnabledForError(): + recv_status = struct.unpack("!H", frame.data[0:2])[0] + if recv_status >= 3000 and recv_status <= 4999: + debug("close status: " + repr(recv_status)) + elif recv_status != STATUS_NORMAL: + error("close status: " + repr(recv_status)) + break + except: + break + self.sock.settimeout(sock_timeout) + self.sock.shutdown(socket.SHUT_RDWR) + except: + pass + + self.shutdown() + + def abort(self): + """ + Low-level asynchronous abort, wakes up other threads that are waiting in recv_* + """ + if self.connected: + self.sock.shutdown(socket.SHUT_RDWR) + + def shutdown(self): + """ + close socket, immediately. + """ + if self.sock: + self.sock.close() + self.sock = None + self.connected = False + + def _send(self, data): + return send(self.sock, data) + + def _recv(self, bufsize): + try: + return recv(self.sock, bufsize) + except WebSocketConnectionClosedException: + if self.sock: + self.sock.close() + self.sock = None + self.connected = False + raise + + +def create_connection(url, timeout=None, class_=WebSocket, **options): + """ + Connect to url and return websocket object. + + Connect to url and return the WebSocket object. + Passing optional timeout parameter will set the timeout on the socket. + If no timeout is supplied, + the global default timeout setting returned by getdefaulttimeout() is used. + You can customize using 'options'. + If you set "header" list object, you can set your own custom header. + + >>> conn = create_connection("ws://echo.websocket.org/", + ... header=["User-Agent: MyProgram", + ... "x-custom: header"]) + + Parameters + ---------- + timeout: int or float + socket timeout time. This value could be either float/integer. + if you set None for this value, + it means "use default_timeout value" + class_: + class to instantiate when creating the connection. It has to implement + settimeout and connect. It's __init__ should be compatible with + WebSocket.__init__, i.e. accept all of it's kwargs. + options: + - header: list or dict + custom http header list or dict. + - cookie: str + cookie value. + - origin: str + custom origin url. + - suppress_origin: bool + suppress outputting origin header. + - host: + custom host header string. + - http_proxy_host: + http proxy host name. + - http_proxy_port: + http proxy port. If not set, set to 80. + - http_no_proxy: + host names, which doesn't use proxy. + - http_proxy_auth: + http proxy auth information. tuple of username and password. default is None + - enable_multithread: bool + enable lock for multithread. + - redirect_limit: + number of redirects to follow. + - sockopt: + socket options + - sslopt: + ssl option + - subprotocols: + array of available sub protocols. default is None. + - skip_utf8_validation: bool + skip utf8 validation. + - socket: + pre-initialized stream socket. + """ + sockopt = options.pop("sockopt", []) + sslopt = options.pop("sslopt", {}) + fire_cont_frame = options.pop("fire_cont_frame", False) + enable_multithread = options.pop("enable_multithread", False) + skip_utf8_validation = options.pop("skip_utf8_validation", False) + websock = class_(sockopt=sockopt, sslopt=sslopt, + fire_cont_frame=fire_cont_frame, + enable_multithread=enable_multithread, + skip_utf8_validation=skip_utf8_validation, **options) + websock.settimeout(timeout if timeout is not None else getdefaulttimeout()) + websock.connect(url, **options) + return websock diff --git a/openpype/vendor/python/python_2/websocket/_exceptions.py b/openpype/vendor/python/python_2/websocket/_exceptions.py new file mode 100644 index 0000000000..83c6e42b7d --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/_exceptions.py @@ -0,0 +1,86 @@ +""" +Define WebSocket exceptions +""" + +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" + + +class WebSocketException(Exception): + """ + WebSocket exception class. + """ + pass + + +class WebSocketProtocolException(WebSocketException): + """ + If the WebSocket protocol is invalid, this exception will be raised. + """ + pass + + +class WebSocketPayloadException(WebSocketException): + """ + If the WebSocket payload is invalid, this exception will be raised. + """ + pass + + +class WebSocketConnectionClosedException(WebSocketException): + """ + If remote host closed the connection or some network error happened, + this exception will be raised. + """ + pass + + +class WebSocketTimeoutException(WebSocketException): + """ + WebSocketTimeoutException will be raised at socket timeout during read/write data. + """ + pass + + +class WebSocketProxyException(WebSocketException): + """ + WebSocketProxyException will be raised when proxy error occurred. + """ + pass + + +class WebSocketBadStatusException(WebSocketException): + """ + WebSocketBadStatusException will be raised when we get bad handshake status code. + """ + + def __init__(self, message, status_code, status_message=None, resp_headers=None): + msg = message % (status_code, status_message) + super(WebSocketBadStatusException, self).__init__(msg) + self.status_code = status_code + self.resp_headers = resp_headers + + +class WebSocketAddressException(WebSocketException): + """ + If the websocket address info cannot be found, this exception will be raised. + """ + pass diff --git a/openpype/vendor/python/python_2/websocket/_handshake.py b/openpype/vendor/python/python_2/websocket/_handshake.py new file mode 100644 index 0000000000..c4d9d169da --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/_handshake.py @@ -0,0 +1,212 @@ +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" +import hashlib +import hmac +import os + +import six + +from ._cookiejar import SimpleCookieJar +from ._exceptions import * +from ._http import * +from ._logging import * +from ._socket import * + +if hasattr(six, 'PY3') and six.PY3: + from base64 import encodebytes as base64encode +else: + from base64 import encodestring as base64encode + +if hasattr(six, 'PY3') and six.PY3: + if hasattr(six, 'PY34') and six.PY34: + from http import client as HTTPStatus + else: + from http import HTTPStatus +else: + import httplib as HTTPStatus + +__all__ = ["handshake_response", "handshake", "SUPPORTED_REDIRECT_STATUSES"] + +if hasattr(hmac, "compare_digest"): + compare_digest = hmac.compare_digest +else: + def compare_digest(s1, s2): + return s1 == s2 + +# websocket supported version. +VERSION = 13 + +SUPPORTED_REDIRECT_STATUSES = (HTTPStatus.MOVED_PERMANENTLY, HTTPStatus.FOUND, HTTPStatus.SEE_OTHER,) +SUCCESS_STATUSES = SUPPORTED_REDIRECT_STATUSES + (HTTPStatus.SWITCHING_PROTOCOLS,) + +CookieJar = SimpleCookieJar() + + +class handshake_response(object): + + def __init__(self, status, headers, subprotocol): + self.status = status + self.headers = headers + self.subprotocol = subprotocol + CookieJar.add(headers.get("set-cookie")) + + +def handshake(sock, hostname, port, resource, **options): + headers, key = _get_handshake_headers(resource, hostname, port, options) + + header_str = "\r\n".join(headers) + send(sock, header_str) + dump("request header", header_str) + + status, resp = _get_resp_headers(sock) + if status in SUPPORTED_REDIRECT_STATUSES: + return handshake_response(status, resp, None) + success, subproto = _validate(resp, key, options.get("subprotocols")) + if not success: + raise WebSocketException("Invalid WebSocket Header") + + return handshake_response(status, resp, subproto) + + +def _pack_hostname(hostname): + # IPv6 address + if ':' in hostname: + return '[' + hostname + ']' + + return hostname + + +def _get_handshake_headers(resource, host, port, options): + headers = [ + "GET %s HTTP/1.1" % resource, + "Upgrade: websocket" + ] + if port == 80 or port == 443: + hostport = _pack_hostname(host) + else: + hostport = "%s:%d" % (_pack_hostname(host), port) + if "host" in options and options["host"] is not None: + headers.append("Host: %s" % options["host"]) + else: + headers.append("Host: %s" % hostport) + + if "suppress_origin" not in options or not options["suppress_origin"]: + if "origin" in options and options["origin"] is not None: + headers.append("Origin: %s" % options["origin"]) + else: + headers.append("Origin: http://%s" % hostport) + + key = _create_sec_websocket_key() + + # Append Sec-WebSocket-Key & Sec-WebSocket-Version if not manually specified + if 'header' not in options or 'Sec-WebSocket-Key' not in options['header']: + key = _create_sec_websocket_key() + headers.append("Sec-WebSocket-Key: %s" % key) + else: + key = options['header']['Sec-WebSocket-Key'] + + if 'header' not in options or 'Sec-WebSocket-Version' not in options['header']: + headers.append("Sec-WebSocket-Version: %s" % VERSION) + + if 'connection' not in options or options['connection'] is None: + headers.append('Connection: Upgrade') + else: + headers.append(options['connection']) + + subprotocols = options.get("subprotocols") + if subprotocols: + headers.append("Sec-WebSocket-Protocol: %s" % ",".join(subprotocols)) + + if "header" in options: + header = options["header"] + if isinstance(header, dict): + header = [ + ": ".join([k, v]) + for k, v in header.items() + if v is not None + ] + headers.extend(header) + + server_cookie = CookieJar.get(host) + client_cookie = options.get("cookie", None) + + cookie = "; ".join(filter(None, [server_cookie, client_cookie])) + + if cookie: + headers.append("Cookie: %s" % cookie) + + headers.append("") + headers.append("") + + return headers, key + + +def _get_resp_headers(sock, success_statuses=SUCCESS_STATUSES): + status, resp_headers, status_message = read_headers(sock) + if status not in success_statuses: + raise WebSocketBadStatusException("Handshake status %d %s", status, status_message, resp_headers) + return status, resp_headers + + +_HEADERS_TO_CHECK = { + "upgrade": "websocket", + "connection": "upgrade", +} + + +def _validate(headers, key, subprotocols): + subproto = None + for k, v in _HEADERS_TO_CHECK.items(): + r = headers.get(k, None) + if not r: + return False, None + r = [x.strip().lower() for x in r.split(',')] + if v not in r: + return False, None + + if subprotocols: + subproto = headers.get("sec-websocket-protocol", None) + if not subproto or subproto.lower() not in [s.lower() for s in subprotocols]: + error("Invalid subprotocol: " + str(subprotocols)) + return False, None + subproto = subproto.lower() + + result = headers.get("sec-websocket-accept", None) + if not result: + return False, None + result = result.lower() + + if isinstance(result, six.text_type): + result = result.encode('utf-8') + + value = (key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").encode('utf-8') + hashed = base64encode(hashlib.sha1(value).digest()).strip().lower() + success = compare_digest(hashed, result) + + if success: + return True, subproto + else: + return False, None + + +def _create_sec_websocket_key(): + randomness = os.urandom(16) + return base64encode(randomness).decode('utf-8').strip() diff --git a/openpype/vendor/python/python_2/websocket/_http.py b/openpype/vendor/python/python_2/websocket/_http.py new file mode 100644 index 0000000000..b0dad48ce0 --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/_http.py @@ -0,0 +1,335 @@ +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" +import errno +import os +import socket +import sys + +import six + +from ._exceptions import * +from ._logging import * +from ._socket import* +from ._ssl_compat import * +from ._url import * + +if six.PY3: + from base64 import encodebytes as base64encode +else: + from base64 import encodestring as base64encode + +__all__ = ["proxy_info", "connect", "read_headers"] + +try: + import socks + ProxyConnectionError = socks.ProxyConnectionError + HAS_PYSOCKS = True +except: + class ProxyConnectionError(BaseException): + pass + HAS_PYSOCKS = False + + +class proxy_info(object): + + def __init__(self, **options): + self.type = options.get("proxy_type") or "http" + if not(self.type in ['http', 'socks4', 'socks5', 'socks5h']): + raise ValueError("proxy_type must be 'http', 'socks4', 'socks5' or 'socks5h'") + self.host = options.get("http_proxy_host", None) + if self.host: + self.port = options.get("http_proxy_port", 0) + self.auth = options.get("http_proxy_auth", None) + self.no_proxy = options.get("http_no_proxy", None) + else: + self.port = 0 + self.auth = None + self.no_proxy = None + + +def _open_proxied_socket(url, options, proxy): + hostname, port, resource, is_secure = parse_url(url) + + if not HAS_PYSOCKS: + raise WebSocketException("PySocks module not found.") + + ptype = socks.SOCKS5 + rdns = False + if proxy.type == "socks4": + ptype = socks.SOCKS4 + if proxy.type == "http": + ptype = socks.HTTP + if proxy.type[-1] == "h": + rdns = True + + sock = socks.create_connection( + (hostname, port), + proxy_type=ptype, + proxy_addr=proxy.host, + proxy_port=proxy.port, + proxy_rdns=rdns, + proxy_username=proxy.auth[0] if proxy.auth else None, + proxy_password=proxy.auth[1] if proxy.auth else None, + timeout=options.timeout, + socket_options=DEFAULT_SOCKET_OPTION + options.sockopt + ) + + if is_secure: + if HAVE_SSL: + sock = _ssl_socket(sock, options.sslopt, hostname) + else: + raise WebSocketException("SSL not available.") + + return sock, (hostname, port, resource) + + +def connect(url, options, proxy, socket): + if proxy.host and not socket and not (proxy.type == 'http'): + return _open_proxied_socket(url, options, proxy) + + hostname, port, resource, is_secure = parse_url(url) + + if socket: + return socket, (hostname, port, resource) + + addrinfo_list, need_tunnel, auth = _get_addrinfo_list( + hostname, port, is_secure, proxy) + if not addrinfo_list: + raise WebSocketException( + "Host not found.: " + hostname + ":" + str(port)) + + sock = None + try: + sock = _open_socket(addrinfo_list, options.sockopt, options.timeout) + if need_tunnel: + sock = _tunnel(sock, hostname, port, auth) + + if is_secure: + if HAVE_SSL: + sock = _ssl_socket(sock, options.sslopt, hostname) + else: + raise WebSocketException("SSL not available.") + + return sock, (hostname, port, resource) + except: + if sock: + sock.close() + raise + + +def _get_addrinfo_list(hostname, port, is_secure, proxy): + phost, pport, pauth = get_proxy_info( + hostname, is_secure, proxy.host, proxy.port, proxy.auth, proxy.no_proxy) + try: + # when running on windows 10, getaddrinfo without socktype returns a socktype 0. + # This generates an error exception: `_on_error: exception Socket type must be stream or datagram, not 0` + # or `OSError: [Errno 22] Invalid argument` when creating socket. Force the socket type to SOCK_STREAM. + if not phost: + addrinfo_list = socket.getaddrinfo( + hostname, port, 0, socket.SOCK_STREAM, socket.SOL_TCP) + return addrinfo_list, False, None + else: + pport = pport and pport or 80 + # when running on windows 10, the getaddrinfo used above + # returns a socktype 0. This generates an error exception: + # _on_error: exception Socket type must be stream or datagram, not 0 + # Force the socket type to SOCK_STREAM + addrinfo_list = socket.getaddrinfo(phost, pport, 0, socket.SOCK_STREAM, socket.SOL_TCP) + return addrinfo_list, True, pauth + except socket.gaierror as e: + raise WebSocketAddressException(e) + + +def _open_socket(addrinfo_list, sockopt, timeout): + err = None + for addrinfo in addrinfo_list: + family, socktype, proto = addrinfo[:3] + sock = socket.socket(family, socktype, proto) + sock.settimeout(timeout) + for opts in DEFAULT_SOCKET_OPTION: + sock.setsockopt(*opts) + for opts in sockopt: + sock.setsockopt(*opts) + + address = addrinfo[4] + err = None + while not err: + try: + sock.connect(address) + except ProxyConnectionError as error: + err = WebSocketProxyException(str(error)) + err.remote_ip = str(address[0]) + continue + except socket.error as error: + error.remote_ip = str(address[0]) + try: + eConnRefused = (errno.ECONNREFUSED, errno.WSAECONNREFUSED) + except: + eConnRefused = (errno.ECONNREFUSED, ) + if error.errno == errno.EINTR: + continue + elif error.errno in eConnRefused: + err = error + continue + else: + raise error + else: + break + else: + continue + break + else: + if err: + raise err + + return sock + + +def _can_use_sni(): + return six.PY2 and sys.version_info >= (2, 7, 9) or sys.version_info >= (3, 2) + + +def _wrap_sni_socket(sock, sslopt, hostname, check_hostname): + context = ssl.SSLContext(sslopt.get('ssl_version', ssl.PROTOCOL_SSLv23)) + + if sslopt.get('cert_reqs', ssl.CERT_NONE) != ssl.CERT_NONE: + cafile = sslopt.get('ca_certs', None) + capath = sslopt.get('ca_cert_path', None) + if cafile or capath: + context.load_verify_locations(cafile=cafile, capath=capath) + elif hasattr(context, 'load_default_certs'): + context.load_default_certs(ssl.Purpose.SERVER_AUTH) + if sslopt.get('certfile', None): + context.load_cert_chain( + sslopt['certfile'], + sslopt.get('keyfile', None), + sslopt.get('password', None), + ) + # see + # https://github.com/liris/websocket-client/commit/b96a2e8fa765753e82eea531adb19716b52ca3ca#commitcomment-10803153 + context.verify_mode = sslopt['cert_reqs'] + if HAVE_CONTEXT_CHECK_HOSTNAME: + context.check_hostname = check_hostname + if 'ciphers' in sslopt: + context.set_ciphers(sslopt['ciphers']) + if 'cert_chain' in sslopt: + certfile, keyfile, password = sslopt['cert_chain'] + context.load_cert_chain(certfile, keyfile, password) + if 'ecdh_curve' in sslopt: + context.set_ecdh_curve(sslopt['ecdh_curve']) + + return context.wrap_socket( + sock, + do_handshake_on_connect=sslopt.get('do_handshake_on_connect', True), + suppress_ragged_eofs=sslopt.get('suppress_ragged_eofs', True), + server_hostname=hostname, + ) + + +def _ssl_socket(sock, user_sslopt, hostname): + sslopt = dict(cert_reqs=ssl.CERT_REQUIRED) + sslopt.update(user_sslopt) + + certPath = os.environ.get('WEBSOCKET_CLIENT_CA_BUNDLE') + if certPath and os.path.isfile(certPath) \ + and user_sslopt.get('ca_certs', None) is None \ + and user_sslopt.get('ca_cert', None) is None: + sslopt['ca_certs'] = certPath + elif certPath and os.path.isdir(certPath) \ + and user_sslopt.get('ca_cert_path', None) is None: + sslopt['ca_cert_path'] = certPath + + check_hostname = sslopt["cert_reqs"] != ssl.CERT_NONE and sslopt.pop( + 'check_hostname', True) + + if _can_use_sni(): + sock = _wrap_sni_socket(sock, sslopt, hostname, check_hostname) + else: + sslopt.pop('check_hostname', True) + sock = ssl.wrap_socket(sock, **sslopt) + + if not HAVE_CONTEXT_CHECK_HOSTNAME and check_hostname: + match_hostname(sock.getpeercert(), hostname) + + return sock + + +def _tunnel(sock, host, port, auth): + debug("Connecting proxy...") + connect_header = "CONNECT %s:%d HTTP/1.1\r\n" % (host, port) + connect_header += "Host: %s:%d\r\n" % (host, port) + + # TODO: support digest auth. + if auth and auth[0]: + auth_str = auth[0] + if auth[1]: + auth_str += ":" + auth[1] + encoded_str = base64encode(auth_str.encode()).strip().decode().replace('\n', '') + connect_header += "Proxy-Authorization: Basic %s\r\n" % encoded_str + connect_header += "\r\n" + dump("request header", connect_header) + + send(sock, connect_header) + + try: + status, resp_headers, status_message = read_headers(sock) + except Exception as e: + raise WebSocketProxyException(str(e)) + + if status != 200: + raise WebSocketProxyException( + "failed CONNECT via proxy status: %r" % status) + + return sock + + +def read_headers(sock): + status = None + status_message = None + headers = {} + trace("--- response header ---") + + while True: + line = recv_line(sock) + line = line.decode('utf-8').strip() + if not line: + break + trace(line) + if not status: + + status_info = line.split(" ", 2) + status = int(status_info[1]) + if len(status_info) > 2: + status_message = status_info[2] + else: + kv = line.split(":", 1) + if len(kv) == 2: + key, value = kv + if key.lower() == "set-cookie" and headers.get("set-cookie"): + headers["set-cookie"] = headers.get("set-cookie") + "; " + value.strip() + else: + headers[key.lower()] = value.strip() + else: + raise WebSocketException("Invalid header") + + trace("-----------------------") + + return status, headers, status_message diff --git a/openpype/vendor/python/python_2/websocket/_logging.py b/openpype/vendor/python/python_2/websocket/_logging.py new file mode 100644 index 0000000000..07d9009031 --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/_logging.py @@ -0,0 +1,92 @@ +""" + +""" + +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" +import logging + +_logger = logging.getLogger('websocket') +try: + from logging import NullHandler +except ImportError: + class NullHandler(logging.Handler): + def emit(self, record): + pass + +_logger.addHandler(NullHandler()) + +_traceEnabled = False + +__all__ = ["enableTrace", "dump", "error", "warning", "debug", "trace", + "isEnabledForError", "isEnabledForDebug", "isEnabledForTrace"] + + +def enableTrace(traceable, handler=logging.StreamHandler()): + """ + Turn on/off the traceability. + + Parameters + ---------- + traceable: bool + If set to True, traceability is enabled. + """ + global _traceEnabled + _traceEnabled = traceable + if traceable: + _logger.addHandler(handler) + _logger.setLevel(logging.DEBUG) + + +def dump(title, message): + if _traceEnabled: + _logger.debug("--- " + title + " ---") + _logger.debug(message) + _logger.debug("-----------------------") + + +def error(msg): + _logger.error(msg) + + +def warning(msg): + _logger.warning(msg) + + +def debug(msg): + _logger.debug(msg) + + +def trace(msg): + if _traceEnabled: + _logger.debug(msg) + + +def isEnabledForError(): + return _logger.isEnabledFor(logging.ERROR) + + +def isEnabledForDebug(): + return _logger.isEnabledFor(logging.DEBUG) + + +def isEnabledForTrace(): + return _traceEnabled diff --git a/openpype/vendor/python/python_2/websocket/_socket.py b/openpype/vendor/python/python_2/websocket/_socket.py new file mode 100644 index 0000000000..2c383ed4d3 --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/_socket.py @@ -0,0 +1,176 @@ +""" + +""" + +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" +import errno +import select +import socket + +import six + +from ._exceptions import * +from ._ssl_compat import * +from ._utils import * + +DEFAULT_SOCKET_OPTION = [(socket.SOL_TCP, socket.TCP_NODELAY, 1)] +if hasattr(socket, "SO_KEEPALIVE"): + DEFAULT_SOCKET_OPTION.append((socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)) +if hasattr(socket, "TCP_KEEPIDLE"): + DEFAULT_SOCKET_OPTION.append((socket.SOL_TCP, socket.TCP_KEEPIDLE, 30)) +if hasattr(socket, "TCP_KEEPINTVL"): + DEFAULT_SOCKET_OPTION.append((socket.SOL_TCP, socket.TCP_KEEPINTVL, 10)) +if hasattr(socket, "TCP_KEEPCNT"): + DEFAULT_SOCKET_OPTION.append((socket.SOL_TCP, socket.TCP_KEEPCNT, 3)) + +_default_timeout = None + +__all__ = ["DEFAULT_SOCKET_OPTION", "sock_opt", "setdefaulttimeout", "getdefaulttimeout", + "recv", "recv_line", "send"] + + +class sock_opt(object): + + def __init__(self, sockopt, sslopt): + if sockopt is None: + sockopt = [] + if sslopt is None: + sslopt = {} + self.sockopt = sockopt + self.sslopt = sslopt + self.timeout = None + + +def setdefaulttimeout(timeout): + """ + Set the global timeout setting to connect. + + Parameters + ---------- + timeout: int or float + default socket timeout time (in seconds) + """ + global _default_timeout + _default_timeout = timeout + + +def getdefaulttimeout(): + """ + Get default timeout + + Returns + ---------- + _default_timeout: int or float + Return the global timeout setting (in seconds) to connect. + """ + return _default_timeout + + +def recv(sock, bufsize): + if not sock: + raise WebSocketConnectionClosedException("socket is already closed.") + + def _recv(): + try: + return sock.recv(bufsize) + except SSLWantReadError: + pass + except socket.error as exc: + error_code = extract_error_code(exc) + if error_code is None: + raise + if error_code != errno.EAGAIN or error_code != errno.EWOULDBLOCK: + raise + + r, w, e = select.select((sock, ), (), (), sock.gettimeout()) + if r: + return sock.recv(bufsize) + + try: + if sock.gettimeout() == 0: + bytes_ = sock.recv(bufsize) + else: + bytes_ = _recv() + except socket.timeout as e: + message = extract_err_message(e) + raise WebSocketTimeoutException(message) + except SSLError as e: + message = extract_err_message(e) + if isinstance(message, str) and 'timed out' in message: + raise WebSocketTimeoutException(message) + else: + raise + + if not bytes_: + raise WebSocketConnectionClosedException( + "Connection is already closed.") + + return bytes_ + + +def recv_line(sock): + line = [] + while True: + c = recv(sock, 1) + line.append(c) + if c == six.b("\n"): + break + return six.b("").join(line) + + +def send(sock, data): + if isinstance(data, six.text_type): + data = data.encode('utf-8') + + if not sock: + raise WebSocketConnectionClosedException("socket is already closed.") + + def _send(): + try: + return sock.send(data) + except SSLWantWriteError: + pass + except socket.error as exc: + error_code = extract_error_code(exc) + if error_code is None: + raise + if error_code != errno.EAGAIN or error_code != errno.EWOULDBLOCK: + raise + + r, w, e = select.select((), (sock, ), (), sock.gettimeout()) + if w: + return sock.send(data) + + try: + if sock.gettimeout() == 0: + return sock.send(data) + else: + return _send() + except socket.timeout as e: + message = extract_err_message(e) + raise WebSocketTimeoutException(message) + except Exception as e: + message = extract_err_message(e) + if isinstance(message, str) and "timed out" in message: + raise WebSocketTimeoutException(message) + else: + raise diff --git a/openpype/vendor/python/python_2/websocket/_ssl_compat.py b/openpype/vendor/python/python_2/websocket/_ssl_compat.py new file mode 100644 index 0000000000..9e201ddf00 --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/_ssl_compat.py @@ -0,0 +1,53 @@ +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" +__all__ = ["HAVE_SSL", "ssl", "SSLError", "SSLWantReadError", "SSLWantWriteError"] + +try: + import ssl + from ssl import SSLError + from ssl import SSLWantReadError + from ssl import SSLWantWriteError + if hasattr(ssl, 'SSLContext') and hasattr(ssl.SSLContext, 'check_hostname'): + HAVE_CONTEXT_CHECK_HOSTNAME = True + else: + HAVE_CONTEXT_CHECK_HOSTNAME = False + if hasattr(ssl, "match_hostname"): + from ssl import match_hostname + else: + from backports.ssl_match_hostname import match_hostname + __all__.append("match_hostname") + __all__.append("HAVE_CONTEXT_CHECK_HOSTNAME") + + HAVE_SSL = True +except ImportError: + # dummy class of SSLError for ssl none-support environment. + class SSLError(Exception): + pass + + class SSLWantReadError(Exception): + pass + + class SSLWantWriteError(Exception): + pass + + ssl = None + + HAVE_SSL = False diff --git a/openpype/vendor/python/python_2/websocket/_url.py b/openpype/vendor/python/python_2/websocket/_url.py new file mode 100644 index 0000000000..92ff939e39 --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/_url.py @@ -0,0 +1,178 @@ +""" + +""" +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" + +import os +import socket +import struct + +from six.moves.urllib.parse import urlparse + + +__all__ = ["parse_url", "get_proxy_info"] + + +def parse_url(url): + """ + parse url and the result is tuple of + (hostname, port, resource path and the flag of secure mode) + + Parameters + ---------- + url: str + url string. + """ + if ":" not in url: + raise ValueError("url is invalid") + + scheme, url = url.split(":", 1) + + parsed = urlparse(url, scheme="http") + if parsed.hostname: + hostname = parsed.hostname + else: + raise ValueError("hostname is invalid") + port = 0 + if parsed.port: + port = parsed.port + + is_secure = False + if scheme == "ws": + if not port: + port = 80 + elif scheme == "wss": + is_secure = True + if not port: + port = 443 + else: + raise ValueError("scheme %s is invalid" % scheme) + + if parsed.path: + resource = parsed.path + else: + resource = "/" + + if parsed.query: + resource += "?" + parsed.query + + return hostname, port, resource, is_secure + + +DEFAULT_NO_PROXY_HOST = ["localhost", "127.0.0.1"] + + +def _is_ip_address(addr): + try: + socket.inet_aton(addr) + except socket.error: + return False + else: + return True + + +def _is_subnet_address(hostname): + try: + addr, netmask = hostname.split("/") + return _is_ip_address(addr) and 0 <= int(netmask) < 32 + except ValueError: + return False + + +def _is_address_in_network(ip, net): + ipaddr = struct.unpack('!I', socket.inet_aton(ip))[0] + netaddr, netmask = net.split('/') + netaddr = struct.unpack('!I', socket.inet_aton(netaddr))[0] + + netmask = (0xFFFFFFFF << (32 - int(netmask))) & 0xFFFFFFFF + return ipaddr & netmask == netaddr + + +def _is_no_proxy_host(hostname, no_proxy): + if not no_proxy: + v = os.environ.get("no_proxy", "").replace(" ", "") + if v: + no_proxy = v.split(",") + if not no_proxy: + no_proxy = DEFAULT_NO_PROXY_HOST + + if '*' in no_proxy: + return True + if hostname in no_proxy: + return True + if _is_ip_address(hostname): + return any([_is_address_in_network(hostname, subnet) for subnet in no_proxy if _is_subnet_address(subnet)]) + for domain in [domain for domain in no_proxy if domain.startswith('.')]: + if hostname.endswith(domain): + return True + return False + + +def get_proxy_info( + hostname, is_secure, proxy_host=None, proxy_port=0, proxy_auth=None, + no_proxy=None, proxy_type='http'): + """ + Try to retrieve proxy host and port from environment + if not provided in options. + Result is (proxy_host, proxy_port, proxy_auth). + proxy_auth is tuple of username and password + of proxy authentication information. + + Parameters + ---------- + hostname: + websocket server name. + is_secure: + is the connection secure? (wss) looks for "https_proxy" in env + before falling back to "http_proxy" + options: + - http_proxy_host: + http proxy host name. + - http_proxy_port: + http proxy port. + - http_no_proxy: + host names, which doesn't use proxy. + - http_proxy_auth: + http proxy auth information. tuple of username and password. default is None + - proxy_type: + if set to "socks5" PySocks wrapper will be used in place of a http proxy. default is "http" + """ + if _is_no_proxy_host(hostname, no_proxy): + return None, 0, None + + if proxy_host: + port = proxy_port + auth = proxy_auth + return proxy_host, port, auth + + env_keys = ["http_proxy"] + if is_secure: + env_keys.insert(0, "https_proxy") + + for key in env_keys: + value = os.environ.get(key, None) + if value: + proxy = urlparse(value) + auth = (proxy.username, proxy.password) if proxy.username else None + return proxy.hostname, proxy.port, auth + + return None, 0, None diff --git a/openpype/vendor/python/python_2/websocket/_utils.py b/openpype/vendor/python/python_2/websocket/_utils.py new file mode 100644 index 0000000000..0072bce8ac --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/_utils.py @@ -0,0 +1,110 @@ +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" +import six + +__all__ = ["NoLock", "validate_utf8", "extract_err_message", "extract_error_code"] + + +class NoLock(object): + + def __enter__(self): + pass + + def __exit__(self, exc_type, exc_value, traceback): + pass + + +try: + # If wsaccel is available we use compiled routines to validate UTF-8 + # strings. + from wsaccel.utf8validator import Utf8Validator + + def _validate_utf8(utfbytes): + return Utf8Validator().validate(utfbytes)[0] + +except ImportError: + # UTF-8 validator + # python implementation of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + + _UTF8_ACCEPT = 0 + _UTF8_REJECT = 12 + + _UTF8D = [ + # The first part of the table maps bytes to character classes that + # to reduce the size of the transition table and create bitmasks. + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, + + # The second part is a transition table that maps a combination + # of a state of the automaton and a character class to a state. + 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12, + 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12, + 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12, + 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12, + 12,36,12,12,12,12,12,12,12,12,12,12, ] + + def _decode(state, codep, ch): + tp = _UTF8D[ch] + + codep = (ch & 0x3f) | (codep << 6) if ( + state != _UTF8_ACCEPT) else (0xff >> tp) & ch + state = _UTF8D[256 + state + tp] + + return state, codep + + def _validate_utf8(utfbytes): + state = _UTF8_ACCEPT + codep = 0 + for i in utfbytes: + if six.PY2: + i = ord(i) + state, codep = _decode(state, codep, i) + if state == _UTF8_REJECT: + return False + + return True + + +def validate_utf8(utfbytes): + """ + validate utf8 byte string. + utfbytes: utf byte string to check. + return value: if valid utf8 string, return true. Otherwise, return false. + """ + return _validate_utf8(utfbytes) + + +def extract_err_message(exception): + if exception.args: + return exception.args[0] + else: + return None + + +def extract_error_code(exception): + if exception.args and len(exception.args) > 1: + return exception.args[0] if isinstance(exception.args[0], int) else None diff --git a/openpype/vendor/python/python_2/websocket/tests/__init__.py b/openpype/vendor/python/python_2/websocket/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openpype/vendor/python/python_2/websocket/tests/data/header01.txt b/openpype/vendor/python/python_2/websocket/tests/data/header01.txt new file mode 100644 index 0000000000..d44d24c205 --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/tests/data/header01.txt @@ -0,0 +1,6 @@ +HTTP/1.1 101 WebSocket Protocol Handshake +Connection: Upgrade +Upgrade: WebSocket +Sec-WebSocket-Accept: Kxep+hNu9n51529fGidYu7a3wO0= +some_header: something + diff --git a/openpype/vendor/python/python_2/websocket/tests/data/header02.txt b/openpype/vendor/python/python_2/websocket/tests/data/header02.txt new file mode 100644 index 0000000000..f481de928a --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/tests/data/header02.txt @@ -0,0 +1,6 @@ +HTTP/1.1 101 WebSocket Protocol Handshake +Connection: Upgrade +Upgrade WebSocket +Sec-WebSocket-Accept: Kxep+hNu9n51529fGidYu7a3wO0= +some_header: something + diff --git a/openpype/vendor/python/python_2/websocket/tests/data/header03.txt b/openpype/vendor/python/python_2/websocket/tests/data/header03.txt new file mode 100644 index 0000000000..012b7d18dd --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/tests/data/header03.txt @@ -0,0 +1,6 @@ +HTTP/1.1 101 WebSocket Protocol Handshake +Connection: Upgrade, Keep-Alive +Upgrade: WebSocket +Sec-WebSocket-Accept: Kxep+hNu9n51529fGidYu7a3wO0= +some_header: something + diff --git a/openpype/vendor/python/python_2/websocket/tests/test_abnf.py b/openpype/vendor/python/python_2/websocket/tests/test_abnf.py new file mode 100644 index 0000000000..acce020682 --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/tests/test_abnf.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +# +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" + +import os +import websocket as ws +from websocket._abnf import * +import sys +sys.path[0:0] = [""] + +if sys.version_info[0] == 2 and sys.version_info[1] < 7: + import unittest2 as unittest +else: + import unittest + + +class ABNFTest(unittest.TestCase): + + def testInit(self): + a = ABNF(0,0,0,0, opcode=ABNF.OPCODE_PING) + self.assertEqual(a.fin, 0) + self.assertEqual(a.rsv1, 0) + self.assertEqual(a.rsv2, 0) + self.assertEqual(a.rsv3, 0) + self.assertEqual(a.opcode, 9) + self.assertEqual(a.data, '') + a_bad = ABNF(0,1,0,0, opcode=77) + self.assertEqual(a_bad.rsv1, 1) + self.assertEqual(a_bad.opcode, 77) + + def testValidate(self): + a = ABNF(0,0,0,0, opcode=ABNF.OPCODE_PING) + self.assertRaises(ws.WebSocketProtocolException, a.validate) + a_bad = ABNF(0,1,0,0, opcode=77) + self.assertRaises(ws.WebSocketProtocolException, a_bad.validate) + a_close = ABNF(0,1,0,0, opcode=ABNF.OPCODE_CLOSE, data="abcdefgh1234567890abcdefgh1234567890abcdefgh1234567890abcdefgh1234567890") + self.assertRaises(ws.WebSocketProtocolException, a_close.validate) + +# This caused an error in the Python 2.7 Github Actions build +# Uncomment test case when Python 2 support no longer wanted +# def testMask(self): +# ab = ABNF(0,0,0,0, opcode=ABNF.OPCODE_PING) +# bytes_val = bytes("aaaa", 'utf-8') +# self.assertEqual(ab._get_masked(bytes_val), bytes_val) + + def testFrameBuffer(self): + fb = frame_buffer(0, True) + self.assertEqual(fb.recv, 0) + self.assertEqual(fb.skip_utf8_validation, True) + fb.clear + self.assertEqual(fb.header, None) + self.assertEqual(fb.length, None) + self.assertEqual(fb.mask, None) + self.assertEqual(fb.has_mask(), False) + + +if __name__ == "__main__": + unittest.main() diff --git a/openpype/vendor/python/python_2/websocket/tests/test_app.py b/openpype/vendor/python/python_2/websocket/tests/test_app.py new file mode 100644 index 0000000000..e5a739008e --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/tests/test_app.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- +# +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" + +import os +import os.path +import websocket as ws +import sys +sys.path[0:0] = [""] + +try: + import ssl +except ImportError: + HAVE_SSL = False + +if sys.version_info[0] == 2 and sys.version_info[1] < 7: + import unittest2 as unittest +else: + import unittest + +# Skip test to access the internet. +TEST_WITH_INTERNET = os.environ.get('TEST_WITH_INTERNET', '0') == '1' +TRACEABLE = True + + +class WebSocketAppTest(unittest.TestCase): + + class NotSetYet(object): + """ A marker class for signalling that a value hasn't been set yet. + """ + + def setUp(self): + ws.enableTrace(TRACEABLE) + + WebSocketAppTest.keep_running_open = WebSocketAppTest.NotSetYet() + WebSocketAppTest.keep_running_close = WebSocketAppTest.NotSetYet() + WebSocketAppTest.get_mask_key_id = WebSocketAppTest.NotSetYet() + + def tearDown(self): + WebSocketAppTest.keep_running_open = WebSocketAppTest.NotSetYet() + WebSocketAppTest.keep_running_close = WebSocketAppTest.NotSetYet() + WebSocketAppTest.get_mask_key_id = WebSocketAppTest.NotSetYet() + + @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") + def testKeepRunning(self): + """ A WebSocketApp should keep running as long as its self.keep_running + is not False (in the boolean context). + """ + + def on_open(self, *args, **kwargs): + """ Set the keep_running flag for later inspection and immediately + close the connection. + """ + WebSocketAppTest.keep_running_open = self.keep_running + + self.close() + + def on_close(self, *args, **kwargs): + """ Set the keep_running flag for the test to use. + """ + WebSocketAppTest.keep_running_close = self.keep_running + + app = ws.WebSocketApp('ws://echo.websocket.org/', on_open=on_open, on_close=on_close) + app.run_forever() + + # if numpy is installed, this assertion fail + # self.assertFalse(isinstance(WebSocketAppTest.keep_running_open, + # WebSocketAppTest.NotSetYet)) + + # self.assertFalse(isinstance(WebSocketAppTest.keep_running_close, + # WebSocketAppTest.NotSetYet)) + + # self.assertEqual(True, WebSocketAppTest.keep_running_open) + # self.assertEqual(False, WebSocketAppTest.keep_running_close) + + @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") + def testSockMaskKey(self): + """ A WebSocketApp should forward the received mask_key function down + to the actual socket. + """ + + def my_mask_key_func(): + pass + + def on_open(self, *args, **kwargs): + """ Set the value so the test can use it later on and immediately + close the connection. + """ + WebSocketAppTest.get_mask_key_id = id(self.get_mask_key) + self.close() + + app = ws.WebSocketApp('ws://echo.websocket.org/', on_open=on_open, get_mask_key=my_mask_key_func) + app.run_forever() + + # if numpy is installed, this assertion fail + # Note: We can't use 'is' for comparing the functions directly, need to use 'id'. + # self.assertEqual(WebSocketAppTest.get_mask_key_id, id(my_mask_key_func)) + + @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") + def testPingInterval(self): + """ A WebSocketApp should ping regularly + """ + + def on_ping(app, msg): + print("Got a ping!") + app.close() + + def on_pong(app, msg): + print("Got a pong! No need to respond") + app.close() + + app = ws.WebSocketApp('wss://api-pub.bitfinex.com/ws/1', on_ping=on_ping, on_pong=on_pong) + app.run_forever(ping_interval=2, ping_timeout=1) # , sslopt={"cert_reqs": ssl.CERT_NONE} + self.assertRaises(ws.WebSocketException, app.run_forever, ping_interval=2, ping_timeout=3, sslopt={"cert_reqs": ssl.CERT_NONE}) + + +if __name__ == "__main__": + unittest.main() diff --git a/openpype/vendor/python/python_2/websocket/tests/test_cookiejar.py b/openpype/vendor/python/python_2/websocket/tests/test_cookiejar.py new file mode 100644 index 0000000000..fc66e58b0e --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/tests/test_cookiejar.py @@ -0,0 +1,117 @@ +""" + +""" + +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" +import unittest + +from websocket._cookiejar import SimpleCookieJar + + +class CookieJarTest(unittest.TestCase): + def testAdd(self): + cookie_jar = SimpleCookieJar() + cookie_jar.add("") + self.assertFalse(cookie_jar.jar, "Cookie with no domain should not be added to the jar") + + cookie_jar = SimpleCookieJar() + cookie_jar.add("a=b") + self.assertFalse(cookie_jar.jar, "Cookie with no domain should not be added to the jar") + + cookie_jar = SimpleCookieJar() + cookie_jar.add("a=b; domain=.abc") + self.assertTrue(".abc" in cookie_jar.jar) + + cookie_jar = SimpleCookieJar() + cookie_jar.add("a=b; domain=abc") + self.assertTrue(".abc" in cookie_jar.jar) + self.assertTrue("abc" not in cookie_jar.jar) + + cookie_jar = SimpleCookieJar() + cookie_jar.add("a=b; c=d; domain=abc") + self.assertEqual(cookie_jar.get("abc"), "a=b; c=d") + + cookie_jar = SimpleCookieJar() + cookie_jar.add("a=b; c=d; domain=abc") + cookie_jar.add("e=f; domain=abc") + self.assertEqual(cookie_jar.get("abc"), "a=b; c=d; e=f") + + cookie_jar = SimpleCookieJar() + cookie_jar.add("a=b; c=d; domain=abc") + cookie_jar.add("e=f; domain=.abc") + self.assertEqual(cookie_jar.get("abc"), "a=b; c=d; e=f") + + cookie_jar = SimpleCookieJar() + cookie_jar.add("a=b; c=d; domain=abc") + cookie_jar.add("e=f; domain=xyz") + self.assertEqual(cookie_jar.get("abc"), "a=b; c=d") + self.assertEqual(cookie_jar.get("xyz"), "e=f") + self.assertEqual(cookie_jar.get("something"), "") + + def testSet(self): + cookie_jar = SimpleCookieJar() + cookie_jar.set("a=b") + self.assertFalse(cookie_jar.jar, "Cookie with no domain should not be added to the jar") + + cookie_jar = SimpleCookieJar() + cookie_jar.set("a=b; domain=.abc") + self.assertTrue(".abc" in cookie_jar.jar) + + cookie_jar = SimpleCookieJar() + cookie_jar.set("a=b; domain=abc") + self.assertTrue(".abc" in cookie_jar.jar) + self.assertTrue("abc" not in cookie_jar.jar) + + cookie_jar = SimpleCookieJar() + cookie_jar.set("a=b; c=d; domain=abc") + self.assertEqual(cookie_jar.get("abc"), "a=b; c=d") + + cookie_jar = SimpleCookieJar() + cookie_jar.set("a=b; c=d; domain=abc") + cookie_jar.set("e=f; domain=abc") + self.assertEqual(cookie_jar.get("abc"), "e=f") + + cookie_jar = SimpleCookieJar() + cookie_jar.set("a=b; c=d; domain=abc") + cookie_jar.set("e=f; domain=.abc") + self.assertEqual(cookie_jar.get("abc"), "e=f") + + cookie_jar = SimpleCookieJar() + cookie_jar.set("a=b; c=d; domain=abc") + cookie_jar.set("e=f; domain=xyz") + self.assertEqual(cookie_jar.get("abc"), "a=b; c=d") + self.assertEqual(cookie_jar.get("xyz"), "e=f") + self.assertEqual(cookie_jar.get("something"), "") + + def testGet(self): + cookie_jar = SimpleCookieJar() + cookie_jar.set("a=b; c=d; domain=abc.com") + self.assertEqual(cookie_jar.get("abc.com"), "a=b; c=d") + self.assertEqual(cookie_jar.get("x.abc.com"), "a=b; c=d") + self.assertEqual(cookie_jar.get("abc.com.es"), "") + self.assertEqual(cookie_jar.get("xabc.com"), "") + + cookie_jar.set("a=b; c=d; domain=.abc.com") + self.assertEqual(cookie_jar.get("abc.com"), "a=b; c=d") + self.assertEqual(cookie_jar.get("x.abc.com"), "a=b; c=d") + self.assertEqual(cookie_jar.get("abc.com.es"), "") + self.assertEqual(cookie_jar.get("xabc.com"), "") diff --git a/openpype/vendor/python/python_2/websocket/tests/test_http.py b/openpype/vendor/python/python_2/websocket/tests/test_http.py new file mode 100644 index 0000000000..0336ff7d7f --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/tests/test_http.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +# +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" + +import os +import os.path +import websocket as ws +from websocket._http import proxy_info, read_headers, _open_proxied_socket, _tunnel +import sys +sys.path[0:0] = [""] + +if sys.version_info[0] == 2 and sys.version_info[1] < 7: + import unittest2 as unittest +else: + import unittest + + +class SockMock(object): + def __init__(self): + self.data = [] + self.sent = [] + + def add_packet(self, data): + self.data.append(data) + + def gettimeout(self): + return None + + def recv(self, bufsize): + if self.data: + e = self.data.pop(0) + if isinstance(e, Exception): + raise e + if len(e) > bufsize: + self.data.insert(0, e[bufsize:]) + return e[:bufsize] + + def send(self, data): + self.sent.append(data) + return len(data) + + def close(self): + pass + + +class HeaderSockMock(SockMock): + + def __init__(self, fname): + SockMock.__init__(self) + path = os.path.join(os.path.dirname(__file__), fname) + with open(path, "rb") as f: + self.add_packet(f.read()) + + +class OptsList(): + + def __init__(self): + self.timeout = 0 + self.sockopt = [] + + +class HttpTest(unittest.TestCase): + + def testReadHeader(self): + status, header, status_message = read_headers(HeaderSockMock("data/header01.txt")) + self.assertEqual(status, 101) + self.assertEqual(header["connection"], "Upgrade") + # header02.txt is intentionally malformed + self.assertRaises(ws.WebSocketException, read_headers, HeaderSockMock("data/header02.txt")) + + def testTunnel(self): + self.assertRaises(ws.WebSocketProxyException, _tunnel, HeaderSockMock("data/header01.txt"), "example.com", 80, ("username", "password")) + self.assertRaises(ws.WebSocketProxyException, _tunnel, HeaderSockMock("data/header02.txt"), "example.com", 80, ("username", "password")) + + def testConnect(self): + # Not currently testing an actual proxy connection, so just check whether TypeError is raised + self.assertRaises(TypeError, _open_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="http")) + self.assertRaises(TypeError, _open_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks4")) + self.assertRaises(TypeError, _open_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks5h")) + + def testProxyInfo(self): + self.assertEqual(proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="http").type, "http") + self.assertRaises(ValueError, proxy_info, http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="badval") + self.assertEqual(proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="http").host, "example.com") + self.assertEqual(proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="http").port, "8080") + self.assertEqual(proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="8080", proxy_type="http").auth, None) + + +if __name__ == "__main__": + unittest.main() diff --git a/openpype/vendor/python/python_2/websocket/tests/test_url.py b/openpype/vendor/python/python_2/websocket/tests/test_url.py new file mode 100644 index 0000000000..b1d8e06f23 --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/tests/test_url.py @@ -0,0 +1,309 @@ +# -*- coding: utf-8 -*- +# +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" + +import sys +import os + +from websocket._url import get_proxy_info, parse_url, _is_address_in_network, _is_no_proxy_host + +if sys.version_info[0] == 2 and sys.version_info[1] < 7: + import unittest2 as unittest +else: + import unittest +sys.path[0:0] = [""] + + +class UrlTest(unittest.TestCase): + + def test_address_in_network(self): + self.assertTrue(_is_address_in_network('127.0.0.1', '127.0.0.0/8')) + self.assertTrue(_is_address_in_network('127.1.0.1', '127.0.0.0/8')) + self.assertFalse(_is_address_in_network('127.1.0.1', '127.0.0.0/24')) + + def testParseUrl(self): + p = parse_url("ws://www.example.com/r") + self.assertEqual(p[0], "www.example.com") + self.assertEqual(p[1], 80) + self.assertEqual(p[2], "/r") + self.assertEqual(p[3], False) + + p = parse_url("ws://www.example.com/r/") + self.assertEqual(p[0], "www.example.com") + self.assertEqual(p[1], 80) + self.assertEqual(p[2], "/r/") + self.assertEqual(p[3], False) + + p = parse_url("ws://www.example.com/") + self.assertEqual(p[0], "www.example.com") + self.assertEqual(p[1], 80) + self.assertEqual(p[2], "/") + self.assertEqual(p[3], False) + + p = parse_url("ws://www.example.com") + self.assertEqual(p[0], "www.example.com") + self.assertEqual(p[1], 80) + self.assertEqual(p[2], "/") + self.assertEqual(p[3], False) + + p = parse_url("ws://www.example.com:8080/r") + self.assertEqual(p[0], "www.example.com") + self.assertEqual(p[1], 8080) + self.assertEqual(p[2], "/r") + self.assertEqual(p[3], False) + + p = parse_url("ws://www.example.com:8080/") + self.assertEqual(p[0], "www.example.com") + self.assertEqual(p[1], 8080) + self.assertEqual(p[2], "/") + self.assertEqual(p[3], False) + + p = parse_url("ws://www.example.com:8080") + self.assertEqual(p[0], "www.example.com") + self.assertEqual(p[1], 8080) + self.assertEqual(p[2], "/") + self.assertEqual(p[3], False) + + p = parse_url("wss://www.example.com:8080/r") + self.assertEqual(p[0], "www.example.com") + self.assertEqual(p[1], 8080) + self.assertEqual(p[2], "/r") + self.assertEqual(p[3], True) + + p = parse_url("wss://www.example.com:8080/r?key=value") + self.assertEqual(p[0], "www.example.com") + self.assertEqual(p[1], 8080) + self.assertEqual(p[2], "/r?key=value") + self.assertEqual(p[3], True) + + self.assertRaises(ValueError, parse_url, "http://www.example.com/r") + + if sys.version_info[0] == 2 and sys.version_info[1] < 7: + return + + p = parse_url("ws://[2a03:4000:123:83::3]/r") + self.assertEqual(p[0], "2a03:4000:123:83::3") + self.assertEqual(p[1], 80) + self.assertEqual(p[2], "/r") + self.assertEqual(p[3], False) + + p = parse_url("ws://[2a03:4000:123:83::3]:8080/r") + self.assertEqual(p[0], "2a03:4000:123:83::3") + self.assertEqual(p[1], 8080) + self.assertEqual(p[2], "/r") + self.assertEqual(p[3], False) + + p = parse_url("wss://[2a03:4000:123:83::3]/r") + self.assertEqual(p[0], "2a03:4000:123:83::3") + self.assertEqual(p[1], 443) + self.assertEqual(p[2], "/r") + self.assertEqual(p[3], True) + + p = parse_url("wss://[2a03:4000:123:83::3]:8080/r") + self.assertEqual(p[0], "2a03:4000:123:83::3") + self.assertEqual(p[1], 8080) + self.assertEqual(p[2], "/r") + self.assertEqual(p[3], True) + + +class IsNoProxyHostTest(unittest.TestCase): + def setUp(self): + self.no_proxy = os.environ.get("no_proxy", None) + if "no_proxy" in os.environ: + del os.environ["no_proxy"] + + def tearDown(self): + if self.no_proxy: + os.environ["no_proxy"] = self.no_proxy + elif "no_proxy" in os.environ: + del os.environ["no_proxy"] + + def testMatchAll(self): + self.assertTrue(_is_no_proxy_host("any.websocket.org", ['*'])) + self.assertTrue(_is_no_proxy_host("192.168.0.1", ['*'])) + self.assertTrue(_is_no_proxy_host("any.websocket.org", ['other.websocket.org', '*'])) + os.environ['no_proxy'] = '*' + self.assertTrue(_is_no_proxy_host("any.websocket.org", None)) + self.assertTrue(_is_no_proxy_host("192.168.0.1", None)) + os.environ['no_proxy'] = 'other.websocket.org, *' + self.assertTrue(_is_no_proxy_host("any.websocket.org", None)) + + def testIpAddress(self): + self.assertTrue(_is_no_proxy_host("127.0.0.1", ['127.0.0.1'])) + self.assertFalse(_is_no_proxy_host("127.0.0.2", ['127.0.0.1'])) + self.assertTrue(_is_no_proxy_host("127.0.0.1", ['other.websocket.org', '127.0.0.1'])) + self.assertFalse(_is_no_proxy_host("127.0.0.2", ['other.websocket.org', '127.0.0.1'])) + os.environ['no_proxy'] = '127.0.0.1' + self.assertTrue(_is_no_proxy_host("127.0.0.1", None)) + self.assertFalse(_is_no_proxy_host("127.0.0.2", None)) + os.environ['no_proxy'] = 'other.websocket.org, 127.0.0.1' + self.assertTrue(_is_no_proxy_host("127.0.0.1", None)) + self.assertFalse(_is_no_proxy_host("127.0.0.2", None)) + + def testIpAddressInRange(self): + self.assertTrue(_is_no_proxy_host("127.0.0.1", ['127.0.0.0/8'])) + self.assertTrue(_is_no_proxy_host("127.0.0.2", ['127.0.0.0/8'])) + self.assertFalse(_is_no_proxy_host("127.1.0.1", ['127.0.0.0/24'])) + os.environ['no_proxy'] = '127.0.0.0/8' + self.assertTrue(_is_no_proxy_host("127.0.0.1", None)) + self.assertTrue(_is_no_proxy_host("127.0.0.2", None)) + os.environ['no_proxy'] = '127.0.0.0/24' + self.assertFalse(_is_no_proxy_host("127.1.0.1", None)) + + def testHostnameMatch(self): + self.assertTrue(_is_no_proxy_host("my.websocket.org", ['my.websocket.org'])) + self.assertTrue(_is_no_proxy_host("my.websocket.org", ['other.websocket.org', 'my.websocket.org'])) + self.assertFalse(_is_no_proxy_host("my.websocket.org", ['other.websocket.org'])) + os.environ['no_proxy'] = 'my.websocket.org' + self.assertTrue(_is_no_proxy_host("my.websocket.org", None)) + self.assertFalse(_is_no_proxy_host("other.websocket.org", None)) + os.environ['no_proxy'] = 'other.websocket.org, my.websocket.org' + self.assertTrue(_is_no_proxy_host("my.websocket.org", None)) + + def testHostnameMatchDomain(self): + self.assertTrue(_is_no_proxy_host("any.websocket.org", ['.websocket.org'])) + self.assertTrue(_is_no_proxy_host("my.other.websocket.org", ['.websocket.org'])) + self.assertTrue(_is_no_proxy_host("any.websocket.org", ['my.websocket.org', '.websocket.org'])) + self.assertFalse(_is_no_proxy_host("any.websocket.com", ['.websocket.org'])) + os.environ['no_proxy'] = '.websocket.org' + self.assertTrue(_is_no_proxy_host("any.websocket.org", None)) + self.assertTrue(_is_no_proxy_host("my.other.websocket.org", None)) + self.assertFalse(_is_no_proxy_host("any.websocket.com", None)) + os.environ['no_proxy'] = 'my.websocket.org, .websocket.org' + self.assertTrue(_is_no_proxy_host("any.websocket.org", None)) + + +class ProxyInfoTest(unittest.TestCase): + def setUp(self): + self.http_proxy = os.environ.get("http_proxy", None) + self.https_proxy = os.environ.get("https_proxy", None) + self.no_proxy = os.environ.get("no_proxy", None) + if "http_proxy" in os.environ: + del os.environ["http_proxy"] + if "https_proxy" in os.environ: + del os.environ["https_proxy"] + if "no_proxy" in os.environ: + del os.environ["no_proxy"] + + def tearDown(self): + if self.http_proxy: + os.environ["http_proxy"] = self.http_proxy + elif "http_proxy" in os.environ: + del os.environ["http_proxy"] + + if self.https_proxy: + os.environ["https_proxy"] = self.https_proxy + elif "https_proxy" in os.environ: + del os.environ["https_proxy"] + + if self.no_proxy: + os.environ["no_proxy"] = self.no_proxy + elif "no_proxy" in os.environ: + del os.environ["no_proxy"] + + def testProxyFromArgs(self): + self.assertEqual(get_proxy_info("echo.websocket.org", False, proxy_host="localhost"), ("localhost", 0, None)) + self.assertEqual(get_proxy_info("echo.websocket.org", False, proxy_host="localhost", proxy_port=3128), + ("localhost", 3128, None)) + self.assertEqual(get_proxy_info("echo.websocket.org", True, proxy_host="localhost"), ("localhost", 0, None)) + self.assertEqual(get_proxy_info("echo.websocket.org", True, proxy_host="localhost", proxy_port=3128), + ("localhost", 3128, None)) + + self.assertEqual(get_proxy_info("echo.websocket.org", False, proxy_host="localhost", proxy_auth=("a", "b")), + ("localhost", 0, ("a", "b"))) + self.assertEqual( + get_proxy_info("echo.websocket.org", False, proxy_host="localhost", proxy_port=3128, proxy_auth=("a", "b")), + ("localhost", 3128, ("a", "b"))) + self.assertEqual(get_proxy_info("echo.websocket.org", True, proxy_host="localhost", proxy_auth=("a", "b")), + ("localhost", 0, ("a", "b"))) + self.assertEqual( + get_proxy_info("echo.websocket.org", True, proxy_host="localhost", proxy_port=3128, proxy_auth=("a", "b")), + ("localhost", 3128, ("a", "b"))) + + self.assertEqual(get_proxy_info("echo.websocket.org", True, proxy_host="localhost", proxy_port=3128, + no_proxy=["example.com"], proxy_auth=("a", "b")), + ("localhost", 3128, ("a", "b"))) + self.assertEqual(get_proxy_info("echo.websocket.org", True, proxy_host="localhost", proxy_port=3128, + no_proxy=["echo.websocket.org"], proxy_auth=("a", "b")), + (None, 0, None)) + + def testProxyFromEnv(self): + os.environ["http_proxy"] = "http://localhost/" + self.assertEqual(get_proxy_info("echo.websocket.org", False), ("localhost", None, None)) + os.environ["http_proxy"] = "http://localhost:3128/" + self.assertEqual(get_proxy_info("echo.websocket.org", False), ("localhost", 3128, None)) + + os.environ["http_proxy"] = "http://localhost/" + os.environ["https_proxy"] = "http://localhost2/" + self.assertEqual(get_proxy_info("echo.websocket.org", False), ("localhost", None, None)) + os.environ["http_proxy"] = "http://localhost:3128/" + os.environ["https_proxy"] = "http://localhost2:3128/" + self.assertEqual(get_proxy_info("echo.websocket.org", False), ("localhost", 3128, None)) + + os.environ["http_proxy"] = "http://localhost/" + os.environ["https_proxy"] = "http://localhost2/" + self.assertEqual(get_proxy_info("echo.websocket.org", True), ("localhost2", None, None)) + os.environ["http_proxy"] = "http://localhost:3128/" + os.environ["https_proxy"] = "http://localhost2:3128/" + self.assertEqual(get_proxy_info("echo.websocket.org", True), ("localhost2", 3128, None)) + + os.environ["http_proxy"] = "http://a:b@localhost/" + self.assertEqual(get_proxy_info("echo.websocket.org", False), ("localhost", None, ("a", "b"))) + os.environ["http_proxy"] = "http://a:b@localhost:3128/" + self.assertEqual(get_proxy_info("echo.websocket.org", False), ("localhost", 3128, ("a", "b"))) + + os.environ["http_proxy"] = "http://a:b@localhost/" + os.environ["https_proxy"] = "http://a:b@localhost2/" + self.assertEqual(get_proxy_info("echo.websocket.org", False), ("localhost", None, ("a", "b"))) + os.environ["http_proxy"] = "http://a:b@localhost:3128/" + os.environ["https_proxy"] = "http://a:b@localhost2:3128/" + self.assertEqual(get_proxy_info("echo.websocket.org", False), ("localhost", 3128, ("a", "b"))) + + os.environ["http_proxy"] = "http://a:b@localhost/" + os.environ["https_proxy"] = "http://a:b@localhost2/" + self.assertEqual(get_proxy_info("echo.websocket.org", True), ("localhost2", None, ("a", "b"))) + os.environ["http_proxy"] = "http://a:b@localhost:3128/" + os.environ["https_proxy"] = "http://a:b@localhost2:3128/" + self.assertEqual(get_proxy_info("echo.websocket.org", True), ("localhost2", 3128, ("a", "b"))) + + os.environ["http_proxy"] = "http://a:b@localhost/" + os.environ["https_proxy"] = "http://a:b@localhost2/" + os.environ["no_proxy"] = "example1.com,example2.com" + self.assertEqual(get_proxy_info("example.1.com", True), ("localhost2", None, ("a", "b"))) + os.environ["http_proxy"] = "http://a:b@localhost:3128/" + os.environ["https_proxy"] = "http://a:b@localhost2:3128/" + os.environ["no_proxy"] = "example1.com,example2.com, echo.websocket.org" + self.assertEqual(get_proxy_info("echo.websocket.org", True), (None, 0, None)) + os.environ["http_proxy"] = "http://a:b@localhost:3128/" + os.environ["https_proxy"] = "http://a:b@localhost2:3128/" + os.environ["no_proxy"] = "example1.com,example2.com, .websocket.org" + self.assertEqual(get_proxy_info("echo.websocket.org", True), (None, 0, None)) + + os.environ["http_proxy"] = "http://a:b@localhost:3128/" + os.environ["https_proxy"] = "http://a:b@localhost2:3128/" + os.environ["no_proxy"] = "127.0.0.0/8, 192.168.0.0/16" + self.assertEqual(get_proxy_info("127.0.0.1", False), (None, 0, None)) + self.assertEqual(get_proxy_info("192.168.1.1", False), (None, 0, None)) + + +if __name__ == "__main__": + unittest.main() diff --git a/openpype/vendor/python/python_2/websocket/tests/test_websocket.py b/openpype/vendor/python/python_2/websocket/tests/test_websocket.py new file mode 100644 index 0000000000..0d1d6395ed --- /dev/null +++ b/openpype/vendor/python/python_2/websocket/tests/test_websocket.py @@ -0,0 +1,433 @@ +# -*- coding: utf-8 -*- +# +""" + +""" + +""" +websocket - WebSocket client library for Python + +Copyright (C) 2010 Hiroki Ohtani(liris) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +""" + +import sys +sys.path[0:0] = [""] + +import os +import os.path +import socket + +import six + +# websocket-client +import websocket as ws +from websocket._handshake import _create_sec_websocket_key, \ + _validate as _validate_header +from websocket._http import read_headers +from websocket._utils import validate_utf8 + +if six.PY3: + from base64 import decodebytes as base64decode +else: + from base64 import decodestring as base64decode + +if sys.version_info[0] == 2 and sys.version_info[1] < 7: + import unittest2 as unittest +else: + import unittest + +try: + from ssl import SSLError +except ImportError: + # dummy class of SSLError for ssl none-support environment. + class SSLError(Exception): + pass + +# Skip test to access the internet. +TEST_WITH_INTERNET = os.environ.get('TEST_WITH_INTERNET', '0') == '1' +TRACEABLE = True + + +def create_mask_key(_): + return "abcd" + + +class SockMock(object): + def __init__(self): + self.data = [] + self.sent = [] + + def add_packet(self, data): + self.data.append(data) + + def gettimeout(self): + return None + + def recv(self, bufsize): + if self.data: + e = self.data.pop(0) + if isinstance(e, Exception): + raise e + if len(e) > bufsize: + self.data.insert(0, e[bufsize:]) + return e[:bufsize] + + def send(self, data): + self.sent.append(data) + return len(data) + + def close(self): + pass + + +class HeaderSockMock(SockMock): + + def __init__(self, fname): + SockMock.__init__(self) + path = os.path.join(os.path.dirname(__file__), fname) + with open(path, "rb") as f: + self.add_packet(f.read()) + + +class WebSocketTest(unittest.TestCase): + def setUp(self): + ws.enableTrace(TRACEABLE) + + def tearDown(self): + pass + + def testDefaultTimeout(self): + self.assertEqual(ws.getdefaulttimeout(), None) + ws.setdefaulttimeout(10) + self.assertEqual(ws.getdefaulttimeout(), 10) + ws.setdefaulttimeout(None) + + def testWSKey(self): + key = _create_sec_websocket_key() + self.assertTrue(key != 24) + self.assertTrue(six.u("¥n") not in key) + + def testNonce(self): + """ WebSocket key should be a random 16-byte nonce. + """ + key = _create_sec_websocket_key() + nonce = base64decode(key.encode("utf-8")) + self.assertEqual(16, len(nonce)) + + def testWsUtils(self): + key = "c6b8hTg4EeGb2gQMztV1/g==" + required_header = { + "upgrade": "websocket", + "connection": "upgrade", + "sec-websocket-accept": "Kxep+hNu9n51529fGidYu7a3wO0="} + self.assertEqual(_validate_header(required_header, key, None), (True, None)) + + header = required_header.copy() + header["upgrade"] = "http" + self.assertEqual(_validate_header(header, key, None), (False, None)) + del header["upgrade"] + self.assertEqual(_validate_header(header, key, None), (False, None)) + + header = required_header.copy() + header["connection"] = "something" + self.assertEqual(_validate_header(header, key, None), (False, None)) + del header["connection"] + self.assertEqual(_validate_header(header, key, None), (False, None)) + + header = required_header.copy() + header["sec-websocket-accept"] = "something" + self.assertEqual(_validate_header(header, key, None), (False, None)) + del header["sec-websocket-accept"] + self.assertEqual(_validate_header(header, key, None), (False, None)) + + header = required_header.copy() + header["sec-websocket-protocol"] = "sub1" + self.assertEqual(_validate_header(header, key, ["sub1", "sub2"]), (True, "sub1")) + self.assertEqual(_validate_header(header, key, ["sub2", "sub3"]), (False, None)) + + header = required_header.copy() + header["sec-websocket-protocol"] = "sUb1" + self.assertEqual(_validate_header(header, key, ["Sub1", "suB2"]), (True, "sub1")) + + header = required_header.copy() + self.assertEqual(_validate_header(header, key, ["Sub1", "suB2"]), (False, None)) + + def testReadHeader(self): + status, header, status_message = read_headers(HeaderSockMock("data/header01.txt")) + self.assertEqual(status, 101) + self.assertEqual(header["connection"], "Upgrade") + + status, header, status_message = read_headers(HeaderSockMock("data/header03.txt")) + self.assertEqual(status, 101) + self.assertEqual(header["connection"], "Upgrade, Keep-Alive") + + HeaderSockMock("data/header02.txt") + self.assertRaises(ws.WebSocketException, read_headers, HeaderSockMock("data/header02.txt")) + + def testSend(self): + # TODO: add longer frame data + sock = ws.WebSocket() + sock.set_mask_key(create_mask_key) + s = sock.sock = HeaderSockMock("data/header01.txt") + sock.send("Hello") + self.assertEqual(s.sent[0], six.b("\x81\x85abcd)\x07\x0f\x08\x0e")) + + sock.send("こんにちは") + self.assertEqual(s.sent[1], six.b("\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc")) + + sock.send(u"こんにちは") + self.assertEqual(s.sent[1], six.b("\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc")) + +# sock.send("x" * 5000) +# self.assertEqual(s.sent[1], six.b("\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc")) + + self.assertEqual(sock.send_binary(b'1111111111101'), 19) + + def testRecv(self): + # TODO: add longer frame data + sock = ws.WebSocket() + s = sock.sock = SockMock() + something = six.b("\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc") + s.add_packet(something) + data = sock.recv() + self.assertEqual(data, "こんにちは") + + s.add_packet(six.b("\x81\x85abcd)\x07\x0f\x08\x0e")) + data = sock.recv() + self.assertEqual(data, "Hello") + + @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") + def testIter(self): + count = 2 + for _ in ws.create_connection('wss://stream.meetup.com/2/rsvps'): + count -= 1 + if count == 0: + break + + @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") + def testNext(self): + sock = ws.create_connection('wss://stream.meetup.com/2/rsvps') + self.assertEqual(str, type(next(sock))) + + def testInternalRecvStrict(self): + sock = ws.WebSocket() + s = sock.sock = SockMock() + s.add_packet(six.b("foo")) + s.add_packet(socket.timeout()) + s.add_packet(six.b("bar")) + # s.add_packet(SSLError("The read operation timed out")) + s.add_packet(six.b("baz")) + with self.assertRaises(ws.WebSocketTimeoutException): + sock.frame_buffer.recv_strict(9) + # if six.PY2: + # with self.assertRaises(ws.WebSocketTimeoutException): + # data = sock._recv_strict(9) + # else: + # with self.assertRaises(SSLError): + # data = sock._recv_strict(9) + data = sock.frame_buffer.recv_strict(9) + self.assertEqual(data, six.b("foobarbaz")) + with self.assertRaises(ws.WebSocketConnectionClosedException): + sock.frame_buffer.recv_strict(1) + + def testRecvTimeout(self): + sock = ws.WebSocket() + s = sock.sock = SockMock() + s.add_packet(six.b("\x81")) + s.add_packet(socket.timeout()) + s.add_packet(six.b("\x8dabcd\x29\x07\x0f\x08\x0e")) + s.add_packet(socket.timeout()) + s.add_packet(six.b("\x4e\x43\x33\x0e\x10\x0f\x00\x40")) + with self.assertRaises(ws.WebSocketTimeoutException): + sock.recv() + with self.assertRaises(ws.WebSocketTimeoutException): + sock.recv() + data = sock.recv() + self.assertEqual(data, "Hello, World!") + with self.assertRaises(ws.WebSocketConnectionClosedException): + sock.recv() + + def testRecvWithSimpleFragmentation(self): + sock = ws.WebSocket() + s = sock.sock = SockMock() + # OPCODE=TEXT, FIN=0, MSG="Brevity is " + s.add_packet(six.b("\x01\x8babcd#\x10\x06\x12\x08\x16\x1aD\x08\x11C")) + # OPCODE=CONT, FIN=1, MSG="the soul of wit" + s.add_packet(six.b("\x80\x8fabcd\x15\n\x06D\x12\r\x16\x08A\r\x05D\x16\x0b\x17")) + data = sock.recv() + self.assertEqual(data, "Brevity is the soul of wit") + with self.assertRaises(ws.WebSocketConnectionClosedException): + sock.recv() + + def testRecvWithFireEventOfFragmentation(self): + sock = ws.WebSocket(fire_cont_frame=True) + s = sock.sock = SockMock() + # OPCODE=TEXT, FIN=0, MSG="Brevity is " + s.add_packet(six.b("\x01\x8babcd#\x10\x06\x12\x08\x16\x1aD\x08\x11C")) + # OPCODE=CONT, FIN=0, MSG="Brevity is " + s.add_packet(six.b("\x00\x8babcd#\x10\x06\x12\x08\x16\x1aD\x08\x11C")) + # OPCODE=CONT, FIN=1, MSG="the soul of wit" + s.add_packet(six.b("\x80\x8fabcd\x15\n\x06D\x12\r\x16\x08A\r\x05D\x16\x0b\x17")) + + _, data = sock.recv_data() + self.assertEqual(data, six.b("Brevity is ")) + _, data = sock.recv_data() + self.assertEqual(data, six.b("Brevity is ")) + _, data = sock.recv_data() + self.assertEqual(data, six.b("the soul of wit")) + + # OPCODE=CONT, FIN=0, MSG="Brevity is " + s.add_packet(six.b("\x80\x8babcd#\x10\x06\x12\x08\x16\x1aD\x08\x11C")) + + with self.assertRaises(ws.WebSocketException): + sock.recv_data() + + with self.assertRaises(ws.WebSocketConnectionClosedException): + sock.recv() + + def testClose(self): + sock = ws.WebSocket() + sock.sock = SockMock() + sock.connected = True + sock.close() + self.assertEqual(sock.connected, False) + + sock = ws.WebSocket() + s = sock.sock = SockMock() + sock.connected = True + s.add_packet(six.b('\x88\x80\x17\x98p\x84')) + sock.recv() + self.assertEqual(sock.connected, False) + + def testRecvContFragmentation(self): + sock = ws.WebSocket() + s = sock.sock = SockMock() + # OPCODE=CONT, FIN=1, MSG="the soul of wit" + s.add_packet(six.b("\x80\x8fabcd\x15\n\x06D\x12\r\x16\x08A\r\x05D\x16\x0b\x17")) + self.assertRaises(ws.WebSocketException, sock.recv) + + def testRecvWithProlongedFragmentation(self): + sock = ws.WebSocket() + s = sock.sock = SockMock() + # OPCODE=TEXT, FIN=0, MSG="Once more unto the breach, " + s.add_packet(six.b("\x01\x9babcd.\x0c\x00\x01A\x0f\x0c\x16\x04B\x16\n\x15" + "\rC\x10\t\x07C\x06\x13\x07\x02\x07\tNC")) + # OPCODE=CONT, FIN=0, MSG="dear friends, " + s.add_packet(six.b("\x00\x8eabcd\x05\x07\x02\x16A\x04\x11\r\x04\x0c\x07" + "\x17MB")) + # OPCODE=CONT, FIN=1, MSG="once more" + s.add_packet(six.b("\x80\x89abcd\x0e\x0c\x00\x01A\x0f\x0c\x16\x04")) + data = sock.recv() + self.assertEqual( + data, + "Once more unto the breach, dear friends, once more") + with self.assertRaises(ws.WebSocketConnectionClosedException): + sock.recv() + + def testRecvWithFragmentationAndControlFrame(self): + sock = ws.WebSocket() + sock.set_mask_key(create_mask_key) + s = sock.sock = SockMock() + # OPCODE=TEXT, FIN=0, MSG="Too much " + s.add_packet(six.b("\x01\x89abcd5\r\x0cD\x0c\x17\x00\x0cA")) + # OPCODE=PING, FIN=1, MSG="Please PONG this" + s.add_packet(six.b("\x89\x90abcd1\x0e\x06\x05\x12\x07C4.,$D\x15\n\n\x17")) + # OPCODE=CONT, FIN=1, MSG="of a good thing" + s.add_packet(six.b("\x80\x8fabcd\x0e\x04C\x05A\x05\x0c\x0b\x05B\x17\x0c" + "\x08\x0c\x04")) + data = sock.recv() + self.assertEqual(data, "Too much of a good thing") + with self.assertRaises(ws.WebSocketConnectionClosedException): + sock.recv() + self.assertEqual( + s.sent[0], + six.b("\x8a\x90abcd1\x0e\x06\x05\x12\x07C4.,$D\x15\n\n\x17")) + + @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") + def testWebSocket(self): + s = ws.create_connection("ws://echo.websocket.org/") + self.assertNotEqual(s, None) + s.send("Hello, World") + result = s.recv() + self.assertEqual(result, "Hello, World") + + s.send(u"こにゃにゃちは、世界") + result = s.recv() + self.assertEqual(result, "こにゃにゃちは、世界") + self.assertRaises(ValueError, s.send_close, -1, "") + s.close() + + @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") + def testPingPong(self): + s = ws.create_connection("ws://echo.websocket.org/") + self.assertNotEqual(s, None) + s.ping("Hello") + s.pong("Hi") + s.close() + + @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") + def testSecureWebSocket(self): + import ssl + s = ws.create_connection("wss://api.bitfinex.com/ws/2") + self.assertNotEqual(s, None) + self.assertTrue(isinstance(s.sock, ssl.SSLSocket)) + self.assertEqual(s.getstatus(), 101) + self.assertNotEqual(s.getheaders(), None) + s.close() + + @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") + def testWebSocketWithCustomHeader(self): + s = ws.create_connection("ws://echo.websocket.org/", + headers={"User-Agent": "PythonWebsocketClient"}) + self.assertNotEqual(s, None) + s.send("Hello, World") + result = s.recv() + self.assertEqual(result, "Hello, World") + self.assertRaises(ValueError, s.close, -1, "") + s.close() + + @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") + def testAfterClose(self): + s = ws.create_connection("ws://echo.websocket.org/") + self.assertNotEqual(s, None) + s.close() + self.assertRaises(ws.WebSocketConnectionClosedException, s.send, "Hello") + self.assertRaises(ws.WebSocketConnectionClosedException, s.recv) + + +class SockOptTest(unittest.TestCase): + @unittest.skipUnless(TEST_WITH_INTERNET, "Internet-requiring tests are disabled") + def testSockOpt(self): + sockopt = ((socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),) + s = ws.create_connection("ws://echo.websocket.org", sockopt=sockopt) + self.assertNotEqual(s.sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY), 0) + s.close() + + +class UtilsTest(unittest.TestCase): + def testUtf8Validator(self): + state = validate_utf8(six.b('\xf0\x90\x80\x80')) + self.assertEqual(state, True) + state = validate_utf8(six.b('\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5\xed\xa0\x80edited')) + self.assertEqual(state, False) + state = validate_utf8(six.b('')) + self.assertEqual(state, True) + + +if __name__ == "__main__": + unittest.main() From 78c2c651c102601e00c9c042e1490a559bff12e8 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 8 Jun 2022 16:17:38 +0200 Subject: [PATCH 344/350] update gazu version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 362f6a62d8..63bd08d644 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,7 @@ clique = "1.6.*" Click = "^7" dnspython = "^2.1.0" ftrack-python-api = "2.0.*" -gazu = "^0.8" +gazu = "^0.8.28" google-api-python-client = "^1.12.8" # sync server google support (should be separate?) jsonschema = "^2.6.0" keyring = "^22.0.1" From f10caed2cdc4830c4a40c0246c7d37b45f368ba6 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 8 Jun 2022 16:56:01 +0200 Subject: [PATCH 345/350] added certifi to python 2 vendor --- .../python/python_2/certifi/__init__.py | 3 + .../python/python_2/certifi/__main__.py | 12 + .../vendor/python/python_2/certifi/cacert.pem | 4362 +++++++++++++++++ .../vendor/python/python_2/certifi/core.py | 60 + 4 files changed, 4437 insertions(+) create mode 100644 openpype/vendor/python/python_2/certifi/__init__.py create mode 100644 openpype/vendor/python/python_2/certifi/__main__.py create mode 100644 openpype/vendor/python/python_2/certifi/cacert.pem create mode 100644 openpype/vendor/python/python_2/certifi/core.py diff --git a/openpype/vendor/python/python_2/certifi/__init__.py b/openpype/vendor/python/python_2/certifi/__init__.py new file mode 100644 index 0000000000..8db1a0e554 --- /dev/null +++ b/openpype/vendor/python/python_2/certifi/__init__.py @@ -0,0 +1,3 @@ +from .core import contents, where + +__version__ = "2021.10.08" diff --git a/openpype/vendor/python/python_2/certifi/__main__.py b/openpype/vendor/python/python_2/certifi/__main__.py new file mode 100644 index 0000000000..8945b5da85 --- /dev/null +++ b/openpype/vendor/python/python_2/certifi/__main__.py @@ -0,0 +1,12 @@ +import argparse + +from certifi import contents, where + +parser = argparse.ArgumentParser() +parser.add_argument("-c", "--contents", action="store_true") +args = parser.parse_args() + +if args.contents: + print(contents()) +else: + print(where()) diff --git a/openpype/vendor/python/python_2/certifi/cacert.pem b/openpype/vendor/python/python_2/certifi/cacert.pem new file mode 100644 index 0000000000..6d0ccc0d1c --- /dev/null +++ b/openpype/vendor/python/python_2/certifi/cacert.pem @@ -0,0 +1,4362 @@ + +# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA +# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA +# Label: "GlobalSign Root CA" +# Serial: 4835703278459707669005204 +# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a +# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c +# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99 +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 +# Label: "GlobalSign Root CA - R2" +# Serial: 4835703278459682885658125 +# MD5 Fingerprint: 94:14:77:7e:3e:5e:fd:8f:30:bd:41:b0:cf:e7:d0:30 +# SHA1 Fingerprint: 75:e0:ab:b6:13:85:12:27:1c:04:f8:5f:dd:de:38:e4:b7:24:2e:fe +# SHA256 Fingerprint: ca:42:dd:41:74:5f:d0:b8:1e:b9:02:36:2c:f9:d8:bf:71:9d:a1:bd:1b:1e:fc:94:6f:5b:4c:99:f4:2c:1b:9e +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 +MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL +v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 +eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq +tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd +C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa +zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB +mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH +V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n +bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG +3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs +J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO +291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS +ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd +AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- + +# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Label: "Entrust.net Premium 2048 Secure Server CA" +# Serial: 946069240 +# MD5 Fingerprint: ee:29:31:bc:32:7e:9a:e6:e8:b5:f7:51:b4:34:71:90 +# SHA1 Fingerprint: 50:30:06:09:1d:97:d4:f5:ae:39:f7:cb:e7:92:7d:7d:65:2d:34:31 +# SHA256 Fingerprint: 6d:c4:71:72:e0:1c:bc:b0:bf:62:58:0d:89:5f:e2:b8:ac:9a:d4:f8:73:80:1e:0c:10:b9:c8:37:d2:1e:b1:77 +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 +MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub +j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo +U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b +u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ +bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er +fF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Label: "Baltimore CyberTrust Root" +# Serial: 33554617 +# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4 +# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74 +# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Label: "Entrust Root Certification Authority" +# Serial: 1164660820 +# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4 +# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9 +# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +# Issuer: CN=AAA Certificate Services O=Comodo CA Limited +# Subject: CN=AAA Certificate Services O=Comodo CA Limited +# Label: "Comodo AAA Services root" +# Serial: 1 +# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0 +# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49 +# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4 +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj +YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM +GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua +BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe +3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 +YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR +rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm +ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU +oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t +b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF +AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q +GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 +G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi +l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 +smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 2 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 2 O=QuoVadis Limited +# Label: "QuoVadis Root CA 2" +# Serial: 1289 +# MD5 Fingerprint: 5e:39:7b:dd:f8:ba:ec:82:e9:ac:62:ba:0c:54:00:2b +# SHA1 Fingerprint: ca:3a:fb:cf:12:40:36:4b:44:b2:16:20:88:80:48:39:19:93:7c:f7 +# SHA256 Fingerprint: 85:a0:dd:7d:d7:20:ad:b7:ff:05:f8:3d:54:2b:20:9d:c7:ff:45:28:f7:d6:77:b1:83:89:fe:a5:e5:c4:9e:86 +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa +GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg +Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J +WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB +rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp ++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 +ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i +Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz +PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og +/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH +oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI +yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud +EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 +A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL +MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f +BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn +g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl +fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K +WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha +B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc +hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR +TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD +mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z +ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y +4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza +8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 3" +# Serial: 1478 +# MD5 Fingerprint: 31:85:3c:62:94:97:63:b9:aa:fd:89:4e:af:6f:e0:cf +# SHA1 Fingerprint: 1f:49:14:f7:d8:74:95:1d:dd:ae:02:c0:be:fd:3a:2d:82:75:51:85 +# SHA256 Fingerprint: 18:f1:fc:7f:20:5d:f8:ad:dd:eb:7f:e0:07:dd:57:e3:af:37:5a:9c:4d:8d:73:54:6b:f4:f1:fe:d1:e1:8d:35 +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM +V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB +4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr +H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd +8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv +vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT +mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe +btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc +T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt +WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ +c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A +4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD +VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG +CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 +aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu +dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw +czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G +A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg +Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 +7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem +d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd ++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B +4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN +t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x +DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 +k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s +zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j +Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT +mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK +4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- + +# Issuer: O=SECOM Trust.net OU=Security Communication RootCA1 +# Subject: O=SECOM Trust.net OU=Security Communication RootCA1 +# Label: "Security Communication Root CA" +# Serial: 0 +# MD5 Fingerprint: f1:bc:63:6a:54:e0:b5:27:f5:cd:e7:1a:e3:4d:6e:4a +# SHA1 Fingerprint: 36:b1:2b:49:f9:81:9e:d7:4c:9e:bc:38:0f:c6:56:8f:5d:ac:b2:f7 +# SHA256 Fingerprint: e7:5e:72:ed:9f:56:0e:ec:6e:b4:80:00:73:a4:3f:c3:ad:19:19:5a:39:22:82:01:78:95:97:4a:99:02:6b:6c +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY +MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t +dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 +WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD +VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 +9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ +DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 +Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N +QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ +xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G +A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG +kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr +Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 +Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU +JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot +RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== +-----END CERTIFICATE----- + +# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com +# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com +# Label: "XRamp Global CA Root" +# Serial: 107108908803651509692980124233745014957 +# MD5 Fingerprint: a1:0b:44:b3:ca:10:d8:00:6e:9d:0f:d8:0f:92:0a:d1 +# SHA1 Fingerprint: b8:01:86:d1:eb:9c:86:a5:41:04:cf:30:54:f3:4c:52:b7:e5:58:c6 +# SHA256 Fingerprint: ce:cd:dc:90:50:99:d8:da:df:c5:b1:d2:09:b7:37:cb:e2:c1:8c:fb:2c:10:c0:ff:0b:cf:0d:32:86:fc:1a:a2 +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB +gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk +MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY +UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx +NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 +dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy +dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 +38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP +KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q +DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 +qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa +JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi +PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P +BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs +jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 +eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR +vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa +IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy +i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ +O+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Label: "Go Daddy Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67 +# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4 +# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4 +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh +MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE +YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 +MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo +ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg +MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN +ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA +PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w +wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi +EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY +avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ +YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE +sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h +/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 +IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy +OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P +TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER +dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf +ReYNnyicsbkqWletNw+vHX/bvZ8= +-----END CERTIFICATE----- + +# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Label: "Starfield Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24 +# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a +# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58 +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root CA" +# Serial: 17154717934120587862167794914071425081 +# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72 +# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43 +# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root CA" +# Serial: 10944719598952040374951832963794454346 +# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e +# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36 +# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61 +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert High Assurance EV Root CA" +# Serial: 3553400076410547919724730734378100087 +# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a +# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25 +# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- + +# Issuer: CN=DST Root CA X3 O=Digital Signature Trust Co. +# Subject: CN=DST Root CA X3 O=Digital Signature Trust Co. +# Label: "DST Root CA X3" +# Serial: 91299735575339953335919266965803778155 +# MD5 Fingerprint: 41:03:52:dc:0f:f7:50:1b:16:f0:02:8e:ba:6f:45:c5 +# SHA1 Fingerprint: da:c9:02:4f:54:d8:f6:df:94:93:5f:b1:73:26:38:ca:6a:d7:7c:13 +# SHA256 Fingerprint: 06:87:26:03:31:a7:24:03:d9:09:f1:05:e6:9b:cf:0d:32:e1:bd:24:93:ff:c6:d9:20:6d:11:bc:d6:77:07:39 +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O +rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq +OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b +xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw +7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD +aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG +SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 +ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr +AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz +R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 +JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo +Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- + +# Issuer: CN=SwissSign Gold CA - G2 O=SwissSign AG +# Subject: CN=SwissSign Gold CA - G2 O=SwissSign AG +# Label: "SwissSign Gold CA - G2" +# Serial: 13492815561806991280 +# MD5 Fingerprint: 24:77:d9:a8:91:d1:3b:fa:88:2d:c2:ff:f8:cd:33:93 +# SHA1 Fingerprint: d8:c5:38:8a:b7:30:1b:1b:6e:d4:7a:e6:45:25:3a:6f:9f:1a:27:61 +# SHA256 Fingerprint: 62:dd:0b:e9:b9:f5:0a:16:3e:a0:f8:e7:5c:05:3b:1e:ca:57:ea:55:c8:68:8f:64:7c:68:81:f2:c8:35:7b:95 +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=SwissSign Silver CA - G2 O=SwissSign AG +# Subject: CN=SwissSign Silver CA - G2 O=SwissSign AG +# Label: "SwissSign Silver CA - G2" +# Serial: 5700383053117599563 +# MD5 Fingerprint: e0:06:a1:c9:7d:cf:c9:fc:0d:c0:56:75:96:d8:62:13 +# SHA1 Fingerprint: 9b:aa:e5:9f:56:ee:21:cb:43:5a:be:25:93:df:a7:f0:40:d1:1d:cb +# SHA256 Fingerprint: be:6c:4d:a2:bb:b9:ba:59:b6:f3:93:97:68:37:42:46:c3:c0:05:99:3f:a9:8f:02:0d:1d:ed:be:d4:8a:81:d5 +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=SecureTrust CA O=SecureTrust Corporation +# Subject: CN=SecureTrust CA O=SecureTrust Corporation +# Label: "SecureTrust CA" +# Serial: 17199774589125277788362757014266862032 +# MD5 Fingerprint: dc:32:c3:a7:6d:25:57:c7:68:09:9d:ea:2d:a9:a2:d1 +# SHA1 Fingerprint: 87:82:c6:c3:04:35:3b:cf:d2:96:92:d2:59:3e:7d:44:d9:34:ff:11 +# SHA256 Fingerprint: f1:c1:b5:0a:e5:a2:0d:d8:03:0e:c9:f6:bc:24:82:3d:d3:67:b5:25:57:59:b4:e7:1b:61:fc:e9:f7:37:5d:73 +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz +MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv +cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz +Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO +0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao +wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj +7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS +8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT +BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg +JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 +6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ +3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm +D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS +CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +# Issuer: CN=Secure Global CA O=SecureTrust Corporation +# Subject: CN=Secure Global CA O=SecureTrust Corporation +# Label: "Secure Global CA" +# Serial: 9751836167731051554232119481456978597 +# MD5 Fingerprint: cf:f4:27:0d:d4:ed:dc:65:16:49:6d:3d:da:bf:6e:de +# SHA1 Fingerprint: 3a:44:73:5a:e5:81:90:1f:24:86:61:46:1e:3b:9c:c4:5f:f5:3a:1b +# SHA256 Fingerprint: 42:00:f5:04:3a:c8:59:0e:bb:52:7d:20:9e:d1:50:30:29:fb:cb:d4:1c:a1:b5:06:ec:27:f1:5a:de:7d:ac:69 +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx +MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg +Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ +iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa +/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ +jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI +HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 +sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w +gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw +KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG +AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L +URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO +H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm +I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY +iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO Certification Authority O=COMODO CA Limited +# Label: "COMODO Certification Authority" +# Serial: 104350513648249232941998508985834464573 +# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75 +# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b +# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66 +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw +MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl +YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P +RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 +UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI +2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 +Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp ++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ +DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O +nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW +/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g +PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u +QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY +SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv +IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 +zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd +BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB +ZQ== +-----END CERTIFICATE----- + +# Issuer: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. +# Subject: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. +# Label: "Network Solutions Certificate Authority" +# Serial: 116697915152937497490437556386812487904 +# MD5 Fingerprint: d3:f3:a6:16:c0:fa:6b:1d:59:b1:2d:96:4d:0e:11:2e +# SHA1 Fingerprint: 74:f8:a3:c3:ef:e7:b3:90:06:4b:83:90:3c:21:64:60:20:e5:df:ce +# SHA256 Fingerprint: 15:f0:ba:00:a3:ac:7a:f3:ac:88:4c:07:2b:10:11:a0:77:bd:77:c0:97:f4:01:64:b2:f8:59:8a:bd:83:86:0c +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi +MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV +UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO +ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz +c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP +OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl +mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF +BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 +qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw +gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu +bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp +dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 +6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ +h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH +/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN +pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- + +# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited +# Label: "COMODO ECC Certification Authority" +# Serial: 41578283867086692638256921589707938090 +# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23 +# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11 +# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7 +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT +IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw +MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy +ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N +T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR +FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J +cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW +BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm +fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv +GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +# Issuer: CN=Certigna O=Dhimyotis +# Subject: CN=Certigna O=Dhimyotis +# Label: "Certigna" +# Serial: 18364802974209362175 +# MD5 Fingerprint: ab:57:a6:5b:7d:42:82:19:b5:d8:58:26:28:5e:fd:ff +# SHA1 Fingerprint: b1:2e:13:63:45:86:a4:6f:1a:b2:60:68:37:58:2d:c4:ac:fd:94:97 +# SHA256 Fingerprint: e3:b6:a2:db:2e:d7:ce:48:84:2f:7a:c5:32:41:c7:b7:1d:54:14:4b:fb:40:c1:1f:3f:1d:0b:42:f5:ee:a1:2d +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV +BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X +DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ +BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 +QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny +gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw +zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q +130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 +JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw +ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT +AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj +AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG +9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h +bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc +fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu +HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w +t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +# Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc +# Subject: CN=Cybertrust Global Root O=Cybertrust, Inc +# Label: "Cybertrust Global Root" +# Serial: 4835703278459682877484360 +# MD5 Fingerprint: 72:e4:4a:87:e3:69:40:80:77:ea:bc:e3:f4:ff:f0:e1 +# SHA1 Fingerprint: 5f:43:e5:b1:bf:f8:78:8c:ac:1c:c7:ca:4a:9a:c6:22:2b:cc:34:c6 +# SHA256 Fingerprint: 96:0a:df:00:63:e9:63:56:75:0c:29:65:dd:0a:08:67:da:0b:9c:bd:6e:77:71:4a:ea:fb:23:49:ab:39:3d:a3 +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG +A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh +bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE +ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS +b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5 +7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS +J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y +HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP +t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz +FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY +XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ +MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw +hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js +MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA +A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj +Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx +XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o +omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc +A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW +WL1WMRJOEcgh4LMRkWXbtKaIOM5V +-----END CERTIFICATE----- + +# Issuer: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority +# Subject: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority +# Label: "ePKI Root Certification Authority" +# Serial: 28956088682735189655030529057352760477 +# MD5 Fingerprint: 1b:2e:00:ca:26:06:90:3d:ad:fe:6f:15:68:d3:6b:b3 +# SHA1 Fingerprint: 67:65:0d:f1:7e:8e:7e:5b:82:40:a4:f4:56:4b:cf:e2:3d:69:c6:f0 +# SHA256 Fingerprint: c0:a6:f4:dc:63:a2:4b:fd:cf:54:ef:2a:6a:08:2a:0a:72:de:35:80:3e:2f:f5:ff:52:7a:e5:d8:72:06:df:d5 +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw +IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL +SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH +SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh +ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X +DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 +TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ +fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA +sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU +WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS +nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH +dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip +NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC +AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF +MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB +uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl +PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP +JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ +gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 +j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 +5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB +o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS +/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z +Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE +W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D +hNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +# Issuer: O=certSIGN OU=certSIGN ROOT CA +# Subject: O=certSIGN OU=certSIGN ROOT CA +# Label: "certSIGN ROOT CA" +# Serial: 35210227249154 +# MD5 Fingerprint: 18:98:c0:d6:e9:3a:fc:f9:b0:f5:0c:f7:4b:01:44:17 +# SHA1 Fingerprint: fa:b7:ee:36:97:26:62:fb:2d:b0:2a:f6:bf:03:fd:e8:7c:4b:2f:9b +# SHA256 Fingerprint: ea:a9:62:c4:fa:4a:6b:af:eb:e4:15:19:6d:35:1c:cd:88:8d:4f:53:f3:fa:8a:e6:d7:c4:66:a9:4e:60:42:bb +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT +AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD +QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP +MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do +0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ +UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d +RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ +OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv +JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C +AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O +BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ +LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY +MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ +44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I +Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw +i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN +9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +# Issuer: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) +# Subject: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) +# Label: "NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny" +# Serial: 80544274841616 +# MD5 Fingerprint: c5:a1:b7:ff:73:dd:d6:d7:34:32:18:df:fc:3c:ad:88 +# SHA1 Fingerprint: 06:08:3f:59:3f:15:a1:04:a0:69:a4:6b:a9:03:d0:06:b7:97:09:91 +# SHA256 Fingerprint: 6c:61:da:c3:a2:de:f0:31:50:6b:e0:36:d2:a6:fe:40:19:94:fb:d1:3d:f9:c8:d4:66:59:92:74:c4:46:ec:98 +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG +EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 +MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR +dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB +pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM +b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz +IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT +lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz +AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 +VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG +ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 +BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG +AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M +U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh +bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C ++C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F +uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 +XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +# Issuer: CN=Hongkong Post Root CA 1 O=Hongkong Post +# Subject: CN=Hongkong Post Root CA 1 O=Hongkong Post +# Label: "Hongkong Post Root CA 1" +# Serial: 1000 +# MD5 Fingerprint: a8:0d:6f:39:78:b9:43:6d:77:42:6d:98:5a:cc:23:ca +# SHA1 Fingerprint: d6:da:a8:20:8d:09:d2:15:4d:24:b5:2f:cb:34:6e:b2:58:b2:8a:58 +# SHA256 Fingerprint: f9:e6:7d:33:6c:51:00:2a:c0:54:c6:32:02:2d:66:dd:a2:e7:e3:ff:f1:0a:d0:61:ed:31:d8:bb:b4:10:cf:b2 +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx +FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg +Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG +A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr +b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ +jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn +PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh +ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9 +nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h +q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED +MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC +mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3 +7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB +oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs +EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO +fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi +AmvZWg== +-----END CERTIFICATE----- + +# Issuer: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. +# Subject: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. +# Label: "SecureSign RootCA11" +# Serial: 1 +# MD5 Fingerprint: b7:52:74:e2:92:b4:80:93:f2:75:e4:cc:d7:f2:ea:26 +# SHA1 Fingerprint: 3b:c4:9f:48:f8:f3:73:a0:9c:1e:bd:f8:5b:b1:c3:65:c7:d8:11:b3 +# SHA256 Fingerprint: bf:0f:ee:fb:9e:3a:58:1a:d5:f9:e9:db:75:89:98:57:43:d2:61:08:5c:4d:31:4f:6f:5d:72:59:aa:42:16:12 +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr +MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG +A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0 +MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp +Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD +QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz +i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8 +h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV +MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9 +UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni +8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC +h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD +VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm +KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ +X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr +QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 +pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN +QSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +# Issuer: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. +# Subject: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. +# Label: "Microsec e-Szigno Root CA 2009" +# Serial: 14014712776195784473 +# MD5 Fingerprint: f8:49:f4:03:bc:44:2d:83:be:48:69:7d:29:64:fc:b1 +# SHA1 Fingerprint: 89:df:74:fe:5c:f4:0f:4a:80:f9:e3:37:7d:54:da:91:e1:01:31:8e +# SHA256 Fingerprint: 3c:5f:81:fe:a5:fa:b8:2c:64:bf:a2:ea:ec:af:cd:e8:e0:77:fc:86:20:a7:ca:e5:37:16:3d:f3:6e:db:f3:78 +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD +VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 +ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G +CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y +OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx +FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp +Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP +kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc +cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U +fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 +N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC +xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 ++rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM +Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG +SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h +mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk +ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c +2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t +HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Label: "GlobalSign Root CA - R3" +# Serial: 4835703278459759426209954 +# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28 +# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad +# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- + +# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" +# Serial: 6047274297262753887 +# MD5 Fingerprint: 73:3a:74:7a:ec:bb:a3:96:a6:c2:e4:e2:c8:9b:c0:c3 +# SHA1 Fingerprint: ae:c5:fb:3f:c8:e1:bf:c4:e5:4f:03:07:5a:9a:e8:00:b7:f7:b6:fa +# SHA256 Fingerprint: 04:04:80:28:bf:1f:28:64:d4:8f:9a:d4:d8:32:94:36:6a:82:88:56:55:3f:3b:14:30:3f:90:14:7f:5d:40:ef +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy +MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD +VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv +ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl +AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF +661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 +am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 +ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 +PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS +3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k +SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF +3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM +ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g +StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz +Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB +jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- + +# Issuer: CN=Izenpe.com O=IZENPE S.A. +# Subject: CN=Izenpe.com O=IZENPE S.A. +# Label: "Izenpe.com" +# Serial: 917563065490389241595536686991402621 +# MD5 Fingerprint: a6:b0:cd:85:80:da:5c:50:34:a3:39:90:2f:55:67:73 +# SHA1 Fingerprint: 2f:78:3d:25:52:18:a7:4a:65:39:71:b5:2c:a2:9c:45:15:6f:e9:19 +# SHA256 Fingerprint: 25:30:cc:8e:98:32:15:02:ba:d9:6f:9b:1f:ba:1b:09:9e:2d:29:9e:0f:45:48:bb:91:4f:36:3b:c0:d4:53:1f +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Label: "Go Daddy Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01 +# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b +# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE----- + +# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Label: "Starfield Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96 +# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e +# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5 +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Label: "Starfield Services Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2 +# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f +# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5 +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs +ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD +VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy +ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy +dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p +OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 +8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K +Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe +hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk +6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q +AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI +bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB +ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z +qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn +0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN +sSi6 +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Commercial O=AffirmTrust +# Subject: CN=AffirmTrust Commercial O=AffirmTrust +# Label: "AffirmTrust Commercial" +# Serial: 8608355977964138876 +# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7 +# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7 +# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7 +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP +Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr +ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL +MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 +yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr +VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ +nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG +XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj +vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt +Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g +N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC +nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Networking O=AffirmTrust +# Subject: CN=AffirmTrust Networking O=AffirmTrust +# Label: "AffirmTrust Networking" +# Serial: 8957382827206547757 +# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f +# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f +# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y +YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua +kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL +QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp +6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG +yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i +QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO +tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu +QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ +Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u +olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 +x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Premium O=AffirmTrust +# Subject: CN=AffirmTrust Premium O=AffirmTrust +# Label: "AffirmTrust Premium" +# Serial: 7893706540734352110 +# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57 +# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27 +# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz +dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG +A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U +cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf +qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ +JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ ++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS +s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 +HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 +70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG +V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S +qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S +5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia +C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX +OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE +FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 +KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B +8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ +MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc +0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ +u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF +u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH +YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 +GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO +RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e +KeC2uAloGRwYQw== +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust +# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust +# Label: "AffirmTrust Premium ECC" +# Serial: 8401224907861490260 +# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d +# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb +# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23 +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ +cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ +BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt +VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D +0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 +ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G +A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs +aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I +flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Network CA" +# Serial: 279744 +# MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78 +# SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e +# SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM +MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D +ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU +cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 +WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg +Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw +IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH +UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM +TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU +BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM +kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x +AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y +sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL +I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 +J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY +VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +# Issuer: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA +# Subject: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA +# Label: "TWCA Root Certification Authority" +# Serial: 1 +# MD5 Fingerprint: aa:08:8f:f6:f9:7b:b7:f2:b1:a7:1e:9b:ea:ea:bd:79 +# SHA1 Fingerprint: cf:9e:87:6d:d3:eb:fc:42:26:97:a3:b5:a3:7a:a0:76:a9:06:23:48 +# SHA256 Fingerprint: bf:d8:8f:e1:10:1c:41:ae:3e:80:1b:f8:be:56:35:0e:e9:ba:d1:a6:b9:bd:51:5e:dc:5c:6d:5b:87:11:ac:44 +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES +MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU +V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz +WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO +LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE +AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH +K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX +RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z +rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx +3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq +hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC +MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls +XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D +lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn +aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ +YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 +# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 +# Label: "Security Communication RootCA2" +# Serial: 0 +# MD5 Fingerprint: 6c:39:7d:a4:0e:55:59:b2:3f:d6:41:b1:12:50:de:43 +# SHA1 Fingerprint: 5f:3b:8c:f2:f8:10:b3:7d:78:b4:ce:ec:19:19:c3:73:34:b9:c7:74 +# SHA256 Fingerprint: 51:3b:2c:ec:b8:10:d4:cd:e5:dd:85:39:1a:df:c6:c2:dd:60:d8:7b:b7:36:d2:b5:21:48:4a:a4:7a:0e:be:f6 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX +DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy +dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj +YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV +OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr +zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM +VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ +hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO +ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw +awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs +OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF +coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc +okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 +t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy +1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ +SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +# Issuer: CN=EC-ACC O=Agencia Catalana de Certificacio (NIF Q-0801176-I) OU=Serveis Publics de Certificacio/Vegeu https://www.catcert.net/verarrel (c)03/Jerarquia Entitats de Certificacio Catalanes +# Subject: CN=EC-ACC O=Agencia Catalana de Certificacio (NIF Q-0801176-I) OU=Serveis Publics de Certificacio/Vegeu https://www.catcert.net/verarrel (c)03/Jerarquia Entitats de Certificacio Catalanes +# Label: "EC-ACC" +# Serial: -23701579247955709139626555126524820479 +# MD5 Fingerprint: eb:f5:9d:29:0d:61:f9:42:1f:7c:c2:ba:6d:e3:15:09 +# SHA1 Fingerprint: 28:90:3a:63:5b:52:80:fa:e6:77:4c:0b:6d:a7:d6:ba:a6:4a:f2:e8 +# SHA256 Fingerprint: 88:49:7f:01:60:2f:31:54:24:6a:e2:8c:4d:5a:ef:10:f1:d8:7e:bb:76:62:6f:4a:e0:b7:f9:5b:a7:96:87:99 +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB +8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy +dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1 +YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3 +dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh +IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD +LUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQG +EwJFUzE7MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8g +KE5JRiBRLTA4MDExNzYtSSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBD +ZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQu +bmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJhcnF1aWEgRW50aXRhdHMg +ZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUNDMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R +85iKw5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm +4CgPukLjbo73FCeTae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaV +HMf5NLWUhdWZXqBIoH7nF2W4onW4HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNd +QlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0aE9jD2z3Il3rucO2n5nzbcc8t +lGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw0JDnJwIDAQAB +o4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4 +opvpXY0wfwYDVR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBo +dHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidW +ZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAwDQYJKoZIhvcN +AQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJlF7W2u++AVtd0x7Y +/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNaAl6k +SBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhy +Rp/7SNVel+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOS +Agu+TGbrIP65y7WZf+a2E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xl +nJ2lYJU6Un/10asIbvPuW/mIPX64b24D5EI= +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions RootCA 2011" +# Serial: 0 +# MD5 Fingerprint: 73:9f:4c:4b:73:5b:79:e9:fa:ba:1c:ef:6e:cb:d5:c9 +# SHA1 Fingerprint: fe:45:65:9b:79:03:5b:98:a1:61:b5:51:2e:ac:da:58:09:48:22:4d +# SHA256 Fingerprint: bc:10:4f:15:a4:8b:e7:09:dc:a5:42:a7:e1:d4:b9:df:6f:05:45:27:e8:02:ea:a9:2d:59:54:44:25:8a:fe:71 +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix +RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p +YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw +NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK +EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl +cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz +dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ +fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns +bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD +75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP +FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV +HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp +5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu +b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA +A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p +6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7 +dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys +Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI +l7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- + +# Issuer: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 +# Subject: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 +# Label: "Actalis Authentication Root CA" +# Serial: 6271844772424770508 +# MD5 Fingerprint: 69:c1:0d:4f:07:a3:1b:c3:fe:56:3d:04:bc:11:f6:a6 +# SHA1 Fingerprint: f3:73:b3:87:06:5a:28:84:8a:f2:f3:4a:ce:19:2b:dd:c7:8e:9c:ac +# SHA256 Fingerprint: 55:92:60:84:ec:96:3a:64:b9:6e:2a:be:01:ce:0b:a8:6a:64:fb:fe:bc:c7:aa:b5:af:c1:55:b3:7f:d7:60:66 +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE +BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w +MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC +SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 +ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv +UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX +4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 +KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ +gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb +rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ +51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F +be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe +KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F +v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn +fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 +jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz +ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL +e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 +jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz +WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V +SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j +pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX +X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok +fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R +K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU +ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU +LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT +LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +# Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 +# Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 +# Label: "Buypass Class 2 Root CA" +# Serial: 2 +# MD5 Fingerprint: 46:a7:d2:fe:45:fb:64:5a:a8:59:90:9b:78:44:9b:29 +# SHA1 Fingerprint: 49:0a:75:74:de:87:0a:47:fe:58:ee:f6:c7:6b:eb:c6:0b:12:40:99 +# SHA256 Fingerprint: 9a:11:40:25:19:7c:5b:b9:5d:94:e6:3d:55:cd:43:79:08:47:b6:46:b2:3c:df:11:ad:a4:a0:0e:ff:15:fb:48 +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr +6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV +L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 +1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx +MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ +QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB +arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr +Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi +FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS +P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN +9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz +uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h +9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t +OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo ++fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 +KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 +DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us +H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ +I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 +5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h +3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz +Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= +-----END CERTIFICATE----- + +# Issuer: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 +# Subject: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 +# Label: "Buypass Class 3 Root CA" +# Serial: 2 +# MD5 Fingerprint: 3d:3b:18:9e:2c:64:5a:e8:d5:88:ce:0e:f9:37:c2:ec +# SHA1 Fingerprint: da:fa:f7:fa:66:84:ec:06:8f:14:50:bd:c7:c2:81:a5:bc:a9:64:57 +# SHA256 Fingerprint: ed:f7:eb:bc:a2:7a:2a:38:4d:38:7b:7d:40:10:c6:66:e2:ed:b4:84:3e:4c:29:b4:ae:1d:5b:93:32:e6:b2:4d +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y +ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E +N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 +tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX +0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c +/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X +KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY +zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS +O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D +34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP +K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv +Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj +QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS +IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 +HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa +O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv +033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u +dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE +kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 +3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD +u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq +4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= +-----END CERTIFICATE----- + +# Issuer: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Subject: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Label: "T-TeleSec GlobalRoot Class 3" +# Serial: 1 +# MD5 Fingerprint: ca:fb:40:a8:4e:39:92:8a:1d:fe:8e:2f:c4:27:ea:ef +# SHA1 Fingerprint: 55:a6:72:3e:cb:f2:ec:cd:c3:23:74:70:19:9d:2a:be:11:e3:81:d1 +# SHA256 Fingerprint: fd:73:da:d3:1c:64:4f:f1:b4:3b:ef:0c:cd:da:96:71:0b:9c:d9:87:5e:ca:7e:31:70:7a:f3:e9:6d:52:2b:bd +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN +8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ +RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 +hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 +ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM +EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 +A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy +WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ +1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 +6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT +91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p +TpPDpFQUWw== +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH +# Subject: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH +# Label: "D-TRUST Root Class 3 CA 2 2009" +# Serial: 623603 +# MD5 Fingerprint: cd:e0:25:69:8d:47:ac:9c:89:35:90:f7:fd:51:3d:2f +# SHA1 Fingerprint: 58:e8:ab:b0:36:15:33:fb:80:f7:9b:1b:6d:29:d3:ff:8d:5f:00:f0 +# SHA256 Fingerprint: 49:e7:a4:42:ac:f0:ea:62:87:05:00:54:b5:25:64:b6:50:e4:f4:9e:42:e3:48:d6:aa:38:e0:39:e9:57:b1:c1 +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha +ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM +HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 +UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 +tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R +ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM +lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp +/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G +A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy +MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl +cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js +L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL +BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni +acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K +zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 +PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y +Johw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH +# Subject: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH +# Label: "D-TRUST Root Class 3 CA 2 EV 2009" +# Serial: 623604 +# MD5 Fingerprint: aa:c6:43:2c:5e:2d:cd:c4:34:c0:50:4f:11:02:4f:b6 +# SHA1 Fingerprint: 96:c9:1b:0b:95:b4:10:98:42:fa:d0:d8:22:79:fe:60:fa:b9:16:83 +# SHA256 Fingerprint: ee:c5:49:6b:98:8c:e9:86:25:b9:34:09:2e:ec:29:08:be:d0:b0:f3:16:c2:d4:73:0c:84:ea:f1:f3:d3:48:81 +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw +NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV +BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn +ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 +3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z +qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR +p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 +HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw +ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea +HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw +Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh +c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E +RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt +dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku +Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp +3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF +CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na +xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX +KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +# Issuer: CN=CA Disig Root R2 O=Disig a.s. +# Subject: CN=CA Disig Root R2 O=Disig a.s. +# Label: "CA Disig Root R2" +# Serial: 10572350602393338211 +# MD5 Fingerprint: 26:01:fb:d8:27:a7:17:9a:45:54:38:1a:43:01:3b:03 +# SHA1 Fingerprint: b5:61:eb:ea:a4:de:e4:25:4b:69:1a:98:a5:57:47:c2:34:c7:d9:71 +# SHA256 Fingerprint: e2:3d:4a:03:6d:7b:70:e9:f5:95:b1:42:20:79:d2:b9:1e:df:bb:1f:b6:51:a0:63:3e:aa:8a:9d:c5:f8:07:03 +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy +MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe +NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH +PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I +x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe +QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR +yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO +QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 +H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ +QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD +i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs +nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 +rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI +hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf +GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb +lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka ++elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal +TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i +nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 +gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr +G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os +zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x +L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +# Issuer: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV +# Subject: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV +# Label: "ACCVRAIZ1" +# Serial: 6828503384748696800 +# MD5 Fingerprint: d0:a0:5a:ee:05:b6:09:94:21:a1:7d:f1:b2:29:82:02 +# SHA1 Fingerprint: 93:05:7a:88:15:c6:4f:ce:88:2f:fa:91:16:52:28:78:bc:53:64:17 +# SHA256 Fingerprint: 9a:6e:c0:12:e1:a7:da:9d:be:34:19:4d:47:8a:d7:c0:db:18:22:fb:07:1d:f1:29:81:49:6e:d1:04:38:41:13 +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE +AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw +CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ +BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND +VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb +qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY +HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo +G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA +lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr +IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ +0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH +k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 +4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO +m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa +cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl +uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI +KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls +ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG +AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT +VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG +CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA +cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA +QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA +7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA +cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA +QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA +czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu +aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt +aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud +DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF +BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp +D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU +JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m +AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD +vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms +tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH +7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA +h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF +d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H +pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +# Issuer: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA +# Subject: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA +# Label: "TWCA Global Root CA" +# Serial: 3262 +# MD5 Fingerprint: f9:03:7e:cf:e6:9e:3c:73:7a:2a:90:07:69:ff:2b:96 +# SHA1 Fingerprint: 9c:bb:48:53:f6:a4:f6:d3:52:a4:e8:32:52:55:60:13:f5:ad:af:65 +# SHA256 Fingerprint: 59:76:90:07:f7:68:5d:0f:cd:50:87:2f:9f:95:d5:75:5a:5b:2b:45:7d:81:f3:69:2b:61:0a:98:67:2f:0e:1b +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx +EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT +VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 +NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT +B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF +10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz +0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh +MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH +zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc +46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 +yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi +laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP +oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA +BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE +qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm +4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL +1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF +H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo +RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ +nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh +15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW +6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW +nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j +wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz +aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy +KwbQBM0= +-----END CERTIFICATE----- + +# Issuer: CN=TeliaSonera Root CA v1 O=TeliaSonera +# Subject: CN=TeliaSonera Root CA v1 O=TeliaSonera +# Label: "TeliaSonera Root CA v1" +# Serial: 199041966741090107964904287217786801558 +# MD5 Fingerprint: 37:41:49:1b:18:56:9a:26:f5:ad:c2:66:fb:40:a5:4c +# SHA1 Fingerprint: 43:13:bb:96:f1:d5:86:9b:c1:4e:6a:92:f6:cf:f6:34:69:87:82:37 +# SHA256 Fingerprint: dd:69:36:fe:21:f8:f0:77:c1:23:a1:a5:21:c1:22:24:f7:22:55:b7:3e:03:a7:26:06:93:e8:a2:4b:0f:a3:89 +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw +NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv +b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD +VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F +VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 +7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X +Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ +/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs +81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm +dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe +Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu +sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 +pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs +slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ +arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD +VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG +9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl +dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj +TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed +Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 +Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI +OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 +vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW +t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn +HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx +SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- + +# Issuer: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi +# Subject: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi +# Label: "E-Tugra Certification Authority" +# Serial: 7667447206703254355 +# MD5 Fingerprint: b8:a1:03:63:b0:bd:21:71:70:8a:6f:13:3a:bb:79:49 +# SHA1 Fingerprint: 51:c6:e7:08:49:06:6e:f3:92:d4:5c:a0:0d:6d:a3:62:8f:c3:52:39 +# SHA256 Fingerprint: b0:bf:d5:2b:b0:d7:d9:bd:92:bf:5d:4d:c1:3d:a2:55:c0:2c:54:2f:37:83:65:ea:89:39:11:f5:5e:55:f2:3c +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV +BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC +aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV +BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 +Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz +MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ +BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp +em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY +B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH +D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF +Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo +q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D +k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH +fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut +dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM +ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 +zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX +U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 +Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 +XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF +Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR +HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY +GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c +77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 ++GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK +vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 +FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl +yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P +AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD +y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d +NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== +-----END CERTIFICATE----- + +# Issuer: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Subject: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Label: "T-TeleSec GlobalRoot Class 2" +# Serial: 1 +# MD5 Fingerprint: 2b:9b:9e:e4:7b:6c:1f:00:72:1a:cc:c1:77:79:df:6a +# SHA1 Fingerprint: 59:0d:2d:7d:88:4f:40:2e:61:7e:a5:62:32:17:65:cf:17:d8:94:e9 +# SHA256 Fingerprint: 91:e2:f5:78:8d:58:10:eb:a7:ba:58:73:7d:e1:54:8a:8e:ca:cd:01:45:98:bc:0b:14:3e:04:1b:17:05:25:52 +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd +AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC +FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi +1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq +jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ +wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ +WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy +NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC +uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw +IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 +g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP +BSeOE6Fuwg== +-----END CERTIFICATE----- + +# Issuer: CN=Atos TrustedRoot 2011 O=Atos +# Subject: CN=Atos TrustedRoot 2011 O=Atos +# Label: "Atos TrustedRoot 2011" +# Serial: 6643877497813316402 +# MD5 Fingerprint: ae:b9:c4:32:4b:ac:7f:5d:66:cc:77:94:bb:2a:77:56 +# SHA1 Fingerprint: 2b:b1:f5:3e:55:0c:1d:c5:f1:d4:e6:b7:6a:46:4b:55:06:02:ac:21 +# SHA256 Fingerprint: f3:56:be:a2:44:b7:a9:1e:b3:5d:53:ca:9a:d7:86:4a:ce:01:8e:2d:35:d5:f8:f9:6d:df:68:a6:f4:1a:a4:74 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE +AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG +EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM +FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC +REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp +Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM +VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ +SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ +4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L +cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi +eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG +A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j +vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP +DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc +maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D +lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv +KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 1 G3" +# Serial: 687049649626669250736271037606554624078720034195 +# MD5 Fingerprint: a4:bc:5b:3f:fe:37:9a:fa:64:f0:e2:fa:05:3d:0b:ab +# SHA1 Fingerprint: 1b:8e:ea:57:96:29:1a:c9:39:ea:b8:0a:81:1a:73:73:c0:93:79:67 +# SHA256 Fingerprint: 8a:86:6f:d1:b2:76:b5:7e:57:8e:92:1c:65:82:8a:2b:ed:58:e9:f2:f2:88:05:41:34:b7:f1:f4:bf:c9:cc:74 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 +MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV +wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe +rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 +68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh +4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp +UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o +abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc +3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G +KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt +hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO +Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt +zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD +ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 +cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN +qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 +YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv +b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 +8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k +NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj +ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp +q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt +nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 2 G3" +# Serial: 390156079458959257446133169266079962026824725800 +# MD5 Fingerprint: af:0c:86:6e:bf:40:2d:7f:0b:3e:12:50:ba:12:3d:06 +# SHA1 Fingerprint: 09:3c:61:f3:8b:8b:dc:7d:55:df:75:38:02:05:00:e1:25:f5:c8:36 +# SHA256 Fingerprint: 8f:e4:fb:0a:f9:3a:4d:0d:67:db:0b:eb:b2:3e:37:c7:1b:f3:25:dc:bc:dd:24:0e:a0:4d:af:58:b4:7e:18:40 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 +MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf +qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW +n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym +c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ +O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 +o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j +IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq +IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz +8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh +vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l +7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG +cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD +ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC +roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga +W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n +lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE ++V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV +csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd +dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg +KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM +HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 +WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 3 G3" +# Serial: 268090761170461462463995952157327242137089239581 +# MD5 Fingerprint: df:7d:b9:ad:54:6f:68:a1:df:89:57:03:97:43:b0:d7 +# SHA1 Fingerprint: 48:12:bd:92:3c:a8:c4:39:06:e7:30:6d:27:96:e6:a4:cf:22:2e:7d +# SHA256 Fingerprint: 88:ef:81:de:20:2e:b0:18:45:2e:43:f8:64:72:5c:ea:5f:bd:1f:c2:d9:d2:05:73:07:09:c5:d8:b8:69:0f:46 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 +MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR +/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu +FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR +U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c +ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR +FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k +A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw +eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl +sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp +VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q +A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ +ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD +ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI +FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv +oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg +u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP +0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf +3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl +8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ +DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN +PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ +ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root G2" +# Serial: 15385348160840213938643033620894905419 +# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d +# SHA1 Fingerprint: a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f +# SHA256 Fingerprint: 7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:49:45:2f:ab:7d:2f:c1:85 +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root G3" +# Serial: 15459312981008553731928384953135426796 +# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb +# SHA1 Fingerprint: f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89 +# SHA256 Fingerprint: 7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:b1:00:71:7f:43:05:3f:c2 +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G2" +# Serial: 4293743540046975378534879503202253541 +# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44 +# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4 +# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G3" +# Serial: 7089244469030293291760083333884364146 +# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca +# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e +# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0 +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Trusted Root G4" +# Serial: 7451500558977370777930084869016614236 +# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49 +# SHA1 Fingerprint: dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4 +# SHA256 Fingerprint: 55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:03:d1:d9:d2:0a:c8:99:88 +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE----- + +# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited +# Label: "COMODO RSA Certification Authority" +# Serial: 101909084537582093308941363524873193117 +# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18 +# SHA1 Fingerprint: af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4 +# SHA256 Fingerprint: 52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:34:63:53:4b:32:b4:02:34 +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT +EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR +6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X +pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC +9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV +/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf +Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z ++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w +qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah +SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC +u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf +Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq +crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl +wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM +4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV +2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna +FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ +CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK +boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke +jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL +S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb +QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl +0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB +NVOFBkpdn627G190 +-----END CERTIFICATE----- + +# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Label: "USERTrust RSA Certification Authority" +# Serial: 2645093764781058787591871645665788717 +# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5 +# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e +# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2 +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw +MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV +BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B +3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY +tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ +Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 +VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT +79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 +c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT +Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l +c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee +UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE +Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF +Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO +VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 +ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs +8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR +iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze +Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ +XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ +qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB +VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB +L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG +jjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- + +# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST Network +# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST Network +# Label: "USERTrust ECC Certification Authority" +# Serial: 123013823720199481456569720443997572134 +# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1 +# SHA1 Fingerprint: d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0 +# SHA256 Fingerprint: 4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:86:e0:6a:dc:d2:a9:ad:7a +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl +eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT +JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT +Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg +VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo +I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng +o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G +A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB +zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW +RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 +# Label: "GlobalSign ECC Root CA - R4" +# Serial: 14367148294922964480859022125800977897474 +# MD5 Fingerprint: 20:f0:27:68:d1:7e:a0:9d:0e:e6:2a:ca:df:5c:89:8e +# SHA1 Fingerprint: 69:69:56:2e:40:80:f4:24:a1:e7:19:9f:14:ba:f3:ee:58:ab:6a:bb +# SHA256 Fingerprint: be:c9:49:11:c2:95:56:76:db:6c:0a:55:09:86:d7:6e:3b:a0:05:66:7c:44:2c:97:62:b4:fb:b7:73:de:22:8c +-----BEGIN CERTIFICATE----- +MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ +FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F +uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX +kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs +ewv4n4Q= +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 +# Label: "GlobalSign ECC Root CA - R5" +# Serial: 32785792099990507226680698011560947931244 +# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08 +# SHA1 Fingerprint: 1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa +# SHA256 Fingerprint: 17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:13:f6:eb:ec:10:0c:89:24 +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc +8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke +hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI +KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg +515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO +xwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- + +# Issuer: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden +# Subject: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden +# Label: "Staat der Nederlanden EV Root CA" +# Serial: 10000013 +# MD5 Fingerprint: fc:06:af:7b:e8:1a:f1:9a:b4:e8:d2:70:1f:c0:f5:ba +# SHA1 Fingerprint: 76:e2:7e:c1:4f:db:82:c1:c0:a6:75:b5:05:be:3d:29:b4:ed:db:bb +# SHA256 Fingerprint: 4d:24:91:41:4c:fe:95:67:46:ec:4c:ef:a6:cf:6f:72:e2:8a:13:29:43:2f:9d:8a:90:7a:c4:cb:5d:ad:c1:5a +-----BEGIN CERTIFICATE----- +MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y +MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg +TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS +b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS +M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC +UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d +Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p +rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l +pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb +j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC +KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS +/ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X +cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH +1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP +px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7 +MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI +eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u +2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS +v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC +wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy +CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e +vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6 +Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa +Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL +eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8 +FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc +7uzXLg== +-----END CERTIFICATE----- + +# Issuer: CN=IdenTrust Commercial Root CA 1 O=IdenTrust +# Subject: CN=IdenTrust Commercial Root CA 1 O=IdenTrust +# Label: "IdenTrust Commercial Root CA 1" +# Serial: 13298821034946342390520003877796839426 +# MD5 Fingerprint: b3:3e:77:73:75:ee:a0:d3:e3:7e:49:63:49:59:bb:c7 +# SHA1 Fingerprint: df:71:7e:aa:4a:d9:4e:c9:55:84:99:60:2d:48:de:5f:bc:f0:3a:25 +# SHA256 Fingerprint: 5d:56:49:9b:e4:d2:e0:8b:cf:ca:d0:8a:3e:38:72:3d:50:50:3b:de:70:69:48:e4:2f:55:60:30:19:e5:28:ae +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu +VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw +MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw +JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT +3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU ++ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp +S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 +bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi +T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL +vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK +Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK +dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT +c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv +l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N +iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD +ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt +LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 +nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 ++wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK +W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT +AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq +l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG +4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ +mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A +7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- + +# Issuer: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust +# Subject: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust +# Label: "IdenTrust Public Sector Root CA 1" +# Serial: 13298821034946342390521976156843933698 +# MD5 Fingerprint: 37:06:a5:b0:fc:89:9d:ba:f4:6b:8c:1a:64:cd:d5:ba +# SHA1 Fingerprint: ba:29:41:60:77:98:3f:f4:f3:ef:f2:31:05:3b:2e:ea:6d:4d:45:fd +# SHA256 Fingerprint: 30:d0:89:5a:9a:44:8a:26:20:91:63:55:22:d1:f5:20:10:b5:86:7a:ca:e1:2c:78:ef:95:8f:d4:f4:38:9f:2f +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu +VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN +MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 +MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 +ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy +RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS +bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF +/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R +3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw +EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy +9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V +GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ +2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV +WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD +W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN +AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV +DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 +TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G +lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW +mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df +WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 ++bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ +tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA +GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv +8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - G2" +# Serial: 1246989352 +# MD5 Fingerprint: 4b:e2:c9:91:96:65:0c:f4:0e:5a:93:92:a0:0a:fe:b2 +# SHA1 Fingerprint: 8c:f4:27:fd:79:0c:3a:d1:66:06:8d:e8:1e:57:ef:bb:93:22:72:d4 +# SHA256 Fingerprint: 43:df:57:74:b0:3e:7f:ef:5f:e4:0d:93:1a:7b:ed:f1:bb:2e:6b:42:73:8c:4e:6d:38:41:10:3d:3a:a7:f3:39 +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - EC1" +# Serial: 51543124481930649114116133369 +# MD5 Fingerprint: b6:7e:1d:f0:58:c5:49:6c:24:3b:3d:ed:98:18:ed:bc +# SHA1 Fingerprint: 20:d8:06:40:df:9b:25:f5:12:25:3a:11:ea:f7:59:8a:eb:14:b5:47 +# SHA256 Fingerprint: 02:ed:0e:b2:8c:14:da:45:16:5c:56:67:91:70:0d:64:51:d7:fb:56:f0:b2:ab:1d:3b:8e:b0:70:e5:6e:df:f5 +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- + +# Issuer: CN=CFCA EV ROOT O=China Financial Certification Authority +# Subject: CN=CFCA EV ROOT O=China Financial Certification Authority +# Label: "CFCA EV ROOT" +# Serial: 407555286 +# MD5 Fingerprint: 74:e1:b6:ed:26:7a:7a:44:30:33:94:ab:7b:27:81:30 +# SHA1 Fingerprint: e2:b8:29:4b:55:84:ab:6b:58:c2:90:46:6c:ac:3f:b8:39:8f:84:83 +# SHA256 Fingerprint: 5c:c3:d7:8e:4e:1d:5e:45:54:7a:04:e6:87:3e:64:f9:0c:f9:53:6d:1c:cc:2e:f8:00:f3:55:c4:c5:fd:70:fd +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD +TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y +aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx +MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j +aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP +T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 +sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL +TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 +/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp +7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz +EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt +hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP +a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot +aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg +TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV +PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv +cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL +tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd +BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT +ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL +jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS +ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy +P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 +xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d +Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN +5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe +/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z +AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ +5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su +-----END CERTIFICATE----- + +# Issuer: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed +# Subject: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed +# Label: "OISTE WISeKey Global Root GB CA" +# Serial: 157768595616588414422159278966750757568 +# MD5 Fingerprint: a4:eb:b9:61:28:2e:b7:2f:98:b0:35:26:90:99:51:1d +# SHA1 Fingerprint: 0f:f9:40:76:18:d3:d7:6a:4b:98:f0:a8:35:9e:0c:fd:27:ac:cc:ed +# SHA256 Fingerprint: 6b:9c:08:e8:6e:b0:f7:67:cf:ad:65:cd:98:b6:21:49:e5:49:4a:67:f5:84:5e:7b:d1:ed:01:9f:27:b8:6b:d6 +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt +MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg +Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i +YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x +CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG +b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 +HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx +WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX +1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk +u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P +99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r +M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB +BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh +cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 +gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO +ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf +aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE----- + +# Issuer: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. +# Subject: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. +# Label: "SZAFIR ROOT CA2" +# Serial: 357043034767186914217277344587386743377558296292 +# MD5 Fingerprint: 11:64:c1:89:b0:24:b1:8c:b1:07:7e:89:9e:51:9e:99 +# SHA1 Fingerprint: e2:52:fa:95:3f:ed:db:24:60:bd:6e:28:f3:9c:cc:cf:5e:b3:3f:de +# SHA256 Fingerprint: a1:33:9d:33:28:1a:0b:56:e5:57:d3:d3:2b:1c:e7:f9:36:7e:b0:94:bd:5f:a7:2a:7e:50:04:c8:de:d7:ca:fe +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL +BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 +ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw +NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L +cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg +Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN +QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT +3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw +3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 +3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 +BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN +XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF +AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw +8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG +nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP +oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy +d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg +LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Network CA 2" +# Serial: 44979900017204383099463764357512596969 +# MD5 Fingerprint: 6d:46:9e:d9:25:6d:08:23:5b:5e:74:7d:1e:27:db:f2 +# SHA1 Fingerprint: d3:dd:48:3e:2b:bf:4c:05:e8:af:10:f5:fa:76:26:cf:d3:dc:30:92 +# SHA256 Fingerprint: b6:76:f2:ed:da:e8:77:5c:d3:6c:b0:f6:3c:d1:d4:60:39:61:f4:9e:62:65:ba:01:3a:2f:03:07:b6:d0:b8:04 +-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB +gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu +QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG +A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz +OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ +VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 +b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA +DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn +0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB +OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE +fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E +Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m +o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i +sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW +OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez +Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS +adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n +3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ +F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf +CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 +XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm +djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ +WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb +AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq +P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko +b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj +XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P +5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi +DrW5viSP +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions RootCA 2015" +# Serial: 0 +# MD5 Fingerprint: ca:ff:e2:db:03:d9:cb:4b:e9:0f:ad:84:fd:7b:18:ce +# SHA1 Fingerprint: 01:0c:06:95:a6:98:19:14:ff:bf:5f:c6:b0:b6:95:ea:29:e9:12:a6 +# SHA256 Fingerprint: a0:40:92:9a:02:ce:53:b4:ac:f4:f2:ff:c6:98:1c:e4:49:6f:75:5e:6d:45:fe:0b:2a:69:2b:cd:52:52:3f:36 +-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix +DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k +IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT +N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v +dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG +A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh +ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx +QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA +4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 +AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 +4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C +ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV +9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD +gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 +Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq +NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko +LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd +ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I +XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI +M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot +9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V +Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea +j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh +X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ +l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf +bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 +pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK +e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 +vm9qp/UsQu0yrbYhnr68 +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions ECC RootCA 2015" +# Serial: 0 +# MD5 Fingerprint: 81:e5:b4:17:eb:c2:f5:e1:4b:0d:41:7b:49:92:fe:ef +# SHA1 Fingerprint: 9f:f1:71:8d:92:d5:9a:f3:7d:74:97:b4:bc:6f:84:68:0b:ba:b6:66 +# SHA256 Fingerprint: 44:b5:45:aa:8a:25:e6:5a:73:ca:15:dc:27:fc:36:d2:4c:1c:b9:95:3a:06:65:39:b1:15:82:dc:48:7b:48:33 +-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN +BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl +bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv +b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ +BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj +YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 +MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 +dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg +QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa +jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi +C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep +lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof +TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE----- + +# Issuer: CN=ISRG Root X1 O=Internet Security Research Group +# Subject: CN=ISRG Root X1 O=Internet Security Research Group +# Label: "ISRG Root X1" +# Serial: 172886928669790476064670243504169061120 +# MD5 Fingerprint: 0c:d2:f9:e0:da:17:73:e9:ed:86:4d:a5:e3:70:e7:4e +# SHA1 Fingerprint: ca:bd:2a:79:a1:07:6a:31:f2:1d:25:36:35:cb:03:9d:43:29:a5:e8 +# SHA256 Fingerprint: 96:bc:ec:06:26:49:76:f3:74:60:77:9a:cf:28:c5:a7:cf:e8:a3:c0:aa:e1:1a:8f:fc:ee:05:c0:bd:df:08:c6 +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- + +# Issuer: O=FNMT-RCM OU=AC RAIZ FNMT-RCM +# Subject: O=FNMT-RCM OU=AC RAIZ FNMT-RCM +# Label: "AC RAIZ FNMT-RCM" +# Serial: 485876308206448804701554682760554759 +# MD5 Fingerprint: e2:09:04:b4:d3:bd:d1:a0:14:fd:1a:d2:47:c4:57:1d +# SHA1 Fingerprint: ec:50:35:07:b2:15:c4:95:62:19:e2:a8:9a:5b:42:99:2c:4c:2c:20 +# SHA256 Fingerprint: eb:c5:57:0c:29:01:8c:4d:67:b1:aa:12:7b:af:12:f7:03:b4:61:1e:bc:17:b7:da:b5:57:38:94:17:9b:93:fa +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx +CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ +WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ +BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG +Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ +yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf +BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz +WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF +tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z +374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC +IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL +mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 +wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS +MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 +ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet +UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H +YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 +LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 +RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM +LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf +77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N +JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm +fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp +6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp +1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B +9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok +RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv +uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 1 O=Amazon +# Subject: CN=Amazon Root CA 1 O=Amazon +# Label: "Amazon Root CA 1" +# Serial: 143266978916655856878034712317230054538369994 +# MD5 Fingerprint: 43:c6:bf:ae:ec:fe:ad:2f:18:c6:88:68:30:fc:c8:e6 +# SHA1 Fingerprint: 8d:a7:f9:65:ec:5e:fc:37:91:0f:1c:6e:59:fd:c1:cc:6a:6e:de:16 +# SHA256 Fingerprint: 8e:cd:e6:88:4f:3d:87:b1:12:5b:a3:1a:c3:fc:b1:3d:70:16:de:7f:57:cc:90:4f:e1:cb:97:c6:ae:98:19:6e +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA +A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI +U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs +N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv +o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU +5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy +rqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 2 O=Amazon +# Subject: CN=Amazon Root CA 2 O=Amazon +# Label: "Amazon Root CA 2" +# Serial: 143266982885963551818349160658925006970653239 +# MD5 Fingerprint: c8:e5:8d:ce:a8:42:e2:7a:c0:2a:5c:7c:9e:26:bf:66 +# SHA1 Fingerprint: 5a:8c:ef:45:d7:a6:98:59:76:7a:8c:8b:44:96:b5:78:cf:47:4b:1a +# SHA256 Fingerprint: 1b:a5:b2:aa:8c:65:40:1a:82:96:01:18:f8:0b:ec:4f:62:30:4d:83:ce:c4:71:3a:19:c3:9c:01:1e:a4:6d:b4 +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK +gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ +W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg +1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K +8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r +2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me +z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR +8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj +mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz +7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 ++XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI +0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm +UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 +LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS +k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl +7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm +btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl +urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ +fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 +n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE +76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H +9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT +4PsJYGw= +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 3 O=Amazon +# Subject: CN=Amazon Root CA 3 O=Amazon +# Label: "Amazon Root CA 3" +# Serial: 143266986699090766294700635381230934788665930 +# MD5 Fingerprint: a0:d4:ef:0b:f7:b5:d8:49:95:2a:ec:f5:c4:fc:81:87 +# SHA1 Fingerprint: 0d:44:dd:8c:3c:8c:1a:1a:58:75:64:81:e9:0f:2e:2a:ff:b3:d2:6e +# SHA256 Fingerprint: 18:ce:6c:fe:7b:f1:4e:60:b2:e3:47:b8:df:e8:68:cb:31:d0:2e:bb:3a:da:27:15:69:f5:03:43:b4:6d:b3:a4 +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl +ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr +ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr +BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM +YyRIHN8wfdVoOw== +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 4 O=Amazon +# Subject: CN=Amazon Root CA 4 O=Amazon +# Label: "Amazon Root CA 4" +# Serial: 143266989758080763974105200630763877849284878 +# MD5 Fingerprint: 89:bc:27:d5:eb:17:8d:06:6a:69:d5:fd:89:47:b4:cd +# SHA1 Fingerprint: f6:10:84:07:d6:f8:bb:67:98:0c:c2:e2:44:c2:eb:ae:1c:ef:63:be +# SHA256 Fingerprint: e3:5d:28:41:9e:d0:20:25:cf:a6:90:38:cd:62:39:62:45:8d:a5:c6:95:fb:de:a3:c2:2b:0b:fb:25:89:70:92 +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi +9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk +M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB +MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw +CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW +1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- + +# Issuer: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM +# Subject: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM +# Label: "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1" +# Serial: 1 +# MD5 Fingerprint: dc:00:81:dc:69:2f:3e:2f:b0:3b:f6:3d:5a:91:8e:49 +# SHA1 Fingerprint: 31:43:64:9b:ec:ce:27:ec:ed:3a:3f:0b:8f:0d:e4:e8:91:dd:ee:ca +# SHA256 Fingerprint: 46:ed:c3:68:90:46:d5:3a:45:3f:b3:10:4a:b8:0d:ca:ec:65:8b:26:60:ea:16:29:dd:7e:86:79:90:64:87:16 +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx +GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp +bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w +KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 +BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy +dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG +EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll +IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU +QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT +TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg +LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 +a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr +LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr +N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X +YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ +iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f +AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH +V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf +IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 +lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c +8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf +lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE----- + +# Issuer: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. +# Subject: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. +# Label: "GDCA TrustAUTH R5 ROOT" +# Serial: 9009899650740120186 +# MD5 Fingerprint: 63:cc:d9:3d:34:35:5c:6f:53:a3:e2:08:70:48:1f:b4 +# SHA1 Fingerprint: 0f:36:38:5b:81:1a:25:c3:9b:31:4e:83:ca:e9:34:66:70:cc:74:b4 +# SHA256 Fingerprint: bf:ff:8f:d0:44:33:48:7d:6a:8a:a6:0c:1a:29:76:7a:9f:c2:bb:b0:5e:42:0f:71:3a:13:b9:92:89:1d:38:93 +-----BEGIN CERTIFICATE----- +MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE +BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ +IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 +MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV +BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w +HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj +Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj +TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u +KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj +qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm +MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12 +ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP +zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk +L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC +jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA +HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC +AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg +p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm +DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5 +COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry +L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf +JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg +IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io +2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV +09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ +XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq +T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe +MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== +-----END CERTIFICATE----- + +# Issuer: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Subject: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Label: "TrustCor RootCert CA-1" +# Serial: 15752444095811006489 +# MD5 Fingerprint: 6e:85:f1:dc:1a:00:d3:22:d5:b2:b2:ac:6b:37:05:45 +# SHA1 Fingerprint: ff:bd:cd:e7:82:c8:43:5e:3c:6f:26:86:5c:ca:a8:3a:45:5b:c3:0a +# SHA256 Fingerprint: d4:0e:9c:86:cd:8f:e4:68:c1:77:69:59:f4:9e:a7:74:fa:54:86:84:b6:c4:06:f3:90:92:61:f4:dc:e2:57:5c +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYD +VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk +MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U +cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29y +IFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkxMjMxMTcyMzE2WjCB +pDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFuYW1h +IENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUG +A1UECwweVHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZU +cnVzdENvciBSb290Q2VydCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAv463leLCJhJrMxnHQFgKq1mqjQCj/IDHUHuO1CAmujIS2CNUSSUQIpid +RtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4pQa81QBeCQryJ3pS/C3V +seq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0JEsq1pme +9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CV +EY4hgLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorW +hnAbJN7+KIor0Gqw/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/ +DeOxCbeKyKsZn3MzUOcwHwYDVR0jBBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD +ggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5mDo4Nvu7Zp5I +/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf +ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZ +yonnMlo2HD6CqFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djts +L1Ac59v2Z3kf9YKVmgenFK+P3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdN +zl/HHk484IkzlQsPpTLWPFp5LBk= +-----END CERTIFICATE----- + +# Issuer: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Subject: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Label: "TrustCor RootCert CA-2" +# Serial: 2711694510199101698 +# MD5 Fingerprint: a2:e1:f8:18:0b:ba:45:d5:c7:41:2a:bb:37:52:45:64 +# SHA1 Fingerprint: b8:be:6d:cb:56:f1:55:b9:63:d4:12:ca:4e:06:34:c7:94:b2:1c:c0 +# SHA256 Fingerprint: 07:53:e9:40:37:8c:1b:d5:e3:83:6e:39:5d:ae:a5:cb:83:9e:50:46:f1:bd:0e:ae:19:51:cf:10:fe:c7:c9:65 +-----BEGIN CERTIFICATE----- +MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNV +BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw +IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy +dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UEAwwWVHJ1c3RDb3Ig +Um9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEyMzExNzI2MzlaMIGk +MQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEg +Q2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYD +VQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRy +dXN0Q29yIFJvb3RDZXJ0IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCnIG7CKqJiJJWQdsg4foDSq8GbZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+ +QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9NkRvRUqdw6VC0xK5mC8tkq +1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1oYxOdqHp +2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nK +DOObXUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hape +az6LMvYHL1cEksr1/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF +3wP+TfSvPd9cW436cOGlfifHhi5qjxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88 +oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQPeSghYA2FFn3XVDjxklb9tTNM +g9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+CtgrKAmrhQhJ8Z3 +mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh +8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAd +BgNVHQ4EFgQU2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6U +nrybPZx9mCAZ5YwwYrIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw +DQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/hOsh80QA9z+LqBrWyOrsGS2h60COX +dKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnpkpfbsEZC89NiqpX+ +MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv2wnL +/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RX +CI/hOWB3S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYa +ZH9bDTMJBzN7Bj8RpFxwPIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW +2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dvDDqPys/cA8GiCcjl/YBeyGBCARsaU1q7 +N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYURpFHmygk71dSTlxCnKr3 +Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANExdqtvArB +As8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp +5KeXRKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu +1uwJ +-----END CERTIFICATE----- + +# Issuer: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Subject: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Label: "TrustCor ECA-1" +# Serial: 9548242946988625984 +# MD5 Fingerprint: 27:92:23:1d:0a:f5:40:7c:e9:e6:6b:9d:d8:f5:e7:6c +# SHA1 Fingerprint: 58:d1:df:95:95:67:6b:63:c0:f0:5b:1c:17:4d:8b:84:0b:c8:78:bd +# SHA256 Fingerprint: 5a:88:5d:b1:9c:01:d9:12:c5:75:93:88:93:8c:af:bb:df:03:1a:b2:d4:8e:91:ee:15:58:9b:42:97:1d:03:9c +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD +VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk +MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U +cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFzAVBgNVBAMMDlRydXN0Q29y +IEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3MjgwN1owgZwxCzAJBgNV +BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw +IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy +dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3Ig +RUNBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb +3w9U73NjKYKtR8aja+3+XzP4Q1HpGjORMRegdMTUpwHmspI+ap3tDvl0mEDTPwOA +BoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23xFUfJ3zSCNV2HykVh0A5 +3ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmcp0yJF4Ou +owReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/ +wZ0+fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZF +ZtS6mFjBAgMBAAGjYzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAf +BgNVHSMEGDAWgBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/ +MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEABT41XBVwm8nHc2Fv +civUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u/ukZMjgDfxT2 +AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F +hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50 +soIipX1TH0XsJ5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BI +WJZpTdwHjFGTot+fDz2LYLSCjaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1Wi +tJ/X5g== +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com Root Certification Authority RSA O=SSL Corporation +# Subject: CN=SSL.com Root Certification Authority RSA O=SSL Corporation +# Label: "SSL.com Root Certification Authority RSA" +# Serial: 8875640296558310041 +# MD5 Fingerprint: 86:69:12:c0:70:f1:ec:ac:ac:c2:d5:bc:a5:5b:a1:29 +# SHA1 Fingerprint: b7:ab:33:08:d1:ea:44:77:ba:14:80:12:5a:6f:bd:a9:36:49:0c:bb +# SHA256 Fingerprint: 85:66:6a:56:2e:e0:be:5c:e9:25:c1:d8:89:0a:6f:76:a8:7e:c1:6d:4d:7d:5f:29:ea:74:19:cf:20:12:3b:69 +-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE +BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK +DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz +OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R +xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX +qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC +C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 +6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh +/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF +YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E +JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc +US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 +ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm ++Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi +M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G +A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV +cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc +Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs +PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ +q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 +cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr +a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I +H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y +K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu +nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf +oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY +Ic2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com Root Certification Authority ECC O=SSL Corporation +# Subject: CN=SSL.com Root Certification Authority ECC O=SSL Corporation +# Label: "SSL.com Root Certification Authority ECC" +# Serial: 8495723813297216424 +# MD5 Fingerprint: 2e:da:e4:39:7f:9c:8f:37:d1:70:9f:26:17:51:3a:8e +# SHA1 Fingerprint: c3:19:7c:39:24:e6:54:af:1b:c4:ab:20:95:7a:e2:c3:0e:13:02:6a +# SHA256 Fingerprint: 34:17:bb:06:cc:60:07:da:1b:96:1c:92:0b:8a:b4:ce:3f:ad:82:0e:4a:a3:0b:9a:cb:c4:a7:4e:bd:ce:bc:65 +-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz +WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 +b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS +b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI +7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg +CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud +EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD +VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T +kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ +gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation +# Subject: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation +# Label: "SSL.com EV Root Certification Authority RSA R2" +# Serial: 6248227494352943350 +# MD5 Fingerprint: e1:1e:31:58:1a:ae:54:53:02:f6:17:6a:11:7b:4d:95 +# SHA1 Fingerprint: 74:3a:f0:52:9b:d0:32:a0:f4:4a:83:cd:d4:ba:a9:7b:7c:2e:c4:9a +# SHA256 Fingerprint: 2e:7b:f1:6c:c2:24:85:a7:bb:e2:aa:86:96:75:07:61:b0:ae:39:be:3b:2f:e9:d0:cc:6d:4e:f7:34:91:42:5c +-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV +BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE +CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy +MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G +A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD +DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq +M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf +OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa +4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 +HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR +aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA +b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ +Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV +PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO +pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu +UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY +MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 +9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW +s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 +Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg +cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM +79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz +/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt +ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm +Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK +QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ +w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi +S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 +mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation +# Subject: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation +# Label: "SSL.com EV Root Certification Authority ECC" +# Serial: 3182246526754555285 +# MD5 Fingerprint: 59:53:22:65:83:42:01:54:c0:ce:42:b9:5a:7c:f2:90 +# SHA1 Fingerprint: 4c:dd:51:a3:d1:f5:20:32:14:b0:c6:c5:32:23:03:91:c7:46:42:6d +# SHA256 Fingerprint: 22:a2:c1:f7:bd:ed:70:4c:c1:e7:01:b5:f4:08:c3:10:88:0f:e9:56:b5:de:2a:4a:44:f9:9c:87:3a:25:a7:c8 +-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx +NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv +bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA +VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku +WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX +5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ +ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg +h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 +# Label: "GlobalSign Root CA - R6" +# Serial: 1417766617973444989252670301619537 +# MD5 Fingerprint: 4f:dd:07:e4:d4:22:64:39:1e:0c:37:42:ea:d1:c6:ae +# SHA1 Fingerprint: 80:94:64:0e:b5:a7:a1:ca:11:9c:1f:dd:d5:9f:81:02:63:a7:fb:d1 +# SHA256 Fingerprint: 2c:ab:ea:fe:37:d0:6c:a2:2a:ba:73:91:c0:03:3d:25:98:29:52:c4:53:64:73:49:76:3a:3a:b5:ad:6c:cf:69 +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg +MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx +MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET +MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI +xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k +ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD +aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw +LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw +1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX +k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 +SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h +bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n +WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY +rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce +MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu +bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt +Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 +55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj +vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf +cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz +oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp +nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs +pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v +JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R +8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 +5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE----- + +# Issuer: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed +# Subject: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed +# Label: "OISTE WISeKey Global Root GC CA" +# Serial: 44084345621038548146064804565436152554 +# MD5 Fingerprint: a9:d6:b9:2d:2f:93:64:f8:a5:69:ca:91:e9:68:07:23 +# SHA1 Fingerprint: e0:11:84:5e:34:de:be:88:81:b9:9c:f6:16:26:d1:96:1f:c3:b9:31 +# SHA256 Fingerprint: 85:60:f9:1c:36:24:da:ba:95:70:b5:fe:a0:db:e3:6f:f1:1a:83:23:be:94:86:85:4f:b3:f3:4a:55:71:19:8d +-----BEGIN CERTIFICATE----- +MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw +CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 +bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg +Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ +BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu +ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS +b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni +eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W +p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T +rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV +57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg +Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R1 O=Google Trust Services LLC +# Subject: CN=GTS Root R1 O=Google Trust Services LLC +# Label: "GTS Root R1" +# Serial: 146587175971765017618439757810265552097 +# MD5 Fingerprint: 82:1a:ef:d4:d2:4a:f2:9f:e2:3d:97:06:14:70:72:85 +# SHA1 Fingerprint: e1:c9:50:e6:ef:22:f8:4c:56:45:72:8b:92:20:60:d7:d5:a7:a3:e8 +# SHA256 Fingerprint: 2a:57:54:71:e3:13:40:bc:21:58:1c:bd:2c:f1:3e:15:84:63:20:3e:ce:94:bc:f9:d3:cc:19:6b:f0:9a:54:72 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH +MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM +QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy +MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl +cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM +f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX +mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7 +zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P +fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc +vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4 +Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp +zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO +Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW +k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+ +DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF +lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW +Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1 +d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z +XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR +gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3 +d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv +J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg +DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM ++SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy +F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9 +SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws +E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R2 O=Google Trust Services LLC +# Subject: CN=GTS Root R2 O=Google Trust Services LLC +# Label: "GTS Root R2" +# Serial: 146587176055767053814479386953112547951 +# MD5 Fingerprint: 44:ed:9a:0e:a4:09:3b:00:f2:ae:4c:a3:c6:61:b0:8b +# SHA1 Fingerprint: d2:73:96:2a:2a:5e:39:9f:73:3f:e1:c7:1e:64:3f:03:38:34:fc:4d +# SHA256 Fingerprint: c4:5d:7b:b0:8e:6d:67:e6:2e:42:35:11:0b:56:4e:5f:78:fd:92:ef:05:8c:84:0a:ea:4e:64:55:d7:58:5c:60 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH +MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM +QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy +MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl +cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv +CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg +GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu +XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd +re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu +PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1 +mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K +8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj +x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR +nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0 +kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok +twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp +8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT +vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT +z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA +pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb +pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB +R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R +RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk +0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC +5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF +izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn +yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R3 O=Google Trust Services LLC +# Subject: CN=GTS Root R3 O=Google Trust Services LLC +# Label: "GTS Root R3" +# Serial: 146587176140553309517047991083707763997 +# MD5 Fingerprint: 1a:79:5b:6b:04:52:9c:5d:c7:74:33:1b:25:9a:f9:25 +# SHA1 Fingerprint: 30:d4:24:6f:07:ff:db:91:89:8a:0b:e9:49:66:11:eb:8c:5e:46:e5 +# SHA256 Fingerprint: 15:d5:b8:77:46:19:ea:7d:54:ce:1c:a6:d0:b0:c4:03:e0:37:a9:17:f1:31:e8:a0:4e:1e:6b:7a:71:ba:bc:e5 +-----BEGIN CERTIFICATE----- +MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout +736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A +DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk +fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA +njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R4 O=Google Trust Services LLC +# Subject: CN=GTS Root R4 O=Google Trust Services LLC +# Label: "GTS Root R4" +# Serial: 146587176229350439916519468929765261721 +# MD5 Fingerprint: 5d:b6:6a:c4:60:17:24:6a:1a:99:a8:4b:ee:5e:b4:26 +# SHA1 Fingerprint: 2a:1d:60:27:d9:4a:b1:0a:1c:4d:91:5c:cd:33:a0:cb:3e:2d:54:cb +# SHA256 Fingerprint: 71:cc:a5:39:1f:9e:79:4b:04:80:25:30:b3:63:e1:21:da:8a:30:43:bb:26:66:2f:ea:4d:ca:7f:c9:51:a4:bd +-----BEGIN CERTIFICATE----- +MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu +hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l +xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0 +CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx +sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w== +-----END CERTIFICATE----- + +# Issuer: CN=UCA Global G2 Root O=UniTrust +# Subject: CN=UCA Global G2 Root O=UniTrust +# Label: "UCA Global G2 Root" +# Serial: 124779693093741543919145257850076631279 +# MD5 Fingerprint: 80:fe:f0:c4:4a:f0:5c:62:32:9f:1c:ba:78:a9:50:f8 +# SHA1 Fingerprint: 28:f9:78:16:19:7a:ff:18:25:18:aa:44:fe:c1:a0:ce:5c:b6:4c:8a +# SHA256 Fingerprint: 9b:ea:11:c9:76:fe:01:47:64:c1:be:56:a6:f9:14:b5:a5:60:31:7a:bd:99:88:39:33:82:e5:16:1a:a0:49:3c +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9 +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH +bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x +CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds +b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr +b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9 +kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm +VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R +VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc +C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj +tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY +D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv +j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl +NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6 +iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP +O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV +ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj +L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 +1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl +1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU +b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV +PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj +y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb +EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg +DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI ++Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy +YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX +UB+K+wb1whnw0A== +-----END CERTIFICATE----- + +# Issuer: CN=UCA Extended Validation Root O=UniTrust +# Subject: CN=UCA Extended Validation Root O=UniTrust +# Label: "UCA Extended Validation Root" +# Serial: 106100277556486529736699587978573607008 +# MD5 Fingerprint: a1:f3:5f:43:c6:34:9b:da:bf:8c:7e:05:53:ad:96:e2 +# SHA1 Fingerprint: a3:a1:b0:6f:24:61:23:4a:e3:36:a5:c2:37:fc:a6:ff:dd:f0:d7:3a +# SHA256 Fingerprint: d4:3a:f9:b3:54:73:75:5c:96:84:fc:06:d7:d8:cb:70:ee:5c:28:e7:73:fb:29:4e:b4:1e:e7:17:22:92:4d:24 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF +eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx +MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV +BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog +D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS +sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop +O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk +sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi +c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj +VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz +KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ +TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G +sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs +1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD +fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN +l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR +ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ +VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 +c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp +4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s +t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj +2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO +vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C +xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx +cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM +fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax +-----END CERTIFICATE----- + +# Issuer: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 +# Subject: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 +# Label: "Certigna Root CA" +# Serial: 269714418870597844693661054334862075617 +# MD5 Fingerprint: 0e:5c:30:62:27:eb:5b:bc:d7:ae:62:ba:e9:d5:df:77 +# SHA1 Fingerprint: 2d:0d:52:14:ff:9e:ad:99:24:01:74:20:47:6e:6c:85:27:27:f5:43 +# SHA256 Fingerprint: d4:8d:3d:23:ee:db:50:a4:59:e5:51:97:60:1c:27:77:4b:9d:7b:18:c9:4d:5a:05:95:11:a1:02:50:b9:31:68 +-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw +WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw +MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x +MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD +VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX +BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO +ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M +CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu +I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm +TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh +C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf +ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz +IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT +Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k +JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 +hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB +GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov +L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo +dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr +aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq +hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L +6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG +HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 +0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB +lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi +o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 +gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v +faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 +Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh +jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw +3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE----- + +# Issuer: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI +# Subject: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI +# Label: "emSign Root CA - G1" +# Serial: 235931866688319308814040 +# MD5 Fingerprint: 9c:42:84:57:dd:cb:0b:a7:2e:95:ad:b6:f3:da:bc:ac +# SHA1 Fingerprint: 8a:c7:ad:8f:73:ac:4e:c1:b5:75:4d:a5:40:f4:fc:cf:7c:b5:8e:8c +# SHA256 Fingerprint: 40:f6:af:03:46:a9:9a:a1:cd:1d:55:5a:4e:9c:ce:62:c7:f9:63:46:03:ee:40:66:15:83:3d:c8:c8:d0:03:67 +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD +VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU +ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH +MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO +MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv +Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz +f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO +8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq +d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM +tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt +Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB +o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x +PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM +wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d +GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH +6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby +RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- + +# Issuer: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI +# Subject: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI +# Label: "emSign ECC Root CA - G3" +# Serial: 287880440101571086945156 +# MD5 Fingerprint: ce:0b:72:d1:9f:88:8e:d0:50:03:e8:e3:b8:8b:67:40 +# SHA1 Fingerprint: 30:43:fa:4f:f2:57:dc:a0:c3:80:ee:2e:58:ea:78:b2:3f:e6:bb:c1 +# SHA256 Fingerprint: 86:a1:ec:ba:08:9c:4a:8d:3b:be:27:34:c6:12:ba:34:1d:81:3e:04:3c:f9:e8:a8:62:cd:5c:57:a3:6b:be:6b +-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG +EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo +bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ +TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s +b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 +WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS +fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB +zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq +hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB +CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD ++JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE----- + +# Issuer: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI +# Subject: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI +# Label: "emSign Root CA - C1" +# Serial: 825510296613316004955058 +# MD5 Fingerprint: d8:e3:5d:01:21:fa:78:5a:b0:df:ba:d2:ee:2a:5f:68 +# SHA1 Fingerprint: e7:2e:f1:df:fc:b2:09:28:cf:5d:d4:d5:67:37:b1:51:cb:86:4f:01 +# SHA256 Fingerprint: 12:56:09:aa:30:1d:a0:a2:49:b9:7a:82:39:cb:6a:34:21:6f:44:dc:ac:9f:39:54:b1:42:92:f2:e8:c8:60:8f +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG +A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg +SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v +dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ +BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ +HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH +3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH +GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c +xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 +aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq +TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 +/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 +kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG +YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT ++xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo +WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE----- + +# Issuer: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI +# Subject: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI +# Label: "emSign ECC Root CA - C3" +# Serial: 582948710642506000014504 +# MD5 Fingerprint: 3e:53:b3:a3:81:ee:d7:10:f8:d3:b0:1d:17:92:f5:d5 +# SHA1 Fingerprint: b6:af:43:c2:9b:81:53:7d:f6:ef:6b:c3:1f:1f:60:15:0c:ee:48:66 +# SHA256 Fingerprint: bc:4d:80:9b:15:18:9d:78:db:3e:1d:8c:f4:f9:72:6a:79:5d:a1:64:3c:a5:f1:35:8e:1d:db:0e:dc:0d:7e:b3 +-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG +EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx +IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND +IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci +MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti +sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O +BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB +Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c +3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J +0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE----- + +# Issuer: CN=Hongkong Post Root CA 3 O=Hongkong Post +# Subject: CN=Hongkong Post Root CA 3 O=Hongkong Post +# Label: "Hongkong Post Root CA 3" +# Serial: 46170865288971385588281144162979347873371282084 +# MD5 Fingerprint: 11:fc:9f:bd:73:30:02:8a:fd:3f:f3:58:b9:cb:20:f0 +# SHA1 Fingerprint: 58:a2:d0:ec:20:52:81:5b:c1:f3:f8:64:02:24:4e:c2:8e:02:4b:02 +# SHA256 Fingerprint: 5a:2f:c0:3f:0c:83:b0:90:bb:fa:40:60:4b:09:88:44:6c:76:36:18:3d:f9:84:6e:17:10:1a:44:7f:b8:ef:d6 +-----BEGIN CERTIFICATE----- +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 +mpv0 +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - G4" +# Serial: 289383649854506086828220374796556676440 +# MD5 Fingerprint: 89:53:f1:83:23:b7:7c:8e:05:f1:8c:71:38:4e:1f:88 +# SHA1 Fingerprint: 14:88:4e:86:26:37:b0:26:af:59:62:5c:40:77:ec:35:29:ba:96:01 +# SHA256 Fingerprint: db:35:17:d1:f6:73:2a:2d:5a:b9:7c:53:3e:c7:07:79:ee:32:70:a6:2f:b4:ac:42:38:37:24:60:e6:f0:1e:88 +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw +gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL +Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg +MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw +BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 +MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 +c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ +bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ +2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E +T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j +5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM +C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T +DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX +wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A +2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm +nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 +dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl +N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj +c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS +5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS +Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr +hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/ +B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI +AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw +H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+ +b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk +2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol +IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk +5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY +n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== +-----END CERTIFICATE----- + +# Issuer: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation +# Subject: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation +# Label: "Microsoft ECC Root Certificate Authority 2017" +# Serial: 136839042543790627607696632466672567020 +# MD5 Fingerprint: dd:a1:03:e6:4a:93:10:d1:bf:f0:19:42:cb:fe:ed:67 +# SHA1 Fingerprint: 99:9a:64:c3:7f:f4:7d:9f:ab:95:f1:47:69:89:14:60:ee:c4:c3:c5 +# SHA256 Fingerprint: 35:8d:f3:9d:76:4a:f9:e1:b7:66:e9:c9:72:df:35:2e:e1:5c:fa:c2:27:af:6a:d1:d7:0e:8e:4a:6e:dc:ba:02 +-----BEGIN CERTIFICATE----- +MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD +VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw +MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV +UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy +b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR +ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb +hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 +FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV +L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB +iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= +-----END CERTIFICATE----- + +# Issuer: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation +# Subject: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation +# Label: "Microsoft RSA Root Certificate Authority 2017" +# Serial: 40975477897264996090493496164228220339 +# MD5 Fingerprint: 10:ff:00:ff:cf:c9:f8:c7:7a:c0:ee:35:8e:c9:0f:47 +# SHA1 Fingerprint: 73:a5:e6:4a:3b:ff:83:16:ff:0e:dc:cc:61:8a:90:6e:4e:ae:4d:74 +# SHA256 Fingerprint: c7:41:f7:0f:4b:2a:8d:88:bf:2e:71:c1:41:22:ef:53:ef:10:eb:a0:cf:a5:e6:4c:fa:20:f4:18:85:30:73:e0 +-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl +MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw +NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG +EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N +aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ +Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 +ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 +HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm +gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ +jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc +aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG +YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 +W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K +UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH ++FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q +W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC +LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC +gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 +tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh +SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 +TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 +pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR +xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp +GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 +dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN +AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB +RA+GsCyRxj3qrg+E +-----END CERTIFICATE----- + +# Issuer: CN=e-Szigno Root CA 2017 O=Microsec Ltd. +# Subject: CN=e-Szigno Root CA 2017 O=Microsec Ltd. +# Label: "e-Szigno Root CA 2017" +# Serial: 411379200276854331539784714 +# MD5 Fingerprint: de:1f:f6:9e:84:ae:a7:b4:21:ce:1e:58:7d:d1:84:98 +# SHA1 Fingerprint: 89:d4:83:03:4f:9e:9a:48:80:5f:72:37:d4:a9:a6:ef:cb:7c:1f:d1 +# SHA256 Fingerprint: be:b0:0b:30:83:9b:9b:c3:2c:32:e4:44:79:05:95:06:41:f2:64:21:b1:5e:d0:89:19:8b:51:8a:e2:ea:1b:99 +-----BEGIN CERTIFICATE----- +MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV +BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk +LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv +b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ +BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg +THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v +IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv +xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H +Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB +eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo +jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ ++efcMQ== +-----END CERTIFICATE----- + +# Issuer: O=CERTSIGN SA OU=certSIGN ROOT CA G2 +# Subject: O=CERTSIGN SA OU=certSIGN ROOT CA G2 +# Label: "certSIGN Root CA G2" +# Serial: 313609486401300475190 +# MD5 Fingerprint: 8c:f1:75:8a:c6:19:cf:94:b7:f7:65:20:87:c3:97:c7 +# SHA1 Fingerprint: 26:f9:93:b4:ed:3d:28:27:b0:b9:4b:a7:e9:15:1d:a3:8d:92:e5:32 +# SHA256 Fingerprint: 65:7c:fe:2f:a7:3f:aa:38:46:25:71:f3:32:a2:36:3a:46:fc:e7:02:09:51:71:07:02:cd:fb:b6:ee:da:33:05 +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV +BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g +Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ +BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ +R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF +dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw +vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ +uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp +n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs +cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW +xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P +rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF +DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx +DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy +LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C +eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ +d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq +kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC +b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl +qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 +OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c +NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk +ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO +pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj +03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk +PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE +1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX +QRBdJ3NghVdJIgc= +-----END CERTIFICATE----- + +# Issuer: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. +# Subject: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. +# Label: "Trustwave Global Certification Authority" +# Serial: 1846098327275375458322922162 +# MD5 Fingerprint: f8:1c:18:2d:2f:ba:5f:6d:a1:6c:bc:c7:ab:91:c7:0e +# SHA1 Fingerprint: 2f:8f:36:4f:e1:58:97:44:21:59:87:a5:2a:9a:d0:69:95:26:7f:b5 +# SHA256 Fingerprint: 97:55:20:15:f5:dd:fc:3c:87:88:c0:06:94:45:55:40:88:94:45:00:84:f1:00:86:70:86:bc:1a:2b:b5:8d:c8 +-----BEGIN CERTIFICATE----- +MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw +CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x +ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1 +c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx +OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI +SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn +swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu +7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8 +1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW +80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP +JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l +RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw +hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10 +coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc +BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n +twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud +DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W +0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe +uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q +lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB +aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE +sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT +MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe +qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh +VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8 +h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9 +EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK +yeC2nOnOcXHebD8WpHk= +-----END CERTIFICATE----- + +# Issuer: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. +# Subject: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. +# Label: "Trustwave Global ECC P256 Certification Authority" +# Serial: 4151900041497450638097112925 +# MD5 Fingerprint: 5b:44:e3:8d:5d:36:86:26:e8:0d:05:d2:59:a7:83:54 +# SHA1 Fingerprint: b4:90:82:dd:45:0c:be:8b:5b:b1:66:d3:e2:a4:08:26:cd:ed:42:cf +# SHA256 Fingerprint: 94:5b:bc:82:5e:a5:54:f4:89:d1:fd:51:a7:3d:df:2e:a6:24:ac:70:19:a0:52:05:22:5c:22:a7:8c:cf:a8:b4 +-----BEGIN CERTIFICATE----- +MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG +SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN +FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w +DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw +CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh +DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 +-----END CERTIFICATE----- + +# Issuer: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. +# Subject: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. +# Label: "Trustwave Global ECC P384 Certification Authority" +# Serial: 2704997926503831671788816187 +# MD5 Fingerprint: ea:cf:60:c4:3b:b9:15:29:40:a1:97:ed:78:27:93:d6 +# SHA1 Fingerprint: e7:f3:a3:c8:cf:6f:c3:04:2e:6d:0e:67:32:c5:9e:68:95:0d:5e:d2 +# SHA256 Fingerprint: 55:90:38:59:c8:c0:c3:eb:b8:75:9e:ce:4e:25:57:22:5f:f5:75:8b:bd:38:eb:d4:82:76:60:1e:1b:d5:80:97 +-----BEGIN CERTIFICATE----- +MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB +BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ +j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF +1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G +A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3 +AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC +MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu +Sw== +-----END CERTIFICATE----- + +# Issuer: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. +# Subject: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. +# Label: "NAVER Global Root Certification Authority" +# Serial: 9013692873798656336226253319739695165984492813 +# MD5 Fingerprint: c8:7e:41:f6:25:3b:f5:09:b3:17:e8:46:3d:bf:d0:9b +# SHA1 Fingerprint: 8f:6b:f2:a9:27:4a:da:14:a0:c4:f4:8e:61:27:f9:c0:1e:78:5d:d1 +# SHA256 Fingerprint: 88:f4:38:dc:f8:ff:d1:fa:8f:42:91:15:ff:e5:f8:2a:e1:e0:6e:0c:70:c3:75:fa:ad:71:7b:34:a4:9e:72:65 +-----BEGIN CERTIFICATE----- +MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM +BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG +T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx +CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD +b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA +iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH +38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE +HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz +kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP +szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq +vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf +nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG +YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo +0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a +CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K +AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I +36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN +qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj +cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm ++LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL +hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe +lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7 +p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8 +piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR +LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX +5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO +dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul +9XXeifdy +-----END CERTIFICATE----- + +# Issuer: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres +# Subject: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres +# Label: "AC RAIZ FNMT-RCM SERVIDORES SEGUROS" +# Serial: 131542671362353147877283741781055151509 +# MD5 Fingerprint: 19:36:9c:52:03:2f:d2:d1:bb:23:cc:dd:1e:12:55:bb +# SHA1 Fingerprint: 62:ff:d9:9e:c0:65:0d:03:ce:75:93:d2:ed:3f:2d:32:c9:e3:e5:4a +# SHA256 Fingerprint: 55:41:53:b1:3d:2c:f9:dd:b7:53:bf:be:1a:4e:0a:e0:8d:0a:a4:18:70:58:fe:60:a2:b8:62:b2:e4:b8:7b:cb +-----BEGIN CERTIFICATE----- +MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw +CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw +FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S +Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5 +MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL +DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS +QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH +sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK +Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu +SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC +MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy +v+c= +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign Root R46 O=GlobalSign nv-sa +# Subject: CN=GlobalSign Root R46 O=GlobalSign nv-sa +# Label: "GlobalSign Root R46" +# Serial: 1552617688466950547958867513931858518042577 +# MD5 Fingerprint: c4:14:30:e4:fa:66:43:94:2a:6a:1b:24:5f:19:d0:ef +# SHA1 Fingerprint: 53:a2:b0:4b:ca:6b:d6:45:e6:39:8a:8e:c4:0d:d2:bf:77:c3:a2:90 +# SHA256 Fingerprint: 4f:a3:12:6d:8d:3a:11:d1:c4:85:5a:4f:80:7c:ba:d6:cf:91:9d:3a:5a:88:b0:3b:ea:2c:63:72:d9:3c:40:c9 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA +MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD +VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy +MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt +c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ +OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG +vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud +316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo +0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE +y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF +zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE ++cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN +I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs +x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa +ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC +4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 +7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti +2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk +pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF +FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt +rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk +ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 +u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP +4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 +N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 +vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign Root E46 O=GlobalSign nv-sa +# Subject: CN=GlobalSign Root E46 O=GlobalSign nv-sa +# Label: "GlobalSign Root E46" +# Serial: 1552617690338932563915843282459653771421763 +# MD5 Fingerprint: b5:b8:66:ed:de:08:83:e3:c9:e2:01:34:06:ac:51:6f +# SHA1 Fingerprint: 39:b4:6c:d5:fe:80:06:eb:e2:2f:4a:bb:08:33:a0:af:db:b9:dd:84 +# SHA256 Fingerprint: cb:b9:c4:4d:84:b8:04:3e:10:50:ea:31:a6:9f:51:49:55:d7:bf:d2:e2:c6:b4:93:01:01:9a:d6:1d:9f:50:58 +-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx +CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD +ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw +MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex +HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq +R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd +yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ +7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 ++RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= +-----END CERTIFICATE----- + +# Issuer: CN=GLOBALTRUST 2020 O=e-commerce monitoring GmbH +# Subject: CN=GLOBALTRUST 2020 O=e-commerce monitoring GmbH +# Label: "GLOBALTRUST 2020" +# Serial: 109160994242082918454945253 +# MD5 Fingerprint: 8a:c7:6f:cb:6d:e3:cc:a2:f1:7c:83:fa:0e:78:d7:e8 +# SHA1 Fingerprint: d0:67:c1:13:51:01:0c:aa:d0:c7:6a:65:37:31:16:26:4f:53:71:a2 +# SHA256 Fingerprint: 9a:29:6a:51:82:d1:d4:51:a2:e3:7f:43:9b:74:da:af:a2:67:52:33:29:f9:0f:9a:0d:20:07:c3:34:e2:3c:9a +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkG +A1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkw +FwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYx +MDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9u +aXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMIICIjANBgkq +hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWiD59b +RatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9Z +YybNpyrOVPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3 +QWPKzv9pj2gOlTblzLmMCcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPw +yJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCmfecqQjuCgGOlYx8ZzHyyZqjC0203b+J+ +BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKAA1GqtH6qRNdDYfOiaxaJ +SaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9ORJitHHmkH +r96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj0 +4KlGDfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9Me +dKZssCz3AwyIDMvUclOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIw +q7ejMZdnrY8XD2zHc+0klGvIg5rQmjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2 +nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1UdIwQYMBaAFNwu +H9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA +VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJC +XtzoRlgHNQIw4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd +6IwPS3BD0IL/qMy/pJTAvoe9iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf ++I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS8cE54+X1+NZK3TTN+2/BT+MAi1bi +kvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2HcqtbepBEX4tdJP7 +wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxSvTOB +TI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6C +MUO+1918oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn +4rnvyOL2NSl6dPrFf4IFYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+I +aFvowdlxfv1k7/9nR4hYJS8+hge9+6jlgqispdNpQ80xiEmEU5LAsTkbOYMBMMTy +qfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== +-----END CERTIFICATE----- + +# Issuer: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz +# Subject: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz +# Label: "ANF Secure Server Root CA" +# Serial: 996390341000653745 +# MD5 Fingerprint: 26:a6:44:5a:d9:af:4e:2f:b2:1d:b6:65:b0:4e:e8:96 +# SHA1 Fingerprint: 5b:6e:68:d0:cc:15:b6:a0:5f:1e:c1:5f:ae:02:fc:6b:2f:5d:6f:74 +# SHA256 Fingerprint: fb:8f:ec:75:91:69:b9:10:6b:1e:51:16:44:c6:18:c5:13:04:37:3f:6c:06:43:08:8d:8b:ef:fd:1b:99:75:99 +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Subject: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Label: "Certum EC-384 CA" +# Serial: 160250656287871593594747141429395092468 +# MD5 Fingerprint: b6:65:b3:96:60:97:12:a1:ec:4e:e1:3d:a3:c6:c9:f1 +# SHA1 Fingerprint: f3:3e:78:3c:ac:df:f4:a2:cc:ac:67:55:69:56:d7:e5:16:3c:e1:ed +# SHA256 Fingerprint: 6b:32:80:85:62:53:18:aa:50:d1:73:c9:8d:8b:da:09:d5:7e:27:41:3d:11:4c:f7:87:a0:f5:d0:6c:03:0c:f6 +-----BEGIN CERTIFICATE----- +MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw +CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw +JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT +EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0 +WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT +LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX +BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE +KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm +Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8 +EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J +UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn +nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Root CA" +# Serial: 40870380103424195783807378461123655149 +# MD5 Fingerprint: 51:e1:c2:e7:fe:4c:84:af:59:0e:2f:f4:54:6f:ea:29 +# SHA1 Fingerprint: c8:83:44:c0:18:ae:9f:cc:f1:87:b7:8f:22:d1:c5:d7:45:84:ba:e5 +# SHA256 Fingerprint: fe:76:96:57:38:55:77:3e:37:a9:5e:7a:d4:d9:cc:96:c3:01:57:c1:5d:31:76:5b:a9:b1:57:04:e1:ae:78:fd +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique +# Subject: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique +# Label: "TunTrust Root CA" +# Serial: 108534058042236574382096126452369648152337120275 +# MD5 Fingerprint: 85:13:b9:90:5b:36:5c:b6:5e:b8:5a:f8:e0:31:57:b4 +# SHA1 Fingerprint: cf:e9:70:84:0f:e0:73:0f:9d:f6:0c:7f:2c:4b:ee:20:46:34:9c:bb +# SHA256 Fingerprint: 2e:44:10:2a:b5:8c:b8:54:19:45:1c:8e:19:d9:ac:f3:66:2c:af:bc:61:4b:6a:53:96:0a:30:f7:d0:e2:eb:41 +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL +BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg +Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv +b3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQwNDI2MDg1NzU2WjBhMQswCQYDVQQG +EwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBDZXJ0aWZpY2F0aW9u +IEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZ +n56eY+hz2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd +2JQDoOw05TDENX37Jk0bbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgF +VwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZ +GoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAdgjH8KcwAWJeRTIAAHDOF +li/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViWVSHbhlnU +r8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2 +eY8fTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIb +MlEsPvLfe/ZdeikZjuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISg +jwBUFfyRbVinljvrS5YnzWuioYasDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB +7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwSVXAkPcvCFDVDXSdOvsC9qnyW +5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI04Y+oXNZtPdE +ITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 +90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+z +xiD2BkewhpMl0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYu +QEkHDVneixCwSQXi/5E/S7fdAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4 +FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRYYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH +22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJpadbGNjHh/PqAulxP +xOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65xxBzn +dFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5 +Xc0yGYuPjCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7b +nV2UqL1g52KAdoGDDIzMMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQ +CvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9zZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZH +u/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3rAZ3r2OvEhJn7wAzMMujj +d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= +-----END CERTIFICATE----- + +# Issuer: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA +# Subject: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA +# Label: "HARICA TLS RSA Root CA 2021" +# Serial: 76817823531813593706434026085292783742 +# MD5 Fingerprint: 65:47:9b:58:86:dd:2c:f0:fc:a2:84:1f:1e:96:c4:91 +# SHA1 Fingerprint: 02:2d:05:82:fa:88:ce:14:0c:06:79:de:7f:14:10:e9:45:d7:a5:6d +# SHA256 Fingerprint: d9:5d:0e:8e:da:79:52:5b:f9:be:b1:1b:14:d2:10:0d:32:94:98:5f:0c:62:d9:fa:bd:9c:d9:99:ec:cb:7b:1d +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBs +MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0Eg +Um9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUzOFoXDTQ1MDIxMzEwNTUzN1owbDEL +MAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl +YXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNBIFJv +b3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569l +mwVnlskNJLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE +4VGC/6zStGndLuwRo0Xua2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uv +a9of08WRiFukiZLRgeaMOVig1mlDqa2YUlhu2wr7a89o+uOkXjpFc5gH6l8Cct4M +pbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K5FrZx40d/JiZ+yykgmvw +Kh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEvdmn8kN3b +LW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcY +AuUR0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqB +AGMUuTNe3QvboEUHGjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYq +E613TBoYm5EPWNgGVMWX+Ko/IIqmhaZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHr +W2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQCPxrvrNQKlr9qEgYRtaQQJKQ +CoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAU +X15QvWiWkKQUEapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3 +f5Z2EMVGpdAgS1D0NTsY9FVqQRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxaja +H6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxDQpSbIPDRzbLrLFPCU3hKTwSUQZqP +JzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcRj88YxeMn/ibvBZ3P +zzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5vZSt +jBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0 +/L5H9MG0qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pT +BGIBnfHAT+7hOtSLIBD6Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79 +aPib8qXPMThcFarmlwDB31qlpzmq6YR/PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YW +xw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnnkf3/W9b3raYvAwtt41dU +63ZTGI0RmLo= +-----END CERTIFICATE----- + +# Issuer: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA +# Subject: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA +# Label: "HARICA TLS ECC Root CA 2021" +# Serial: 137515985548005187474074462014555733966 +# MD5 Fingerprint: ae:f7:4c:e5:66:35:d1:b7:9b:8c:22:93:74:d3:4b:b0 +# SHA1 Fingerprint: bc:b0:c1:9d:e9:98:92:70:19:38:57:e9:8d:a7:b4:5d:6e:ee:01:48 +# SHA256 Fingerprint: 3f:99:cc:47:4a:cf:ce:4d:fe:d5:87:94:66:5e:47:8d:15:47:73:9f:2e:78:0f:1b:b4:ca:9b:13:30:97:d4:01 +-----BEGIN CERTIFICATE----- +MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw +CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh +cmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9v +dCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoXDTQ1MDIxMzExMDEwOVowbDELMAkG +A1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj +aCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJvb3Qg +Q0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7 +KKrxcm1lAEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9Y +STHMmE5gEYd103KUkE+bECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQD +AgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAircJRQO9gcS3ujwLEXQNw +SaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/QwCZ61IygN +nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps +-----END CERTIFICATE----- diff --git a/openpype/vendor/python/python_2/certifi/core.py b/openpype/vendor/python/python_2/certifi/core.py new file mode 100644 index 0000000000..5d2b8cd32f --- /dev/null +++ b/openpype/vendor/python/python_2/certifi/core.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- + +""" +certifi.py +~~~~~~~~~~ + +This module returns the installation location of cacert.pem or its contents. +""" +import os + +try: + from importlib.resources import path as get_path, read_text + + _CACERT_CTX = None + _CACERT_PATH = None + + def where(): + # This is slightly terrible, but we want to delay extracting the file + # in cases where we're inside of a zipimport situation until someone + # actually calls where(), but we don't want to re-extract the file + # on every call of where(), so we'll do it once then store it in a + # global variable. + global _CACERT_CTX + global _CACERT_PATH + if _CACERT_PATH is None: + # This is slightly janky, the importlib.resources API wants you to + # manage the cleanup of this file, so it doesn't actually return a + # path, it returns a context manager that will give you the path + # when you enter it and will do any cleanup when you leave it. In + # the common case of not needing a temporary file, it will just + # return the file system location and the __exit__() is a no-op. + # + # We also have to hold onto the actual context manager, because + # it will do the cleanup whenever it gets garbage collected, so + # we will also store that at the global level as well. + _CACERT_CTX = get_path("certifi", "cacert.pem") + _CACERT_PATH = str(_CACERT_CTX.__enter__()) + + return _CACERT_PATH + + +except ImportError: + # This fallback will work for Python versions prior to 3.7 that lack the + # importlib.resources module but relies on the existing `where` function + # so won't address issues with environments like PyOxidizer that don't set + # __file__ on modules. + def read_text(_module, _path, encoding="ascii"): + with open(where(), "r", encoding=encoding) as data: + return data.read() + + # If we don't have importlib.resources, then we will just do the old logic + # of assuming we're on the filesystem and munge the path directly. + def where(): + f = os.path.dirname(__file__) + + return os.path.join(f, "cacert.pem") + + +def contents(): + return read_text("certifi", "cacert.pem", encoding="ascii") From e2717ac9636154f0b8cfc733dd7bc45fd86589db Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 8 Jun 2022 16:56:09 +0200 Subject: [PATCH 346/350] updated poetry lock file --- poetry.lock | 870 +++++++++++++++++++++++++++++----------------------- 1 file changed, 493 insertions(+), 377 deletions(-) diff --git a/poetry.lock b/poetry.lock index a79c865a9e..47509f334e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -94,7 +94,7 @@ python-dateutil = ">=2.7.0" [[package]] name = "astroid" -version = "2.9.3" +version = "2.11.5" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false @@ -104,7 +104,7 @@ python-versions = ">=3.6.2" lazy-object-proxy = ">=1.4.0" typed-ast = {version = ">=1.4.0,<2.0", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""} -wrapt = ">=1.11,<1.14" +wrapt = ">=1.11,<2" [[package]] name = "async-timeout" @@ -172,7 +172,7 @@ pytz = ">=2015.7" [[package]] name = "bcrypt" -version = "3.2.0" +version = "3.2.2" description = "Modern password hashing for your software and your servers" category = "main" optional = false @@ -180,7 +180,6 @@ python-versions = ">=3.6" [package.dependencies] cffi = ">=1.1" -six = ">=1.4.1" [package.extras] tests = ["pytest (>=3.2.1,!=3.3.0)"] @@ -201,7 +200,7 @@ wcwidth = ">=0.1.4" [[package]] name = "cachetools" -version = "5.0.0" +version = "5.2.0" description = "Extensible memoizing collections and decorators" category = "main" optional = false @@ -209,11 +208,11 @@ python-versions = "~=3.7" [[package]] name = "certifi" -version = "2021.10.8" +version = "2022.5.18.1" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false -python-versions = "*" +python-versions = ">=3.6" [[package]] name = "cffi" @@ -226,17 +225,9 @@ python-versions = "*" [package.dependencies] pycparser = "*" -[[package]] -name = "chardet" -version = "4.0.0" -description = "Universal encoding detector for Python 2 and 3" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - [[package]] name = "charset-normalizer" -version = "2.0.11" +version = "2.0.12" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = false @@ -295,21 +286,21 @@ python-versions = "*" [[package]] name = "coverage" -version = "6.3.1" +version = "6.4.1" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" [package.dependencies] -tomli = {version = "*", optional = true, markers = "extra == \"toml\""} +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} [package.extras] toml = ["tomli"] [[package]] name = "cryptography" -version = "36.0.1" +version = "37.0.2" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "main" optional = false @@ -324,7 +315,7 @@ docstest = ["pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] sdist = ["setuptools_rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["pytest (>=6.2.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] +test = ["pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] [[package]] name = "cx-freeze" @@ -346,9 +337,34 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "deprecated" +version = "1.2.13" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +wrapt = ">=1.10,<2" + +[package.extras] +dev = ["tox", "bump2version (<1)", "sphinx (<2)", "importlib-metadata (<3)", "importlib-resources (<4)", "configparser (<5)", "sphinxcontrib-websupport (<2)", "zipp (<2)", "PyTest (<5)", "PyTest-Cov (<2.6)", "pytest", "pytest-cov"] + +[[package]] +name = "dill" +version = "0.3.5.1" +description = "serialize all of python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" + +[package.extras] +graph = ["objgraph (>=1.7.2)"] + [[package]] name = "dnspython" -version = "2.2.0" +version = "2.2.1" description = "DNS toolkit" category = "main" optional = false @@ -364,7 +380,7 @@ wmi = ["wmi (>=1.5.1,<2.0.0)"] [[package]] name = "docutils" -version = "0.18.1" +version = "0.17.1" description = "Docutils -- Python Documentation Utilities" category = "dev" optional = false @@ -372,7 +388,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "dropbox" -version = "11.26.0" +version = "11.31.0" description = "Official Dropbox API Client" category = "main" optional = false @@ -397,7 +413,7 @@ prefixed = ">=0.3.2" [[package]] name = "evdev" -version = "1.4.0" +version = "1.5.0" description = "Bindings to the Linux input handling subsystem" category = "main" optional = false @@ -451,6 +467,23 @@ category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +[[package]] +name = "gazu" +version = "0.8.28" +description = "Gazu is a client for Zou, the API to store the data of your CG production." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +deprecated = "1.2.13" +python-socketio = {version = "4.6.1", extras = ["client"], markers = "python_version >= \"3.5\""} +requests = ">=2.25.1,<=2.27.1" + +[package.extras] +dev = ["wheel"] +test = ["pytest-cov (==2.12.1)", "requests-mock (==1.9.3)", "pytest (==4.6.11)", "pytest (==6.1.2)", "pytest (==6.2.5)", "black (==21.12b0)", "pre-commit (==2.17.0)"] + [[package]] name = "gitdb" version = "4.0.9" @@ -464,7 +497,7 @@ smmap = ">=3.0.1,<6" [[package]] name = "gitpython" -version = "3.1.26" +version = "3.1.27" description = "GitPython is a python library used to interact with Git repositories" category = "dev" optional = false @@ -476,7 +509,7 @@ typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\"" [[package]] name = "google-api-core" -version = "2.4.0" +version = "2.8.1" description = "Google API client core library" category = "main" optional = false @@ -484,18 +517,18 @@ python-versions = ">=3.6" [package.dependencies] google-auth = ">=1.25.0,<3.0dev" -googleapis-common-protos = ">=1.52.0,<2.0dev" -protobuf = ">=3.12.0" +googleapis-common-protos = ">=1.56.2,<2.0dev" +protobuf = ">=3.15.0,<4.0.0dev" requests = ">=2.18.0,<3.0.0dev" [package.extras] grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio-status (>=1.33.2,<2.0dev)"] -grpcgcp = ["grpcio-gcp (>=0.2.2)"] -grpcio-gcp = ["grpcio-gcp (>=0.2.2)"] +grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0dev)"] +grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0dev)"] [[package]] name = "google-api-python-client" -version = "1.12.10" +version = "1.12.11" description = "Google API Client Library for Python" category = "main" optional = false @@ -511,7 +544,7 @@ uritemplate = ">=3.0.0,<4dev" [[package]] name = "google-auth" -version = "2.6.0" +version = "2.7.0" description = "Google Authentication Library" category = "main" optional = false @@ -525,6 +558,7 @@ six = ">=1.9.0" [package.extras] aiohttp = ["requests (>=2.20.0,<3.0.0dev)", "aiohttp (>=3.6.2,<4.0.0dev)"] +enterprise_cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"] pyopenssl = ["pyopenssl (>=20.0.0)"] reauth = ["pyu2f (>=0.1.5)"] @@ -543,21 +577,21 @@ six = "*" [[package]] name = "googleapis-common-protos" -version = "1.54.0" +version = "1.56.2" description = "Common protobufs used in Google APIs" category = "main" optional = false python-versions = ">=3.6" [package.dependencies] -protobuf = ">=3.12.0" +protobuf = ">=3.15.0,<4.0.0dev" [package.extras] -grpc = ["grpcio (>=1.0.0)"] +grpc = ["grpcio (>=1.0.0,<2.0.0dev)"] [[package]] name = "httplib2" -version = "0.20.2" +version = "0.20.4" description = "A comprehensive HTTP client library." category = "main" optional = false @@ -568,11 +602,11 @@ pyparsing = {version = ">=2.4.2,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.0.2 || >3.0 [[package]] name = "idna" -version = "2.10" +version = "3.3" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.5" [[package]] name = "imagesize" @@ -584,7 +618,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "importlib-metadata" -version = "4.10.1" +version = "4.11.4" description = "Read metadata from Python packages" category = "main" optional = false @@ -595,9 +629,9 @@ typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] perf = ["ipython"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] [[package]] name = "iniconfig" @@ -663,7 +697,7 @@ i18n = ["Babel (>=0.8)"] [[package]] name = "jinxed" -version = "1.1.0" +version = "1.2.0" description = "Jinxed Terminal Library" category = "main" optional = false @@ -777,7 +811,7 @@ pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" [[package]] name = "paramiko" -version = "2.10.1" +version = "2.11.0" description = "SSH2 protocol library" category = "main" optional = false @@ -809,7 +843,7 @@ testing = ["docopt", "pytest (<6.0.0)"] [[package]] name = "pathlib2" -version = "2.3.6" +version = "2.3.7.post1" description = "Object-oriented filesystem paths" category = "main" optional = false @@ -820,23 +854,27 @@ six = "*" [[package]] name = "pillow" -version = "9.0.1" +version = "9.1.1" description = "Python Imaging Library (Fork)" category = "main" optional = false python-versions = ">=3.7" +[package.extras] +docs = ["olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinx-rtd-theme (>=1.0)", "sphinxext-opengraph"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] + [[package]] name = "platformdirs" -version = "2.4.1" +version = "2.5.2" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" [package.extras] -docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] +docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"] +test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"] [[package]] name = "pluggy" @@ -958,29 +996,33 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pygments" -version = "2.11.2" +version = "2.12.0" description = "Pygments is a syntax highlighting package written in Python." category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [[package]] name = "pylint" -version = "2.12.2" +version = "2.13.9" description = "python code static checker" category = "dev" optional = false python-versions = ">=3.6.2" [package.dependencies] -astroid = ">=2.9.0,<2.10" +astroid = ">=2.11.5,<=2.12.0-dev0" colorama = {version = "*", markers = "sys_platform == \"win32\""} +dill = ">=0.2" isort = ">=4.2.5,<6" -mccabe = ">=0.6,<0.7" +mccabe = ">=0.6,<0.8" platformdirs = ">=2.2.0" -toml = ">=0.9.2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} +[package.extras] +testutil = ["gitpython (>3)"] + [[package]] name = "pymongo" version = "3.12.3" @@ -1031,7 +1073,7 @@ six = "*" [[package]] name = "pyobjc-core" -version = "8.2" +version = "8.5" description = "Python<->ObjC Interoperability Module" category = "main" optional = false @@ -1039,39 +1081,39 @@ python-versions = ">=3.6" [[package]] name = "pyobjc-framework-applicationservices" -version = "8.2" +version = "8.5" description = "Wrappers for the framework ApplicationServices on macOS" category = "main" optional = false python-versions = ">=3.6" [package.dependencies] -pyobjc-core = ">=8.2" -pyobjc-framework-Cocoa = ">=8.2" -pyobjc-framework-Quartz = ">=8.2" +pyobjc-core = ">=8.5" +pyobjc-framework-Cocoa = ">=8.5" +pyobjc-framework-Quartz = ">=8.5" [[package]] name = "pyobjc-framework-cocoa" -version = "8.2" +version = "8.5" description = "Wrappers for the Cocoa frameworks on macOS" category = "main" optional = false python-versions = ">=3.6" [package.dependencies] -pyobjc-core = ">=8.2" +pyobjc-core = ">=8.5" [[package]] name = "pyobjc-framework-quartz" -version = "8.2" +version = "8.5" description = "Wrappers for the Quartz frameworks on macOS" category = "main" optional = false python-versions = ">=3.6" [package.dependencies] -pyobjc-core = ">=8.2" -pyobjc-framework-Cocoa = ">=8.2" +pyobjc-core = ">=8.5" +pyobjc-framework-Cocoa = ">=8.5" [[package]] name = "pyparsing" @@ -1154,6 +1196,39 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" [package.dependencies] six = ">=1.5" +[[package]] +name = "python-engineio" +version = "3.14.2" +description = "Engine.IO server" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +six = ">=1.9.0" + +[package.extras] +asyncio_client = ["aiohttp (>=3.4)"] +client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] + +[[package]] +name = "python-socketio" +version = "4.6.1" +description = "Socket.IO server" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +python-engineio = ">=3.13.0,<4" +requests = {version = ">=2.21.0", optional = true, markers = "extra == \"client\""} +six = ">=1.9.0" +websocket-client = {version = ">=0.54.0", optional = true, markers = "extra == \"client\""} + +[package.extras] +asyncio_client = ["aiohttp (>=3.4)", "websockets (>=7.0)"] +client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] + [[package]] name = "python-xlib" version = "0.31" @@ -1175,7 +1250,7 @@ python-versions = "*" [[package]] name = "pytz" -version = "2021.3" +version = "2022.1" description = "World timezone definitions, modern and historical" category = "dev" optional = false @@ -1199,7 +1274,7 @@ python-versions = "*" [[package]] name = "qt.py" -version = "1.3.6" +version = "1.3.7" description = "Python 2 & 3 compatibility wrapper around all Qt bindings - PySide, PySide2, PyQt4 and PyQt5." category = "main" optional = false @@ -1240,21 +1315,21 @@ sphinx = ">=1.3.1" [[package]] name = "requests" -version = "2.25.1" +version = "2.27.1" description = "Python HTTP for Humans." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [package.dependencies] certifi = ">=2017.4.17" -chardet = ">=3.0.2,<5" -idna = ">=2.5,<3" +charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} +idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} urllib3 = ">=1.21.1,<1.27" [package.extras] -security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] [[package]] name = "rsa" @@ -1269,7 +1344,7 @@ pyasn1 = ">=0.1.3" [[package]] name = "secretstorage" -version = "3.3.1" +version = "3.3.2" description = "Python bindings to FreeDesktop.org Secret Service API" category = "main" optional = false @@ -1297,7 +1372,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "slack-sdk" -version = "3.13.0" +version = "3.17.0" description = "The Slack API Platform SDK for Python" category = "main" optional = false @@ -1305,7 +1380,7 @@ python-versions = ">=3.6.0" [package.extras] optional = ["aiodns (>1.0)", "aiohttp (>=3.7.3,<4)", "boto3 (<=2)", "SQLAlchemy (>=1,<2)", "websockets (>=10,<11)", "websocket-client (>=1,<2)"] -testing = ["pytest (>=6.2.5,<7)", "pytest-asyncio (<1)", "Flask-Sockets (>=0.2,<1)", "Flask (>=1,<2)", "Werkzeug (<2)", "pytest-cov (>=2,<3)", "codecov (>=2,<3)", "flake8 (>=4,<5)", "black (==21.12b0)", "psutil (>=5,<6)", "databases (>=0.3)", "boto3 (<=2)", "moto (<2)"] +testing = ["pytest (>=6.2.5,<7)", "pytest-asyncio (<1)", "Flask-Sockets (>=0.2,<1)", "Flask (>=1,<2)", "Werkzeug (<2)", "itsdangerous (==1.1.0)", "Jinja2 (==3.0.3)", "pytest-cov (>=2,<3)", "codecov (>=2,<3)", "flake8 (>=4,<5)", "black (==22.3.0)", "click (==8.0.4)", "psutil (>=5,<6)", "databases (>=0.5)", "boto3 (<=2)", "moto (>=3,<4)"] [[package]] name = "smmap" @@ -1325,7 +1400,7 @@ python-versions = "*" [[package]] name = "speedcopy" -version = "2.1.2" +version = "2.1.4" description = "Replacement or alternative for python copyfile() utilizing server side copy on network shares for faster copying." category = "main" optional = false @@ -1333,18 +1408,19 @@ python-versions = "*" [[package]] name = "sphinx" -version = "3.5.3" +version = "5.0.1" description = "Python documentation generator" category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [package.dependencies] alabaster = ">=0.7,<0.8" babel = ">=1.3" colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.12" +docutils = ">=0.14,<0.19" imagesize = "*" +importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} Jinja2 = ">=2.3" packaging = "*" Pygments = ">=2.0" @@ -1352,19 +1428,19 @@ requests = ">=2.5.0" snowballstemmer = ">=1.1" sphinxcontrib-applehelp = "*" sphinxcontrib-devhelp = "*" -sphinxcontrib-htmlhelp = "*" +sphinxcontrib-htmlhelp = ">=2.0.0" sphinxcontrib-jsmath = "*" sphinxcontrib-qthelp = "*" -sphinxcontrib-serializinghtml = "*" +sphinxcontrib-serializinghtml = ">=1.1.5" [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.800)", "docutils-stubs"] -test = ["pytest", "pytest-cov", "html5lib", "cython", "typed-ast"] +lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.950)", "docutils-stubs", "types-typed-ast", "types-requests"] +test = ["pytest (>=4.6)", "html5lib", "cython", "typed-ast"] [[package]] name = "sphinx-qt-documentation" -version = "0.3" +version = "0.4" description = "Plugin for proper resolve intersphinx references for Qt elements" category = "dev" optional = false @@ -1374,16 +1450,22 @@ python-versions = ">=3.6" docutils = "*" sphinx = "*" +[package.extras] +dev = ["pre-commit"] +lint = ["black", "flake8", "pylint"] +test = ["pytest (>=3.0.0)", "pytest-cov"] + [[package]] name = "sphinx-rtd-theme" -version = "0.5.1" +version = "1.0.0" description = "Read the Docs theme for Sphinx" category = "dev" optional = false -python-versions = "*" +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" [package.dependencies] -sphinx = "*" +docutils = "<0.18" +sphinx = ">=1.6" [package.extras] dev = ["transifex-client", "sphinxcontrib-httpdomain", "bump2version"] @@ -1504,7 +1586,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "tomli" -version = "2.0.0" +version = "2.0.1" description = "A lil' TOML parser" category = "dev" optional = false @@ -1512,7 +1594,7 @@ python-versions = ">=3.7" [[package]] name = "typed-ast" -version = "1.5.2" +version = "1.5.4" description = "a fork of Python 2 and 3 ast modules with type comment support" category = "dev" optional = false @@ -1536,14 +1618,14 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "urllib3" -version = "1.26.8" +version = "1.26.9" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" [package.extras] -brotli = ["brotlipy (>=0.6.0)"] +brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] @@ -1568,9 +1650,9 @@ six = "*" [[package]] name = "wrapt" -version = "1.13.3" +version = "1.14.1" description = "Module for decorators, wrappers and monkey patching." -category = "dev" +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" @@ -1606,20 +1688,20 @@ typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} [[package]] name = "zipp" -version = "3.7.0" +version = "3.8.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false python-versions = ">=3.7" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "1.1" python-versions = "3.7.*" -content-hash = "b02313c8255a1897b0f0617ad4884a5943696c363512921aab1cb2dd8f4fdbe0" +content-hash = "bd8e0a03668c380c6e76c8cd6c71020692f4ea9f32de7a4f09433564faa9dad0" [metadata.files] acre = [] @@ -1722,8 +1804,8 @@ arrow = [ {file = "arrow-0.17.0.tar.gz", hash = "sha256:ff08d10cda1d36c68657d6ad20d74fbea493d980f8b2d45344e00d6ed2bf6ed4"}, ] astroid = [ - {file = "astroid-2.9.3-py3-none-any.whl", hash = "sha256:506daabe5edffb7e696ad82483ad0228245a9742ed7d2d8c9cdb31537decf9f6"}, - {file = "astroid-2.9.3.tar.gz", hash = "sha256:1efdf4e867d4d8ba4a9f6cf9ce07cd182c4c41de77f23814feb27ca93ca9d877"}, + {file = "astroid-2.11.5-py3-none-any.whl", hash = "sha256:14ffbb4f6aa2cf474a0834014005487f7ecd8924996083ab411e7fa0b508ce0b"}, + {file = "astroid-2.11.5.tar.gz", hash = "sha256:f4e4ec5294c4b07ac38bab9ca5ddd3914d4bf46f9006eb5c0ae755755061044e"}, ] async-timeout = [ {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, @@ -1750,28 +1832,29 @@ babel = [ {file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"}, ] bcrypt = [ - {file = "bcrypt-3.2.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:b589229207630484aefe5899122fb938a5b017b0f4349f769b8c13e78d99a8fd"}, - {file = "bcrypt-3.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c95d4cbebffafcdd28bd28bb4e25b31c50f6da605c81ffd9ad8a3d1b2ab7b1b6"}, - {file = "bcrypt-3.2.0-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:63d4e3ff96188e5898779b6057878fecf3f11cfe6ec3b313ea09955d587ec7a7"}, - {file = "bcrypt-3.2.0-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:cd1ea2ff3038509ea95f687256c46b79f5fc382ad0aa3664d200047546d511d1"}, - {file = "bcrypt-3.2.0-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:cdcdcb3972027f83fe24a48b1e90ea4b584d35f1cc279d76de6fc4b13376239d"}, - {file = "bcrypt-3.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a0584a92329210fcd75eb8a3250c5a941633f8bfaf2a18f81009b097732839b7"}, - {file = "bcrypt-3.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:56e5da069a76470679f312a7d3d23deb3ac4519991a0361abc11da837087b61d"}, - {file = "bcrypt-3.2.0-cp36-abi3-win32.whl", hash = "sha256:a67fb841b35c28a59cebed05fbd3e80eea26e6d75851f0574a9273c80f3e9b55"}, - {file = "bcrypt-3.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:81fec756feff5b6818ea7ab031205e1d323d8943d237303baca2c5f9c7846f34"}, - {file = "bcrypt-3.2.0.tar.gz", hash = "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29"}, + {file = "bcrypt-3.2.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:7180d98a96f00b1050e93f5b0f556e658605dd9f524d0b0e68ae7944673f525e"}, + {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:61bae49580dce88095d669226d5076d0b9d927754cedbdf76c6c9f5099ad6f26"}, + {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88273d806ab3a50d06bc6a2fc7c87d737dd669b76ad955f449c43095389bc8fb"}, + {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6d2cb9d969bfca5bc08e45864137276e4c3d3d7de2b162171def3d188bf9d34a"}, + {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b02d6bfc6336d1094276f3f588aa1225a598e27f8e3388f4db9948cb707b521"}, + {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2c46100e315c3a5b90fdc53e429c006c5f962529bc27e1dfd656292c20ccc40"}, + {file = "bcrypt-3.2.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7d9ba2e41e330d2af4af6b1b6ec9e6128e91343d0b4afb9282e54e5508f31baa"}, + {file = "bcrypt-3.2.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cd43303d6b8a165c29ec6756afd169faba9396a9472cdff753fe9f19b96ce2fa"}, + {file = "bcrypt-3.2.2-cp36-abi3-win32.whl", hash = "sha256:4e029cef560967fb0cf4a802bcf4d562d3d6b4b1bf81de5ec1abbe0f1adb027e"}, + {file = "bcrypt-3.2.2-cp36-abi3-win_amd64.whl", hash = "sha256:7ff2069240c6bbe49109fe84ca80508773a904f5a8cb960e02a977f7f519b129"}, + {file = "bcrypt-3.2.2.tar.gz", hash = "sha256:433c410c2177057705da2a9f2cd01dd157493b2a7ac14c8593a16b3dab6b6bfb"}, ] blessed = [ {file = "blessed-1.19.1-py2.py3-none-any.whl", hash = "sha256:63b8554ae2e0e7f43749b6715c734cc8f3883010a809bf16790102563e6cf25b"}, {file = "blessed-1.19.1.tar.gz", hash = "sha256:9a0d099695bf621d4680dd6c73f6ad547f6a3442fbdbe80c4b1daa1edbc492fc"}, ] cachetools = [ - {file = "cachetools-5.0.0-py3-none-any.whl", hash = "sha256:8fecd4203a38af17928be7b90689d8083603073622229ca7077b72d8e5a976e4"}, - {file = "cachetools-5.0.0.tar.gz", hash = "sha256:486471dfa8799eb7ec503a8059e263db000cdda20075ce5e48903087f79d5fd6"}, + {file = "cachetools-5.2.0-py3-none-any.whl", hash = "sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db"}, + {file = "cachetools-5.2.0.tar.gz", hash = "sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757"}, ] certifi = [ - {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, - {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, + {file = "certifi-2022.5.18.1-py3-none-any.whl", hash = "sha256:f1d53542ee8cbedbe2118b5686372fb33c297fcd6379b050cca0ef13a597382a"}, + {file = "certifi-2022.5.18.1.tar.gz", hash = "sha256:9c5705e395cd70084351dd8ad5c41e65655e08ce46f2ec9cf6c2c08390f71eb7"}, ] cffi = [ {file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"}, @@ -1825,13 +1908,9 @@ cffi = [ {file = "cffi-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139"}, {file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"}, ] -chardet = [ - {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, - {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, -] charset-normalizer = [ - {file = "charset-normalizer-2.0.11.tar.gz", hash = "sha256:98398a9d69ee80548c762ba991a4728bfc3836768ed226b3945908d1a688371c"}, - {file = "charset_normalizer-2.0.11-py3-none-any.whl", hash = "sha256:2842d8f5e82a1f6aa437380934d5e1cd4fcf2003b06fed6940769c164a480a45"}, + {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, + {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, ] click = [ {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, @@ -1854,69 +1933,71 @@ coolname = [ {file = "coolname-1.1.0.tar.gz", hash = "sha256:410fe6ea9999bf96f2856ef0c726d5f38782bbefb7bb1aca0e91e0dc98ed09e3"}, ] coverage = [ - {file = "coverage-6.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeffd96882d8c06d31b65dddcf51db7c612547babc1c4c5db6a011abe9798525"}, - {file = "coverage-6.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:621f6ea7260ea2ffdaec64fe5cb521669984f567b66f62f81445221d4754df4c"}, - {file = "coverage-6.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84f2436d6742c01136dd940ee158bfc7cf5ced3da7e4c949662b8703b5cd8145"}, - {file = "coverage-6.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de73fca6fb403dd72d4da517cfc49fcf791f74eee697d3219f6be29adf5af6ce"}, - {file = "coverage-6.3.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78fbb2be068a13a5d99dce9e1e7d168db880870f7bc73f876152130575bd6167"}, - {file = "coverage-6.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f5a4551dfd09c3bd12fca8144d47fe7745275adf3229b7223c2f9e29a975ebda"}, - {file = "coverage-6.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7bff3a98f63b47464480de1b5bdd80c8fade0ba2832c9381253c9b74c4153c27"}, - {file = "coverage-6.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a06c358f4aed05fa1099c39decc8022261bb07dfadc127c08cfbd1391b09689e"}, - {file = "coverage-6.3.1-cp310-cp310-win32.whl", hash = "sha256:9fff3ff052922cb99f9e52f63f985d4f7a54f6b94287463bc66b7cdf3eb41217"}, - {file = "coverage-6.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:276b13cc085474e482566c477c25ed66a097b44c6e77132f3304ac0b039f83eb"}, - {file = "coverage-6.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:56c4a409381ddd7bbff134e9756077860d4e8a583d310a6f38a2315b9ce301d0"}, - {file = "coverage-6.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eb494070aa060ceba6e4bbf44c1bc5fa97bfb883a0d9b0c9049415f9e944793"}, - {file = "coverage-6.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e15d424b8153756b7c903bde6d4610be0c3daca3986173c18dd5c1a1625e4cd"}, - {file = "coverage-6.3.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d47a897c1e91f33f177c21de897267b38fbb45f2cd8e22a710bcef1df09ac1"}, - {file = "coverage-6.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:25e73d4c81efa8ea3785274a2f7f3bfbbeccb6fcba2a0bdd3be9223371c37554"}, - {file = "coverage-6.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fac0bcc5b7e8169bffa87f0dcc24435446d329cbc2b5486d155c2e0f3b493ae1"}, - {file = "coverage-6.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:72128176fea72012063200b7b395ed8a57849282b207321124d7ff14e26988e8"}, - {file = "coverage-6.3.1-cp37-cp37m-win32.whl", hash = "sha256:1bc6d709939ff262fd1432f03f080c5042dc6508b6e0d3d20e61dd045456a1a0"}, - {file = "coverage-6.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:618eeba986cea7f621d8607ee378ecc8c2504b98b3fdc4952b30fe3578304687"}, - {file = "coverage-6.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5ed164af5c9078596cfc40b078c3b337911190d3faeac830c3f1274f26b8320"}, - {file = "coverage-6.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:352c68e233409c31048a3725c446a9e48bbff36e39db92774d4f2380d630d8f8"}, - {file = "coverage-6.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:448d7bde7ceb6c69e08474c2ddbc5b4cd13c9e4aa4a717467f716b5fc938a734"}, - {file = "coverage-6.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9fde6b90889522c220dd56a670102ceef24955d994ff7af2cb786b4ba8fe11e4"}, - {file = "coverage-6.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e647a0be741edbb529a72644e999acb09f2ad60465f80757da183528941ff975"}, - {file = "coverage-6.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a5cdc3adb4f8bb8d8f5e64c2e9e282bc12980ef055ec6da59db562ee9bdfefa"}, - {file = "coverage-6.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2dd70a167843b4b4b2630c0c56f1b586fe965b4f8ac5da05b6690344fd065c6b"}, - {file = "coverage-6.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9ad0a117b8dc2061ce9461ea4c1b4799e55edceb236522c5b8f958ce9ed8fa9a"}, - {file = "coverage-6.3.1-cp38-cp38-win32.whl", hash = "sha256:e92c7a5f7d62edff50f60a045dc9542bf939758c95b2fcd686175dd10ce0ed10"}, - {file = "coverage-6.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:482fb42eea6164894ff82abbcf33d526362de5d1a7ed25af7ecbdddd28fc124f"}, - {file = "coverage-6.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c5b81fb37db76ebea79aa963b76d96ff854e7662921ce742293463635a87a78d"}, - {file = "coverage-6.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a4f923b9ab265136e57cc14794a15b9dcea07a9c578609cd5dbbfff28a0d15e6"}, - {file = "coverage-6.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56d296cbc8254a7dffdd7bcc2eb70be5a233aae7c01856d2d936f5ac4e8ac1f1"}, - {file = "coverage-6.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1245ab82e8554fa88c4b2ab1e098ae051faac5af829efdcf2ce6b34dccd5567c"}, - {file = "coverage-6.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f2b05757c92ad96b33dbf8e8ec8d4ccb9af6ae3c9e9bd141c7cc44d20c6bcba"}, - {file = "coverage-6.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9e3dd806f34de38d4c01416344e98eab2437ac450b3ae39c62a0ede2f8b5e4ed"}, - {file = "coverage-6.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d651fde74a4d3122e5562705824507e2f5b2d3d57557f1916c4b27635f8fbe3f"}, - {file = "coverage-6.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:704f89b87c4f4737da2860695a18c852b78ec7279b24eedacab10b29067d3a38"}, - {file = "coverage-6.3.1-cp39-cp39-win32.whl", hash = "sha256:2aed4761809640f02e44e16b8b32c1a5dee5e80ea30a0ff0912158bde9c501f2"}, - {file = "coverage-6.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:9976fb0a5709988778ac9bc44f3d50fccd989987876dfd7716dee28beed0a9fa"}, - {file = "coverage-6.3.1-pp36.pp37.pp38-none-any.whl", hash = "sha256:463e52616ea687fd323888e86bf25e864a3cc6335a043fad6bbb037dbf49bbe2"}, - {file = "coverage-6.3.1.tar.gz", hash = "sha256:6c3f6158b02ac403868eea390930ae64e9a9a2a5bbfafefbb920d29258d9f2f8"}, + {file = "coverage-6.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f1d5aa2703e1dab4ae6cf416eb0095304f49d004c39e9db1d86f57924f43006b"}, + {file = "coverage-6.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4ce1b258493cbf8aec43e9b50d89982346b98e9ffdfaae8ae5793bc112fb0068"}, + {file = "coverage-6.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83c4e737f60c6936460c5be330d296dd5b48b3963f48634c53b3f7deb0f34ec4"}, + {file = "coverage-6.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84e65ef149028516c6d64461b95a8dbcfce95cfd5b9eb634320596173332ea84"}, + {file = "coverage-6.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f69718750eaae75efe506406c490d6fc5a6161d047206cc63ce25527e8a3adad"}, + {file = "coverage-6.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e57816f8ffe46b1df8f12e1b348f06d164fd5219beba7d9433ba79608ef011cc"}, + {file = "coverage-6.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:01c5615d13f3dd3aa8543afc069e5319cfa0c7d712f6e04b920431e5c564a749"}, + {file = "coverage-6.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:75ab269400706fab15981fd4bd5080c56bd5cc07c3bccb86aab5e1d5a88dc8f4"}, + {file = "coverage-6.4.1-cp310-cp310-win32.whl", hash = "sha256:a7f3049243783df2e6cc6deafc49ea123522b59f464831476d3d1448e30d72df"}, + {file = "coverage-6.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:ee2ddcac99b2d2aec413e36d7a429ae9ebcadf912946b13ffa88e7d4c9b712d6"}, + {file = "coverage-6.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb73e0011b8793c053bfa85e53129ba5f0250fdc0392c1591fd35d915ec75c46"}, + {file = "coverage-6.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106c16dfe494de3193ec55cac9640dd039b66e196e4641fa8ac396181578b982"}, + {file = "coverage-6.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87f4f3df85aa39da00fd3ec4b5abeb7407e82b68c7c5ad181308b0e2526da5d4"}, + {file = "coverage-6.4.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:961e2fb0680b4f5ad63234e0bf55dfb90d302740ae9c7ed0120677a94a1590cb"}, + {file = "coverage-6.4.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:cec3a0f75c8f1031825e19cd86ee787e87cf03e4fd2865c79c057092e69e3a3b"}, + {file = "coverage-6.4.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:129cd05ba6f0d08a766d942a9ed4b29283aff7b2cccf5b7ce279d50796860bb3"}, + {file = "coverage-6.4.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bf5601c33213d3cb19d17a796f8a14a9eaa5e87629a53979a5981e3e3ae166f6"}, + {file = "coverage-6.4.1-cp37-cp37m-win32.whl", hash = "sha256:269eaa2c20a13a5bf17558d4dc91a8d078c4fa1872f25303dddcbba3a813085e"}, + {file = "coverage-6.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f02cbbf8119db68455b9d763f2f8737bb7db7e43720afa07d8eb1604e5c5ae28"}, + {file = "coverage-6.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ffa9297c3a453fba4717d06df579af42ab9a28022444cae7fa605af4df612d54"}, + {file = "coverage-6.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:145f296d00441ca703a659e8f3eb48ae39fb083baba2d7ce4482fb2723e050d9"}, + {file = "coverage-6.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d44996140af8b84284e5e7d398e589574b376fb4de8ccd28d82ad8e3bea13"}, + {file = "coverage-6.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2bd9a6fc18aab8d2e18f89b7ff91c0f34ff4d5e0ba0b33e989b3cd4194c81fd9"}, + {file = "coverage-6.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3384f2a3652cef289e38100f2d037956194a837221edd520a7ee5b42d00cc605"}, + {file = "coverage-6.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9b3e07152b4563722be523e8cd0b209e0d1a373022cfbde395ebb6575bf6790d"}, + {file = "coverage-6.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1480ff858b4113db2718848d7b2d1b75bc79895a9c22e76a221b9d8d62496428"}, + {file = "coverage-6.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:865d69ae811a392f4d06bde506d531f6a28a00af36f5c8649684a9e5e4a85c83"}, + {file = "coverage-6.4.1-cp38-cp38-win32.whl", hash = "sha256:664a47ce62fe4bef9e2d2c430306e1428ecea207ffd68649e3b942fa8ea83b0b"}, + {file = "coverage-6.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:26dff09fb0d82693ba9e6231248641d60ba606150d02ed45110f9ec26404ed1c"}, + {file = "coverage-6.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d9c80df769f5ec05ad21ea34be7458d1dc51ff1fb4b2219e77fe24edf462d6df"}, + {file = "coverage-6.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:39ee53946bf009788108b4dd2894bf1349b4e0ca18c2016ffa7d26ce46b8f10d"}, + {file = "coverage-6.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5b66caa62922531059bc5ac04f836860412f7f88d38a476eda0a6f11d4724f4"}, + {file = "coverage-6.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd180ed867e289964404051a958f7cccabdeed423f91a899829264bb7974d3d3"}, + {file = "coverage-6.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84631e81dd053e8a0d4967cedab6db94345f1c36107c71698f746cb2636c63e3"}, + {file = "coverage-6.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8c08da0bd238f2970230c2a0d28ff0e99961598cb2e810245d7fc5afcf1254e8"}, + {file = "coverage-6.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d42c549a8f41dc103a8004b9f0c433e2086add8a719da00e246e17cbe4056f72"}, + {file = "coverage-6.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:309ce4a522ed5fca432af4ebe0f32b21d6d7ccbb0f5fcc99290e71feba67c264"}, + {file = "coverage-6.4.1-cp39-cp39-win32.whl", hash = "sha256:fdb6f7bd51c2d1714cea40718f6149ad9be6a2ee7d93b19e9f00934c0f2a74d9"}, + {file = "coverage-6.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:342d4aefd1c3e7f620a13f4fe563154d808b69cccef415415aece4c786665397"}, + {file = "coverage-6.4.1-pp36.pp37.pp38-none-any.whl", hash = "sha256:4803e7ccf93230accb928f3a68f00ffa80a88213af98ed338a57ad021ef06815"}, + {file = "coverage-6.4.1.tar.gz", hash = "sha256:4321f075095a096e70aff1d002030ee612b65a205a0a0f5b815280d5dc58100c"}, ] cryptography = [ - {file = "cryptography-36.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:73bc2d3f2444bcfeac67dd130ff2ea598ea5f20b40e36d19821b4df8c9c5037b"}, - {file = "cryptography-36.0.1-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:2d87cdcb378d3cfed944dac30596da1968f88fb96d7fc34fdae30a99054b2e31"}, - {file = "cryptography-36.0.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74d6c7e80609c0f4c2434b97b80c7f8fdfaa072ca4baab7e239a15d6d70ed73a"}, - {file = "cryptography-36.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:6c0c021f35b421ebf5976abf2daacc47e235f8b6082d3396a2fe3ccd537ab173"}, - {file = "cryptography-36.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d59a9d55027a8b88fd9fd2826c4392bd487d74bf628bb9d39beecc62a644c12"}, - {file = "cryptography-36.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a817b961b46894c5ca8a66b599c745b9a3d9f822725221f0e0fe49dc043a3a3"}, - {file = "cryptography-36.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:94ae132f0e40fe48f310bba63f477f14a43116f05ddb69d6fa31e93f05848ae2"}, - {file = "cryptography-36.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7be0eec337359c155df191d6ae00a5e8bbb63933883f4f5dffc439dac5348c3f"}, - {file = "cryptography-36.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:e0344c14c9cb89e76eb6a060e67980c9e35b3f36691e15e1b7a9e58a0a6c6dc3"}, - {file = "cryptography-36.0.1-cp36-abi3-win32.whl", hash = "sha256:4caa4b893d8fad33cf1964d3e51842cd78ba87401ab1d2e44556826df849a8ca"}, - {file = "cryptography-36.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:391432971a66cfaf94b21c24ab465a4cc3e8bf4a939c1ca5c3e3a6e0abebdbcf"}, - {file = "cryptography-36.0.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bb5829d027ff82aa872d76158919045a7c1e91fbf241aec32cb07956e9ebd3c9"}, - {file = "cryptography-36.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebc15b1c22e55c4d5566e3ca4db8689470a0ca2babef8e3a9ee057a8b82ce4b1"}, - {file = "cryptography-36.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:596f3cd67e1b950bc372c33f1a28a0692080625592ea6392987dba7f09f17a94"}, - {file = "cryptography-36.0.1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:30ee1eb3ebe1644d1c3f183d115a8c04e4e603ed6ce8e394ed39eea4a98469ac"}, - {file = "cryptography-36.0.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec63da4e7e4a5f924b90af42eddf20b698a70e58d86a72d943857c4c6045b3ee"}, - {file = "cryptography-36.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca238ceb7ba0bdf6ce88c1b74a87bffcee5afbfa1e41e173b1ceb095b39add46"}, - {file = "cryptography-36.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:ca28641954f767f9822c24e927ad894d45d5a1e501767599647259cbf030b903"}, - {file = "cryptography-36.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:39bdf8e70eee6b1c7b289ec6e5d84d49a6bfa11f8b8646b5b3dfe41219153316"}, - {file = "cryptography-36.0.1.tar.gz", hash = "sha256:53e5c1dc3d7a953de055d77bef2ff607ceef7a2aac0353b5d630ab67f7423638"}, + {file = "cryptography-37.0.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:ef15c2df7656763b4ff20a9bc4381d8352e6640cfeb95c2972c38ef508e75181"}, + {file = "cryptography-37.0.2-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:3c81599befb4d4f3d7648ed3217e00d21a9341a9a688ecdd615ff72ffbed7336"}, + {file = "cryptography-37.0.2-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2bd1096476aaac820426239ab534b636c77d71af66c547b9ddcd76eb9c79e004"}, + {file = "cryptography-37.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:31fe38d14d2e5f787e0aecef831457da6cec68e0bb09a35835b0b44ae8b988fe"}, + {file = "cryptography-37.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:093cb351031656d3ee2f4fa1be579a8c69c754cf874206be1d4cf3b542042804"}, + {file = "cryptography-37.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59b281eab51e1b6b6afa525af2bd93c16d49358404f814fe2c2410058623928c"}, + {file = "cryptography-37.0.2-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:0cc20f655157d4cfc7bada909dc5cc228211b075ba8407c46467f63597c78178"}, + {file = "cryptography-37.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:f8ec91983e638a9bcd75b39f1396e5c0dc2330cbd9ce4accefe68717e6779e0a"}, + {file = "cryptography-37.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:46f4c544f6557a2fefa7ac8ac7d1b17bf9b647bd20b16decc8fbcab7117fbc15"}, + {file = "cryptography-37.0.2-cp36-abi3-win32.whl", hash = "sha256:731c8abd27693323b348518ed0e0705713a36d79fdbd969ad968fbef0979a7e0"}, + {file = "cryptography-37.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:471e0d70201c069f74c837983189949aa0d24bb2d751b57e26e3761f2f782b8d"}, + {file = "cryptography-37.0.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a68254dd88021f24a68b613d8c51d5c5e74d735878b9e32cc0adf19d1f10aaf9"}, + {file = "cryptography-37.0.2-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:a7d5137e556cc0ea418dca6186deabe9129cee318618eb1ffecbd35bee55ddc1"}, + {file = "cryptography-37.0.2-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aeaba7b5e756ea52c8861c133c596afe93dd716cbcacae23b80bc238202dc023"}, + {file = "cryptography-37.0.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95e590dd70642eb2079d280420a888190aa040ad20f19ec8c6e097e38aa29e06"}, + {file = "cryptography-37.0.2-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:1b9362d34363f2c71b7853f6251219298124aa4cc2075ae2932e64c91a3e2717"}, + {file = "cryptography-37.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e53258e69874a306fcecb88b7534d61820db8a98655662a3dd2ec7f1afd9132f"}, + {file = "cryptography-37.0.2-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:1f3bfbd611db5cb58ca82f3deb35e83af34bb8cf06043fa61500157d50a70982"}, + {file = "cryptography-37.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:419c57d7b63f5ec38b1199a9521d77d7d1754eb97827bbb773162073ccd8c8d4"}, + {file = "cryptography-37.0.2-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:dc26bb134452081859aa21d4990474ddb7e863aa39e60d1592800a8865a702de"}, + {file = "cryptography-37.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3b8398b3d0efc420e777c40c16764d6870bcef2eb383df9c6dbb9ffe12c64452"}, + {file = "cryptography-37.0.2.tar.gz", hash = "sha256:f224ad253cc9cea7568f49077007d2263efa57396a2f2f78114066fd54b5c68e"}, ] cx-freeze = [ {file = "cx_Freeze-6.9-cp310-cp310-win32.whl", hash = "sha256:776d4fb68a4831691acbd3c374362b9b48ce2e568514a73c3d4cb14d5dcf1470"}, @@ -1946,25 +2027,33 @@ cx-logging = [ {file = "cx_Logging-3.0-cp39-cp39-win_amd64.whl", hash = "sha256:302e9c4f65a936c288a4fa59a90e7e142d9ef994aa29676731acafdcccdbb3f5"}, {file = "cx_Logging-3.0.tar.gz", hash = "sha256:ba8a7465facf7b98d8f494030fb481a2e8aeee29dc191e10383bb54ed42bdb34"}, ] +deprecated = [ + {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"}, + {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"}, +] +dill = [ + {file = "dill-0.3.5.1-py2.py3-none-any.whl", hash = "sha256:33501d03270bbe410c72639b350e941882a8b0fd55357580fbc873fba0c59302"}, + {file = "dill-0.3.5.1.tar.gz", hash = "sha256:d75e41f3eff1eee599d738e76ba8f4ad98ea229db8b085318aa2b3333a208c86"}, +] dnspython = [ - {file = "dnspython-2.2.0-py3-none-any.whl", hash = "sha256:081649da27ced5e75709a1ee542136eaba9842a0fe4c03da4fb0a3d3ed1f3c44"}, - {file = "dnspython-2.2.0.tar.gz", hash = "sha256:e79351e032d0b606b98d38a4b0e6e2275b31a5b85c873e587cc11b73aca026d6"}, + {file = "dnspython-2.2.1-py3-none-any.whl", hash = "sha256:a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f"}, + {file = "dnspython-2.2.1.tar.gz", hash = "sha256:0f7569a4a6ff151958b64304071d370daa3243d15941a7beedf0c9fe5105603e"}, ] docutils = [ - {file = "docutils-0.18.1-py2.py3-none-any.whl", hash = "sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c"}, - {file = "docutils-0.18.1.tar.gz", hash = "sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06"}, + {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, + {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, ] dropbox = [ - {file = "dropbox-11.26.0-py2-none-any.whl", hash = "sha256:abd29587fa692bde0c3a48ce8efb56c24d8df92c5f402bbcdd78f3089d5ced5c"}, - {file = "dropbox-11.26.0-py3-none-any.whl", hash = "sha256:84becf043a63007ae67620946acb0fa164669ce691c7f1dbfdabb6712a258b29"}, - {file = "dropbox-11.26.0.tar.gz", hash = "sha256:dd79e3dfc216688020959462aefac54ffce7c07a45e89f4fb258348885195a73"}, + {file = "dropbox-11.31.0-py2-none-any.whl", hash = "sha256:393a99dfe30d42fd73c265b9b7d24bb21c9a961739cd097c3541e709eb2a209c"}, + {file = "dropbox-11.31.0-py3-none-any.whl", hash = "sha256:5f924102fd6464def81573320c6aa4ea9cd3368e1b1c13d838403dd4c9ffc919"}, + {file = "dropbox-11.31.0.tar.gz", hash = "sha256:f483d65b702775b9abf7b9328f702c68c6397fc01770477c6ddbfb1d858a5bcf"}, ] enlighten = [ {file = "enlighten-1.10.2-py2.py3-none-any.whl", hash = "sha256:b237fe562b320bf9f1d4bb76d0c98e0daf914372a76ab87c35cd02f57aa9d8c1"}, {file = "enlighten-1.10.2.tar.gz", hash = "sha256:7a5b83cd0f4d095e59d80c648ebb5f7ffca0cd8bcf7ae6639828ee1ad000632a"}, ] evdev = [ - {file = "evdev-1.4.0.tar.gz", hash = "sha256:8782740eb1a86b187334c07feb5127d3faa0b236e113206dfe3ae8f77fb1aaf1"}, + {file = "evdev-1.5.0.tar.gz", hash = "sha256:5b33b174f7c84576e7dd6071e438bf5ad227da95efd4356a39fe4c8355412fe6"}, ] flake8 = [ {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, @@ -2038,49 +2127,52 @@ ftrack-python-api = [ future = [ {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, ] +gazu = [ + {file = "gazu-0.8.28-py2.py3-none-any.whl", hash = "sha256:ec4f7c2688a2b37ee8a77737e4e30565ad362428c3ade9046136a998c043e51c"}, +] gitdb = [ {file = "gitdb-4.0.9-py3-none-any.whl", hash = "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd"}, {file = "gitdb-4.0.9.tar.gz", hash = "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"}, ] gitpython = [ - {file = "GitPython-3.1.26-py3-none-any.whl", hash = "sha256:26ac35c212d1f7b16036361ca5cff3ec66e11753a0d677fb6c48fa4e1a9dd8d6"}, - {file = "GitPython-3.1.26.tar.gz", hash = "sha256:fc8868f63a2e6d268fb25f481995ba185a85a66fcad126f039323ff6635669ee"}, + {file = "GitPython-3.1.27-py3-none-any.whl", hash = "sha256:5b68b000463593e05ff2b261acff0ff0972df8ab1b70d3cdbd41b546c8b8fc3d"}, + {file = "GitPython-3.1.27.tar.gz", hash = "sha256:1c885ce809e8ba2d88a29befeb385fcea06338d3640712b59ca623c220bb5704"}, ] google-api-core = [ - {file = "google-api-core-2.4.0.tar.gz", hash = "sha256:ba8787b7c61632cd0340f095e1c036bef9426b2594f10afb290ba311ae8cb2cb"}, - {file = "google_api_core-2.4.0-py2.py3-none-any.whl", hash = "sha256:58e2c1171a3d51778bf4e428fbb4bf79cbd05007b4b44deaa80cf73c80eebc0f"}, + {file = "google-api-core-2.8.1.tar.gz", hash = "sha256:958024c6aa3460b08f35741231076a4dd9a4c819a6a39d44da9627febe8b28f0"}, + {file = "google_api_core-2.8.1-py3-none-any.whl", hash = "sha256:ce1daa49644b50398093d2a9ad886501aa845e2602af70c3001b9f402a9d7359"}, ] google-api-python-client = [ - {file = "google-api-python-client-1.12.10.tar.gz", hash = "sha256:1cb773647e7d97048d9d1c7fa746247fbad39fd1a3b5040f2cb2645dd7156b11"}, - {file = "google_api_python_client-1.12.10-py2.py3-none-any.whl", hash = "sha256:5a8742b9b604b34e13462cc3d6aedbbf11d3af1ef558eb95defe74a29ebc5c28"}, + {file = "google-api-python-client-1.12.11.tar.gz", hash = "sha256:1b4bd42a46321e13c0542a9e4d96fa05d73626f07b39f83a73a947d70ca706a9"}, + {file = "google_api_python_client-1.12.11-py2.py3-none-any.whl", hash = "sha256:7e0a1a265c8d3088ee1987778c72683fcb376e32bada8d7767162bd9c503fd9b"}, ] google-auth = [ - {file = "google-auth-2.6.0.tar.gz", hash = "sha256:ad160fc1ea8f19e331a16a14a79f3d643d813a69534ba9611d2c80dc10439dad"}, - {file = "google_auth-2.6.0-py2.py3-none-any.whl", hash = "sha256:218ca03d7744ca0c8b6697b6083334be7df49b7bf76a69d555962fd1a7657b5f"}, + {file = "google-auth-2.7.0.tar.gz", hash = "sha256:8a954960f852d5f19e6af14dd8e75c20159609e85d8db37e4013cc8c3824a7e1"}, + {file = "google_auth-2.7.0-py2.py3-none-any.whl", hash = "sha256:df549a1433108801b11bdcc0e312eaf0d5f0500db42f0523e4d65c78722e8475"}, ] google-auth-httplib2 = [ {file = "google-auth-httplib2-0.1.0.tar.gz", hash = "sha256:a07c39fd632becacd3f07718dfd6021bf396978f03ad3ce4321d060015cc30ac"}, {file = "google_auth_httplib2-0.1.0-py2.py3-none-any.whl", hash = "sha256:31e49c36c6b5643b57e82617cb3e021e3e1d2df9da63af67252c02fa9c1f4a10"}, ] googleapis-common-protos = [ - {file = "googleapis-common-protos-1.54.0.tar.gz", hash = "sha256:a4031d6ec6c2b1b6dc3e0be7e10a1bd72fb0b18b07ef9be7b51f2c1004ce2437"}, - {file = "googleapis_common_protos-1.54.0-py2.py3-none-any.whl", hash = "sha256:e54345a2add15dc5e1a7891c27731ff347b4c33765d79b5ed7026a6c0c7cbcae"}, + {file = "googleapis-common-protos-1.56.2.tar.gz", hash = "sha256:b09b56f5463070c2153753ef123f07d2e49235e89148e9b2459ec8ed2f68d7d3"}, + {file = "googleapis_common_protos-1.56.2-py2.py3-none-any.whl", hash = "sha256:023eaea9d8c1cceccd9587c6af6c20f33eeeb05d4148670f2b0322dc1511700c"}, ] httplib2 = [ - {file = "httplib2-0.20.2-py3-none-any.whl", hash = "sha256:6b937120e7d786482881b44b8eec230c1ee1c5c1d06bce8cc865f25abbbf713b"}, - {file = "httplib2-0.20.2.tar.gz", hash = "sha256:e404681d2fbcec7506bcb52c503f2b021e95bee0ef7d01e5c221468a2406d8dc"}, + {file = "httplib2-0.20.4-py3-none-any.whl", hash = "sha256:8b6a905cb1c79eefd03f8669fd993c36dc341f7c558f056cb5a33b5c2f458543"}, + {file = "httplib2-0.20.4.tar.gz", hash = "sha256:58a98e45b4b1a48273073f905d2961666ecf0fbac4250ea5b47aef259eb5c585"}, ] idna = [ - {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, - {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, + {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, + {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, ] imagesize = [ {file = "imagesize-1.3.0-py2.py3-none-any.whl", hash = "sha256:1db2f82529e53c3e929e8926a1fa9235aa82d0bd0c580359c67ec31b2fddaa8c"}, {file = "imagesize-1.3.0.tar.gz", hash = "sha256:cd1750d452385ca327479d45b64d9c7729ecf0b3969a58148298c77092261f9d"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.10.1-py3-none-any.whl", hash = "sha256:899e2a40a8c4a1aec681feef45733de8a6c58f3f6a0dbed2eb6574b4387a77b6"}, - {file = "importlib_metadata-4.10.1.tar.gz", hash = "sha256:951f0d8a5b7260e9db5e41d429285b5f451e928479f19d80818878527d36e95e"}, + {file = "importlib_metadata-4.11.4-py3-none-any.whl", hash = "sha256:c58c8eb8a762858f49e18436ff552e83914778e50e9d2f1660535ffb364552ec"}, + {file = "importlib_metadata-4.11.4.tar.gz", hash = "sha256:5d26852efe48c0a32b0509ffbc583fda1a2266545a78d104a6f4aff3db17d700"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, @@ -2103,8 +2195,8 @@ jinja2 = [ {file = "Jinja2-2.11.3.tar.gz", hash = "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"}, ] jinxed = [ - {file = "jinxed-1.1.0-py2.py3-none-any.whl", hash = "sha256:6a61ccf963c16aa885304f27e6e5693783676897cea0c7f223270c8b8e78baf8"}, - {file = "jinxed-1.1.0.tar.gz", hash = "sha256:d8f1731f134e9e6b04d95095845ae6c10eb15cb223a5f0cabdea87d4a279c305"}, + {file = "jinxed-1.2.0-py2.py3-none-any.whl", hash = "sha256:cfc2b2e4e3b4326954d546ba6d6b9a7a796ddcb0aef8d03161d005177eb0d48b"}, + {file = "jinxed-1.2.0.tar.gz", hash = "sha256:032acda92d5c57cd216033cbbd53de731e6ed50deb63eb4781336ca55f72cda5"}, ] jsonschema = [ {file = "jsonschema-2.6.0-py2.py3-none-any.whl", hash = "sha256:000e68abd33c972a5248544925a0cae7d1125f9bf6c58280d37546b946769a08"}, @@ -2298,57 +2390,60 @@ packaging = [ {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] paramiko = [ - {file = "paramiko-2.10.1-py2.py3-none-any.whl", hash = "sha256:f6cbd3e1204abfdbcd40b3ecbc9d32f04027cd3080fe666245e21e7540ccfc1b"}, - {file = "paramiko-2.10.1.tar.gz", hash = "sha256:443f4da23ec24e9a9c0ea54017829c282abdda1d57110bf229360775ccd27a31"}, + {file = "paramiko-2.11.0-py2.py3-none-any.whl", hash = "sha256:655f25dc8baf763277b933dfcea101d636581df8d6b9774d1fb653426b72c270"}, + {file = "paramiko-2.11.0.tar.gz", hash = "sha256:003e6bee7c034c21fbb051bf83dc0a9ee4106204dd3c53054c71452cc4ec3938"}, ] parso = [ {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, ] pathlib2 = [ - {file = "pathlib2-2.3.6-py2.py3-none-any.whl", hash = "sha256:3a130b266b3a36134dcc79c17b3c7ac9634f083825ca6ea9d8f557ee6195c9c8"}, - {file = "pathlib2-2.3.6.tar.gz", hash = "sha256:7d8bcb5555003cdf4a8d2872c538faa3a0f5d20630cb360e518ca3b981795e5f"}, + {file = "pathlib2-2.3.7.post1-py2.py3-none-any.whl", hash = "sha256:5266a0fd000452f1b3467d782f079a4343c63aaa119221fbdc4e39577489ca5b"}, + {file = "pathlib2-2.3.7.post1.tar.gz", hash = "sha256:9fe0edad898b83c0c3e199c842b27ed216645d2e177757b2dd67384d4113c641"}, ] pillow = [ - {file = "Pillow-9.0.1-1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a5d24e1d674dd9d72c66ad3ea9131322819ff86250b30dc5821cbafcfa0b96b4"}, - {file = "Pillow-9.0.1-1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2632d0f846b7c7600edf53c48f8f9f1e13e62f66a6dbc15191029d950bfed976"}, - {file = "Pillow-9.0.1-1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b9618823bd237c0d2575283f2939655f54d51b4527ec3972907a927acbcc5bfc"}, - {file = "Pillow-9.0.1-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:9bfdb82cdfeccec50aad441afc332faf8606dfa5e8efd18a6692b5d6e79f00fd"}, - {file = "Pillow-9.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5100b45a4638e3c00e4d2320d3193bdabb2d75e79793af7c3eb139e4f569f16f"}, - {file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:528a2a692c65dd5cafc130de286030af251d2ee0483a5bf50c9348aefe834e8a"}, - {file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f29d831e2151e0b7b39981756d201f7108d3d215896212ffe2e992d06bfe049"}, - {file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:855c583f268edde09474b081e3ddcd5cf3b20c12f26e0d434e1386cc5d318e7a"}, - {file = "Pillow-9.0.1-cp310-cp310-win32.whl", hash = "sha256:d9d7942b624b04b895cb95af03a23407f17646815495ce4547f0e60e0b06f58e"}, - {file = "Pillow-9.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:81c4b81611e3a3cb30e59b0cf05b888c675f97e3adb2c8672c3154047980726b"}, - {file = "Pillow-9.0.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:413ce0bbf9fc6278b2d63309dfeefe452835e1c78398efb431bab0672fe9274e"}, - {file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80fe64a6deb6fcfdf7b8386f2cf216d329be6f2781f7d90304351811fb591360"}, - {file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cef9c85ccbe9bee00909758936ea841ef12035296c748aaceee535969e27d31b"}, - {file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d19397351f73a88904ad1aee421e800fe4bbcd1aeee6435fb62d0a05ccd1030"}, - {file = "Pillow-9.0.1-cp37-cp37m-win32.whl", hash = "sha256:d21237d0cd37acded35154e29aec853e945950321dd2ffd1a7d86fe686814669"}, - {file = "Pillow-9.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ede5af4a2702444a832a800b8eb7f0a7a1c0eed55b644642e049c98d589e5092"}, - {file = "Pillow-9.0.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:b5b3f092fe345c03bca1e0b687dfbb39364b21ebb8ba90e3fa707374b7915204"}, - {file = "Pillow-9.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:335ace1a22325395c4ea88e00ba3dc89ca029bd66bd5a3c382d53e44f0ccd77e"}, - {file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db6d9fac65bd08cea7f3540b899977c6dee9edad959fa4eaf305940d9cbd861c"}, - {file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f154d173286a5d1863637a7dcd8c3437bb557520b01bddb0be0258dcb72696b5"}, - {file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d4b1341ac07ae07eb2cc682f459bec932a380c3b122f5540432d8977e64eae"}, - {file = "Pillow-9.0.1-cp38-cp38-win32.whl", hash = "sha256:effb7749713d5317478bb3acb3f81d9d7c7f86726d41c1facca068a04cf5bb4c"}, - {file = "Pillow-9.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:7f7609a718b177bf171ac93cea9fd2ddc0e03e84d8fa4e887bdfc39671d46b00"}, - {file = "Pillow-9.0.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:80ca33961ced9c63358056bd08403ff866512038883e74f3a4bf88ad3eb66838"}, - {file = "Pillow-9.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c3c33ac69cf059bbb9d1a71eeaba76781b450bc307e2291f8a4764d779a6b28"}, - {file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12875d118f21cf35604176872447cdb57b07126750a33748bac15e77f90f1f9c"}, - {file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:514ceac913076feefbeaf89771fd6febde78b0c4c1b23aaeab082c41c694e81b"}, - {file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3c5c79ab7dfce6d88f1ba639b77e77a17ea33a01b07b99840d6ed08031cb2a7"}, - {file = "Pillow-9.0.1-cp39-cp39-win32.whl", hash = "sha256:718856856ba31f14f13ba885ff13874be7fefc53984d2832458f12c38205f7f7"}, - {file = "Pillow-9.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:f25ed6e28ddf50de7e7ea99d7a976d6a9c415f03adcaac9c41ff6ff41b6d86ac"}, - {file = "Pillow-9.0.1-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:011233e0c42a4a7836498e98c1acf5e744c96a67dd5032a6f666cc1fb97eab97"}, - {file = "Pillow-9.0.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:253e8a302a96df6927310a9d44e6103055e8fb96a6822f8b7f514bb7ef77de56"}, - {file = "Pillow-9.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6295f6763749b89c994fcb6d8a7f7ce03c3992e695f89f00b741b4580b199b7e"}, - {file = "Pillow-9.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a9f44cd7e162ac6191491d7249cceb02b8116b0f7e847ee33f739d7cb1ea1f70"}, - {file = "Pillow-9.0.1.tar.gz", hash = "sha256:6c8bc8238a7dfdaf7a75f5ec5a663f4173f8c367e5a39f87e720495e1eed75fa"}, + {file = "Pillow-9.1.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:42dfefbef90eb67c10c45a73a9bc1599d4dac920f7dfcbf4ec6b80cb620757fe"}, + {file = "Pillow-9.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ffde4c6fabb52891d81606411cbfaf77756e3b561b566efd270b3ed3791fde4e"}, + {file = "Pillow-9.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c857532c719fb30fafabd2371ce9b7031812ff3889d75273827633bca0c4602"}, + {file = "Pillow-9.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59789a7d06c742e9d13b883d5e3569188c16acb02eeed2510fd3bfdbc1bd1530"}, + {file = "Pillow-9.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d45dbe4b21a9679c3e8b3f7f4f42a45a7d3ddff8a4a16109dff0e1da30a35b2"}, + {file = "Pillow-9.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e9ed59d1b6ee837f4515b9584f3d26cf0388b742a11ecdae0d9237a94505d03a"}, + {file = "Pillow-9.1.1-cp310-cp310-win32.whl", hash = "sha256:b3fe2ff1e1715d4475d7e2c3e8dabd7c025f4410f79513b4ff2de3d51ce0fa9c"}, + {file = "Pillow-9.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:5b650dbbc0969a4e226d98a0b440c2f07a850896aed9266b6fedc0f7e7834108"}, + {file = "Pillow-9.1.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:0b4d5ad2cd3a1f0d1df882d926b37dbb2ab6c823ae21d041b46910c8f8cd844b"}, + {file = "Pillow-9.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9370d6744d379f2de5d7fa95cdbd3a4d92f0b0ef29609b4b1687f16bc197063d"}, + {file = "Pillow-9.1.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b761727ed7d593e49671d1827044b942dd2f4caae6e51bab144d4accf8244a84"}, + {file = "Pillow-9.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a66fe50386162df2da701b3722781cbe90ce043e7d53c1fd6bd801bca6b48d4"}, + {file = "Pillow-9.1.1-cp37-cp37m-win32.whl", hash = "sha256:2b291cab8a888658d72b575a03e340509b6b050b62db1f5539dd5cd18fd50578"}, + {file = "Pillow-9.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:1d4331aeb12f6b3791911a6da82de72257a99ad99726ed6b63f481c0184b6fb9"}, + {file = "Pillow-9.1.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8844217cdf66eabe39567118f229e275f0727e9195635a15e0e4b9227458daaf"}, + {file = "Pillow-9.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b6617221ff08fbd3b7a811950b5c3f9367f6e941b86259843eab77c8e3d2b56b"}, + {file = "Pillow-9.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20d514c989fa28e73a5adbddd7a171afa5824710d0ab06d4e1234195d2a2e546"}, + {file = "Pillow-9.1.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:088df396b047477dd1bbc7de6e22f58400dae2f21310d9e2ec2933b2ef7dfa4f"}, + {file = "Pillow-9.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53c27bd452e0f1bc4bfed07ceb235663a1df7c74df08e37fd6b03eb89454946a"}, + {file = "Pillow-9.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3f6c1716c473ebd1649663bf3b42702d0d53e27af8b64642be0dd3598c761fb1"}, + {file = "Pillow-9.1.1-cp38-cp38-win32.whl", hash = "sha256:c67db410508b9de9c4694c57ed754b65a460e4812126e87f5052ecf23a011a54"}, + {file = "Pillow-9.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:f054b020c4d7e9786ae0404278ea318768eb123403b18453e28e47cdb7a0a4bf"}, + {file = "Pillow-9.1.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:c17770a62a71718a74b7548098a74cd6880be16bcfff5f937f900ead90ca8e92"}, + {file = "Pillow-9.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3f6a6034140e9e17e9abc175fc7a266a6e63652028e157750bd98e804a8ed9a"}, + {file = "Pillow-9.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f372d0f08eff1475ef426344efe42493f71f377ec52237bf153c5713de987251"}, + {file = "Pillow-9.1.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09e67ef6e430f90caa093528bd758b0616f8165e57ed8d8ce014ae32df6a831d"}, + {file = "Pillow-9.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66daa16952d5bf0c9d5389c5e9df562922a59bd16d77e2a276e575d32e38afd1"}, + {file = "Pillow-9.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d78ca526a559fb84faaaf84da2dd4addef5edb109db8b81677c0bb1aad342601"}, + {file = "Pillow-9.1.1-cp39-cp39-win32.whl", hash = "sha256:55e74faf8359ddda43fee01bffbc5bd99d96ea508d8a08c527099e84eb708f45"}, + {file = "Pillow-9.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:7c150dbbb4a94ea4825d1e5f2c5501af7141ea95825fadd7829f9b11c97aaf6c"}, + {file = "Pillow-9.1.1-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:769a7f131a2f43752455cc72f9f7a093c3ff3856bf976c5fb53a59d0ccc704f6"}, + {file = "Pillow-9.1.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:488f3383cf5159907d48d32957ac6f9ea85ccdcc296c14eca1a4e396ecc32098"}, + {file = "Pillow-9.1.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b525a356680022b0af53385944026d3486fc8c013638cf9900eb87c866afb4c"}, + {file = "Pillow-9.1.1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6e760cf01259a1c0a50f3c845f9cad1af30577fd8b670339b1659c6d0e7a41dd"}, + {file = "Pillow-9.1.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4165205a13b16a29e1ac57efeee6be2dfd5b5408122d59ef2145bc3239fa340"}, + {file = "Pillow-9.1.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937a54e5694684f74dcbf6e24cc453bfc5b33940216ddd8f4cd8f0f79167f765"}, + {file = "Pillow-9.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:baf3be0b9446a4083cc0c5bb9f9c964034be5374b5bc09757be89f5d2fa247b8"}, + {file = "Pillow-9.1.1.tar.gz", hash = "sha256:7502539939b53d7565f3d11d87c78e7ec900d3c72945d4ee0e2f250d598309a0"}, ] platformdirs = [ - {file = "platformdirs-2.4.1-py3-none-any.whl", hash = "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca"}, - {file = "platformdirs-2.4.1.tar.gz", hash = "sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"}, + {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, + {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, ] pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, @@ -2449,12 +2544,12 @@ pyflakes = [ {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, ] pygments = [ - {file = "Pygments-2.11.2-py3-none-any.whl", hash = "sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65"}, - {file = "Pygments-2.11.2.tar.gz", hash = "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"}, + {file = "Pygments-2.12.0-py3-none-any.whl", hash = "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519"}, + {file = "Pygments-2.12.0.tar.gz", hash = "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb"}, ] pylint = [ - {file = "pylint-2.12.2-py3-none-any.whl", hash = "sha256:daabda3f7ed9d1c60f52d563b1b854632fd90035bcf01443e234d3dc794e3b74"}, - {file = "pylint-2.12.2.tar.gz", hash = "sha256:9d945a73640e1fec07ee34b42f5669b770c759acd536ec7b16d7e4b87a9c9ff9"}, + {file = "pylint-2.13.9-py3-none-any.whl", hash = "sha256:705c620d388035bdd9ff8b44c5bcdd235bfb49d276d488dd2c8ff1736aa42526"}, + {file = "pylint-2.13.9.tar.gz", hash = "sha256:095567c96e19e6f57b5b907e67d265ff535e588fe26b12b5ebe1fc5645b2c731"}, ] pymongo = [ {file = "pymongo-3.12.3-cp27-cp27m-macosx_10_14_intel.whl", hash = "sha256:c164eda0be9048f83c24b9b2656900041e069ddf72de81c17d874d0c32f6079f"}, @@ -2583,40 +2678,40 @@ pynput = [ {file = "pynput-1.7.6.tar.gz", hash = "sha256:3a5726546da54116b687785d38b1db56997ce1d28e53e8d22fc656d8b92e533c"}, ] pyobjc-core = [ - {file = "pyobjc-core-8.2.tar.gz", hash = "sha256:6afb8ee1dd0647cbfaaf99906eca3b43ce045b27e3d4510462d04e7e5361c89b"}, - {file = "pyobjc_core-8.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:311e45556c3afa8831713b89017e0204562f51f35661d76c07ffe04985f44e1d"}, - {file = "pyobjc_core-8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:711f361e83382e405e4273ff085178b0cf730901ccf6801f834e7037e50278f9"}, - {file = "pyobjc_core-8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bdd2e2960ec73214bcfe2d86bb4ca94f5f5119db86d129fa32d3c003b6532c50"}, - {file = "pyobjc_core-8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b879f91fc614c399aafa1d08cf5e279c267510e904bad5c336c3a6064c0eb3aa"}, - {file = "pyobjc_core-8.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:b4ef4bdb99a330f5e15cc6273098964276fccbc432453cdba3c2963292bc066c"}, - {file = "pyobjc_core-8.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fd8e5be0955790ff8f9d17a0f356b6eb7eb1ce4995e0c94355c462dd52d22d6d"}, + {file = "pyobjc-core-8.5.tar.gz", hash = "sha256:704c275439856c0d1287469f0d589a7d808d48b754a93d9ce5415d4eaf06d576"}, + {file = "pyobjc_core-8.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0c234143b48334443f5adcf26e668945a6d47bc1fa6223e80918c6c735a029d9"}, + {file = "pyobjc_core-8.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:1486ee533f0d76f666804ce89723ada4db56bfde55e56151ba512d3f849857f8"}, + {file = "pyobjc_core-8.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:412de06dfa728301c04b3e46fd7453320a8ae8b862e85236e547cd797a73b490"}, + {file = "pyobjc_core-8.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b3e09cccb1be574a82cc9f929ae27fc4283eccc75496cb5d51534caa6bb83a3"}, + {file = "pyobjc_core-8.5-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:eeafe21f879666ab7f57efcc6b007c9f5f8733d367b7e380c925203ed83f000d"}, + {file = "pyobjc_core-8.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c0071686976d7ea8c14690950e504a13cb22b4ebb2bc7b5ec47c1c1c0f6eff41"}, ] pyobjc-framework-applicationservices = [ - {file = "pyobjc-framework-ApplicationServices-8.2.tar.gz", hash = "sha256:f901b2ebb278b7d00033b45cf9ee9d43f651e096ff4c4defa261509238138da8"}, - {file = "pyobjc_framework_ApplicationServices-8.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b5be1757a8df944a58449c628ed68fc76dd746fcd1e96ebb6db0f734e94cdfc8"}, - {file = "pyobjc_framework_ApplicationServices-8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:32657c4b89983a98fbe831a14884954710719e763197968a20ac07e1daa21f1e"}, - {file = "pyobjc_framework_ApplicationServices-8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6ce2c9701590f752a75151b2fe1e462e7a7ad67dec3119a796711ea93ea01031"}, - {file = "pyobjc_framework_ApplicationServices-8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:28124bc892045222305cf8953b163495bf662c401e54f48905dafb1104d9c1d1"}, - {file = "pyobjc_framework_ApplicationServices-8.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:d5c60d66c6ed2569cb042a6c14dd5b9f4d01e182a464b893cd6002ce445b4ddf"}, - {file = "pyobjc_framework_ApplicationServices-8.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e1727fccc1d48922fa28a4cebf4a6d287d633f451cb03779968df60de8cb1bd0"}, + {file = "pyobjc-framework-ApplicationServices-8.5.tar.gz", hash = "sha256:fa3015ef8e3add90af3447d7fdcc7f8dd083cc2a1d58f99a569480a2df10d2b1"}, + {file = "pyobjc_framework_ApplicationServices-8.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:436b16ebe448a829a8312e10208eec81a2adcae1fff674dbcc3262e1bd76e0ca"}, + {file = "pyobjc_framework_ApplicationServices-8.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:408958d14aa7fcf46f2163754c211078bc63be1368934d86188202914dce077d"}, + {file = "pyobjc_framework_ApplicationServices-8.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1d6cd4ce192859a22e208da4d7177a1c3ceb1ef2f64c339fd881102b1210cadd"}, + {file = "pyobjc_framework_ApplicationServices-8.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0251d092adb1d2d116fd9f147ceef0e53b158a46c21245131c40b9d7b786d0db"}, + {file = "pyobjc_framework_ApplicationServices-8.5-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:9742e69fe6d4545d0e02b0ad0a7a2432bc9944569ee07d6e90ffa5ef614df9f7"}, + {file = "pyobjc_framework_ApplicationServices-8.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16f5677c14ea903c6aaca1dd121521825c39e816cae696d6ae32c0b287252ab2"}, ] pyobjc-framework-cocoa = [ - {file = "pyobjc-framework-Cocoa-8.2.tar.gz", hash = "sha256:f0901998e2f18415ef6d1f8a12b083f69fc93bd56b3e88040002e3c09bd8c304"}, - {file = "pyobjc_framework_Cocoa-8.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5af73f150e242542735e0663bb5504f88aabaec2a54c60e856cfca3ff6dd9712"}, - {file = "pyobjc_framework_Cocoa-8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d1de3763ee01850c311da74de5c82c85ec199120e85ab45acaf203accc37a470"}, - {file = "pyobjc_framework_Cocoa-8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:86d69bf667f99f3c43184d8830567195fff94c675fe7f60f899dd90553d9b265"}, - {file = "pyobjc_framework_Cocoa-8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9dbadb22826392c48b00087359f66579f8404a4f4f77498f31f9869c54bb0fa9"}, - {file = "pyobjc_framework_Cocoa-8.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:7adf8b57da1c1292c24375b8e74b6dd45f99a4d3c10ba925a9b38f63a97ba782"}, - {file = "pyobjc_framework_Cocoa-8.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bc8279c8c1544087d46a7e99324f093029df89b8c527c5da2a682bad4cb3197e"}, + {file = "pyobjc-framework-Cocoa-8.5.tar.gz", hash = "sha256:569bd3a020f64b536fb2d1c085b37553e50558c9f907e08b73ffc16ae68e1861"}, + {file = "pyobjc_framework_Cocoa-8.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7a7c160416696bf6035dfcdf0e603aaa52858d6afcddfcc5ab41733619ac2529"}, + {file = "pyobjc_framework_Cocoa-8.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6ceba444282030be8596b812260e8d28b671254a51052ad778d32da6e17db847"}, + {file = "pyobjc_framework_Cocoa-8.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f46b2b161b8dd40c7b9e00bc69636c3e6480b2704a69aee22ee0154befbe163a"}, + {file = "pyobjc_framework_Cocoa-8.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b31d425aee8698cbf62b187338f5ca59427fa4dca2153a73866f7cb410713119"}, + {file = "pyobjc_framework_Cocoa-8.5-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:898359ac1f76eedec8aa156847682378a8950824421c40edb89391286e607dc4"}, + {file = "pyobjc_framework_Cocoa-8.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:baa2947f76b119a3360973d74d57d6dada87ac527bab9a88f31596af392f123c"}, ] pyobjc-framework-quartz = [ - {file = "pyobjc-framework-Quartz-8.2.tar.gz", hash = "sha256:219d8797235bf071723f8b0f30a681de0b12875e2d04ae902a3a269f72de0b66"}, - {file = "pyobjc_framework_Quartz-8.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e5ab3117201a494b11bb1b80febf5dd288111a196b35731815b656ae30ee6ce3"}, - {file = "pyobjc_framework_Quartz-8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4941b3039ab7bcf89cb4255c381358de2383c1ab45c9e00c3b64655f271a3b32"}, - {file = "pyobjc_framework_Quartz-8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ab75a50dea84ec794641522d9f035fc6c19ec4eb37a56c9186b9943575fbc7ab"}, - {file = "pyobjc_framework_Quartz-8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8cb687b20ebfc467034868b38945b573d1c50f237e379cf86c4f557c9766b759"}, - {file = "pyobjc_framework_Quartz-8.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:8b5c3ca1fef900fa66aafe82fff07bc352c60ea7dceed2bb9b5b1db0957b4fea"}, - {file = "pyobjc_framework_Quartz-8.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7bca7e649da77056348d71032def44e345043319d71b0c592197888d92e3eec1"}, + {file = "pyobjc-framework-Quartz-8.5.tar.gz", hash = "sha256:d2bc5467a792ddc04814f12a1e9c2fcaf699a1c3ad3d4264cfdce6b9c7b10624"}, + {file = "pyobjc_framework_Quartz-8.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e9f0fb663f7872c9de94169031ac42b91ad01bd4cad49a9f1a0164be8f028426"}, + {file = "pyobjc_framework_Quartz-8.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:567eec91287cfe9a1b6433717192c585935de8f3daa28d82ce72fdd6c7ac00f6"}, + {file = "pyobjc_framework_Quartz-8.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9f910ab41a712ffc7a8c3e3716a2d6f39ea4419004b26a2fd2d2f740ff5c262c"}, + {file = "pyobjc_framework_Quartz-8.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:29d07066781628278bf0e5278abcfc96ef6724c66c5629a0b4c214d319a82e55"}, + {file = "pyobjc_framework_Quartz-8.5-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:72abcde1a3d72be11f2c881c9b9872044c8f2de86d2047b67fe771713638b107"}, + {file = "pyobjc_framework_Quartz-8.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8809b9a2df2f461697bdb45b6d1b5a4f881f88f09450e3990858e64e3e26c530"}, ] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, @@ -2641,6 +2736,14 @@ python-dateutil = [ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, ] +python-engineio = [ + {file = "python-engineio-3.14.2.tar.gz", hash = "sha256:eab4553f2804c1ce97054c8b22cf0d5a9ab23128075248b97e1a5b2f29553085"}, + {file = "python_engineio-3.14.2-py2.py3-none-any.whl", hash = "sha256:5a9e6086d192463b04a1428ff1f85b6ba631bbb19d453b144ffc04f530542b84"}, +] +python-socketio = [ + {file = "python-socketio-4.6.1.tar.gz", hash = "sha256:cd1f5aa492c1eb2be77838e837a495f117e17f686029ebc03d62c09e33f4fa10"}, + {file = "python_socketio-4.6.1-py2.py3-none-any.whl", hash = "sha256:5a21da53fdbdc6bb6c8071f40e13d100e0b279ad997681c2492478e06f370523"}, +] python-xlib = [ {file = "python-xlib-0.31.tar.gz", hash = "sha256:74d83a081f532bc07f6d7afcd6416ec38403d68f68b9b9dc9e1f28fbf2d799e9"}, {file = "python_xlib-0.31-py2.py3-none-any.whl", hash = "sha256:1ec6ce0de73d9e6592ead666779a5732b384e5b8fb1f1886bd0a81cafa477759"}, @@ -2649,8 +2752,8 @@ python3-xlib = [ {file = "python3-xlib-0.15.tar.gz", hash = "sha256:dc4245f3ae4aa5949c1d112ee4723901ade37a96721ba9645f2bfa56e5b383f8"}, ] pytz = [ - {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, - {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, + {file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"}, + {file = "pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"}, ] pywin32 = [ {file = "pywin32-301-cp35-cp35m-win32.whl", hash = "sha256:93367c96e3a76dfe5003d8291ae16454ca7d84bb24d721e0b74a07610b7be4a7"}, @@ -2669,8 +2772,8 @@ pywin32-ctypes = [ {file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"}, ] "qt.py" = [ - {file = "Qt.py-1.3.6-py2.py3-none-any.whl", hash = "sha256:7edf6048d07a6924707506b5ba34a6e05d66dde9a3f4e3a62f9996ccab0b91c7"}, - {file = "Qt.py-1.3.6.tar.gz", hash = "sha256:0d78656a2f814602eee304521c7bf5da0cec414818b3833712c77524294c404a"}, + {file = "Qt.py-1.3.7-py2.py3-none-any.whl", hash = "sha256:150099d1c6f64c9621a2c9d79d45102ec781c30ee30ee69fc082c6e9be7324fe"}, + {file = "Qt.py-1.3.7.tar.gz", hash = "sha256:803c7bdf4d6230f9a466be19d55934a173eabb61406d21cb91e80c2a3f773b1f"}, ] qtawesome = [ {file = "QtAwesome-0.7.3-py2.py3-none-any.whl", hash = "sha256:ddf4530b4af71cec13b24b88a4cdb56ec85b1e44c43c42d0698804c7137b09b0"}, @@ -2685,16 +2788,16 @@ recommonmark = [ {file = "recommonmark-0.7.1.tar.gz", hash = "sha256:bdb4db649f2222dcd8d2d844f0006b958d627f732415d399791ee436a3686d67"}, ] requests = [ - {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, - {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, + {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, + {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"}, ] rsa = [ {file = "rsa-4.8-py3-none-any.whl", hash = "sha256:95c5d300c4e879ee69708c428ba566c59478fd653cc3a22243eeb8ed846950bb"}, {file = "rsa-4.8.tar.gz", hash = "sha256:5c6bd9dc7a543b7fe4304a631f8a8a3b674e2bbfc49c2ae96200cdbe55df6b17"}, ] secretstorage = [ - {file = "SecretStorage-3.3.1-py3-none-any.whl", hash = "sha256:422d82c36172d88d6a0ed5afdec956514b189ddbfb72fefab0c8a1cee4eaf71f"}, - {file = "SecretStorage-3.3.1.tar.gz", hash = "sha256:fd666c51a6bf200643495a04abb261f83229dcb6fd8472ec393df7ffc8b6f195"}, + {file = "SecretStorage-3.3.2-py3-none-any.whl", hash = "sha256:755dc845b6ad76dcbcbc07ea3da75ae54bb1ea529eb72d15f83d26499a5df319"}, + {file = "SecretStorage-3.3.2.tar.gz", hash = "sha256:0a8eb9645b320881c222e827c26f4cfcf55363e8b374a021981ef886657a912f"}, ] semver = [ {file = "semver-2.13.0-py2.py3-none-any.whl", hash = "sha256:ced8b23dceb22134307c1b8abfa523da14198793d9787ac838e70e29e77458d4"}, @@ -2705,8 +2808,8 @@ six = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] slack-sdk = [ - {file = "slack_sdk-3.13.0-py2.py3-none-any.whl", hash = "sha256:54f2a5f7419f1ab932af9e3200f7f2f93db96e0f0eb8ad7d3b4214aa9f124641"}, - {file = "slack_sdk-3.13.0.tar.gz", hash = "sha256:aae6ce057e286a5e7fe7a9f256e85b886eee556def8e04b82b08f699e64d7f67"}, + {file = "slack_sdk-3.17.0-py2.py3-none-any.whl", hash = "sha256:0816efc43d1d2db8286e8dbcbb2e86fd0f71c206c01c521c2cb054ecb40f9ced"}, + {file = "slack_sdk-3.17.0.tar.gz", hash = "sha256:860cd0e50c454b955f14321c8c5486a47cc1e0e84116acdb009107f836752feb"}, ] smmap = [ {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, @@ -2717,20 +2820,20 @@ snowballstemmer = [ {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, ] speedcopy = [ - {file = "speedcopy-2.1.2-py3-none-any.whl", hash = "sha256:91e271b84c00952812dbf669d360b2610fd8fa198670373e02acf2a04db89a4c"}, - {file = "speedcopy-2.1.2.tar.gz", hash = "sha256:1b2d779fadebd53a59384f7d286c40b2ef382e0d000fa53011699fcd3190d33f"}, + {file = "speedcopy-2.1.4-py3-none-any.whl", hash = "sha256:e09eb1de67ae0e0b51d5b99a28882009d565a37a3cb3c6bae121e3a5d3cccb17"}, + {file = "speedcopy-2.1.4.tar.gz", hash = "sha256:eff007a97e49ec1934df4fa8074f4bd1cf4a3b14c5499d914988785cff0c199a"}, ] sphinx = [ - {file = "Sphinx-3.5.3-py3-none-any.whl", hash = "sha256:3f01732296465648da43dec8fb40dc451ba79eb3e2cc5c6d79005fd98197107d"}, - {file = "Sphinx-3.5.3.tar.gz", hash = "sha256:ce9c228456131bab09a3d7d10ae58474de562a6f79abb3dc811ae401cf8c1abc"}, + {file = "Sphinx-5.0.1-py3-none-any.whl", hash = "sha256:36aa2a3c2f6d5230be94585bc5d74badd5f9ed8f3388b8eedc1726fe45b1ad30"}, + {file = "Sphinx-5.0.1.tar.gz", hash = "sha256:f4da1187785a5bc7312cc271b0e867a93946c319d106363e102936a3d9857306"}, ] sphinx-qt-documentation = [ - {file = "sphinx_qt_documentation-0.3-py3-none-any.whl", hash = "sha256:bee247cb9e4fc03fc496d07adfdb943100e1103320c3e5e820e0cfa7c790d9b6"}, - {file = "sphinx_qt_documentation-0.3.tar.gz", hash = "sha256:f09a0c9d9e989172ba3e282b92bf55613bb23ad47315ec5b0d38536b343ac6c8"}, + {file = "sphinx_qt_documentation-0.4-py3-none-any.whl", hash = "sha256:fa131093f75cd1bd48699cd132e18e4d46ba9eaadc070e6026867cea75ecdb7b"}, + {file = "sphinx_qt_documentation-0.4.tar.gz", hash = "sha256:f43ba17baa93e353fb94045027fb67f9d935ed158ce8662de93f08b88eec6774"}, ] sphinx-rtd-theme = [ - {file = "sphinx_rtd_theme-0.5.1-py2.py3-none-any.whl", hash = "sha256:fa6bebd5ab9a73da8e102509a86f3fcc36dec04a0b52ea80e5a033b2aba00113"}, - {file = "sphinx_rtd_theme-0.5.1.tar.gz", hash = "sha256:eda689eda0c7301a80cf122dad28b1861e5605cbf455558f3775e1e8200e83a5"}, + {file = "sphinx_rtd_theme-1.0.0-py2.py3-none-any.whl", hash = "sha256:4d35a56f4508cfee4c4fb604373ede6feae2a306731d533f409ef5c3496fdbd8"}, + {file = "sphinx_rtd_theme-1.0.0.tar.gz", hash = "sha256:eec6d497e4c2195fa0e8b2016b337532b8a699a68bcb22a512870e16925c6a5c"}, ] sphinxcontrib-applehelp = [ {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, @@ -2773,34 +2876,34 @@ toml = [ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] tomli = [ - {file = "tomli-2.0.0-py3-none-any.whl", hash = "sha256:b5bde28da1fed24b9bd1d4d2b8cba62300bfb4ec9a6187a957e8ddb9434c5224"}, - {file = "tomli-2.0.0.tar.gz", hash = "sha256:c292c34f58502a1eb2bbb9f5bbc9a5ebc37bee10ffb8c2d6bbdfa8eb13cc14e1"}, + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] typed-ast = [ - {file = "typed_ast-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:183b183b7771a508395d2cbffd6db67d6ad52958a5fdc99f450d954003900266"}, - {file = "typed_ast-1.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:676d051b1da67a852c0447621fdd11c4e104827417bf216092ec3e286f7da596"}, - {file = "typed_ast-1.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc2542e83ac8399752bc16e0b35e038bdb659ba237f4222616b4e83fb9654985"}, - {file = "typed_ast-1.5.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74cac86cc586db8dfda0ce65d8bcd2bf17b58668dfcc3652762f3ef0e6677e76"}, - {file = "typed_ast-1.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:18fe320f354d6f9ad3147859b6e16649a0781425268c4dde596093177660e71a"}, - {file = "typed_ast-1.5.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:31d8c6b2df19a777bc8826770b872a45a1f30cfefcfd729491baa5237faae837"}, - {file = "typed_ast-1.5.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:963a0ccc9a4188524e6e6d39b12c9ca24cc2d45a71cfdd04a26d883c922b4b78"}, - {file = "typed_ast-1.5.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0eb77764ea470f14fcbb89d51bc6bbf5e7623446ac4ed06cbd9ca9495b62e36e"}, - {file = "typed_ast-1.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:294a6903a4d087db805a7656989f613371915fc45c8cc0ddc5c5a0a8ad9bea4d"}, - {file = "typed_ast-1.5.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:26a432dc219c6b6f38be20a958cbe1abffcc5492821d7e27f08606ef99e0dffd"}, - {file = "typed_ast-1.5.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7407cfcad702f0b6c0e0f3e7ab876cd1d2c13b14ce770e412c0c4b9728a0f88"}, - {file = "typed_ast-1.5.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f30ddd110634c2d7534b2d4e0e22967e88366b0d356b24de87419cc4410c41b7"}, - {file = "typed_ast-1.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8c08d6625bb258179b6e512f55ad20f9dfef019bbfbe3095247401e053a3ea30"}, - {file = "typed_ast-1.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:90904d889ab8e81a956f2c0935a523cc4e077c7847a836abee832f868d5c26a4"}, - {file = "typed_ast-1.5.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bbebc31bf11762b63bf61aaae232becb41c5bf6b3461b80a4df7e791fabb3aca"}, - {file = "typed_ast-1.5.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29dd9a3a9d259c9fa19d19738d021632d673f6ed9b35a739f48e5f807f264fb"}, - {file = "typed_ast-1.5.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:58ae097a325e9bb7a684572d20eb3e1809802c5c9ec7108e85da1eb6c1a3331b"}, - {file = "typed_ast-1.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:da0a98d458010bf4fe535f2d1e367a2e2060e105978873c04c04212fb20543f7"}, - {file = "typed_ast-1.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:33b4a19ddc9fc551ebabca9765d54d04600c4a50eda13893dadf67ed81d9a098"}, - {file = "typed_ast-1.5.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1098df9a0592dd4c8c0ccfc2e98931278a6c6c53cb3a3e2cf7e9ee3b06153344"}, - {file = "typed_ast-1.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42c47c3b43fe3a39ddf8de1d40dbbfca60ac8530a36c9b198ea5b9efac75c09e"}, - {file = "typed_ast-1.5.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f290617f74a610849bd8f5514e34ae3d09eafd521dceaa6cf68b3f4414266d4e"}, - {file = "typed_ast-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:df05aa5b241e2e8045f5f4367a9f6187b09c4cdf8578bb219861c4e27c443db5"}, - {file = "typed_ast-1.5.2.tar.gz", hash = "sha256:525a2d4088e70a9f75b08b3f87a51acc9cde640e19cc523c7e41aa355564ae27"}, + {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"}, + {file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"}, + {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"}, + {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"}, + {file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"}, + {file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"}, + {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"}, + {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"}, + {file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"}, + {file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"}, + {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"}, + {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"}, + {file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"}, + {file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"}, + {file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"}, + {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"}, + {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"}, + {file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"}, + {file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"}, + {file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"}, + {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"}, + {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"}, + {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, + {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, ] typing-extensions = [ {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"}, @@ -2811,8 +2914,8 @@ uritemplate = [ {file = "uritemplate-3.0.1.tar.gz", hash = "sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae"}, ] urllib3 = [ - {file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"}, - {file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"}, + {file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"}, + {file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"}, ] wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, @@ -2823,57 +2926,70 @@ websocket-client = [ {file = "websocket_client-0.59.0-py2.py3-none-any.whl", hash = "sha256:2e50d26ca593f70aba7b13a489435ef88b8fc3b5c5643c1ce8808ff9b40f0b32"}, ] wrapt = [ - {file = "wrapt-1.13.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:e05e60ff3b2b0342153be4d1b597bbcfd8330890056b9619f4ad6b8d5c96a81a"}, - {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:85148f4225287b6a0665eef08a178c15097366d46b210574a658c1ff5b377489"}, - {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:2dded5496e8f1592ec27079b28b6ad2a1ef0b9296d270f77b8e4a3a796cf6909"}, - {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e94b7d9deaa4cc7bac9198a58a7240aaf87fe56c6277ee25fa5b3aa1edebd229"}, - {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:498e6217523111d07cd67e87a791f5e9ee769f9241fcf8a379696e25806965af"}, - {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ec7e20258ecc5174029a0f391e1b948bf2906cd64c198a9b8b281b811cbc04de"}, - {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:87883690cae293541e08ba2da22cacaae0a092e0ed56bbba8d018cc486fbafbb"}, - {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:f99c0489258086308aad4ae57da9e8ecf9e1f3f30fa35d5e170b4d4896554d80"}, - {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6a03d9917aee887690aa3f1747ce634e610f6db6f6b332b35c2dd89412912bca"}, - {file = "wrapt-1.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:936503cb0a6ed28dbfa87e8fcd0a56458822144e9d11a49ccee6d9a8adb2ac44"}, - {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f9c51d9af9abb899bd34ace878fbec8bf357b3194a10c4e8e0a25512826ef056"}, - {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:220a869982ea9023e163ba915077816ca439489de6d2c09089b219f4e11b6785"}, - {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0877fe981fd76b183711d767500e6b3111378ed2043c145e21816ee589d91096"}, - {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:43e69ffe47e3609a6aec0fe723001c60c65305784d964f5007d5b4fb1bc6bf33"}, - {file = "wrapt-1.13.3-cp310-cp310-win32.whl", hash = "sha256:78dea98c81915bbf510eb6a3c9c24915e4660302937b9ae05a0947164248020f"}, - {file = "wrapt-1.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:ea3e746e29d4000cd98d572f3ee2a6050a4f784bb536f4ac1f035987fc1ed83e"}, - {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8c73c1a2ec7c98d7eaded149f6d225a692caa1bd7b2401a14125446e9e90410d"}, - {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:086218a72ec7d986a3eddb7707c8c4526d677c7b35e355875a0fe2918b059179"}, - {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:e92d0d4fa68ea0c02d39f1e2f9cb5bc4b4a71e8c442207433d8db47ee79d7aa3"}, - {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:d4a5f6146cfa5c7ba0134249665acd322a70d1ea61732723c7d3e8cc0fa80755"}, - {file = "wrapt-1.13.3-cp35-cp35m-win32.whl", hash = "sha256:8aab36778fa9bba1a8f06a4919556f9f8c7b33102bd71b3ab307bb3fecb21851"}, - {file = "wrapt-1.13.3-cp35-cp35m-win_amd64.whl", hash = "sha256:944b180f61f5e36c0634d3202ba8509b986b5fbaf57db3e94df11abee244ba13"}, - {file = "wrapt-1.13.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2ebdde19cd3c8cdf8df3fc165bc7827334bc4e353465048b36f7deeae8ee0918"}, - {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:610f5f83dd1e0ad40254c306f4764fcdc846641f120c3cf424ff57a19d5f7ade"}, - {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5601f44a0f38fed36cc07db004f0eedeaadbdcec90e4e90509480e7e6060a5bc"}, - {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:e6906d6f48437dfd80464f7d7af1740eadc572b9f7a4301e7dd3d65db285cacf"}, - {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:766b32c762e07e26f50d8a3468e3b4228b3736c805018e4b0ec8cc01ecd88125"}, - {file = "wrapt-1.13.3-cp36-cp36m-win32.whl", hash = "sha256:5f223101f21cfd41deec8ce3889dc59f88a59b409db028c469c9b20cfeefbe36"}, - {file = "wrapt-1.13.3-cp36-cp36m-win_amd64.whl", hash = "sha256:f122ccd12fdc69628786d0c947bdd9cb2733be8f800d88b5a37c57f1f1d73c10"}, - {file = "wrapt-1.13.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:46f7f3af321a573fc0c3586612db4decb7eb37172af1bc6173d81f5b66c2e068"}, - {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:778fd096ee96890c10ce96187c76b3e99b2da44e08c9e24d5652f356873f6709"}, - {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0cb23d36ed03bf46b894cfec777eec754146d68429c30431c99ef28482b5c1df"}, - {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:96b81ae75591a795d8c90edc0bfaab44d3d41ffc1aae4d994c5aa21d9b8e19a2"}, - {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7dd215e4e8514004c8d810a73e342c536547038fb130205ec4bba9f5de35d45b"}, - {file = "wrapt-1.13.3-cp37-cp37m-win32.whl", hash = "sha256:47f0a183743e7f71f29e4e21574ad3fa95676136f45b91afcf83f6a050914829"}, - {file = "wrapt-1.13.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fd76c47f20984b43d93de9a82011bb6e5f8325df6c9ed4d8310029a55fa361ea"}, - {file = "wrapt-1.13.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b73d4b78807bd299b38e4598b8e7bd34ed55d480160d2e7fdaabd9931afa65f9"}, - {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ec9465dd69d5657b5d2fa6133b3e1e989ae27d29471a672416fd729b429eb554"}, - {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dd91006848eb55af2159375134d724032a2d1d13bcc6f81cd8d3ed9f2b8e846c"}, - {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ae9de71eb60940e58207f8e71fe113c639da42adb02fb2bcbcaccc1ccecd092b"}, - {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:51799ca950cfee9396a87f4a1240622ac38973b6df5ef7a41e7f0b98797099ce"}, - {file = "wrapt-1.13.3-cp38-cp38-win32.whl", hash = "sha256:4b9c458732450ec42578b5642ac53e312092acf8c0bfce140ada5ca1ac556f79"}, - {file = "wrapt-1.13.3-cp38-cp38-win_amd64.whl", hash = "sha256:7dde79d007cd6dfa65afe404766057c2409316135cb892be4b1c768e3f3a11cb"}, - {file = "wrapt-1.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:981da26722bebb9247a0601e2922cedf8bb7a600e89c852d063313102de6f2cb"}, - {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:705e2af1f7be4707e49ced9153f8d72131090e52be9278b5dbb1498c749a1e32"}, - {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:25b1b1d5df495d82be1c9d2fad408f7ce5ca8a38085e2da41bb63c914baadff7"}, - {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:77416e6b17926d953b5c666a3cb718d5945df63ecf922af0ee576206d7033b5e"}, - {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:865c0b50003616f05858b22174c40ffc27a38e67359fa1495605f96125f76640"}, - {file = "wrapt-1.13.3-cp39-cp39-win32.whl", hash = "sha256:0a017a667d1f7411816e4bf214646d0ad5b1da2c1ea13dec6c162736ff25a374"}, - {file = "wrapt-1.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:81bd7c90d28a4b2e1df135bfbd7c23aee3050078ca6441bead44c42483f9ebfb"}, - {file = "wrapt-1.13.3.tar.gz", hash = "sha256:1fea9cd438686e6682271d36f3481a9f3636195578bab9ca3382e2f5f01fc185"}, + {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1"}, + {file = "wrapt-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320"}, + {file = "wrapt-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, + {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, + {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d"}, + {file = "wrapt-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7"}, + {file = "wrapt-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00"}, + {file = "wrapt-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569"}, + {file = "wrapt-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed"}, + {file = "wrapt-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471"}, + {file = "wrapt-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a"}, + {file = "wrapt-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853"}, + {file = "wrapt-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c"}, + {file = "wrapt-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456"}, + {file = "wrapt-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57"}, + {file = "wrapt-1.14.1-cp38-cp38-win32.whl", hash = "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5"}, + {file = "wrapt-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d"}, + {file = "wrapt-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383"}, + {file = "wrapt-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe"}, + {file = "wrapt-1.14.1-cp39-cp39-win32.whl", hash = "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5"}, + {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"}, + {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, ] wsrpc-aiohttp = [ {file = "wsrpc-aiohttp-3.2.0.tar.gz", hash = "sha256:f467abc51bcdc760fc5aeb7041abdeef46eeca3928dc43dd6e7fa7a533563818"}, @@ -2954,6 +3070,6 @@ yarl = [ {file = "yarl-1.7.2.tar.gz", hash = "sha256:45399b46d60c253327a460e99856752009fcee5f5d3c80b2f7c0cae1c38d56dd"}, ] zipp = [ - {file = "zipp-3.7.0-py3-none-any.whl", hash = "sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375"}, - {file = "zipp-3.7.0.tar.gz", hash = "sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d"}, + {file = "zipp-3.8.0-py3-none-any.whl", hash = "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"}, + {file = "zipp-3.8.0.tar.gz", hash = "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad"}, ] From 93caf11efdc0f4bfe0504bdb5ac973babf06028a Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 8 Jun 2022 17:10:55 +0200 Subject: [PATCH 347/350] added fake 'charset_normalizer' for python 2 hosts --- openpype/vendor/python/python_2/charset_normalizer.py | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 openpype/vendor/python/python_2/charset_normalizer.py diff --git a/openpype/vendor/python/python_2/charset_normalizer.py b/openpype/vendor/python/python_2/charset_normalizer.py new file mode 100644 index 0000000000..84ec661759 --- /dev/null +++ b/openpype/vendor/python/python_2/charset_normalizer.py @@ -0,0 +1,8 @@ +"""Fake 'charset_normalizer' for Python 2 to raise ImportError. + +Needed for 'requests' module which first checks for existence of +'charset_normalizer' (Python 3) but does not raise 'ImportError' but +'SyntaxError'. +""" + +raise ImportError("charset_normalizer not available") From 886646c0269d3188c9f46deb5bc6f4a7d6a8f131 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 9 Jun 2022 10:34:55 +0200 Subject: [PATCH 348/350] modified implemenetation to be able also use review session to download delivery --- .../event_handlers_user/action_delivery.py | 244 ++++++++++++------ 1 file changed, 169 insertions(+), 75 deletions(-) diff --git a/openpype/modules/ftrack/event_handlers_user/action_delivery.py b/openpype/modules/ftrack/event_handlers_user/action_delivery.py index 9ef2a1668e..86d88ef7cc 100644 --- a/openpype/modules/ftrack/event_handlers_user/action_delivery.py +++ b/openpype/modules/ftrack/event_handlers_user/action_delivery.py @@ -8,6 +8,9 @@ from bson.objectid import ObjectId from openpype.api import Anatomy, config from openpype_modules.ftrack.lib import BaseAction, statics_icon from openpype_modules.ftrack.lib.avalon_sync import CUST_ATTR_ID_KEY +from openpype_modules.ftrack.lib.custom_attributes import ( + query_custom_attributes +) from openpype.lib.delivery import ( path_from_representation, get_format_dict, @@ -28,14 +31,14 @@ class Delivery(BaseAction): settings_key = "delivery_action" def __init__(self, *args, **kwargs): - self.db_con = AvalonMongoDB() + self.dbcon = AvalonMongoDB() super(Delivery, self).__init__(*args, **kwargs) def discover(self, session, entities, event): is_valid = False for entity in entities: - if entity.entity_type.lower() == "assetversion": + if entity.entity_type.lower() in ("assetversion", "reviewsession"): is_valid = True break @@ -54,9 +57,9 @@ class Delivery(BaseAction): project_entity = self.get_project_from_entity(entities[0]) project_name = project_entity["full_name"] - self.db_con.install() - self.db_con.Session["AVALON_PROJECT"] = project_name - project_doc = self.db_con.find_one({"type": "project"}) + self.dbcon.install() + self.dbcon.Session["AVALON_PROJECT"] = project_name + project_doc = self.dbcon.find_one({"type": "project"}, {"name": True}) if not project_doc: return { "success": False, @@ -65,8 +68,8 @@ class Delivery(BaseAction): ).format(project_name) } - repre_names = self._get_repre_names(entities) - self.db_con.uninstall() + repre_names = self._get_repre_names(session, entities) + self.dbcon.uninstall() items.append({ "type": "hidden", @@ -195,47 +198,109 @@ class Delivery(BaseAction): "title": title } - def _get_repre_names(self, entities): - version_ids = self._get_interest_version_ids(entities) - repre_docs = self.db_con.find({ + def _get_repre_names(self, session, entities): + version_ids = self._get_interest_version_ids(session, entities) + if not version_ids: + return [] + repre_docs = self.dbcon.find({ "type": "representation", "parent": {"$in": version_ids} }) return list(sorted(repre_docs.distinct("name"))) - def _get_interest_version_ids(self, entities): - parent_ent_by_id = {} + def _get_interest_version_ids(self, session, entities): + # Extract AssetVersion entities + asset_versions = self._extract_asset_versions(session, entities) + # Prepare Asset ids + asset_ids = { + asset_version["asset_id"] + for asset_version in asset_versions + } + # Query Asset entities + assets = session.query(( + "select id, name, context_id from Asset where id in ({})" + ).format(self.join_query_keys(asset_ids))).all() + assets_by_id = { + asset["id"]: asset + for asset in assets + } + parent_ids = set() subset_names = set() version_nums = set() - for entity in entities: - asset = entity["asset"] - parent = asset["parent"] - parent_ent_by_id[parent["id"]] = parent + for asset_version in asset_versions: + asset_id = asset_version["asset_id"] + asset = assets_by_id[asset_id] - subset_name = asset["name"] - subset_names.add(subset_name) + parent_ids.add(asset["context_id"]) + subset_names.add(asset["name"]) + version_nums.add(asset_version["version"]) - version = entity["version"] - version_nums.add(version) - - asset_docs_by_ftrack_id = self._get_asset_docs(parent_ent_by_id) + asset_docs_by_ftrack_id = self._get_asset_docs(session, parent_ids) subset_docs = self._get_subset_docs( - asset_docs_by_ftrack_id, subset_names, entities + asset_docs_by_ftrack_id, + subset_names, + asset_versions, + assets_by_id ) version_docs = self._get_version_docs( - asset_docs_by_ftrack_id, subset_docs, version_nums, entities + asset_docs_by_ftrack_id, + subset_docs, + version_nums, + asset_versions, + assets_by_id ) return [version_doc["_id"] for version_doc in version_docs] + def _extract_asset_versions(self, session, entities): + asset_version_ids = set() + review_session_ids = set() + for entity in entities: + entity_type_low = entity.entity_type.lower() + if entity_type_low == "assetversion": + asset_version_ids.add(entity["id"]) + elif entity_type_low == "reviewsession": + review_session_ids.add(entity["id"]) + + for version_id in self._get_asset_version_ids_from_review_sessions( + session, review_session_ids + ): + asset_version_ids.add(version_id) + + asset_versions = session.query(( + "select id, version, asset_id from AssetVersion where id in ({})" + ).format(self.join_query_keys(asset_version_ids))).all() + + return asset_versions + + def _get_asset_version_ids_from_review_sessions( + self, session, review_session_ids + ): + if not review_session_ids: + return set() + review_session_objects = session.query(( + "select version_id from ReviewSessionObject" + " where review_session_id in ({})" + ).format(self.join_query_keys(review_session_ids))).all() + + return { + review_session_object["version_id"] + for review_session_object in review_session_objects + } + def _get_version_docs( - self, asset_docs_by_ftrack_id, subset_docs, version_nums, entities + self, + asset_docs_by_ftrack_id, + subset_docs, + version_nums, + asset_versions, + assets_by_id ): subset_docs_by_id = { subset_doc["_id"]: subset_doc for subset_doc in subset_docs } - version_docs = list(self.db_con.find({ + version_docs = list(self.dbcon.find({ "type": "version", "parent": {"$in": list(subset_docs_by_id.keys())}, "name": {"$in": list(version_nums)} @@ -255,11 +320,13 @@ class Delivery(BaseAction): ) filtered_versions = [] - for entity in entities: - asset = entity["asset"] - - parent = asset["parent"] - asset_doc = asset_docs_by_ftrack_id[parent["id"]] + for asset_version in asset_versions: + asset_id = asset_version["asset_id"] + asset = assets_by_id[asset_id] + parent_id = asset["context_id"] + asset_doc = asset_docs_by_ftrack_id.get(parent_id) + if not asset_doc: + continue subsets_by_name = version_docs_by_parent_id.get(asset_doc["_id"]) if not subsets_by_name: @@ -270,20 +337,24 @@ class Delivery(BaseAction): if not version_docs_by_version: continue - version = entity["version"] + version = asset_version["version"] version_doc = version_docs_by_version.get(version) if version_doc: filtered_versions.append(version_doc) return filtered_versions def _get_subset_docs( - self, asset_docs_by_ftrack_id, subset_names, entities + self, + asset_docs_by_ftrack_id, + subset_names, + asset_versions, + assets_by_id ): - asset_doc_ids = list() - for asset_doc in asset_docs_by_ftrack_id.values(): - asset_doc_ids.append(asset_doc["_id"]) - - subset_docs = list(self.db_con.find({ + asset_doc_ids = [ + asset_doc["_id"] + for asset_doc in asset_docs_by_ftrack_id.values() + ] + subset_docs = list(self.dbcon.find({ "type": "subset", "parent": {"$in": asset_doc_ids}, "name": {"$in": list(subset_names)} @@ -295,11 +366,14 @@ class Delivery(BaseAction): subset_docs_by_parent_id[asset_id][subset_name] = subset_doc filtered_subsets = [] - for entity in entities: - asset = entity["asset"] + for asset_version in asset_versions: + asset_id = asset_version["asset_id"] + asset = assets_by_id[asset_id] - parent = asset["parent"] - asset_doc = asset_docs_by_ftrack_id[parent["id"]] + parent_id = asset["context_id"] + asset_doc = asset_docs_by_ftrack_id.get(parent_id) + if not asset_doc: + continue subsets_by_name = subset_docs_by_parent_id.get(asset_doc["_id"]) if not subsets_by_name: @@ -311,40 +385,60 @@ class Delivery(BaseAction): filtered_subsets.append(subset_doc) return filtered_subsets - def _get_asset_docs(self, parent_ent_by_id): - asset_docs = list(self.db_con.find({ + def _get_asset_docs(self, session, parent_ids): + asset_docs = list(self.dbcon.find({ "type": "asset", - "data.ftrackId": {"$in": list(parent_ent_by_id.keys())} + "data.ftrackId": {"$in": list(parent_ids)} })) - asset_docs_by_ftrack_id = { - asset_doc["data"]["ftrackId"]: asset_doc - for asset_doc in asset_docs + + asset_docs_by_ftrack_id = {} + for asset_doc in asset_docs: + ftrack_id = asset_doc["data"].get("ftrackId") + if ftrack_id: + asset_docs_by_ftrack_id[ftrack_id] = asset_doc + + attr_def = session.query(( + "select id from CustomAttributeConfiguration where key is \"{}\"" + ).format(CUST_ATTR_ID_KEY)).first() + if attr_def is None: + return asset_docs_by_ftrack_id + + avalon_mongo_id_values = query_custom_attributes( + session, [attr_def["id"]], parent_ids, True + ) + entity_ids_by_mongo_id = { + ObjectId(item["value"]): item["entity_id"] + for item in avalon_mongo_id_values + if item["value"] } - entities_by_mongo_id = {} - entities_by_names = {} - for ftrack_id, entity in parent_ent_by_id.items(): - if ftrack_id not in asset_docs_by_ftrack_id: - parent_mongo_id = entity["custom_attributes"].get( - CUST_ATTR_ID_KEY - ) - if parent_mongo_id: - entities_by_mongo_id[ObjectId(parent_mongo_id)] = entity - else: - entities_by_names[entity["name"]] = entity + missing_ids = set(parent_ids) + for entity_id in set(entity_ids_by_mongo_id.values()): + if entity_id in missing_ids: + missing_ids.remove(entity_id) + + entity_ids_by_name = {} + if missing_ids: + not_found_entities = session.query(( + "select id, name from TypedContext where id in ({})" + ).format(self.join_query_keys(missing_ids))).all() + entity_ids_by_name = { + entity["name"]: entity["id"] + for entity in not_found_entities + } expressions = [] - if entities_by_mongo_id: + if entity_ids_by_mongo_id: expression = { "type": "asset", - "_id": {"$in": list(entities_by_mongo_id.keys())} + "_id": {"$in": list(entity_ids_by_mongo_id.keys())} } expressions.append(expression) - if entities_by_names: + if entity_ids_by_name: expression = { "type": "asset", - "name": {"$in": list(entities_by_names.keys())} + "name": {"$in": list(entity_ids_by_name.keys())} } expressions.append(expression) @@ -354,15 +448,15 @@ class Delivery(BaseAction): else: filter = {"$or": expressions} - asset_docs = self.db_con.find(filter) + asset_docs = self.dbcon.find(filter) for asset_doc in asset_docs: - if asset_doc["_id"] in entities_by_mongo_id: - entity = entities_by_mongo_id[asset_doc["_id"]] - asset_docs_by_ftrack_id[entity["id"]] = asset_doc + if asset_doc["_id"] in entity_ids_by_mongo_id: + entity_id = entity_ids_by_mongo_id[asset_doc["_id"]] + asset_docs_by_ftrack_id[entity_id] = asset_doc - elif asset_doc["name"] in entities_by_names: - entity = entities_by_names[asset_doc["name"]] - asset_docs_by_ftrack_id[entity["id"]] = asset_doc + elif asset_doc["name"] in entity_ids_by_name: + entity_id = entity_ids_by_name[asset_doc["name"]] + asset_docs_by_ftrack_id[entity_id] = asset_doc return asset_docs_by_ftrack_id @@ -396,7 +490,7 @@ class Delivery(BaseAction): session.commit() try: - self.db_con.install() + self.dbcon.install() report = self.real_launch(session, entities, event) except Exception as exc: @@ -422,7 +516,7 @@ class Delivery(BaseAction): else: job["status"] = "failed" session.commit() - self.db_con.uninstall() + self.dbcon.uninstall() if not report["success"]: self.show_interface( @@ -464,11 +558,11 @@ class Delivery(BaseAction): if not os.path.exists(location_path): os.makedirs(location_path) - self.db_con.Session["AVALON_PROJECT"] = project_name + self.dbcon.Session["AVALON_PROJECT"] = project_name self.log.debug("Collecting representations to process.") - version_ids = self._get_interest_version_ids(entities) - repres_to_deliver = list(self.db_con.find({ + version_ids = self._get_interest_version_ids(session, entities) + repres_to_deliver = list(self.dbcon.find({ "type": "representation", "parent": {"$in": version_ids}, "name": {"$in": repre_names} From 5d36e381906d25ae8593c72ee0d409090e842ecf Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 9 Jun 2022 15:21:12 +0200 Subject: [PATCH 349/350] extractor does not change output frame range --- .../plugins/publish/extract_sequence.py | 34 ++----------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/openpype/hosts/tvpaint/plugins/publish/extract_sequence.py b/openpype/hosts/tvpaint/plugins/publish/extract_sequence.py index d4fd1dff4b..77712347bd 100644 --- a/openpype/hosts/tvpaint/plugins/publish/extract_sequence.py +++ b/openpype/hosts/tvpaint/plugins/publish/extract_sequence.py @@ -73,14 +73,8 @@ class ExtractSequence(pyblish.api.Extractor): scene_bg_color = instance.context.data["sceneBgColor"] - # --- Fallbacks ---------------------------------------------------- - # This is required if validations of ranges are ignored. - # - all of this code won't change processing if range to render - # match to range of expected output - # Prepare output frames output_frame_start = frame_start - handle_start - output_frame_end = frame_end + handle_end # Change output frame start to 0 if handles cause it's negative number if output_frame_start < 0: @@ -90,32 +84,8 @@ class ExtractSequence(pyblish.api.Extractor): ).format(frame_start, handle_start)) output_frame_start = 0 - # Check Marks range and output range - output_range = output_frame_end - output_frame_start - marks_range = mark_out - mark_in - - # Lower Mark Out if mark range is bigger than output - # - do not rendered not used frames - if output_range < marks_range: - new_mark_out = mark_out - (marks_range - output_range) - self.log.warning(( - "Lowering render range to {} frames. Changed Mark Out {} -> {}" - ).format(marks_range + 1, mark_out, new_mark_out)) - # Assign new mark out to variable - mark_out = new_mark_out - - # Lower output frame end so representation has right `frameEnd` value - elif output_range > marks_range: - new_output_frame_end = ( - output_frame_end - (output_range - marks_range) - ) - self.log.warning(( - "Lowering representation range to {} frames." - " Changed frame end {} -> {}" - ).format(output_range + 1, mark_out, new_output_frame_end)) - output_frame_end = new_output_frame_end - - # ------------------------------------------------------------------- + # Calculate frame end + output_frame_end = output_frame_start + (mark_out - mark_in) # Save to staging dir output_dir = instance.data.get("stagingDir") From d09697db6b2a8d1cf9b9ff35d4e743f43528ae27 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 9 Jun 2022 15:21:20 +0200 Subject: [PATCH 350/350] make sure members are strings --- openpype/hosts/tvpaint/api/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/tvpaint/api/pipeline.py b/openpype/hosts/tvpaint/api/pipeline.py index f473f51457..60c61a8cbf 100644 --- a/openpype/hosts/tvpaint/api/pipeline.py +++ b/openpype/hosts/tvpaint/api/pipeline.py @@ -385,7 +385,7 @@ def ls(): if "objectName" not in item and "members" in item: members = item["members"] if isinstance(members, list): - members = "|".join(members) + members = "|".join([str(member) for member in members]) item["objectName"] = members return output

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 z z^fX;~&JKEbYMlC@3RZfWR-6MHlp|F^!*^eozFhu!V#m@WIH@Rl%@pT)vC)ReLMk*v zGuU}FgrAnz-{!N^N$HO?+6mI{>d&aUSNoTiI>EtGOIW}+xV@F)-5ek;yo1}F+;%r$ zEDgs@Nk~b6XHz0+OY*afhV;WoA}rV69o)KYE8RGGlDe=X7u`S<@I@qXO;dTe`#Xoq z(60U)oap<)yQ076j4F-sB2B6*iOUJ>V5Z~svuzmmd+Ym!X*4U&C$Uzu3CABHvDTLq zOHNoa#_-+z_VW~Ps6!s;w{xGr;=V&mJ)TCR#Hy9!dYSY>+z}#)O87#ULB(Q;F5J3} zPIh!%v+2dvE(R5^~wmD?IIkcJQzGw&#~^v5Wfu#iId z3hwi@b_jVoyCE;&J`!R!Bqp& zQigcp0P0zS zC1HWI?%;p?C;9DPQ2esHjN5Cu&sW-sv?fbM!*LzO1ODQVIHpsjlYvXqg&8{c?Co@f zO3^RN4PU4N5lJh!)-2NU&KDU*l`&m}-?+Xc<@t5FBvnWubD8QErm3v-l+vE=Z3{_O zNXmIxLKjR2xH0^wQDbTtVM)A~L}~jtXHoz`(|1rC6l!lbn zCHxYIPLGe%Q_ek)?wuH;tQC4pk&`R_u6!SIs}C1cB_%2OJBY4NOu;1;(FqkYTzl1% z(O5DARk?Pfr;tVifgJ5`sB#>M`QFo@v3O|cY-1)q#jO3e{PtfdK8McJxqX29ya9b1 zIku(3RIx;5H!Mj>X-9SNNx%@E=KMNc$kRpJ&Z6{&b#(m50YA{$LztwJ%tyYY6{8+f zU?q!)Ytqgo$jJy?Fy!&T*)-4_O)KiprO`g%H8{X8A0V+N;{f-Czisq7U5=l}pOe`B zjEghG^oMZ|I`hXGIjE&V$tgSF8_K z3}#7PvxzH6Vk%WXa{V1e5vnMOD>Q0@0!a<82*6Hj#%fn!4Pq@OJ>YMWSj!DX!wHKS zd79b#?@2hJ#btBIar-d$xtIIi+St+6ALWwkiiNMdpem?JIgd(-rdTS`;F>kGX~#MA zt%rV1DG|3PJICCh^4KhEIfaa6!M%NHOZs1VBU8g5Ve9g2TAoB@3aQWyQsm%#i(5+b zRoj8r9s-*`Ocbg*5(Tm`T#dEdxKRl#ivdEahVLg~(~8Tni!Tc4l=pDo{S6&losqK5 z%*;&5R*p@xgd}KVj_`5vc#BElDd+5@yT?Z zL250Fb-lf392gz#L*g$bX8{pc2Icm|tk9EA)8=i1^v#2NsoS<^lM_)gSt%shx%|&( zkHYtPH$oc&5jO}yxGMV5izT!ye$|ZCX26=O7Jlq|HeyVVuEW*=zSh+?qp zKaczc+`^>wDH5?tae&H*pv!9hAWe&Wu`FGygw&~nedUlWY&n^&%)(u#gMb?hKN z7-jvg@kX_{It0Ur@8`R@yOBOdh}48)=y;!HJ(W;9j;+aQx*=YWMN$XP0AVVlhArp_h^Ytrt@0MgARY!y@wXPhGHmJ3UsIV1h$_ zmjohM=&qb1s!Fm7d&m2KCydfiT}7s>F2iQ(YL+Rau@LaOLiPpZXMcH>Za*QhMwcDU zGTZiXyNX0vpg3I!PHgxEIKW@<4NO{2OrNGi+4E}vGehmG?-Z@K<^c)FXc683AihL#1dC20Nsg~Zw#NazOJF*d&THELYd z&=iCvllR@uU*Nk)xcbN0vydt7|Bxuq`27YBZ&B#BGkvFvlOYmT7NLM`CiBzu^quF? zLFOsT4GB1^d!;{BCFb&YuZASji`{7yB9@BqAbiujj2DtvQ%PAEmA}>PjT=&R zGzDRW@I?}FhObOGzM0#VOl%LdihovbI(6phg3(3g7@<%S#dJPT+qR!gcTZ1JT9t?o z_lZN?ZeS&`RT2XT>G^g9v*mw>QD@v=!nFi*7khu2%rscf<@#?~tzY^z^f~Q@%e(6T`=|aSp2J8l6?Ib1SgVu5t)?nj?R6ClIuq3V_ zk?TRj46R_iz2c z08RAv(9Ee3>Z$Z>uV!niMGZ_cvd@KzUBi62T~FfF zOo4Xvt)$D>Y@pwa4$<8whpC69EZfVQCg%rr+_Htoa#;9qz_kR1CFDT6UC1@-gcrC!k z3SR8LTcsN|uCTU#+>k*n5-mYk(skiBegN3vfFs+vG2M^|5Zkp|W#0I^mpdiR6GNw% zpvnPV$P_aO!&!ayHo9l*6lLSWaFW!yxc5o@syKmS7og-io-Hb4*|a8;r3?F4(rUw^ zLn9+}+uq;Mk*NvFv6O}I8&t`0+@h$KW14Q-upZ4h=H2uCJ~SEwnJVUKBn<4oRi*1g zBr-7kv>^kl16qQxLih!@zainukYqf>148nAY~3#FgDB)D+_YEsJz$opLV?cPGDt(V zNtsfWoxxhAt1uZ=GprlJEg@endp5L4k1Km zsme?0=a?>~Qs(}2seJu6E`L$e?j&_Gc+SJl`w>d6B?x!{&Ac{lY|N!hWaL*`*5~_EnPvGtHL8Q>I(E}xv#Lf`@MK2* zxz9FaP<2L25*8ECX<2y(nHwP1CXv>wxMk$-;bRROphUi0>gH9S@iqyWKzdRs+PHHE zJy0x!gA1!mSwvA=R3$=oscEO=Ie8ASnzw!RD%#nxGX8Xg*=2OqkJzJK@-jj;Mx zdQC}+U+0>jO6P2`8xt`kRiVIr8Y1A1Q%B zG3lyoSlAgH92}%WJsFxgeaed=j37o*nuQRNm04XY@%-}==`j(mWtHx{-T~Uo(vm%0 zp#A&z(~oxDLA&?wqsc;nvMfnuxPg??h+Zzs#Gd;%DsE4%(iK6>@U!|%BgVBVBO6EaSP?No80H1cl{ z6n5|M(T;&t^xK;U>7u>?8a;S~ezNOM`pPeVL3QA$ia;j)yYOH?4VxCfeup38lEuQk_V#a@!w(K^+c$H3 z0LJXTGdIx)951W+Q~}aQ3WjqK4}7+^clXlP?jBlirfF(;g!cb%7hQYbeRSa1QJR>V zqONp?R`&OkN>vK=)8{*=f3Qozg#vae%Oj^EQ(3{bjDlradrWC=Hy=?H{>q;{Mn0dBaOFp2>Wcm9FX4j^kuj_VrV~zlX|&3S&FqXG9>%dq#7w z_$r;nlGNr@hPtN{k(A>n}IlG2m zUQZ&BIVtJ`z;lEe__py8|XEbjXeKJO>>9?OB# zd&$a|;cMmgZ{0$tnPkHGqd+btDMe-M6s=%MYD-rSt>fRsiDSp$_W~kcWl<&(+^1VXu1e99(x_aUJ)7 zowi3=Qaj9qHsl!AXfB(Y<{M3AGTk$2bEc3hm7MFY{s*0IuSFrN+dPBYC%HXoj_!y+ zz}#=j1bmA{TN0M^h`*B`G-3-8FrAcY88)w{aQiAZWQ6!`y~Z%u-)D@S7)|9itTziR zS`|xt;pSM#05=$A@Og59A%ywmlt&}~SBI{7s zK>v|$*L}h=vq$WlbtvnWhs$>Mm^nT@ar65>pe3dD$4j__SW-iP*#6r{sS# zCIrG7E|lRs_b%q%xxTbHp6{FNE0y+Vrl&^SvB^UxC#DXMPfZRN^7%vAo}Q62vt5S_ zgT|=nPTDCuZ_gA8j@?z*b>(}OHOqv?@`L9fB!86}CRe2^=E}9)-qi~EtQL#5CM*Sh zkb8Lo;Fk)bGIkQ<3R?h}7$CQ&$sNaUFLZ}xB)wuZmmj^lYbO8knX++;$UHrrPUV00 z=T~Z5l13tU-l4o5(kQ|8W^j(~i1t7tfX_F3rqFt!BM1wS>6ZVQL|TojDA}$B408Jr zw+mz`v3bWKe&f<-LVY{5fT3!1C}cd~|K#>+Zfoc0j=6Oew`-a?2YbEIF@y!k2m1x- z_V5F4eO0<+!n}psv$_A<_}p6?F-DEf1kbVOk#M!SsD|z+a{Bu`CtE6)RXxyAgr$H7 z%@YJZTAv_cBj~Bp9TN!U#1Pu>&wTDsBgUxF8Q^(^AI3lD_C{{&=jc93qI~?Do3Y4g zBhZnA1;`515Wi8Y?SoYPyTC+38k=+ZoKNt%KWoGoHQF0ImryDmIo)1F)eY+ajO(zg zezDog$2SrkOIUz>@E_%g^Gg!;fM-?djtTV#+@8bz|D9hy&F!J3j7QXHKgc*h)FgNl z3ID1!HJk=l1yp0ceJRJ*3g~FU3Sk$C_$>IlAb7gFN?%Mc>^NRRLRG{Ljm{CJF(-Jg z43O|bhi~8oHJpM>B=Bzk9JhT-IJB05CM@#(wJ;&x!INqizoO!FwU8bF6Ao2Lu#@Tq*x zzmX{RdVsH?)3RuQq>wog4#{v+K<3+|VEiy(Vt|eGO+1etT*BeCBs5{g0275L+aHl2 zBc$l4wu=a0BEl;f!PH;lbHCb7DLpji59t7k`2(^-SXicp)36JO)JR`l&T3E13{6-G zkQ3&^Jn>Ln1f&In`x#YE!Gye2wpa6cNJk4_uLGUr*w@M6XO614kf-$LTB+dm)*o$Smg3oFhM>RsmAp$TgqkQ3|8JV_zGBlF|4skUEIOk|vME9_hR zdJngwd_A3&p#{Ou5bFk6Yhjy$oeE(!wafzmw#^@L`$#+Ity(H*!dd_@(Rk9rLmt1Z z@2A>!e=wn6L4xG&<90oWkFRxn=|-wiZ}2l)M>y~uS|sEIL}t!<-et{K{ot)zeT!4e03ptxHJ|InU@OE6kHRkr6x`S{Hfp$^EPd#tS>ZS)ft$e zJmHaB8!7!AGD%_M?f5An4pmte>p5B{FJtCkU51hs5`F8Hqep@JPo_?Lz1N2@>gE zP*wRJz3bOlXu@hRc_mGphh6$BtkRN^Sl(E-Fn$TfG8RZqPkbQN_gsHr%7H? zl2U3OHZf2xtCqmyxqu8D2+cyq+2J}|Ph$blgtd&26aQVj$gmJ#uR?x#s4KOqim|kd~mnz&Gn@wD4zy^9CuXZ3oE?>I?`AeqN98{b0;L zK*A2TuUS<|soKFnK1gC06~^%$+~6k#!h%{oS5EX=f$!ih5+nt(`gNyCsm%;cSWN`E zFn%K2hj^hP>nWtJmyxi=z|quN;N^3&VZp}*>5lUKQ0oqvE+L6Qx;Q9b$4S(4L~=QJ zZWm-L$_90*ESsYwHz^63a?EH@dsDJyWJ6>Ck|bui^^%Y-&y=r_obVk$Vp_StfA?I# zm_gh~mWK+;KhP>)^Fk9=6N48H$m4S|n<=CUs66oNdanGto>(bcIM+CcN0C&`gvH}k zs^)wNOTC{feNR0AlKLSDzp00~?a`7{^FtF>3xF3AB%FI?`!^}Mz`^nLB!Y0~Yp|~s zxKCELb^wU=yWFnfc2ld`@H!cquv!pup=MnY>^FQiKJS5nK8QH$eu>rINy$1(2Rlxd<*J zkVK*Kd4we;RE;)(CagAsT$m5bcB}ea`X(Wu7a0ehOu~V3m24|WNMrTzRa#2GW(KJV zInPhX2HVqa5}7U@(>AE~hbF8JfLzGR2BzEu!i0qew*l-RZj=ok;q~xmnlF&u0Fn_r z_z%kl*9+8*JV_zKYF0N4jirMotPX@+=tpGpAW00nbTF`YQLu9dGE=@zcn`I+PrfRH ze42vYz3?ud+GWJ6+F6{I4btG4d{rbgD&MOe$-I0&rO8PH(1fMoK@tL*E;FUkw9tg5 zp`p<-(1fL-q0utXgr%XO(K674rJe~&FgEY`8E2Dh<9#OCiw%Y~Ha0mK zyaW@T0UHBLhGoI*vUyo;RF+1XJahBC{h#lgQ{8oYMp}(Dl4eHz&D8CxQ>Q}ry?wqu zRo&IW6TkFHN|9m}p@+jp4(m9q<*;q!@gKGMT+H(lt5A}N0c~R%Ha|YSJ?JKQsO|~YDSfmNFLzuLk@S@_CCu?kz&~( zC6E+n8W>`_+QQ>(3-2Q9E2W?osh4s)hacD$0mEV`Qk)T_1d`%(0>ev>=kR0>PvP(+ z(xImmCk_mGeV4;`YNC_mxVu5*#XK;9qg>(*M zWdpYof6l^JDV;w_u?VCDlHz#KM@kkyPwH(f_h&6qoEYXviR9xPKF^`jnVlj=6h5$g$4_ziRSwVN(AAl} zB7g~Ew|vME3%Cmj0n3YE2@(VtNa$k71_2N0!AN3`085m#zV{Q)#{@Jz>84NNMgTmQ zk|&+x!Epki!V^OP*}_X3uz+Pza0eQ~hy^UIvfgx88gRV+jl;({+(deeQlv-;B!vLa zX1s`$IAHXaGqAoCmI6V*5+Hj>pM^l!&*1;e-+OT;fJyA{la80)#^DD{7LRnQq*w|tsbKgE%f(znIa#~31vHP zo`|RgEMj@Ohb?g@8*T@F3+eh?DOM3u0$Du(Q9PH!pOCI}dpZG+0?T6{e1{1mT^?f@ zf(ZrQ34R+`as~k&%jpDG4E`GqpCu)h6e}DlfvkLBb=&`s!z)N9S5Fr(9EFu$B`|3m zNaUwj#$YnR?Zj9q*#!)Hoi1RW2-NOAa3*eRwm)3PVaDD-R$J+)?!^Iz2-W z7>@c1=|X#7Wzt9&+grt8GI5J#B0Q6HQvOr}L~=dpom(l9tRSQWvT}eqj$h&M8qx>M zP9+{CeRl+wt+qM8U;FYQ#`&4p)!Ff@ymfm1AFqy)0O z@gp4GNP1iDslwf)OLu>sNdv=FDN-C0OePrK!m|Ddc$o220XJyi=8#*G87Yi%Ybmjd!|#*M z@1;16ND1WhVgo60;A(6s@t+(%j=;n*m&{C&V!42c1fKUVTKMTi_Q?Xq46iRZn9N9V zYLF7h>B9>-+(1kF&hamE_!vU!aimyDFpuPyEc|#P`(!Y|;g2}{b21~v(jz61Q;#hi z-bs4D{89lAR$;k^kEC-PDONIUjs#2eAmG8-rNV!3_&*%>CNokj9Z~{0wSd?0_Z$Y2 z87Bz5EBr1rlrQXOXLP{W~26&C=J80?VI`CRp zygT8;OdPi+GgG8kEnp(St9bE#8-%5L9WRXBZeO(`df+etl}A0{(WEDkAwoIGAc`fLa8Z$DXJeV_L+ao|bv6e&`8U?Rbj z?7vC6ZrsTN&r9K%kq;!~DHefr2VcdX@OCyl`F*lORxQ#A_xGf$n4ihbJfV774860PiL> zh>JivgmwJDv3fm+f2ETnk2Z(5bNKC)JW`}MIoLUbXFPCD;oLe=;GD*}jdMJ;i^qx7 z135n6Npd{Mce1bT`~in|@Q?mo$&3^!Qk)#v8~H6#GI?AwZ;`;WBELrZBzuZuAZ6Oe z#>J$=O(#npALQ_olsrm{V;+Q|S91LK^>xu4<~ND1WFz$&5Np_BU|;avr< zW~g$9UZv4lNpNu-qZ1q z{GVe1X2&A6Ide$ljSF~iZ1RY|9k%N;_37hDN-y0 zus4FI&at#Rp5Z!Cz*u6H;A%4CY(+{SF@`w&8;7SQGZuj_a(F9~2VQ1#%JJ@ZzLUOj z@eZ0Tw1%iv=`G}oRIk@3CMjF)>+PrhR;4{UQ=y=1kOl?@s4#b!4o=so&@)2)gM-wh z2|AFOqk+jjDp!aGuI{HFtM8?I_IA;|hubuG#SlHEE1>o+qQi6Jv?6)b1qAzc7uYgBlLuUDGK(^ z(YI@Tlq=ULbIu4ok;~GaSeD&3LRa@s(xE+NdYEO!D)*Q5wzKTOo(fIXdMT*XsI;AB zeG{~APnD)wmTNYtUF@ZEx3{T2d5|8R9;Q;cO^s}u)(#BO2pwW(&rvweA#6}?a1C7; z%+djxq9fG-X*)MO!q#Pm4w|gcXj8M@r2e51+7cY0huSTwPn9T}38|6E(x%>S>Io0h z17SDiCo|Lv>(s|}474U`_f(bgg&uCJ#dUwb{BC^M0vAjkTxHVq98(T3nKJ=o^^{Zpv{ztww|LEI&V(rv2dzO;q}+z;(16O$xZ4^EXszVswlSREMZkZA)L< z#eO<(TZ<}u3?G^3rS8%YU9hP_NA{1>!Tff*yiuXC>V7)1^#Zy)Tc!Q`X85;7G+pNX z>S|M-`_(Kos8#Hu_4|jYz2+btnW<8yzK+5*8LIK`i4PssvjO#$%e3(@?{{xV0Uzsj zt(#gwlZx3nJ_h`gZe}S6=HHq7#>;jjMaKmu5xmsx4>|l~GH(&U!j3=7VLX{}HX?P& z6x%p_i%yO_Fy!^er;9v*iH9DhwbNrgJyd;8rBVH>vGUZLX4}o{!q)5`RHyg-?o?&w z*TQW3M;p!2C%30|J*i%;T$C%chl6l(uxoa7pr=~N4c3`Ba&6ky-KI^md||~zlFenP zl+99+4Oy0dB4NPBij5%dvaj-qpUni+qCgBHKrQ5QDN-yq*tz+~baL|< zun`~;*o?CtDS_zQ&p;k0c3GoWBLA0^Jnl_qo=V)^&eQ(NT;uSO!&~MmwV$63f?t|$ z)n8U?hp(A!1+O1(Hs4rj)&H*12;Vwht^fU4*nCT^RlB}kpLzXEZS1v;^4uTyPgQ=c zyEXO8TT8WH-g;#Ee~gV49zPV&Mb~b~U3|@4^@7~t>QE~)SLp377TR4w@xs}5rcw*3 z$kfqYEK-TD7<)P03_u})k_dlhGi`aQtI`gr(h8}}`R!aFMAKxY1_ESEMk(E-I9;%F z6eNOk_C&o1*b3N;rFwJXipAMZAXrZaR}&|?MD*PpUdBJlzvO_`Jx?nheZf=c;e4Y$ z`sn_#){*gQkxg+UlgY8Y9%xWFP;0k0)x+@WTG)Q_Oso0i=|=t8F*kPfNT&SE^=rC*e7HXMjCJGLD-KfE#&fgH^-mlKH(WAVUNbjQ$gv|s z+lwtaw<|*zwQAHo-Jp7qB~DT=do6uolZuTNg&ExH5>TBPrv~qZ^V&g3^)R3sydEPT zB`5WA-~ojx^Q1Td;9SKy%h8vSp2H^s*bLZ?Cnht_CY;R#@(d1N;jku|ah$-)pfBei z;s=r$rwiY@x;P?dMJNGo^o%_W-@=>m2F+$mup>LnybHVs$Bfz zzA$|8g{ZuPXRpW{3^&iU^F8Nh>)kv0 zGChy0m%F=nJ#B{Pl_xKryD z`~&<#GUIe2?8#HJtH1=34KNgR_>o7cceX;gu96x^yF$kX7xsS0@CSnYVXh;SfqfS8 zskB-&*{IXrN|_#*n+fikp6I@Le6;&3hxd1Vadh9%*AE}K@aDsZuDoM%?25zn>Q#-f z^{l~s;f33K27hyF_rPy#>h1fTjopRodJFl#s#9?NXrpoc?po~)<6-M9VHm!ZP5a-q zIaKS-8z!2;-!z)^>NP?Ay5VAY-C(8is=2A)cY2z^|2Q{Oe(rg_^t|)RGtVv_3ZJm1 z9&A4+Tite1UuN6Ivoq%u4mA6Rnqg*Brk>eUXlF0Z*RpHJtCX$fsKm5U%C%`I8_;0D z{tXjOi}$k)&js@|vfoUodL;xEC zTLPPM*5Pct3k!Epe2haOnQ@%Bfx{d5hlh78pHUR=dK0bP7tppJ1}~ltYS&LrPOUp{ z(OJ85zO3^0a{+L$=!EB{to$`>;jlFHIxu}EtQ zB^oJ~WZRd^QGdQjr40Opkjkwl%{7}e!^AYjq0(;Z#5~9=2pU=GDyU4hGhx`C2w~qd zpgFl|X|&yLAL1Ug3fWwc4KuBJJKPtxoBJtfw+i_j^=7lws)rMkt@fTu*r>297|4}^ z5_7|Jt9EF#5zb=Vt0#jyhDy}cu9Y8c*XmP^B6T+#ROlI`jX{<624xzn_EMqQrgp1A z{ex?1Q)Y~IawqB&U6jeRsTyQyYkv<7&_239?4|q>ctLgQ9a&2wt#R5tRiS*LmphKT zu-de7%`nl-!SpVyGk6!)vGAmuK807_;^}qFkDLhV9Da$z|4U}9W}IyV@&XPw(uqAF zh~=K&$l-68JetYOGl6H{`7hMiU#8gyre8eMu3cZL)z`Hv6}tR!SJTwGVVa(qp**gr zePZy5!=-(3l0=RLSa|+`F|4zZL_i!CzmJXNK(5GyQlxdIZd%L4GRTC|m&?l?UTCku z`tWq7>NT2Z)P!K_>;b_C$cl%QQ5PAk5;2+c572hdVvlB4eFbh-oQF)g-3~`trwUmv z%LEi=YHY;!w%d&((CNw*f+9N?^)?+UH(I-!L8IAS$OS!Nwp|Z`(aC1(U?ps|irk4l z%-Q6Mtya()-`8l))>|3sWqV%8=4rTCY}Q+|tp{2;DpWI+W8*#0KTP@7EIm3^r+g8& z@iI{|^KKd$rq;|M+Eu}EDNuuVsK)!=H?oe-&x|sGG^sk-!#mNEd7v%*{nQ`sPYL8S z5eUE}!Y(NN2`Q1B$co!|YW-I^d?J~#T5&cJ2wsB;H}ynbKC_#YIIy(IvcdE3*h$U9 zyJ-5MyIwp|WdfwENsp(Ue6qt}%!4z=o(D3|D_IE1d_SG21Kvf0O?)5z#Fj85=p)X$$PX)vSPi4AZrz5qhkjpH401du62SuO`+(L|II`7>A zjloS}X{fgo17H;)9>}zBZZs-@9)Hd;0ZmE;oPZa^k+F6wJjCX#nPu;%$bDwIYc#@O zPp#1yZD-re3eGx>I}Sx*;cj?ixQg65`rgg}~n9CO2K=|U!u1KdVRAjbzL z60D^KA~`3ScO1Y=;_$E`UQfO1akdZ$-Zu6TIx+IVT^es-@_^^Etnky{yPrxk`>DP6 z?*FxKdhYt^YIQ9Jf##;C>4}$KMy(6arANjOQx6+E?*e{4ft(B$s>_!dp{N}X#p|f! zfxHj~i@gEv+hCy}q_UAoWlLADkjem)N+FvOomnQ5!%Qeg>Q$Oxf}CTLsk0%(oDJ^u zlKC6>Ds8l*jbp2~6^EUDkjzl};*Z&d=+6QNB(4wtK}9|ZMP;;&9f|M=i{>E9Wk7LZ zo8t$YVe0^sXgkmQ(4ET#8Rmz2JKR-mHI6ixk$N!fr=Cz_wn_WO8m+^PY%A<%hV0Me zf>JhLn+cnT4>a0kwAjlZeL;cxyNm5sd#>_elUu1}<)Owro2>r+K^mY*dVu$%I@86T zCmZB?lM2IY=)7QxcF`P-&ka(6NeILeu31BuZe;>tV%T39p;Cp(gT19@aeyv7pTDE= zef02npAg7}o0&lNojn8sFp0pE_%jZdC-aU2AQ4=!u6j@8Y#@-IBfT0pkvWfBI9$)< z@!4d?a=`N+y_>p54^ZR22Y%z>>6yQts#ey)kTsf3>S9Cv_-mg^4;0u!@reo}Yqs#{ z#(tr+gBjs@IGX-r!Rl+VA;-K*l}QEU0?(q0ulk1zC0gIr#e~vB8#%0lr;;nMksaZ%A638!a8gR0&=^J zEv9r-CR6lI**`S1oG7DGjJ9Qjg#xC+@Guk6ILq6-e*qIGM%pTDQ+GF7jd9HFmsrC4 zALN-f$}QS8)2JT_^X;&UNoz1yqV7zlHQQ<)JltrHvFFF~Owf}lP){L`fw`&O&F0K( zD;t)$Q^j_cx_Y{4u)EeeP@bbh^=>LPxIb*GGsPY{XJeDbW{=QA?1A(!fn2hsLI?I8 zqpAZaR757AdyceGgcE;JAvTN z2z-GjLLRt159EPceU~ME|9gK*_2~_?dsqLn56m8V^K89#F>Z5(ahjZ&rmMDYqmgT_ zq92TpQlCs_Cm;sTw!ra_fGcw}JXW0xl~2e(D$Y}>@ixb1wl|xnwWTiF)YVPru$QvA zyGJJMyIBt3VW!!j(Q26va5z${(M+Spq$Dm0u`Q*11~&%Bq~f|Ko{A*QTd_~g(+^F@ z@)-V(&fn!I$5n(paa>$m5NONzOg>U+w@B8(GjMGJxsf@*Jq#0E$qX`eSdR%O$h3km zJj5hA%EzOP{VlNPQ(%5>gu#Jkv$?k!G@E%Dek(BH1XSlkHq&nJtx~Ol8xy)RMd~Z$ z!fdNObGTI>Wx{E6vv=56XjVq6)!IyMgtmoMCY&*v*tDH?Hx-HmrdWAl%+&Hi`D+#!f) zC5Sa}k)V0*(BZ~~j6VD0st>fRRfM~hXE`FP%w*AIfIZJltM}7x;8?)>;lMwgU@B~f zyR+1;@No*8A&qj8JxtZLFq;`~hQa=PHdD)Gvf~qBeWsM7`cx}N#R8LkE=#pSlUk(` zZQ4Cd?U4g3nm_<15qKcik-lhZvB1KMD7S1cL{A2*l|Y`%0rz*~RkVx6r#QTx$>a89 z#&SdOkMHE`(HiZjO)@+};7&+TBYd z?6s7#IT<3uaM!-_938Cc&=1gr!mS5PT|#$V28zBogWAzUmIk;8kGT zP$mA3Nd2O!a_4;j;+;fr2T#eB6Q*sp*{y>1>=?>bHxMP zmVk7H_h~W%?}su|Y}OCv!*)3gGW&BuxI1hIyO?|SwS(|Lroe|c+n#P?h-`eAn!^WZ zbh<*>>IMo%f)z<10F%hoq|2YcqgX8PYTTb9eaqph!fGUt%Q$?M!`fuVaRASUfIRL= zW-LbpZ~7<7hYh+kKYdj@2yUo1+s}~uhzRy66hksTIY~cx%@e48;dZ+F;C||7Bim_; z7eJ@YQ^Xc#VcGG()$7;qBh82WT$Y3c+HSsd(t}$yi;f;7Z zw2%*y+(no2OU07du*Y>P`KUaeR}qR+M3+ukmRM~Bg7sX zwdz$=Z`@F8HlGn0It*jAL#j6F)X(PO>Cb!y-AZ+8%vC6dwLp%BPFvWSj%}G5rdVr! zIVS_G%)ETStFxmW7m4DCy6bt@39kVmP9+kT#IP416DAc5dWCYU@GyHM80tE=caY9w z?`#W`OJAW#O)iK#y>`t_)1LCI#PQH0hRx7gk&hXMy<*dAUB+=n%nW|irARB@X=lV; zJnp?3c$C!%cqdgw{6(bcK7+Vs*C+W_MczpuPDf;D!^XKZEdr|#Jwh$opLlM@bfs8K zAS#RV0eC4aV{awgmkGjq3RL)Ew#`4ieEW`iseA9(V3F#j3^lm!!P&VLMIZo^2wrvj zY7W1W%sUS3N+<7B{;hnQ>e^C)T|U9KyyVA2*4zA5h;n_R^P?qF4868 zF|4)Xv04a(9b;LK1}@@a0ng(#D~&vWpSkVB6xNzFd*9SmvoqBj<{H&!IIAUB#&TaN z7XN5byIiH`{lt&cJ-r1Q9UqtHFWlAXV*=GYmaa3F$I|obaq)%9$r2|{2(QACha?T5 zS!ne-qG}{!Da$Y|iD)xc#v>HWqjY6*a;MkU-hR4ZU`WC_ef>-*C3*H_FMB4B%udpt zxjFGrrW!Sw(8o|$5pyVPgoXEPUtHV~iSs&iuQcIyJKBAVM1~ka40*;Xc6+Kin%|k0 zc;MxewF@Hh`r^{g*t`1UQhq)73$3kK!M&SX+X~|3kb9)fTx|-Uauf zFBzngE@=lu8tUC$$kbspeZNawuMvpV-Pu;$Pp290uH~76-1|jzI2VTBE>QN9nSAiM zdN)ntX_$6pOiWJFFFo^FbYQ~}-FxuB(I?c+{&u7R zUj`)g9FC?BB=cMyjx8jOD|y#>w=qSLD`BW-5=vI=c{m+S#pGdL4Ai6ixUAFDGJ3q^ z)?p@-YO^6S3~g=b?xl14hvg_D!(%PbxkeK66mlN$v;RW_#=wKKNq#yBso%B^zFxAH%$*rP0;T042@Q+G~2{0vvlbe z+~Fl_3`_mGabyyGA=3R&jI&6@`g za`{7}qi;DdJN+ySVd<@>7~WCq6v$TNqhn+AYd`u-nmd0heS7yKvSf&wVuRY#g|Sec zE9&G&(@DyJs9948l@=m(v5n5Kg|JAn)!l;ehnC9X@>a&xZ8A9`qH0F1?a0Oz*R(Y% zLaW^rv@8T-6S+KyWDXPStrm6X^0dCEht36=tXWH!j;y0C{R48TeULqpozoNa;PfP3 zK}?gFI|=n+NDvAh;?st-Zb_QV9X4zwPmhMlV2oW+^DIOsq34y8eF{w1+SKPkOc!lp z&O#JLqB^)LvHoaZRPLvv_U5HcSH2W2q3wuJo>R$ZGPf2og}R-~jMLsmy#x)$i6nN#uD<2NMM;SQTc1SK45^auwKy_z&(G+w^XfCwh|0P= zIi9h+E#65(0x(!A(boP!x`@f-inZ%yJJ8il<4hh8vS)HXhh6NQjMb|0kYf?c#xt2< z*%tW%qvIDFethWsmi9yB0gSBnCnAl&&81jb6NM2tP^wsxdc>}A zORLOJYlZPI%k~TXH1A1NY=4l*XXuU+1%DQ1!_UuV`>0rMQJ%fIda-@(^21MbqAGMQ{VWf=DmZw53%^vg@WBM42p+n6OwJPS=IaUdv}#&YMSXr2sz zMQz7*xnmg*k7?QsfH{vw-jBjw$y~io4K{#1`8;jx>8A^rL@rymo-SoV+1NKgRWA3) z^c3AUH73uW;8tNw#N&CBZp@pw=XKoGKI#`EZA5{-?|t-O}C&_N)oGv43b2 z&GZx~pJ0#=uRYPXP@j6(0*u$w;#ctnd4NP#)a|`1jX?1G#@!2x9c$dp;m?-ilI$mg z;4S}1I3)e8$?kJ9wd)#`c^MN(K@FrDGNOdzTG!J{=M9h06&p6v73(+A z_8~TixvbpPb??LxdXP!wKxK~RnhhnB0z8v!v=0%9*m02inlxeijy&}pBrc!&Ay2NL z`vHnLZ3~V7&<^4eFL~`Pq_5&A9qDxB*VlX+)Px$^37U-I}vd;5B1 zF*{c;aI+U*j*q?d**BM>uqh={=mZ4IXoSA0YVjvS_6e9}{C_z73hCm+0z*7|cH z&i?slt=gjb>7?98GS79u7dcs{*fKDw4GRY{VkjL?pC8|mteo9Xx0$3Z5Ovcm9etIp&j?-rrF5C;BXgwaQ5kah0MQj(|rGz0C*gc?V#7y7jpj>R?19J?u^2D2U^x3gAZE;9FzR>*cq^nA{oK#dSDSM*IyEVa4n}Zx zBe_lH`*3G@QVzHYZ_gCOhF1+zRHZ!QVfipe z=;V52{w=$0<>uFia@t4yYgx_Kt>j_EP0C3HQCU3#`rWuP7~-0(R%OVmuUMjU*c-WQ z<3_q>(^k4<-3IC^m1M21d&fswtLeXQ+D_ZLdS&s*F?mBHULI_O z6~Wq(n4jZjZ03Jek(O5tjJvA^|86bfIDcX2o<}A94=aO%Y$EfNTqaWOcKEbxHu#yb z!S3A6`2yXV$SaAa*`*7j{(1oXFMe446!Ik$4EUCH|L@KSGlW3%Q&O1r8Pg2YgEcbLr9i~ z80?hOLcSP7I6E*}dVnI*kvvf~8A@8imZWGH%*tusR7Yf5N_2g>MdGN%l}IJYet3qsuruC_QG#Zk(+94PDbr9PB1F9eOtFr2k3 zZDyzt(7$I|^wNj&y*sCJ#pr(hPh5Du#g;$V3)#S%H<7+4eKEL$16-|Tz1+!4@IWwA zyjb%15{JKC&Ex?*q0I)RwT(u?K6zu1K;4kYP{l?Hc`l;DLOw^MR0kG@{P*7rYujkDDIPo^#R_6>4L=LK4?BX5%GvzKxa%3 z&+#B&!N!4Ni8l84Q&&Duj~+QpAOEjg=r#ZTDSG9nKT7Xq&tz(1oPK8WcKU1+c{NlmKd5~`C&baOh-1ilzNV}|k_OuOgT#u@sqr@4d^`JQR@Z{KK zX++zyEEh$&Mi@RWPxU9PALyde;1HGi2dOkL7}c>7U^WO(oWmw92C#X{e%^Mu6Uc9H zcu`XL7{KkiZ{{x!48E!{6I@Bt!8MdEj8IojmmN1NM$vVlY~0xiYoMpN8~PdPAD}Pa zb0>9AOw;A-Hqfj+$DsOgQGpl%FYS=jageTf#>N>FUyMs&yOI}^Eq#Pc4Uz1J=$cpJ zG(&4j_Q#W18_uvf5^#AgHwvzd{#*N2uk}F;JN}|#&{2{@*YU)^4!60nFDv5;h)k88 zNC`4TVQVwAA+fj&{#q^VLqC(rCjPE^3k7=Q@F?AQ%eU#ePyZ{u;u9aCf4TV^M6+f3 zxosEH?=hMD!uAVkNB@xAEHR0@zvTTWs5c(Ia)^#$)J=T241P~Nj+1O1ASv-lp8xtg)zKVV`af?(VJ=U?*jRC4!@ZcE+;H!0>P~o z|Bw_u2F6Lr18*Zd3sB{=tU~!*hKhWZDzqR5$Q$RDNR)~$0-c>IkfUhUK66u~Z<_mn^+I#mq0#wP#6?%-Eyc6#G_TYxAuv@NC(dp~} zi-JZgysALKc^kIZXkYkjTE7%K}VK2nj zKPG%V7spmClR~3nh9binvy_Y@>2QV^%pkT_rXuD^|D`S!&wsky)u=i`BT<)}T+}^- zjkFqer`5R?xebX4%uCSvG#*tBxsz!_Cf2wPcbVLI8<4p=T@ap%b>ZPSLW$~UBEWR= zPwkWhUV7sP=?$Ox6y5#M1N7vfwe&memHf{OFQ=;q*HE61`xJX6 zWtn&4&tY{S1vIj9j)Z3F` z3dzB|(888qWyrGAvg2fj7jk%RmhQRtKJ`M{-U`!DjL!O4d`$R828P0`Kuu9#hS(^; z8B$S`0?}49LN!FrGl)%%%TtJ4+O}aK5$a@l)P~h7O=I{e>Z|L6>f&m@gAAm7wRd9V zN$;X^Ls3!NmUeR*(PX^UrFC1qo-95F2xwd9Nji1WXVk4jWlA50M?1*FHh=nkq#-v#393#B5(?FEFF07MzTcb)rwvD{rNsRoLlT;70V8= zQLt5u0p>$6kFxBr90>$3TKT=C@GD52HkT2bNJN3?#%?qg~PJF{cG9QuE&@GHX)RU+zB0B7&eL}>v zyt3$*Kb#~RF`Q<9qB#dOImmMa0idiJU`4!IWB03x8FvW_w>_mu~+gd7w(`-2Zn`{ChN86^}P{M_?zfU)QBE&1!79< zPT=Rpa=(PO1T|-FM%8^z?O`sRDzgXZgb4#=_O;M}iAPAnlsO>w`XDsFV6?KVU%I@RY04 z>3dr-w6RExDa;LwDXHO(T9GWs+xCoyc?MDsbUV#rRIl|#%7{my#1RpVWa~C6B<;p= z?PuKAXjsZ*(%(o=)7ZMNomg}+8cpp0^WZg7BPXi`L#54$*&QMx1=b!fe%BNp08h z0tex z0~-r+Vn2`6IPeL)hOb(`%w9U7hkD#%1Hlck5KBEyqU9YQ#p1Yr@j5LP?t3c``yC_){xt^|^Xn z9acUxV#2X@GQ^|dI@6K9qW?+~P6mQfGHF{G&2vHJAda@Y$1ZH?P?zhoyp2+Zx2(L8 zUfW)51ut`L-vAw+n4lZK`ek~>``=Bk{+EBI+wQ)Lp2FYvZ(Z>Odd{{BXdT{Z(yY@= zvmvkS#ZirqrS81!HtE;ydlHIdnsm-hs<3(zL#^&xjj)l+2Fr;+UP!uJ$zt#i{6*+`9%mz({M&1AXyNWEJbD$x^N$_p zXBb&qJ>e4uA<$G;u}Hhd$LPVG_tTGV+^Uo5u8_Y4{GYv4=n2eFNL!KI84wuKz;(jP znGOu4q(bd7>X0Z5p;cq*&co2A)HrLKswit{nGpu$YTd}dRMdz|T0I_jbuS8%=V~=M zWEegYqb&t|4b2ys`ZwBqTvmv{^xQC*5QoT2Pll>AuESKSr^MmB4J&7JA%rm-E-t~6+*iB!g^~~zOdD+$U%NJcn+k5({ z%9sA|O7Q*?_uJ|GA?WTnna1_gK}(YU1iY-c7F@u%sP|n1p>%sN*US!Y*gQ#VF5l~A zu56g?TI`*sc=O?}CxvGU%Y{I;kh1Y&@Sn8!gTJ~^zk;axc%l#YpC2ZFXXu4#;zSS<(YdmY@xOpi@in`NLxuYVrF5a zs2EsNvwA@Wet9I5hRcv)^|~P{F~k`5l01_+U6~7s^&+chQ8(8S_0{wu zuLCtl?YTlyq4vom4p`8LIE)-X1hNkip(tTUooGjhLkUHmHHmZ(hgZ_3JbNYU`Ug1- z(4K<_>0ST+8Tx~Fyp3-7*N;(U^a%aJg_qL*+;J6MGPp*TO_^?D!X16|hp-Z?fZRA! z({VHsyYH$)=oF(n1YNmsU3ad%`H^atzA@43N~{*ZhQXFC1{nT=%{=2+E(G!}THMQ_ zc5(PeX7C4-8D|wXmx;Db^Xb*1Y_@23#@bowPF^_|#q6p;vO@1H2Lky=k>0K@y8qw- z+Wo*o^o-5h@MzG0yBadb^btLhE$D)$RdMj2-Wbzut;xRH83_+yVl%g7N@5<)(Pr=q&i*Eq=CSyH7N;&OS~j?^W3I(IVA-9sDsf&okYfAX7O zr8m<_{f8@rNu#{g_4Y~~rqav%__5rbDcE(Rcv&n1Ot z8-g8t5?{r3;9R0yn4zo~Y~QlGsKo;{d@^M%qWElfW*Qm2-CcCk?YGhvu5(j=Kh@gJ zNKbGyBLLgvYLa#k3*z=oB6+@%fkBINRl$=xQEY@Y?&c}XQbt$d+C5Jfe@;&eD*-sU zgXyTT#w5f1He9`qDEuJ3m3Ul_oA`EqnGRXSWt>M6-&LhXUWTiz4)q$e&k>=B7Xdx> zP8@kjn^FxvY-r0o5b2YZhunE25s|Q`Q_AIO6B9{SAx~fb!L9UX?|m1&{9SLS+it&| zp1yW7{l?|j(A8_!36WrkQ|5C#CJ}@0C9q3Lh_@U%$CC)-tbV>4y?ytiba?k3`q3@hX@ajx=TDS6_$Rx@qqzn0j5$8dFhmAK z`lO}Qs9HIzQspX(hLIQ;iqf)i>u#$Ft4j=O)Ox(@kXfE8Xo$TPE#daqscAxWqxKMi zQASjZwCcF}mC~&rQCr$K*Pgr8SY;Fsxmi6TlQ=vM=UqUq+sMl>vWVoO7w74m2?ztk z5)X@Mf1R#Qy5}+(+AuUsLp{B8+x_>^>pt`Wdf7YPM&G>U7P@wL9leN&#J{1~zd(MhVVNS0(?Nf4Cbunu>yL`op)qmA>}vZ_`tU*3k2ym_#!4EA**G zGIE(*d!$-!cOSfG#Xm^6Ak3z{oz%u1FNWw0&jX)H0>MKuFGvcH0oaar@PWqr&{HtV z!Id1INR90IRLBOhcpgr|=ydhZ*be^iPfwLNlP7ULgNOS1>E;K1NR@+!=)Y|_hbC&Z z#7Qlh9kC7r5s`;8$eIJp001BWNklQY;4h2>u}BO7E9 zpA1|VoDK}NGuqm;=Lx`|TAk_%xq@c2wJNDM>H`E~h>?pP$;^qCL;J3mmX0U%RVHoY z!GDv-1g32};_wLoq(EE0K}Z9C&~wILbd3P4ooJ{_yb8!WJr$Q$;&5`;zB?{fFSj?` z*GHSyjL@!w2k37;dL#YOKmI-4{GFTW>1#LAFI{>iZSL(8Z=}|?g+0mpEk<#dfx0c~ zPo{VmGLp1yo%>bckGZ)qldL|NZF>i~ljisU8;bX^pAnoX0>P~miyek~Cm-NtF>$nf zfHCMA<+A!9puF!Ic3X_Mo_x`%31i@dVi(*A9G~j$qy^y7RO=18<<2|l8ot8JW;14Z z9lW?i(W4pdXfp99Q0oMO`B`j7kV9^oO{d4YH)d31Ijlfo?sUWf3JV z#9@-P4ONQ!5bJ6;tUoZ$B6Et)kb62&z6GmHWoEpcZWt4rt3MvXGUBnauDp_o8F(WO zgm~!6WG>H$L-J6+5lpNbla2FA+>lvR56cF7K_qMFkpuhbuWtMhz5MNOqkHeTlb*fx zJbK=RJE$jLkoC4&LOe0#2-t`0YV-rOV}qX$_El3cLJ&xc^7#y1F|an7yQ*L|Zn4jL zzzaDex2K&c0(muuZAsxV0A^0fV;*3_utF~+U0E;W zN?#xR(|HFcv%2L&+eS*s#CZy4;E~sk38-VJ%;e7aJ5MAUszTdQeMV4zFhWtn(K4|o zq+v*iWQ6YDvzuQ1!S~Ut-uX{7_ULZ+v=j;Trt3cylPPO9F?s*d%aUqMcyfDY=Y0&#IjdY$kXBJDZ20eopkN` z%~WgKvj>rm)~{v!Q(khsPd^eTV56<{TldX~uqvz{bLi9vn$yh1UAtM3paHOwE zyTXpjhh2dhF=jOfTS@S(2#?g>2X`e^>`)S?K5Z$)(etPA* z-%fA-mk-lmrB1)R<4U?%0>O@Ij-;+su5TXyF?CQ~t=t@2esKqT4 zHdc(klUr6q4lv^OrzGf;hw4h%ws{(+<9ig&po@M)5=KZKLBzvO&^JN=QP?&f!cu~9 z4<<@oR=#5r9&HOzX-COAQ-u8F&=`VbNo;q^Jkvp|G z-30P09G;dG9s_uj*J2LhS%r~&APo^-SX0+{f|CMPv5d#9wLi=p@|be7GN8-=otv>m)GdLU%OaHHA*h- zcTj6q+Xh628&cRdPaRvAryiNB$F8VF0yM6L<~t&Z z$;^3F+9vd~nG9`RJ0gbV9iRIQz3iXfMtgQXKtFr_C3MC5jWlbo+I4GVg*bKzk0kl4 zKnm?NnvL)~c^sg#2C#jLd9x~PD{Sm(!|5atO!B-jDSQmT`}lrRm_qUOo&EH+`$y=T zyEC+V_Tb@qvvCl&;JVY#W*___nwGN`h$434MhOdA7DnM~cic`Fm3nARsf+3`B&LDS z&Y~`1?Ml*&P*g(IbkaSlC2mnfT3&}s!bmSBBgjaILF$sE%3M3DV6vzV&5Ot)5?L8n zv_mJZPx~#I611pR5~(HHRe9W2L^@=~o{W>EZZ+s`DHBH?5iyAvar0zMu6afZF!s*K z8xc4Xkj_}X4p+H)T2Z`%c)a$tf7X`t*L3tKXdYoz`H;GcMLK8QI(l^U0KMu1@1eJU z{9|-Mwn)#paEC0Rg2ftfApKvbi@W-KDDO3CW>KR$D;s9}7JC5=8++O&)K4dYyo$r- zr0^KPTe#Apt7G8a$#2oU6W^eFCca9CD^q+4nr+1f*fxoCQSyByCy!3%?a8G|?Y3ymDm3SX-$Mvd}8s zkeOS!v6C!fL+^&290Td?yXK9UMZ^$n6L#R|^@@(jsmzI!wM;XnNY{qU~4>AB}$MCT8$mERGnmLV;xD!#h|@i>WZ3#+mv zU&(tG05%Y|@OS|m3tM|yaJmTO91ee+6dnUua`S!6z?Ec13J;l09QgMVY@tk03@D?E zj*InjM$&_%%vhRoBxKfI5w8D1wReCI8_4o>Fk?Q9?DC?&?I z6Z2{n1EWal0{%RPMqR{=tuKp$m~fX9H#$GjQ6}oItKT&J>79;AbNsn-u8yc)({W{^ zbQo9Y)Ge<2W5g4}8Hoy8yDF2OLGF=&|6B-`X>s!)5;u~-cN*QsYb1p>QLp@LB;WPP z+Z7ivXj)~c6Az`HvvwU#SLWz-ANdfy^OK*TE4usW$F`qO)pkpQc+Nrmt8~X%c2A>0 zo0bM7IXW=2l&8!DJe{mK=4EkKf)*56R0aF z@JXody*r)dr1z|@$lV!fCwZLh?ssw$oU#ZgqWAuP^{zXqr&6OGBY0PcE%mOIN=X-& z4U9pQXIuH#tq<*qHD~>E##gRQMQ*xLbzZ&l=~rrHqFj}Ufr^^9R?SF8A-d67Wy-$Y4c4DLs+9OI`Hv z!2`7Gkw@sMo3>H8p(k=@8E0C|g1FF;t8GO?Ad#+_&*(#YsRqT>+fiL--4c%tdNdN^ zjHG5;bFNL3yL3l|eiX*p1W>g)qzOs8%6uY-;r7?bBd-YvjnqO%E|9@sTfOeMSlvM6 zd02>tzEo3XI%MU%4mUKV!&U@Nvf(QPO=A}WyyZ*UiOI%!Rc?QyV+wukQq-MJm=fvt zfqd~s)@`7@<74!vA9yc)>z41(v$kxfP5pz>(5U+oqpwin!J2%Ywzitt#oWQUn(zTq z+jzWy&3#f*xYRfu1oCEze+$Qh4>IFEloX~|09*L5Ze;_oHK0~0$0vXMAYrsTgl&8? zq-mFFCCm~eZ9r5X2TXo`^X|Lof>JlF?dl?oM>~QM>mWt~ACdXDc0DYR^hI&+k~t2c zC-x1eWkqotZt>A!;WX|OtLwM6+}VET4>%@frjopqk`si=!XzWw6(Z;Dyl2NZQ%7ph`-VJ*Au5ZkCRZ3#C$z? zL+b_ysmPwkTmJ3S^#0HO8$Eew9qm}ZK|EXZAz2syKC|UqQ0hL?TwUwAA1BNvelRIN z25|WPHYr?coN5BWdRL3NZTBOzxPx?7Be;yi6>I`84=Ga$$fnQ*I{XlrL5WJti-}Go z_R2?}S`T7_eSP%32kxiJ;Uo0qOd4y4O||b$M}0Opwd(utsqLvDo|oUKtNs zpGA@~`;3gOlSK8Hk@f0z1SHiV>I`Z}|Kci~NZU|>_TIIrLEAN%pA~K5M8{VqW#f7} zbhOea%k{wx)9G;zg#d)Z_#=b;ZQGJ1p}V_F$w!9|T^nwzAC@At5+7eXPVtXPY;e(_$ z@^}H;3mbgOa4HD|b^ldTcnloj@F8Z}vu}{|1aWPxMNh4^=)culG{Dzo&CJ3VXRrm% z$S-seD>Cr)_l9 zkW{gJog32T;wIy3d%xA#GqL)jYE|aG1E&-Bz_$KfP?C;izLRA?kEnFASQ5!>byP#S zMSRQJwRHQVyXen9^nRMyvzMN}^<2vEZ_U5sN*t%K6*h4%)>#U(jUOVlmB$O%;8SMj zPg%u`U*>RCQg{q}m=DnBlfo272TZtxFhkuzfr3ou*Qv(FH_M*6P%C0VH)2j?+j+W2 zHH7+L;n(lJlZKmZx?pgK=9-Pzia=A8r4m;tPDXk$Vo}F933Vv@<*Y8>kotM^;}&5H zCuQ`*%dvc^*9^8w=3703E9aN@hnu1%d>M2^Gj0cf!PmJ49J?^C$Rh#OjVtp#GnWSf z?ik9meAP2;w{e9zq6=`MZ3O&&^r8W2$U6>!>;&YZroHGmSgJ1~r(`;MQ=sW|RI0SQ zam_G|m&^3JkAH-|`(NLuC$8H_rD8E!0tIE7p@y>=W+OkGlph1I!LY@r1gDBX@*G~5 z6dnWj(c%tD3PvTkhRVScXpXL-Fw;eaZ1OHFjdh%_20e*m?;@7RSNHgc4Yi`LyPNLY zvx^Sx-AC7M*(UFR(7IyX&OweC&ZKyDE|NQ=t3yij%f_U)-OPJ0&DjaqO4!Wf1#B^F@{;3J5y-D| zI6o;o25w|#y)`LJ@mT2Nv#+1e{{brIi+V3TCCv?~5pWTT^CP2dwm@_JPZx==cwuxJ zttNf<-h1e>{$c9P<*6w{4cf9^O?wsC*0tql#T`*|0ysnGbRq-l3>tJSCziOlT+ge- zBOFAdNpI_(Bo`v8L`wH6M(1&fA><`n&5F9~1U_qel_bfsBipc0T1$C3(x}Ou5$A0P ztBa^pK*vBB5-e`SAmkxVh>?PP7fLLm5Rn7wboE)?rh|>Xn8q}%oGBpJ>WY)DIF4Z# zdmZbChv-wcevdx!J^j?xRg~L+TkUo*QYcuVvlnJ7Z%oRM0odYSPYRa;r-DGh zbc=Zs@)la$!AM~U35(O!WSh?gl=Dv94!y`mMW)k}1tOB9XXE^|AH_+I`}uFa|6a<^ zmFdd08)(KY^X?&On_)B5IL0-(t*@%>x(+#kmUA{ICW%-_;=&XrGdbWyemmL^bV_TC z;l-sJaU;0H%u2ZiBh{$c5G9OAUA|M(f|?eY-|oVQdlyk`l#Znu9BD*yi>tv7#p?+8 zHzEPXUgD;f!J&ZMc_vog5l5geER(qlX%2F5g>JPh#M-8i7G&B3(U+g6d`J=1wco6E zLia6~&C{zlfq|fk$)R_36vTy$@DPaP)RnE_WrmLC zqz^9BD?oAo<8VOSnN!0sHl!|4Nos`d)BzxpKJ@1>bq-;>Vs0J3?MvXr_4R|9e zH1EUYm^%Y;=oT{dFkFy4D;Ex_<9&RY7IzR*c!;lb zNuES6WO6uFB}el;ggA9I*PX|r>6F~roG?=EA+QGlKd!Q2Hp&`RTvxoASMS($6kmLMj|-!a0C<89o6fGyig}a z1fiY?$iwpDgJ5+)SJR^FGQEI)xqWbb9qR9=uiSMf-L><6HZDO|v)() z$BRFwCH6v=nm~Sy!+A;JG4L^F(!)t%isM7OI7sc%5VZ;el*?y>yqv&hj*^B_V)1~C zq$3@J#TPK46ibz~`g?om)(3Y|YjT>dUcZrMu)69zxXQg6VIMqcWJ{uMJEI(#pcu}$ zI~5m~togmx3Hi8~N#mQHTwytG+Ao!O1zd(F)}(Lze4s(w0HC8mcwl4$CC160Ja%6ddaYq z1cI;ql}X_-@Sn7}ollX#=G@n4YyQi$Isa8QMsu}#J3FH}-Wg~oZHFjnof7a>BSgbB zdX|^+McO|$MmryQn4Y*{i!9+C(Nk1`PY036gLyZ;EOb5ggi+Ltkq;4QpIlyCGT!gV zC`AU`(jwCmQ8|mu)3Zvv?j#Tk#K0ng{Xs;#7zZ3LGp;xZ{X-D#jZ~+%+KK@deQz$o z47V76jY}cmii+Uv**C5{{ z>XClO`i@LoUD6+G)8!-G=7ZN$EYe)PMmzWJp*=^&;{%lffDMH$Jzl^@py#3|?-LW}4L4f`dD zP9*g^kdSg&%(>ir-#xUsP@)Z8y|SvR=sC+7HF1=Nq&G;-ZxIqF_lXHHn3s88g~eQr z4jnC{KYDOn(litO>qy3lqlg8rr`mqp18?u)jodA_b3 z8}mM}b#pUF3pvWJ>+cjh=ZI%)b}l$De%NWGAn`(ALqDFB9|N$_&rJ$X6iZ1Uf07g& z19%u_F*}`N0etpINS`^9;ZUa^Ozx?dtCeXst#vt(&5%W=%rm(0`!Et2mh#Wgg-x-V zz5bqFy5r%8s6H`8S8v!zbB%`T*@^FfSZ6B+xeB+a_Zh)5qng5_*A>fRBQ7bFfuXV; z^UKOn@Q(`ubgjG;i>pc?*^596ASN56btA^nw4~GmSL*tmc@P6?MpO)__AQcOFGa59 z;|X#L&TFu^5Cpba5DU^-9c~hmQ9_A_v8=2RjFxkRB1T@ej*PTD>6=)84e@W#@24G4 z)M07eZC8iJ#nUo9m#zCn%~}mluBJ!;wsbKMVK2s39}`POAW!G;l%((&_yjZOTvC`~ zai~sxgTvRUGX4dcsU8f1Y`5i@IgZXg+gKD=^cIca(sq65$-VLdmmg56SfGR6FqWvu zyo2eu_B?kXX?7hcs470)P?$3)i2Avn$lr-59?X|_G@7K4q|8UO_nt)IXiCy(GU}_Z z6&p^`wgTGP{JJ$iu1ro&mxeKQgg~*8SHr8GL~PL2xC_}>+Rbl7p@T5gJJC55-MU+O zolK3o5{j!&NG94x*GFv3+p+#S;#_=6+ys(#acrZ)8g=#h2P=rH^D0z>9rsRU*b^~|UKuN*wo)@- zkY$D;GNRCdOt-H6*aPS^$|9HGh`kbn4 zkA#;EfeRg&Czw}8`Vcj!8IjQysVZp7PD86!jjkDQlrddLP)@G(=rCa0j53V3w1cgA z6^HhJ5HlSQC*XSt}9~kK_{^OcL;nmaS@SZ6srkDq_sh>>Bj{(?h*zS|UQV_@=(DB#v zEe@Yb3R9dsiu@H6WaL>-K;Lkgz%~|-kUSy7`J(xPNP@S?$uQQVkI>`RZ?g6+*L5Y* zPYj(!#Nf3V%$qvbI!z{@fyTT&>)5TRw+m%jr$nct0@q?^TWY6GhN6+-R)N_-QH-iX z+?6wft9^zXG8kUf^L535y5=noV!%6|5O>6&!&jX|kj-SVZLqMx@HXFA4q!2vuON$|`dB6*b_jBk?W*h}CXQspprcx{cg1>v4M#2njqIz~yru=(z zjrwaFt@Z#coW87xeJ|jzxa#v+FQO(W%fc!nVjjPS=6gtb#=Hl#2(1Yk6=RaehNtJ?Rlj8ASJxE5#s*4 zI(6%Y?IN$m`XBFy9R%o-+YeEU^g51-)Fp~qAJXVAdB@kg_y8sJs5o~x6{NbM<|DHI%rZZ%aX8!azUxL(8v_K_BPAqgF#pCVcxHO zg|4nc&933{Xue3TgO5;U&lGiEo~PTM^ZT+-DdyuzH~s(Yy$QS}*Ig#|uUmDuw=ex( zZ|X(6guKbJfidtKCdm&HCWFZsuswKe zVq+n^BV>8sv{_3_y}o_9`%*do?bNAr?|ofQ?(X;GsjvIII_H1Zs=D=kb(X4nFAhy* z{gBkQaaS4lv>&edW(DMDjQd01I09cb?g#J7zczTu5d6Lfh`F*4hwbpHxbZXFZ6hGv z9tj8$7LgnB2o4nBmdVT&3MFGAKAT>`lm@?6N11I}wt z<}vvAQ;)-Z8DCk%b-4mUL@Qe~5j7FVasuXQB~{L^1T6*7hKR3EvdA_kJqeMuyXmXS6MMX@0fp`x)394B)&T|@RQBM$3^aMw&v zVFfzf(?KC>S1YCEPQCGjQG!;rGzq1#@>Z?2{$#Du+K!5)V7y!orm9t#s#HwRGwiHv zZZ17=;i>J-jZMHuN~r?usl?3t_|~*0R&4I#O&xDmjEsYJ4Ce6s@b72|I4jU(_IMm&DSH|BWyD11!LdnJIy zQ{C{oQ_Y`QgXUY>9U~whq$y;`{FU4pQ?Q?W_d1mx|DnktM9r^`h+fL;n{rk**5P-5 z>h;h%vIxKTnNPq%8CQgHU0R-!DsMzUaEozVfwd#av(O}V$!NEFH=k-7BxO>p+VD?L zKG{l)NeNhNs1PN2ZJUZ7r^DBcC&w;*j5MA0Dky}7I{QGQP7u_iAXqBI@#$g|oeBH! zgt?PnE{>I-3fkTCrkv$=SXi1Vg}qL_Svwbnn|*WFe$%xjh)%7;QhN$MKk+cM&TYdh z7M=&=&pHI{@#n(AHy(hk2Ofe?_D{q4Pnb)xFv0tXB0<1?6F-laF|=WcLAH*K?-V$S zdJjPRMZmnZm_M!jQWI{WUGmCt;NxfVg}0ir9yI=SV>1dC95Lx%4#D%*;iWe|A8vVY z48C#yM6!&d(!EcG^_aPIM3Kr+IJ$gi8tFZ=cp_!?yA@Bw6< zyBG#s29~vA9On9K-=ldvy?wB z@g^}AniYXV7VS<4KL5x=aP8C#%$6$9>Gu+@*GxmeWBb4)L4k?tr>1`syFzl6!(UX&v%BN?` zlmB6^I`y^#;}dV1nVR~!v2y86g}KSM965C0_exOuvx%E#KC)dq`}uhB_)~|ERnBfL zpWR$H$8l?V9Lgt5PXNwBp#@Mc_YF_ic_OhTV*+uFi$G=NQ z(9z4e(T@iSU&Dm2V@GHFfjL_EjlEVEdi^d0VFBV!%j}OH zf9JsF*bR_tk#n;EA1r*iZ_J8sMnHbbH|&7_YYJwymfyZzZvREQTDh;;uRM04-`zTR_&___Xh3(S zXoR5#y)HiY5YxnYq1T77+k;*M2YyP1gJb#beZ;+_ZXXJUaIr@~tE5Jqs2u-ALAdrm z`}Q61lfEG1Lp)A+qFRN=&Ypqgr6qXI!6T*zLK7P{wJkP9${fc7Q5q50F?r@`vD=-IR7&QF zCAA&+%ezlbtz3o;(bksZ1XJVxIxJ+2JQsv3g90c=(W>cbeDc8L#5)hpPQ7V&@A|XQN-QsOpc5Q3eOk!5_89T#27k;goIWtQA)rgd^Z8d zipSl$K~GJ5dW)hEHnz9mD~~=3-!{JhVk=BT^n97*gL>!U>v%umWpR5D&@agoSyuZnW@R23xdj9 z`oY+{Tiwc6>T!9y8AnivS`b3l^cVt&VtJU31X3H5BgdtMaBf!KMK1sEePb3pT>*Km zZ`c7J^bI*K6>v;BGE@{nF)SLVq(`^#;LaFm6P+>^JX_4h>hqw)J=!QMkB7a#N-2B|+M6hh6L)M87Ic>2vCm_N? z%Uc24!E?$e0M%mg+{{?zFBiwhe{pVn_7~!~@<*-8-2Jt7VY^lDQO^Q<6NR8p%UqL( z8gt~hV%QD$zScKn!P60t+aUWAFo~*GdOPshwlUZ+CP^x#DH+*Rq`iQVhq*B@nQE~!Z$Q0Xa0R}_Nphsu_@@&D?U(yoaak&P+G@VRFsW`RDzOsXPzcggywNI zL73Naw?Ey^w!!c~DkB!9QVG8D_+wD*#&BYC8tPqK=&!9AY>(SYHgJfW#Ibe`gp96V z+98D`y%q{2ajAOQ@yh^tPcfg)r|=5_IThNBc(f);hSYgDZI2Krtn)O2iE(wC#{q zAUzVaNICk0*0O0&uxN2qjnqw|fx~{37Cp)3fPIQ`7`CU1rGHzkjQvWzT>WCZ6anrI zy|Tlm%#mZ?V>ev98;;+VfZ&T0v%a?daoAm>b36@%b93Tmpj53I4WXBE&}jUqv3OSy z?8+cYs?TF2@ropmPn_wL7*{No=(Q$~oqh^#oL|5P>$oXyRfKe2eJGEKUE{Tfz<)F^ z=S&Z8>9ZR6hd16rIueQz z~lRO;Z{l!UUYal}IbUHMQb=CMJ%vZ*sCA|>sEm$FtB550o zI8lX|CRsy8liL!dE3x=vQ6e}}pcN5GulXpA)U9>e<3n+@^R!qO%L>D&H(4zGUzKX~ z*5*uQ8PniX;Wkr_9M2#K7iaz06mmRreJ1QiK>i!wumkS)4LL479{$>=$vyJ*Ps0Oe z9)`2E#*^J%?}C1BTKN=#CM8>5DRG1#ZLZ#t5a<-~+__>6X(SyVt<9o3x zaO&(?*jQbI>*p4r>kX%2>ugP0ob^ha6%Kb^!?ujTdchfSI1cSJ365H0k3lk&WgP{j z)mlGr-cnS2Xrfg7qt@i~S2v<5=*MMfhZSg+#-SFJA*5$-()*Jm$1?!P$;i!F@Ji$G z8`&2{Rsnf6;79MW;U3dvTJ?=NE(02;+0~zbZhHyhFrtr_Cc{`A|8}R7q(?&oJ;AAwt`a=nus9Uz&qrhD5@KPcMnwaC9_K-keSX$z? z(-8^u>QI)ABYV0&oINTQ3cZ<1`2)o$yrRG3!fiy7GK)=A z%lyfnivUxkQn@^wc+-&bJDn~KV;vqFqu0B)hde8xBE$lRa3svF9LuyuT{fk5eYX^b zrE&x=NRxQ7h@FMiDNVkRhw+tS`KycN=x-($4%esV55mIi6dahFgL&f?W~N}_&^$~p zTn(k!lk^JpxR<HgML_V=a#_~~-v_&EWR7nJL0eqQ++}x?UV+1D z+7q#yYZFu^kO(VF$GO|9z60d?5J(0)!A{#`$7x>z8P3x3weWz;O}Zf5`kuTDy!)P`0|bCM*LQk2G}Lc6e66VljNnyASv7Pq{yY89S5e-5@c zx8Q0+zBmtJ)3^zxsAP&pMMaVgREJjn*}8KgluXm9sE{|{PK!p`E&tJHM2cbf^&7#-Px~veL&rM~?jl;pUI}_7T9v7ixts!uH&w z&>OEozl#T7+LI&4{>8_9!w$G8_g_pv@OrywA%f2t_i^8t<8mSthp%-H)5}+5<}>0n zG4h*uWoU>Z1{u$;x?-j!F-XPBpTufwbbR zp+Jk%V^C73cxec=+qQ@Iz+Xj$;q)?H8=$SfI*a~NTwnwwTrWn!m*TLp4BJL-Hfj)T zwJz$ywFY$RZKy$)zQ{;l1=I%R$gw|x9F1I^1>X-B`9WVyKyEeexNjVRPns^$wr|XF zIf3&E=sJLG8y8SWWU`!m;HU^2)W$@b{5FJV!482@zChqE}hwoS_*t1XZnufR$YL}7Tg zQ|LZYX-05(;~31XUuE3Ui@S}hV0QT!99*r!$;l#&$9-sStef5lo)4!1Idbe12uFX? zw~xS4U=0|FiwQ{9$#X>3M&-Cv=!k2@^wFZA7|LtK!FD6kG=?F+PodD1F4?9KGh&&T|2# zXQ9(-*}ce-W1nF+T)m?PTueY-}p6_%kQIT z&6O4P4;LFPIvwdsh=J+7RLd1Ox3UbYt7~xe>>Lq(G6ydVF707+(l+-sBuN&riAZpq zF5~5|23km3?P*Y)ibyQYN1;I%7FK2o(Z*5({naPn zhHI~Z*(ii|qdxTbpFEMBB6#B4z9Z$rc4>=r9&d zSp@j$_ETGh?#j6{55Ur+UxcN{zO-w%{MeV_g2{X4;m^U!_8BN#vjElE8Gw2d`uOU1 zx3T*jNbFf0{%G(WVOtxf7mRL`U8e@n6kB_X-PSrlW5pbgW#c~suwk|xe1mkEKL5K- z-wNJ|j&fWo2v>jFw~xS!jhpa|ik;5bDRm`NyM9WEZ8iQy% zNE5#sO4FN@YREi@O-mjgGV}T$1SHK?rwxytIRgi)6EImULbs3Uk=!{w6|W5r2Ko`S zLtGz=2>oD5Byd}h-Ut`L#Yk(MC)7!RC`wu`B7?6#DHMWkuix2jMN{q0p&Oue;A&_s zJY9DUw2f;_9fj`9ahST{W|+F>S}2BH=(P-q?s&Q3v53i0JI!(G^}6H&Fs|2zxYL2Q z*+RDkk+Bz{4@Hv}mr=y+Hq~a<+0@9%SWg{J<1y z!B7OZf8;&BP4RDx`&Yhk2=HrHFE*-{^*t*&E)iaQ?;p}OC>nyS8S?pB`^8(e<~y6+ z<{d~t)EkNWq5(0pHTt=`L1e|iv@wwuM{_)i0=^-hvnTmAUdzOrNBjO1vD2q)&HwX; ztX}=Hm%|%g_v7%^&wK(N+g^vsutZCG5dnFq28OhW<5?831@`e4H(vZmH27u_6)~DC zAurw~lZn$wdTya~Z+gy${3kHP3~xQi2ye zs|Ur;JqG9MC*i&Wk3jRuHTaH$FMzRUAA;K0^I`FUFF@}bkHJI7r(yXk-!P(B!JWkh zP%|R4ujc+AHca@C5us|S2t5>YBLqQ#(B0mq4{zbq`t?>F zro$dY(}!SlW1YUz*y#sQZm+=&cf1rSD z&MJiG9*6DITQK&lB7E-qUhf>_98U*#-2Gmh9RCN%)=Bt%7@-9_3CI_Xdya1$f{z>V zc!h7waryDXj)3$UF`P95va!{CXRF&10YQ#U3kciTPtp)GvC^HdlCvWQ_O6(UP@DLP zs5zW2Lj@#;&8;oC{`d)a$G>_5{Mq9V!ADO&4s&Jv&5}H6vzYw3dTA>MZ5yS2v{^s) zE~rPN*|ZEyr$c#tu1U+#ynq4%_`Q>k>eRw-w#OD5fD`?f6sD4J+K})T^fta~ z+Pnzu?M-OHq`5mU!fd|FGgvxa{!s_}u6r*%cXTqfWqS^bem^=GduC2jUv$N2g zo`TKu7a%N^@QY0h0>gd#NgHtHL2(DbB=2d{-?(|aiy0cskt zh&CRF>8S&7zG1|&(-Z-D$_U7D7La-krdrD|b?`Vmy1EU=jer!*eyw!R!|{Fg5$UzGnJUfBzwfN@dsxt8jX@2NxFR;cWF9csy)F`^+P-{n$E8yr2Y+y($-wO93My zA2XYm`}QIDGK|oIQGIIswBfUS;|OGZG(N{AM$K^zLyCB(NE6DIh!H}YWMe;%`d~Us zsT}15U6W^KQWt2PC3f*EO2rZ^udPDOkkOIJDZquioDvyIhoVH35L5^?5RllgoxDpZ z7;NWs$*>d+M{z*XB*R@4Pla(_tVT*@lW`?OkmbR_vr7O&{6Pf0xCzBABO2kgaO}EU zVb%yi>F9B|`np@79+jbY_0>?SoPYy2+y)iXd8p6b025c=0@ZQ^MMKoFXc;BB1Q?w zx5MZ-A6XlbB3Luxan=ylF>}{k3i*qFSPnjO!tJ$e?-V6M;P@q%((J|&4ojy7-P$HiF86Q(-kSsI${YywZp?lZXf;!h#q${s+yngX<8~>6w)w40 zHkBv3%IVA;6O_{JPp20?H$yTY?g z;2N}myf8$FSlAMQ1gYe#W+5CRyBLF-kCB!a*Q&&x#JDM}Kj4=tHX02$b^aV29Gigg zs7PPbkR?!n{Mb!oumhR`q z!O)?uQ3CP`-!KCA-*@L-kNd_PR|vs%;%+n)coJem*2K$5vBS7Zc-IPvl?YAjsE4(t zZA_28jZ+O;u`V83J9Yj%j28+pU8+EbK5?tm&W+-_OvweOO=Pr@9G~(#Eeu%H=r0u= zB)u9d80eKA3B?uY8H8597q>~4zL|fF0vLe|N>IV2tF_0VP4($Sb&eeS2g2R=`}PsY zEFkz6#^?FQ5%{cc$Z;i+3}F?51{9H}kjjM3v1dUb4pp*caj`ti(F`Kqgy=?79_APw zn?!ROto!ux5|mAFzEXi!FKL%mI%y-d)BGw)C~OrJDVo4(R7eKqMFM&4JI0y(xQd9< zI!~W-iTLR)9_p%fyU^?faagPx5jMBDyL6nV3=uxfS?EB!`-C|yYqb8c&x)QS$9_dt z4o6KuZAf9*ulohSZ|BQ`tS{xtaT$Rm7@0fwQivy%hlWTCoCG8$4(AKCTduchM?y0@ z9$4XMt3u8u0IU0@dWgD>0;x$>t~?RJq5k+>*jE;nR<(+E}WIhkz-#Y zD~F>dpf;p1OhB?eeU3}Z^JhQy6iAOcWs3w{1b!K!qZC#u_zy`&EMXEBA45Vu>szYRivZ<)peV5@av-d~CesN)GtPZEA&cfM=rHi_AlV&@97M`rs z%=Q2@W~WUruw)9u8?_w|V2&L72EyU^%wHB{5|BH5!w6)pG{+SJK5)j%Vg-(ufOpB- zWe}lA=+%KU55i$Lz!}{XOw{PuYLiQ%LJ&f;)q=AtORz9D4&zY-J@*^wlmY)xgT&9J zkQT%!G`K9*CT1f>#wre)n4_sp8paKZhlq^sGwq47^#eE>_u*u3dkMnr6^LqUJG=Ti zz00Z4I0Mx}8{g&uLD%`DaE=_$EM(>KfzE|5AP0@R%Cn8amwZExy#W#z-uIShb&)V= zDpm-VJV^{fbj14UZ!F~MCUW3P4(SnQkr)^B4k~n}P57|cndKFjDV1TesIM~N^puws zfE{gkUIb$?N`;Y!wa{PSj3Okw44H*O%d%~9ghdijkY2KAw%s^B78d%?uM`fJ+rbUc z4X!ornn73KZ6`hnLFri#P239Q!T~UOVc1|`jvUVrWaaWBz#3uU3rN=0SBR{Y=D0$L z0M`~dP)pa|(`jT%e!!jr88{`r-Xt=;jti@+=1#o}Gq0|k3IG5g z07*naRON~x;l33HEi+C08m93p`md|2=*e~5C-SqAdlzh^Tqq706eo$2hEhDb0v?-E zyC2_C3A@+eTULsdF(_B6gU+-&sFtBH9zuDh4MA}`+f&v#a_n#HhRahQnDPbW`CfPw zzG2)~d}EHi0+JZMvj`{AmDZUo$&Y_5d8Y4_-QI*+)PN}yVoz*{R4$v|mlc7DFB$<^ zT3y7Iz4eR`4pRWFCa}!3qgb$3%M$I)|YRU_n90`+%vEhZHFZ*Aqxs zY}k@!+`Bz)1>dn4jX^LKL%-63xZ1X^Up3)MG<^j_TMe*m@c_ZyEx1#PySo>6Dems> z?!_HSDO%hiKyWBf+}+)+kMG|5{z1-}v)S3**;(LD8RCzG9jv=@yzp9%k0g_Yw(GKc z%OqnR#!Ai~&^_I!bz{>U^|8MlT zn|=yqna23k5udX_2g!pG%AG5>n=vv=9G*!vrgn=)yz%EBecBH|*thoaEvpjOU9Wwy z*4L_Te^`&xU~`iG=WNH}de3Rct4-f>6$$-I5^mt7pz4OoJ2KrFy7wj9cY=|{6z+^7 z(%y>%={kej)F`HeL~)4?KN*fq_?rsNWcn@SH8Td%pW7zP`VHf6$aR!rxR@xGP3cj{ zdVBsRnpV&+oifbloo>}@|GK?rRgoqM`@CF$HkJ%^-tEw?j8Nn55Jks5mrgf!=>$P( zO(kXPuraPj)j8YTOQpy5k94xv*A@AFpF2q*7Nf>78SH5}I{4FE z?yU|y7OE~jPgs+|O2pp@6dskl-U}xu-ep%6^cJiWb>`=FMv{>2W;4$BY*<#0@TdHn28ueK<)(PzW=>DQqoxS*V^{vqxGDM_PZ#FlD8nR3UEnd3D6$waCoK z&B9T*$bq=_Jm?oQGErom>yIdK3fGQ$m-lHDGDlT7Ka9U=m4-`|&~q?5o2Log)eOLk zJCtgc6uavP6?KfwG74;YyF2441+y+wv_U?#H@QthohHBZy(WvI@oTc_`nI((o+-Lv zQ&v9OdoAQ2zs@j-yA5ivh4($rX{Z(9BRUupOU!0>6No&2aH5`hRIMN19eWr6EV2O{aSJyJT%d4Fwe4d^+Vijyr2@jCU*TtD;05wH`Wi635B!eRk&FfA!_f%VwO z-{#m>TJg^e77ccVp(6i&+fi7a=E3gpseS3Pv~4QT(RCm@gAVj&l}>PUCa<7su?+r; zq$P4$LZNec>F>E7PUbaP5BVYZ=XD-EkrwnH*LGb>*9wj#`9*fAq1_- zn6HEevZdx_`Me%@j0)-Bt904=EP@YWP6O*<*mBy~VYUC`rF6pu9TBuTHbKV|d zA|4wQ-$^t^lf>DDKV;iAnOI;yAMksry2lH6nX{#@pFq4(JUn_P?n}P#0o`TPM_6+I zs0~zH)hcR!mi)neITofGH+w8mpOLh*(_J)hP40uqoXjb!+`o5Q0T=0ZWzrw7i_(6^ zrI3DQ?N;knkoy(ZExwipuiI10?#PwoXD*-Jkj3VdJ_$rc=GsYUgfaEP1S<3X-lS{R z`|exI8~=pit67qBT4hOta3?3 zk~snD^6x&0=Yh6)S>KRAx*wztE$&La&y8M~7`UmQv|_T1yEc4BbZcLlr8@5B_dQNJ zLMN(Sf;RHg^W|rZ#y;kP@xN9Rpv8oJaFR;ccFicLlA2P8Gl^K}3GsID;-;0uNRS<$ zcgqzlh({5jh$4mrVw5>QlWZJBqUwCHs z)!uhh|MP+7Qi_9gSrr=vvqcq>T|WG6qv`4XCnf@24UTA~7lS-rnGIQ8Y_p$v7S33S zb8^X6o?_k*`@-#d>^?FTVpOdm4P!m5d27ulChoS*^yU~HP=cNt`$~nkj4I^Z-uGe$ za+=FVrYodqKJ{RKA?T-ry=4NRniU0Y&K}Mo6C~RgLX#~k_6i5+{(+|X2U5$XoE&kS zEmZWOH3!Rw4ZIJAke?5qMyh=7+p6--hNc5a{&Z?De4r0!(v@!@I6T;VQ=D2BL zMlk8IE*ig%hx`D2k%f7nf+oo@vkc_5VwIq)+$Rh0EeE(Es{$s3q-d6TsIa5NYRynR zAjDNQ&NPa)DBree(k8ZY?Q4|`|3)2Dbfk*Y|h@;PJMKr`r`CH48Wks)0{1uwe>50n6wuvD-?vBG->~-E)AaUbE z4Go}o1V#Wgav6o){mX)*o3C)^oWtAklhR3^9^*_4^!~)Hl{!9~HX=3Z&(71l3RvN30kc z$NFwkO}?=`568Aut9)kney4`6CO?i}1znYM23__iv5y2(wg;OzS0mE`vkg4BbQ;%$8#=CX3he(}Jxz;j;V1>MRD1 z#W0X6z+zj!iuNEV6vEcetQB$}cbU2A@-HI)-23q!&l8=+pVh6_Xv(qS;Tl`mqY(au zQDHEy^!H&24}$M4)V|kV~IeposOU9Q?&AYxl+*1BWCT5M!luwR;VpmxyWkHq|gSziizZy_WkeS`&ztM5j~oWab0ivDh`qa`$_M+-(JYw66E9f z&jT*VzE7O^zo5Tv40S2N?NSY`WhIcsa1%gzM}81m?n}7cD1gjotG7lITb~m$=5*?a zlQB#K&QXn8>W6^>%0LeOt;H;9*)mHa4Ev8mWdkuSt9D_t2UB1oqZhu%bFD7SfG4u^ z;Bu214wl$1e6}9tOQF^gen1QjKI)RiZCO?7{!LgrVJc5knOx#h+^Qp}!c4|><(45M zKClFRz_K5IK2~&^Z7qwIuWNo(n>~inxk&Q_FJJ$nsrj<(`;ICF{%66a5xNk1brpK1 zJFVlcboGhnXZ3w!ZZl%e7&Cn+*JAA~J|07X>G&7bl8tZ_*KR#2H^PW%qBS9W6gI&G zL;ZNUEmI9XeUvTZ-=DTLJ8%|!46JT}dqjO%Ea?yk@}Iv_w%-V)v~6et#|8*gnbN@9 zrWEI7?1II0vk=yzfmYYARPe}ahCLb=?v+&BM!&G}82?(;bHIP43R=7=?Gs1^HwGtQ z6(ryf)*Hl)_V8{X2A&vK%^p8PJOPHDkh5-j2z3ZX5_k5*$_Emw_N$CvMK0Mr{P5-n zFH1i3CaeDwK0U$`BJENlg-^577kJ;%liyk)MPgg2ojACR06VaTHI#`S=Dyd@$m=>I zU(RvtqxF%jk1-hSzZJ4zvgbasAfv7av$}bQnbaey;3XC*hU{-G)=yJTi*7S5mj#ld zz^XCp&}!(1yol)(s|g#}vTv^_*g&iej;6fNg0c3esp-I{?c_ek;Y=~{rv2XL?f0cK zrIWZL4mayCBxP-E+@YAgK^t^K3m>7u=6d%X7B{o}N80W3{L-aVu_$WhZ2o^bspGFU zty$V}uM9Ee?z2M*6^biyy=*b?O~Qql%KaHfWrczD`oTM9SWcyUsK3jQ(xCl{d(c+O zwPsG8l>tVNmC`|hm>}|ax%$`U5r@b7k#7}$i98epU#HrF^tte%yyKTT$6C<(#D~^? zK!+$7TIdYDkVuIL?Gw44qDb9~5JRa#O(VMFVqznW4>=PjZUu}cG@FR)9)49-fvPuo zJt%Fl*qXK*i7+eQcOyXaW*(s0R%Bf&GX`iXM18YcfLaO4N#?wdXT%?$M>Xsb{Osv)Ec?3oz z#~cS$K|s8?AdOgRDsl`&nT&;mH#-*cOcW^*LlZ8tyEAbWZU^GPTC5~R0dyUs=5#Yw z<64h}j3lThJHLKmM9D=ci74S@ljl(1MXuaUTS`CZkD|e1DwJpqnLOEB{vJ;ho$X9w;#e zCCs>>sX5?TVSHL{6aHcOx!gyE@Q_#L=TIg73dW_)=Xi*BO8UpeTm?txc8!n=T>&Iv zk8SwJiv$A%Ry`gd!su6RuHviSdp?0bixE;S@?GV{zl3&{>jfLc&5L64xXgG8Iq_V1 zSr{8!1Z;+2k%lRRzri-g^Pha+N^xnb7HLPJEOl}s185|SWYwlbZVNI<8mYfAXUnYo zRu1(_CDf7t#YW-$E0tzwA8y*JxzM=*x}1vCwrCF=#HebWEaY&&?)gd^_ig!002tUX;(#@HZ4TL z{RMEkY0Wxl(XLhi@nzwpp>SKz6$x)s4}P4&Z*s@z9d_){|B~5^Dft4wYYI>$M-N~ zA~UPb=Xeq6y#AwM)n{bz^mV`i9WgtFUABtn@KpjyjTnVjc1hqBL|^s`q{JbUuh9WQ zt1iYO%4EF4CQ0)AJsWWo4==I5=(o^UwP_h=^(sHR(rWL3A^a2Wf#A>M=`rT!XR<{- zi9aGsDu^-xTEVB{3Z|lwIk-=9NH&0r#OGla2o5(%uX8HC4Z;6DR^TT%^U0P3k$Ev! zeR^yM*Hz>qLIts+pv+?ZtN}j1BAU74KZvg7m0$dwD?UW`C(2d>P;iUetBz`bOt43X zpp|EPMA{|2RV}4b2KM(FrurxA)d-5$SDW6;B!GWayHtjChMpB}0M3@{om_&*0SJ(RME;`wXCx1f09Z~W=S_+P4Wq*Tq%u+ASv^D@e zPP5gQp^%!Qg)u*CR}`UoKU~sU$3JZZv6R{93+2{0%?x2ex~v`1?z3SnAU98~BIf>Y zJ2_92MBvEy7j5{=odzn#g{ccE5zYVb8~U<+`Ssg^_=tXtXwcLHv{4g`0=-s&9i|PG z&f0dlawMzATDeVekP$Z)Q0QX%$YZ!DNQJ1;X=0muu$uU--8R4#BS5ES0>ajjQFTXW z!jCYaNv+C9JkSNSg{p5g zU+9qVf~K z28}K$u2Z(-uqAy}&dT+s!+ znBk#@IVq<<1xvN_;VxJpMY=Mie3+%*q3saty~)^0;>&mxSoO>p2#ExFyfOY4#|t@; z>z2!N{zHpjsI01Zw|HUwu!i#}7?cD&wL-B`EvZF*1EXAY0v zbzml;Y$TcW^yL($cZm9`qKOQT8g}N&wTdc$U3Jk3c(&6Vf~xgoBMl=RhEWXI(<;*Z zLquEm9u=pd*Zhu^&k}p5YU>apJVLhiB|r0)sVGHyuJLiEgVO3eutbK_u6IhC0ImL|711sx#UY!4{`VvxVr}YsE}@QQ zi7`h=@pShO^q-wye!|sMPw@TKO4G^0yc=@e-XCLN_V1usDnJ= zJh<6F_q&1`s*P^eb#5|UZiF}GJtYe~(j*{4Pp@K^biM?vz*?0vpdd?J7z`D%3D$W45ZO7^`$ZzzOr*meV_8F5d-BoN*mdGf=xb zWl;=P#B|*GA>f>n&^#wzq%P9YvToP=)0tJD2e#)n7q7pkbxY?q=AnoGAGV)~eK_ed zG2?J)Ypg!5RW3MtnW`{+jDY)5Uud|`+oCF6qDRc2T%$4ChC z2RMP0gXu0;vWy^^=w^s^f$8EQ{qkbTCY`*}#`Oo>RKf|zI|UdwqM7PSiPV60JO zkxXZ!zKfk!Xnd;X7heM&gOw2QU&O~Y%dSs`|Lms_{9-QzrFgone27~=#>m|JQ;x0E zmB_X&_VS%S?iuibEK~2zZY-c7f8}G!oX^Vrdhcdqll28j=_jOZl9ji4_{Cx zzdEpj=lnt9HG8EMoB$5K8#!t#c?1d21z=ard}R&Iy{U3@Yx$~&zn$lvl^^v2r2A=Qpm43-=NX_W@+ z5Ul^agoa9WRQu&v#kOTDQfd8D&+}_$uc9l$rn_EU@*hGx3zikpn2{ZTC6#TCI4iKhJ6Ee;(xuCY9}6Px@2l^X{USQ}w#Ow^%SD3Y%VGqU|32GbsMiY(J_LmYk#5Bu}Vols{TMF-M!d(*&H% zDc8TKQc<5GHKONB3~;CdGRyMyqRq~rr`>YNi2wMc$MQ8YOv!ryHM-8KHY93}q#skd z3;WLOO+zzf@+`P+ajO~a;8-tcWA$-R&j?uC_Kxc{7k0t>0Q%**3?hEy5O=^l1H5!q zQ(Ckf1XVK-j}V~d)-BG^>ZHmbVoqO!2m-%glnicjGe8U}7#9-vps(X142x@0y_!-IoZhNfXr=Pzh z-Y>~kndBN3?lmcK+OsRosQ4t52DairO1>gq?XcnAl$I{|rD(nJ0HwI3{j6jZUbUq< zRziO_*|(Z)v32gL&AANuvWN}}~x!D%L0>#@Kmb;fKC z6rGq@MkMw46*Yn$Ysd6}7m_ZfSyRz+_02$c?PJmGp5m3!4Lb^%_}d+u)zZrn&N|#+TlC*w|L`?=cv9XtBnB&~b))igKQ4KqWMQTp07uN* zR&tU;w6UKjZ%FuF!8LJ@{-ce6$GHC_PF4M_)G(GX(=K%Ak$ZvV7P&6`5MG%#W4zgEY-o1}PqXFb?#d zG)7xp7n~<)53Zr@0F05#1muf)ZWa~coL)&W1u}*OmWdB z$Om=RGH)gF8_EKg)stQyFK^H7h}8RMt|;ErRcnQrpXUn z|536TiLkE9@9R#-nFLgt#svOAU1~>B(n|SsCe!fIBaj)Oey9{vJC7+h#~+RMY`Ha( z==*KUJAUG9vn~clzSiNC%g8{9t{aI%ewO@W@pdV(mb$N~hpc-`r;+m^IR48sO{5Gw z2toM`*aU2ezwa_34ttYt79aDOFTdQHtJ-D0jFU=oCoQhi>q#7+7Tgv8c%62Abv zj@p!1wA(40I;KGDN^J%IUkji_bC3m(VylEqPuX@0L(hkvFEhv!P@xY*?t8=zxuPSz zmBXU6st6Ef?{85JE&HoPjKO*sFeF>VC5S*56A=eOvH#MA$+yx3=?lPxYA~4!_8}~P z5MgYZc4ifq?5&xj42B}upW$c>NPyfg7I7Y@*X8+e4B2xLUY^1rY|-p=H*|{~r1y-~ zBM-lqO=T@FDR)#SANHxULd0*Z`B06+UWKqVhKO?Gy*O+13?7b{8%IQFHrf_5-oj|LFT~lNWz1OKaj2~iy`l`{_tr^Jt*@MA z$W2BA>OI(AF+aAvf}quI;=xXkwTp?tZ#|;!;(7WB_fJd|Fzu@5SULv4oHT`GKypZ$ zZFNi|HKMi8J0uu{J6M8#t>-=R^Dl}SHVPU#ZcfT|Ql6Z+;~WkSfmtk)6B zCs6)1Mp5V)N}U0$s1NYG4jZedTvj3&4$+r+wZoV{7G|klzg~6mDEwBD^mYF+cocuG zon$$4j&b&bSNXDi?&W{G_iC@}VU?m>WWZKqJulCu7ii=}ew(X?R=0f0+_^Tz)8FU~ zGuYsR*3q)vYgL=J)yfNPWIIf^7YBClFPZ%t5^yw09hPLt66hvC(rXzJ-`?9T^E3`G za>j6b=9!DJPraV?>+h}W3H%;DjQG#QFuD<%yp)M%#dX?+t(Hd%R>Ll-@$Y2nDxI6$ zqZ&eaW;mvyIJ`Mmg%!h}5)ag!3!PmDke{d*7TQiLja zld)bOM#SxWAhU`fj1`sUz6PW@j|5j+yjqHDRADh^edggBja)6Cg7sPH9Dg!3dlgD|GpR*Vk{BdCn)+S91Zhy{l9JLcH|b ziKSlLDuD&OcRYUQmFi9_ed2Qtul>f)z*dT7UfMVc+}lQXZMk~BLFep64{Z7_^O+nR z1M5r%d1xD=riuEC58mpVbs$3iqUY;+O1-O8AoGU`>iq<(=XbVri75>b56tQ@!UjrN z-h`jCUB=mpeUFiRUi~?XAe${sV-wb7>lkCx=n*$c>5jTZ2 z8W*$~Z*5j|(^sE;ae7jC?4)L==u6^S86-cjm1mj^ z2iub^?QU(+S_bSl#6?}1?^$RQFN;c~Ai)KheUy=+L{mJF4 z2s?w=QfmYTx&cMm)sd8`Fw{z$xxLiO_LO7a7`!u2lkK_2nG;3@8|E8(}h9hKbz|-9?-v67O;&n=?2>p#d;wT7v=UE2T1Rl!c`v z&brJdeP61NAJNU+W_bEg>GS_`vMnH?2u}7Ik?tZSnfc(o>*00=&N95GZFR%FBFg5C z;Lb=I+AZV?(nzECUSFtX60g6}wnb`DR?)SjtV6wjXswXm?ScI*v^`iO1W{A)U23_7 zE7^aBGZ-K^lA1LeVo)Qm=bj&b1c?}7)(C#Q+mdB?Z33w;FuQWp;TQEl-t9I52i(nSHKQ zG|Wob{8$GXsLOfYm^EWj!voj?UiZMxBmavC$6SA;?t|SXCpW(o!=r?PS`vZcdnX`b z#T3=c8EXV8b@=6hIJ{zX^MJABYH%~yajI^E2wE>??|)hR2lx8*GLP~7zX}9j;%9>T z^~3wNq%=FW42#Gp#p&jED6D6^E@~v!5V|l%S=HcjS}RHR@-NV8l_DFkMEePO3(4|J zhp{@8i>!OoxJx8m!AX@^c)vI64rRLVX(&DgPy@=qDLOJqr#e5rAGSpXAF+qCEbZ0J zi*})$;P-N{6RGXdy!W$LwxO#DC!I-L2+oPF^MFuK`?sTDjDIK8aDjFVY8LI~@MtvmlU6iAj4wshx2DQ>_OEc2-}?-2oUW1d0~&d`LqU({Ng z={Ehi6dC^lN!lo^Byl?wnrcrDEy$Oeryy8qOqGAWL|mQH$x7?b;Sh+>p*DQGjJ81v{cQL}*RzlIk8Aal);X;r^J<7& z#b=wuYGO6$ti_~U$LQ_Z^iPot)f@3Dsma(eoR-(Sjp)2>1_IsxO)TznEL$g31OSbu(U%%)DDX-u^SWBk6CtpN}n$Iwfni+_xV4hx%qwKhI2C`@GUtQMu~f+s0RmH321Re^jS#IXtAbQ0j{M z-b}|fa*4ZKiZUi;f|>#X}%5Snz}%_%0LbU8KsTJ~Nt4?a@!lg% z-dV9Oe)>n7$$A5Aw40q-UE+ZW6D?IdBN)}T3JT=V>W%(NOzwTC3@5r1w{svk%}%dwn8T%GQU=!e zzCLM&9&N^lgMxvI1I($R1?$PZ;#*#C!K61L#qJ!r3N6DFdo88N&rrMH%ZND1Ap0su zDms2_PhQviZca$abiYoEU!FxK_RA*{N74aOTb^fB%f+Pw+zz#>1Y3O6F*gG-d~+sQ zErw6-QUy19BS>}~p!A&)l(}&m7qV1stYXYf+XRYS_Z+)i}Rs7DlzbTWP zr`crVIlb}XViHhUdAVT|npoKe`r+Y%)C$x}D|U+Y>QSfBSke+Qo= zSnD8M_6iG=Bp!-@^Kd621#x-DKgxnI>y&LLApV17Qh7OvR?DIg(*qe9Yz2S1Phzk7 zw6RDJ0qvA*b`^2ikN2iurdtwiUQ)}byP!LKA$rkMZkDe z)>TqRcnZ&~@xi3_UgnhPI_+)*oK1J-W>~IM^pK4Vhg#&+i1E=qB!8Vm(MBpgyTZog z+=zOQ=xH%kbohbLk&Vgl+gYpw22gWmk!g^}v3pW+-Si@2$3if*{&GLR6r74<<5mVso=VeVLZc?jqR- zx^pmnT3P1agm0T9o;}v{Uw7rG4ja)cQfsj;$_qGyq+AEk=;Lxhbi3bv9#Vc~G(7=Up!j}ewZ z3SN00?{o2p3JD&o)|g@ZaF}SJW-;Rt9Usz+-0;mN&%zrbk9Tl<2`SVArkjI=k!7(U zE>hJGw>EAuB|9b&gPi2mLY-L;1Rr1e*_e=wa7SY)At z0U}~9Yo}0{DdtDD#O}P!EGjaGtCxr=Cg9#T3@>y&hS7JM{|pZxWVdJHLD`~?JCXuN zLvf#Q{T4rzNaDkTRZJ5COi+fN^qH2=+q8004(^JR?g}1}Y>N<_rR{1#***)NJ6|hL zK2E={m6|4h0WvB2HoYh*j;5FxBK)+4RxWa{#Ey}bVW%(V=Foo+gzRd?2SmbQ&Ojn^ z{d~dkPx^g@)wc{xqOLyFj!IR<jd~hIhK5l@P}{G+^OcH8MW3Nk z7Ek9m1tnUS97fa+e*o8CWA>#*MWor!b0amwd~*PZ6M+Lv__sPb(NtoCJRnsy9b6Ru z&#dL@l(d)`0u03Tk>=H|cpx4nWzm~h87CgaXAQJ_7OSx?MBI3gf!JeBl#IcQQZ<$A z)SYVWXiSQk^i`bmyYwj6OAs0bXB-g0>Ks^T&c2>{2j`QyJul2(Uj zT$hC@eC`K*?c7`rEi+b5JX0uEFW5H{B(Wks!N@41J#ziLAc*4;!jp9C}a?b)A!3fbeKk~MB z&+`T&M&|c3`2%R2XdFlwD1*@(lp~V7@Uh?imIaV2Sp%el!vbiLe<20fP|)`YeU#dztyLf&A~;KM?BQg`lUnr8|mYvlpxb zzgt+hN#a!U<`^L&95$lBA1^`)?P-TV+mVT(UQGc`K*Uu1VQ1Dq{)u|LkJmAGv}pga zQLx2Z^Xa_v>dUU7_pERvf9<=a6Zo_~%Z68Az%eHs`74WD(Khz<`uW0AJ;Hbvg1a9RSjs1GY8<|`-f&{nqzO`IIEJlRcBydunY z(UBxb!|60Boe_7tf-SjG{2D~AFs~5-fXz%UZ4wLGPA1Hd<0tN(Sr416sxz9AX`8>W zt1fKwSi|#i%$%$?7Ci4hs?%1}qGsyHn59BgM7t6ZM_5M)^m&Nf>Q}GWnm_XP z`jcE`{4?ZY>39Z-&o={xcj|*K3CNFsQuEj5+iUYW{cOJXsDTEm3L?JwsGm@6rEy1? zNdy6R;F~%&_HH&qCRx0+XzYJHeEsAWvS_Rrm_kWC)`TKzT4YpNy0ld+L{bOwCgeI> zpUGo?yVm`&p0QQ9BtWO}8J+k?(x=jIIb&HN2wc(YV_q{MLR%-6CmA=3-*r5b_>u1i`dpZTDm#dR79#)GWkwu#nc$DEGu-^{ z0PMKpL~r;R^9#Ku$?^6vk2^=&AmtC}&@ME24?@~5wB{1yOHIgYG|vd?{bbI*f(H68 zuK|glZjq!rT;Eia+_JUux~d+AiIP;@TVs4sS}iaaOy~?P(jQ^8un#NUJTx+}9N}br zsVHUUUI=8UUO)joZ=G{G38|+gzT-~sup82x`?PGlK!44=Jk-HEZR548sOVZyI!sLHx)nBDCSt}M| zw|0tAs)gCv+2KTJ&{%0UqH63y&PjfI#Cwv#jg?alL99@=x2QmSKjJV13Hze}FpCW) zV@;N!A!Dy1l!W+w1IK72e{5(TPkh2QZMcH%yA=*0XR_d7FJ!FP)UNemYs%WM>%l z93U5j3qN+C^}SrYVe9j_64q43_1)m2^}RmARG^+=1)=-D8mzJs6FzczgZLs z$BsD@IQMhM^_DzJe^{_loq-%cN~_KfzQ4OG**_Ll*GDKIjr;=U;5@|4a|G7*T_SQM z6F(@!cP==i8!A>KT0Lk=3Pm!Jmf6o;iPpOP9U8UuIAiJKzkDbqL6m$7;iB{aSw$qp z>Y*7f*dW&qyD9kvJi%)8WfOSiXJ5~A9lDonX$Gn zF^B%(Q7ceiSAIKm%OqiRuX*c+SeHvNX2qv1-UC%?Su&*XB~=%@u)l9x)cX%>2v|G> zvjXya3hO+wyu45Yu(b{$3m1N$livErE|@wcc=EqQa*qF~3D z6M_{5*t0p%^v{VW0Brdec+N^}eaX6!e)xHPhzbfz}H)<=T9yT8FdNvVJ1x1bPO3r0Bt3T=c?JQX&THt$t*Y*gl z$+DYhEju?bHZ@fRKy^6EE3Trf5`cg2DPNHv=#J;f%Ysz{zyBBu)dc;8${T-i(*)9k zRde?dK!jeZTWh4kk9+#b;}zXVH0`FE0GC?I6r{kKcT<-t3o8I!_7sr@*(Qy&5 zd=IA7SouOHeAR>}9AL7SC$FdHIjw?gn3nOwOJ;aol@jJQJSn;yOHFAQA1vdMq8!CX zvM=ym$*5}5-Q)?I98*`vDAdSr?H^#ucO-UmLCCwMjp|H%BnfdLC#^(W32yoJhm{T5 z*O-AwV(I8`{P4JsYBNcwf;uIwA^dfB z2$Dk7Chtd?J+Z+FF|O1CX#Fg+>Cs?nd_KFc{MPb&6^()=eN>d5L8J&hTY%!cmDsjh zRHUe%g2IoUIzA<9$IK>7DbAG&YCJ4m&fVoyf*r8W_r_zD^^1h5gy{RfazzTR^aN*O zxNx;fd=jK$t092e^pLpe%(kA()t0EfpUJW=5Gj0#oGDEqX!~&q4HL@MxG3mYt9Ng4 zaUB|h@NI<)0-I^Gld>tEs_x|W4HtE4yzh}GFdowrQJCSI$Is7NaqB)sU*D?{2)i_S zLla&nVjXW3d0C*&TVJ~V#V);OIFg051Y3oF*qySU8xSr+1=_*x(*Dm*s@BE>!Sav^ z;;58}Tw>tapfU?{YS5t*6lPKkY$^r^9Q@TY1SM54Rro*_8E`;712QqrK?0;xaWRYE z%rY>8^>}h;?7nPy2E5}H26|zvzbBGKjsRZBTjR6_;AiFX+6iS=%8M(owl%STwDVB- zU|_9upf?ck)XOkLZXh)=K0^J!Q=!z2Is`f<1bAs3|O%^bks zc0S_m$#np#roC84mKV(Ql2dlYg3t_*y+5Ud8n#^4QFMCkt3!t~Ok^BS9apzbwL%Bl$DU zVq2Zz3&iYx`99(6mRM1G-YWjo3_v!!C(({R&W4Qz5LFDVr773HFvaLnPO^K zScUQ;=I!(pkoxOOMszt-$260x*`vaFimZ<*VaA$i&NtU~ZMKa=JbN>aaG18201Dliu!v-@ocow zxG|<@xrWS=#7y;=?Fe5dNtWi>v}$y)EuOo27Pe_JozTB?;X$l$&hG17uoY^AB$34G zwNF%N`oXqcTg~zgY;}#6N6T zKah#Vd>y&-N9K3%q*0-FBx?v>eYZFCl3T`hUSVjyW$3KJ6bf8r1$mPJET`)`uvpJ* z2Is!8N`-h+drU#W=I8e+6Or{l$`TDqk0hF2)Ru+iWuEruAKJh!ob^ThjWq5?fFwvc zn--%<-dK~jBCb#p)z{Rc*XL-4L$JJQM8JoGJT$b2*(%2X37EB_XDaVge^Ij}t#9ac=O!!579rT1odUzZiW`CaRts2jT#iElh^vo)d zsXfe`xnBR?1Zr_VeTQL#dgA5RuUKK+G?l6Te*g+W^}g_qfgFGw7&!~JuoKnkMjs0g zN#pzWaViP*C6Y(0fxr~=0D|-mQz$ZFHEH`Y+X4a`@a)s17>y7-{kI=R2NdGmcn=eGO0)?ISn z==z5H4sJK@pQ`Kl)hfIB-=gbxe#va?{6c;6sylP7-FKdB+w=u?H}SdpsP&<`NaLR{ z$LcSV&4Hg5(}lvOpP$0|2m8(%e9S#0r*F~i6+m}3&!~h~KvFCm^`xtTRyuFjjXoA0 zMDv{LO;b$g%;n_H5VSd=@;?L_^H*0Nq`?KxBJ$)ZZ>B@zp12}!Wf%1v;^zb|^I0Uv zuB)S^6~RateThll&BIH|LQ(^y$0CA?3r|WmCfgI$+2)W|=u~3Nh(3qgiC3406o7EQaC;hU$=t znaD6IDjGJ7U=))b-Gy|dsSs~jT}ZX8EgWm#QZ&L=As-8loN3s4e8A40v{FM;nQ#zO z4G|>k!)FaX<^{y*wQQtF8bMmY;S~_VV_LczcIXBliwC6#G%(G{6@qjfLidyrLZKpV zDN#~@q(`KcRj{0DPlsz&ckRbe7;e&OP3RDJTN_NZ{zZ^`6kjBA`}IFVhHJ zKx!ESA=G*@AM*;j8w;~P<1q3FA)~r#K!4}TKXDfXDiKj}b#&>?;D5-f4cA&7qDzU_ zEVq+csug)0YuY<8$?jOkGHHGXuTJ5}g>1(w6uezY@{UOGcLw1|OHy;}Dy}{UE)G7s*Z-)!vGLEMEiE4?wl@ACRTmu1 zu)BEb8Zv3>5}!RK-j0v6phPq6Xr`d^jrv$z)XM2)8lelwBU-u|cIpNni-7?d`dJtT zr(@2?Ua1fee5`Dg@Jfh+DpAQ+8I6K96q9E!iK~W;32I56IF)l)j{%BEN zC>R)RuCKeJxw-LA%$DFcGxZ@R92QFCl~5bb`|;sp*`iiXpHV<+?ZVo1`A@zR(TzS9 z7Nz22GCaf*`$3aD3vv@G;d!{^PZa0%63WCx%bWFGwBfd*VuHQJ3iRg2Ms&2c;^g=k za*UYiN5@M_E*J44zb4U@A&8vn3vJ;_z{@)xi7e}OQwbrEMWtwvn<7ud^F+I4V#B-r zl$aG+v|@3$ZuGIRFleBX0$(#g+eL8d6-4QwbS?;76cp)6h2Sh&?hUv{1-)}h!EN6; zdfFp$r<&<>23>9Kh{R(!$vhC7PtQ{I-OdYsiNfT`mSvnv5+cDxfW|DOaB!(qm85qe z!~%{es4gvcyAHX^T-x2Pt&&)s&GPDE(F5IG9Ut1%-1)h9ux=vBJPnfur+xTXSs*U2 zWfgiaghn{f1%&V$-B1M==msAPi@0To5HJv9G)hmjrTch6`HpHxaux83f#7n<+K#a- z1yzC*d6~5wJna-vHA>tAS=-r3TL+^zF+pPqBA@=tQ>!i}PWtpuiGtIdOYUWFMz$k* ztVBL{I(WO3r@FX2ZP3xq&jg6Q0hx;YgOaP!KP{l@D=euXtC{GUX{Mc4~Qz(@;*F zs(rV(mt57cgn(^f)2h`N&ZID!$%q+PoYN(-3wED=TI$+TgkSQUPYHvpPgm|NI#g}R zdNL`5M|OJ&uSIz%6l7iLsT2x%M8cu5)lKbR+!Sy8r&t~ZGn0o!Gg>{D=flSeLakgb zS1!A#Bp}mNrV9N11Qr=jJZkXp_-_n6a)5E5QRGu11%DI8N@8Yd@3@9b^WvX_nHW;? zu_x)K%Mz}z(7J(WB#I48Ku%9iU^175O?xUibyP*So2twck>z-to87WJs+u6E@o^;{ zyrLM}P=n-Zjfk_}#N&yO2$6V%?LfY>vH5SK&GmOC>&(n(3>a)MF%>uX{#-tMtU%Pt z<lbTX--#=mvmL8w3SuS>Q{p( zCcCvrpm=}?KnC*jC@f(g^-t09t8y{7qY%H=Anc@##MKeDofLE zMFYHmYOE~E#X>5M*E3O~;&fv%v9k;l_3_xFsK2x-E!-l<9gl0Bq2`+=V5OeZdzl(zm5=kSudEbJj|DI>DbG(McREZ9wpEG0rxFq~`^5q26t-_+fWtYzZN)C9sd z?G{MIXf~7}bw%z}M-jYg$H`J~E>vWQF$@R~Le=Ay%7sHTBJDiz>1s}z1jM$iY&;bC zju{R80uc)>i9FT~0No=j43@BFqKH-b7~0VWgiSHW-L=DOisY4W@I)D=iHwJzb?7D`9@2wRj)w;{SZy=G*t%vd2GdEtg-MWa zVdBE!cDhDK96Xsa!aX0=btKEFEll`}(lIhQqQMg~?FN;0y%Di4B^nGp7>UOIZ9LpO zH53S8Bo;=0Ll^_~EYPtojKN?KgH|K*W+O_`Ad0k!p?=*yd@L{2%HhAz4TNd}LTXdX zE!L%%|KvOCb)%03Lh%t9?q@{y4C76;L{DNGw}~z!l|kG`&js>UAwl2|4Jw1TfFx;aIbD8R1*;9xMQDgtbkS)F4K)Z779@rV#pzaG!Z1- zS*vXBB$Tf|_n3uUXFo~2uHV8-t1R*2n%pCAj9$dqQt33hTHDal(u|`c!xehPIE%}m zZ0bdv-N|vh51IB>Eo)aAlnOx#5m}{Rh$5nWKK+-)!hygu@o?SGO0o7-p|u@$YX|I> zPFO7+Wr1vz2UaHA+70^o=Q1{OMe@XS(e>eD$%D9?IQ(pQ3SzIMX{aV3grDk$D!5!X z_*fvge9a$2T5yO{8aa1*7*>`iiSZJ8IrWt>^7OPSEZZrEVrV8H*)%qFuYnzj;P}`m zf|go9D6Y?Kl^RkVZ62$P@{*2Vx#b)|kZn2x+v@0zdu+U(w9z<*Wm| zkRR)YDya1$e9SdGoJ$;Q%I81Ov#lMY;U#OH=|)xXlCH|p<^zlF9~F0xs;1-TltfvY zakYKjdW`0>=ub}}%mqZ0mpaDJ!N(y~8=lJ$QIAOQOs-l^u6xwp2T#ZY4X`@~l`rG$ zf5^56duOCq!1<&?W;-#IBK{hM>5q6|)<%7}ip}1k3Z0jjv zO>YC%4>n-kECQ8pKWd=oaq)@4% zfn+*`jjLB96p!KP=!h8qki0I=C8UBwo}YV7u1QAam1>@cNP4^z39cP-wWBk+j0=Wn zQM`XrA5qpa&2%gnIAq!Oa4{c-U8sYdkIg<5;xKdU$lBh}u?nGRD>8;Inm&9iDb&i@ zGit!u1muUhp$eYMT%s=B=wp7-wDXlb)NOw?)~vn;o9g1-0n2PJdbZmTT~UHM#eKi( zoN@)l3y~)o7|wxWUgdCY)6!yL-i~z}Fj*|{1%we25T4~>dk(?!9yx*2rZRY{xYzC0 z5${ewz1Q-~5~aOoR`qSm9w?ah!R$yXTS{kRJV4Mh!TdfY8&YPU*%9*ucWoy3xn{VzfTMLw{2MfdTX=6bb51AJgX#kHc?U|>UnFG^L&YKpja1+W9Rw}I6OLx@myAJ;qHOs zA$ia3^%O)}K&G6x;C9Bj5e79`K=f0|mOR-W5#b&UD<80|0UPG2^yWCGE^b0tFp$*#h zXgFw(uNmycnlmS`y8raE4&4K1(9zq2_7f*?6DF~1AcLtfdRC+y(D&hE@lh*Re;4YH zrwYy{AcXJfhAOz4xkho_=wtq1+BOe%&_=cZB(pg&jP4M$OY9EqN&*(aEm0FBGtcyk zN~TiSx^^9cb#WXT8A8aCE4AfGx!2(|;GWytrlNZl=V|rgt*&o9T$ahTMA-N{l^J}o zKDA@QDB{GFRUGIq#xazr!%#9lCt)~Qhry{B3t^0P?nZ3)I)riw6mxlXQ9gVu3M5C@ zDj;|31|78s2rVe29eU3O+LY^B-RNWfL8M$LWtoU%Jp;@-QAq-II95@rV%*9TcRd|H z<@ru?UaNSn#_o-qFqY4uFPT8t3V2FTjL2K0rpbqUiDjU32vHO{dcF&K-z<=OK`AUzpLH>LEdr8a;Rm|03a--)KIRW%)IfCcFls`&Sb*4RR^4$ciSUrT z!{06;E4vpwSrU}2AZb}E>*nVQdDPd{VGk1!KK_wSBVg(y9qLt$c?gu1@gyi(-nm9X z;O2S3MMepYs~qAiPGN(u)38{6Ysg0XsaC0Z}VQ)8ILA|BR?bKnVY)8>--X<|5JNOgCe^I)q()N+}Sy06xEt-`9#PVDRNi%p*!lJFqN2RWHiVeaxP~b0fYR;^WqQNji{-hL0q%<#;=GO*!;70~Ga4Cb8J$Y6 z`{Bdr{>kI${^^tR5?0^yIM)5guhB4)z&f)I&B-DP7Cn~NhmVDWhmp^ZAe)=MGi>GF60cZzJpp|n-HYit`m9_UK&RPP z2#0ZWY=m!LQeH$7yQ>zSbCcMSO-YA>!A%}15?1Gp>DR^8L5hYv4K*Q};V?~;x{=0) z63Lzelf9Ya69;i(;xJB(&sR8t6JrN(v~M4JgE^$*jR*uS1ZkF={)PGQF@LxLwQXNQ zTz}T_4??X1GQq-+bYm6JMfz9>l=ksp6dyqj1IU&vNl1cJ%f-VL2bX*mSrh3>lVcTd z&7Ae!3=MQY9k6Ze-Le&@Qwj8?rx3AeX`KgBJ6xk6d4A2Ff;>tua#1~9uD70ZeV)tq zdKYe{@IX|WmoW_*|Dfy5CUUvt{l`w?`+Yt5!O$5NPS0aFgCEj4PVd8iKXeQaJQYGT zZy^G?M#hJa`Ns{qp$cdpMB@CjqE-PR{Ht!Lf*YBu)T|qQ%ss+ZgolVttDsBB7IU6E zTEW)5yQ-YE!SDJ@8gFT3yed-8Z*EHI5Ve=dX3^Tz%r{VcYM>9ve4dXph-L+u>n(9` zZ^4NwqjPjTlnV7lx0J`skMdmHE{@zAkp;y$3>s)RLPiKiT?VD5VU!xi7ATCO&_01v z@dADvO(GXe!pi7hh7TWe3(3hh>h>!5mTstq*$Bvgptjjqv`N>^y3xnn zJZB)3FM{T#Dw0$hFm1C$dB^YGofCmke0rCP8ZW5^(Sm`gWD=XZ*PyYb8T$tN5it0C zS&?5h=%Q*=23@Nd+Yp5BRS03GS5v$vo~80td0v#;MK-l3>?J-sOQbE+rk!|=e5Vbp z4+CpL3l!M7*0E!I2v4*oaZgt-3MTvBQaSlveE66b5GU8N=`C?QaeYmgjety|_C`+vtThmzR}zp254a5X@tH zaw{$vxe>d^pS!@}O6;1v8r$<%;Gzq!LYR4x7)#LfF!knq_?S!7%E`p>#Pu~{HUdKU zXWdW*&topr7TxG$jxiM#ArVI)WguJ1c?em=ydH#;=kl#<_b@p{Wo=tYKV*2l1y9WQB*;G#V(xbclwBG4LPcLWnc+^T`L z#n0zixqjfx8K9TlIiynV`}5&LgXH4p>Gmq9mE$>PDzd~Hmqmi`MS}^93yZ> zgy1R0IioNN^i)E)B+Da;`ki}l*-hn<1WvH7O(Zo%nE_LB`tI7*tMO>x8R+XfyuOE+ zmMa41J9WK0Ey_8s(oRCaZJxSfixw#kP6i!#h7Y z%<7!z!6|Y>OJbIp4<8;77q8ci6+qlRL zLl|bs;YbcnvQEks2%0iGO&3b^U#EX>Oyzh>(DvE)w)ZbQcg-xHgCVJu1MXLPVTyDVfJ(l;#cxFTnH3R%CI@HW3do?JaF&cks`F zk=eUw!OC8Yi8Gtg(0(m$c=w+m)X^?H3=#t6aY*5K$qQeAAASC>@vYl$$M4^GBfk5A z_v4#i_#8g|p7-Ilz1QN@crSXBdU5y5-K?%=qmjPfQ_TQW~95+vbqT9@q`f_Rm1P+jhc&|SS~hwjqj zp&)Fl0fk~CYin_XVK!lW08B(S;D-0S3z3cvppSVJCr+^Y!V$dS`On8MzxYMm{oxPe z`4_okp@S@JSictUz4g`j=3C#3_q^&4(O#^_;i(}EXQ%k+kB{>gl7nBM+pFL%-EcOX zi-0`H!jrnO0@(c>UZfj+%pDr-79N^|?WjYjlq=-9V^K!Pa8up|gB18`bD47O1R@FiojeEXuCw};mkKpPH_Q-eTf_5Gl9iKqY&@fLwZ~M*o_T@L=gPV4vJJf}vBYhZ~ z8ig}ZryiwJiK!`UU%MW$#s=&k>PN)(ER6G1@=B91 zPnRuqtzvwGOPo_)*+jk)4OvHt1dke$E9oe_5MEXahtt(%A|EOhbIpy7Xl?I8OXsR3 z5!zO*LD;l`jhpd>FMSE$`|M|M<3)SL8=nED=X<7!T(522g}ZM0J-p}ES7Jl+I_AwB zWlA&RdS*UWJS6wldK3Q-x}g@FtAKnRwe^+lX5q!U(Z}4Nedo1k-*qk8wq1*Dt?L@P z;?cFGQYprFSu%)#-E|%G5G78;DlLN!d4DfasZ_ZiLtR*xZ{LA|d=@>431|AQC?i`^ z#H~z{=($~*s63DJveJhU2Ir^-&Ut;&nv6(clx;falSgis;~#t*chf>PU+h1fN%a;7 z2hno;1nN$nS{mWhX(SFF#04jh<89rm)w?_=ghD2M`||6s@AY@#Bd_{XtX{VYID7=9 zkrCd7=X@tVRw{^liG$Au;&S5jS;M&O$2IMlRSEyX!fSM61>F6>&9}ZxH~M(?xb^T+ zJ|Ijx-mX2ef8DVohd%Mt@ZhVng#up%E_9^CRijjt#LwsT3Slth9A6R_{**qImUUDR zqT{Cd6LZ-yo6YdS+B@HQJ02}%@wKNPLwhK~w>9B?E6%yZIb`FaO}d_vxCYumn6l|w zo$H|dA~gbj6n2)7af2VFoi2zUi%z>L4o?|sr&tirDi6ZC+Xxwdl4u$^2;?F5;aUnX zaANor{{3a|!ON4Ei!%TKAOJ~3K~#5Ksb@~ZVHSGEC$Kf2$C{RzH-JcHGWhbh{}Z42 z)pyX}9KlVEThMX+t1xICLu26yJn=*e_K);1vAqYOhHG(Qb`#cjjw5^Fi;x{GA#NVS zuS5HB>gfQ2^>x^tw6L)~fnw*?NDUXzV1@CU(vvtI9LCn3)wm`Q!Nkt(m^gC=bpaa( z*n2x*hH=&SGw5olM(wvRKZKx8>!_@_?RV9{rw^g3@~!Y83mNY_bIvBA#8{n^D=O| zFv=oyAJ0=NT?uYkV3NA8)~!QxTPq&vJA)u~y?6`pf}%~`?0Od}xVg^d3;E-B%KX|? zQL^)PmEH9?%DfNNm8J5S(3%!`AQU$X6S+*WXXF|5jO@pW(F2Pg#tz~{&o9wh7sShU zTt0bih<SnjBmbBV)$p&M((vk?$NtzO8>m?F;oEtL;J z%?3UBC5vpaAZ_lex|Cy$1BobSH7Z+H+1Mnbk) zz(z#POHo_}LHz34oEBxC6I7l|d(X@ViYf2`b5(~9BCZw-s&Nk`Cawpf#Khz?dc#%_ zR*C&AOV4GkKWCA{6~OpTtljwgc>Rv+u@GpE$MF6g8*tYJ*W$Okuf`-TR2=LBaw*U_ zl#k^J$+fi(8=SNEL3p;mlCQCl(2W(aiiKNrqmO5Y64;%y5o5$3Mk-SPjeT&hf>>9L zIY1<((Wxt4k}^1S?Xb3N!zioC<23tf+nTj#>+HlM{bvwTiw9*1;%gW33aA|-caPbb z&dY85hTL5Q9ZL{}KZLCv@_#VjjTm)he4#&Y(N96aU=y+aX{%r0hU0iBB< z@=f^5t6zbI#-?Z^-nr=|_~CEA8gIPzdL|%6q=!zj8Te%2?*%69g=dVLud*3Y$ur((xC3_D~XJ#p<1M4K3_mQ z7RO~fcHqg8K}_VbvinM%o8ofXu&U`fa1vJ~ofml?LwFvd3<-ktEZoXMI7lq$AjdjH zU5bl9^&Am#y1bNk!i2*z5occ0?)m_BHY{$~QE#EMu7tnaLtSZ$kITDu;_ElvhW~oa zZMbIlrFdp|2xr(01HXCD3;S4VAda2B;&eKQvx&Q(6`svBUN30>_*zu&UKVbB;O1Lt z2L>O{5*xpDC;yA4KkDY8?7G5K@{@^d=C(qyApX$h)K@-T7c~8rrp+q5$Rp8EQ)k7L zS|u*R=1lP=DG&#YjE`a0hE4eJTi=GyAAAB&j}D`Owl5JC*k4bxYy!L z(dBV9WmjGgH>+v8GVWX#ZQUZ;=Tm-VJyl<|QKa+BDZT15hy?BLHplDUyJOv^XDriV zWoo$xntPD04X4v+i`U_fE3ebD&x+Yh<2_gWWN-lAI5UX@V-Mliktb0++KOO(J$5He ze;V%+0`orF*x@@YT&?F-z<**6Zs_O210md@8>)cb*sZ$J$GPFyF%!p*m^gaGLLyyc zH`d$*p?h(sj2dweuOj6JVf8}qtPtsP4=`jv0`dzM?$?b~@JgnX^}5l=IUvG9lo4XI2&78P;#LLrIpDQ z49U-q%^~V(q9Ub6Dnzc3M_nwAOSWyp~~Q56$|$xQ%V9w&od+>VM~gY5%-Rs zgKqmhdZ9~)g1X-)(Bi=zYuBNrvl9>Yo_4lwS3e}tM#(v!(<%|V=j`0;a1t_)4`p!H zXHn6j8aVgP#8SFJm(RroGLL%}qJD`_*%clKc`qVgEh1!Rvn_-y(%&K?Mrlz(l)bxr zA%{O&vw9v^eat<6Z|iP6apiC0AFh5r)^>K`v9VE1=JQhAeJm1)Q)_)_)F*VqxneE_ zgqF?My0Gw7Ofh4+(Z?*2Imto~O4*Z`D(2nc3Q4+^)Io?!seG)RD$-FBHBVGf6Uw6P zFs|CM3lr>)|HuT*zEadD8WS9%#6g@ym^?N~H2hRjFt{*qA&{r$LP0KvEGX+Jp>PM; z-8k8~XTpVp>I%US*{)kcfRQg2Bq6&f(*dC_;D6p~pqc-*i#qhGOkM_1dP0i_8{>7jc*jmWIy}I) zz~DZQtmEwu=d$4y2RiT1sgV^siPea^qvx1mv~O%H020@h?hZ2 zJ4xP-5DcXQ;(AFmM4Z~>KUgIqhU&5c7X~#z&OH$sC(#kzU?R@DS-9OoFi2a^%kiBB z1YL1I^W@0;xT$q{dLKGk0ztfCeFuJh@o(Xe*S`Q!c5`ufd>qUlnRAly;X-m~tvBOG zS@k3caV9SpiI%G@+OGTT~A4R63+FA zG?Bj&Covu(^9`9I5s@B^GqBD@h4RU6@_Y(n>vAy;qRQCp+GEUaEwp+_Bnkz*zPnpD zFMF&F)#J0PFT<~&|3bX#(!DstZaR*qQYf&`*&idB7Z8UMm)3%hLU8n)VXg&)@Qo-UD?-fkZ&m z6K0vOybmbR5p{XHREB#c-mWYY0oyV{hGi6)DCStmFHk7t^Ek~&^|Jap+^|Btk4ord z-qoA8Y{BQ(uEC2}bzzjf_hZQvvL%0el(~ZB&RTE6iIa(&=M?iHAUPI3rW>o^CY<9w z^gh^^mmWtTGloKTg5A;P4DvqspC*xTNrXz^QlawrQFsaZpS4Tt2F4OoxR{AYq@@{; z^q)ptuKg%0DGidkAyx{?JfRq#sN1@*5wVkaNFm@kBm|J2hVUYkXzMq2q=-VRXW<}$&hI)Kz=MH>+ z&u%=wt%dGHaA+#QA4KMRB+nYeoy4KFfV>al<~hZD2ngXW7LMq~DtIkZ(v7;&$Jt>R zHv1#AnNMmWozF8)lnX)Bs5BiE%S%()7zgK856L?a0^=2+LZN`GckjW8TpGQ}DTMiM zgc7QH*-?mqD;y;!?nsq(T9u=`4##GQx5R})iU>E#AVfoSS*aOX%6s8mT237jBa_M$ z6GriL|LFKg;J`7&4u$m6(;UBdPC=hyJx?uG_@iwVh3cW=duI#;7N zn@3+Z%fD~!XW*j-NY1SF=9{?qtGaP6Fkb?aW8nk3u?ntW;eY8yAGLtC-A*%dPa?_g z?3^7#q(JaLO!e2PbVB=U^=O1lPZtzgdA_E-4VyP@!u@@x_`)$>qO2&fvr|QIyC=&{ zi6bX@PW*1SQ&}lTAn3nrOlI;`B2*7bRD|@1(-^LZctyhy1MZfXm6aY#r+N=(3zLVD z!QtE_4(I1TJj1-jqlGEFvihYXNaFaq^sFuJ*#J1QMr5Sh!HnsDP(g_}vF?zV%@}!$)O>a@lzQtZrV(%yKo>nT4%JIj~ax;~qy`n@B;eLp`-k|}!`q~@t zvRiJ!haS2Y0UCs+yL~F67@r`|>)3cwN)o-eM&~HbFZadbW^rErDqpx%$hP=@)m6ve zpL`sy)26Je)KtDt-WJ5(SgiDvl`i~Me~0W08pKOhUxNSIQ0scH zvtuFl!kRDS@Vcty(~cV>tYxm3*JK%jls)ii5 zkf174$t1RQuR+(EHMsB0NilWTTWA`}RYi3#5!5ta-T;k`OFJ*Y$1HdSc@(+a(c#@v zB9H#@%@JvR2k-Wx?lgDRy6O@WV;|Iwq1o5mc@i5(8vlhy*1X)Z!lTNwBg3i zo90wJe4Kxf9QiukUIoOx^CljI`4$kuyKolDk!WS%ci9KzeYBmAnGhKOVttI%hfvJr zL3{BE?lojr4Fp*dwcyaS za!f?pS=mci*ge0YxC^i^!>89=Bj1w`AG3$##@~hD%Cmv~`iOhy6$>FC53ukJ-B<-Q ztKjvz(MJ{Jf5yW1FMyuR6gKN<_#i!%+_|JZ??#-1Ej*92aiij)#Z( zcsCLM!RX>4ifiX`BmlK&0q>Yd zWEX?#WTzqqY?FyiiAgSPLRm`BUqA*(jp2Fi_1GI-h(9+UD;UI$wa&cyCIt7+D;DY( z{bwxDUsEl3{pJ3nZ)-wZcq2L@+tF^fA(PLQisDI1PQD;&4^);rqU}O)HmH~&`?16% zF5kKhvGz9JeN`U_mTQE9I*<2!lGwdzmE>B(Tx0g|Gi#D#*> zE#-8Bi8Ujt3rp0YvJ`c_5&34talQgQsLC?&@inXA!^gQoav}*xEg-J_Q{6ZpSSSJM zLG2GPAwT~Oy3xmUTpeGFYw9=RlDf^P3x-0BFav7L!x?OrV&P~950a=Wz#(lzJi7L} zJs09wE{(xt5+ObvRu=L$sE*2}=XsQ%?A%1`sv=hxgC8lz$=~rf+^eNrF#$~EQJRl= z$T~DWLgFLD#S%iIR;o*Z;TtTnH18`_=bev0;+4tZhK>$g6pg}%k7t25KyYI%phwmA z=*IcLLJ0_gRzjZEjaBdlrnqxA*KviSafgBWZ3VPuWmjy^6q*c_H zWt_Hz*CD#HTrWcf;bDku(S;?-IDrP!nWzM)9f)qZ`3QD_c^~XNpIf`~_Pp}3aFAU1 z2Hjo-eW-mu!e} zfC$2Myb+J6D5BP#1uuwy#}Wx#vuih!u?U_T8sJ-()C9@(<+kZYAtKy=(7Lneg?^SK z1~N%6UT;JmgZ4#i2pP8 zac+XQE6t=nnpQdB^_?qn4(iNhBEq8- z=LMutNN++Vc(y3-2nDqzvs5{I51BA-9Suq=Et!prAKaQA9jO&g~u%QNqFV zC{ubPAm>2{gmybB>5Ua=8&(Yz29%d$`k1duJ!9uLNxhf~=cUbT7^*2U&` z>_dER^0V-Fvl zhLOsdVjB|9C4y0%txHh8cu>T}lwTervgH|~OgfXnb$j;WL@AHHsRTln{FzkyX)3#y z$12&Xfop*BfheJ-Bg^;Uj4FsS!qxH$iFhBXiV_L#l^Am1oaY-(7nU<_GEbnV@lEAv zWzPIzl7#^lLd7ETG~3I^N&|6UEn7hmXyE)Y-8kP^3;`kh1!|uqKwgO7l~n=R+#%$% z`;p0xAS<~_P@-UOPPZjD<$!qAO*z6rgc0m$ViGs(z5uCs6#EAI5f22)N!Aeok4<4F zGS=$|c6W^`kBfuyN2K2*%c=LngA@@*Aow7Sw+y{SRjyn_=x9rUndy?B4XAyZ@pjkA zQ+n2%flouuIPjAzZvu44zM0d0q{w880K(%FMiN z?F547c|_&7gY06~7KuaAnXM&Ow~JtK?}8TX}&JNUScO;CT z4Gm-8F0nJKd`A|4o}`xsCD z9A>GnR4CZ$cAe)@RNcpW?L0=q?PTs#0dT&ps#cwEuA8&@`8 zjOI`)a>bk)5s>iQTdO;9Pt+*MyKxUPxh$^Ub0LoA(-=-A*KsQ#wMJ&9PebDneH*%R^`{o<5 zWBm=-+_I`Z9=6+yrIK<(JkXe1-SP98PA(Fu6t;G*LidLC_~q#y)Z4+bF0pBFJO_Dn z+V$k?Q2CYexC%g)QH^*Z1dm28L=z>)yKtq2CuDsY=s(q?*;nKe@IW)zgt(~M^YM?` z79womA5Yb~34@RG5t7s13c+!;fH?Cm-MG+L3IakPw{2WER>A8b293^pq}FXharJt% zM(SFlcCec$m2;c_XrWOP-Yc6|p}Sdw&K!+oaN)n>*0t+SQ>D z?qOcY6B9J?)`yRZAWkE0s|CcBOQJh}sR#&7Rrx=xfjn8@~M%XhP6VOqD-Jp8lx`7y6EvV1IGNG_YrO)))< za7p}_mWqH7zRJRPbYm5)gAkF;ddB&LK%fDp6~SaCS;`dhLNArv^C@5-qWb3mFIj~uWW+X_r!Hk(D<4|7maFV1fNg4+%j;RDrihUx1o0( z2{GYCr-=!P2oN+4gs8)h#)9VgA6@S1a0EYLUdWS^z8B)dh2$_258||1K(nsy(v6FS zr6eE(nteb6>$Tv8sC_NTibT-b&*PR{R)EFa4b#9_o`wSc&>))`t0f~6)PLlCPkYyGQ!2UGAxoyNA9$Yh>D zCVLp^Tn1&kW=QT7AEKgC521PlW+E|#i`Q>N{pwY?_jC^$y;FB*f}XE)x;H&j9zj2! zitFXP(7UQ+9jB@k5_habtoh*iEEzH_1PtoJS{M{*Mpl@{LPqeoKNjKx-1{Kzs`VzA zeyX&%a8S=!Oe{44A$*U8FY3lBAZGaA?2CA@o^d|lo=2MT%O~oQOcqcy@`5xeL$acx z*Q(>htiV(%jjQ)ufRjc6!^s2!>Y-7U$h#I|KNmO`DudpBwd?0)<;7MI6An){pVBM; z1(|pRVDmxlg#vjYBw=4YwIsT)eJmm*XZ>$X|Fu`c|6}29-MH9TiULA-H^iokwO|Vi z|A&1cJN1l}j_g!FrjoSXdWMUH&YP8(m(N0?W63}=lfkC;cC1>zp6`1#ZP#6eO2Xld zE8^EHSF%-uBzmXaN^Nq%@T3)-dQvGWl~IsF5~Qt0SaOPea7lJth%m)Mb2yB<2Z!;X zKNfP{LUI*N8Y1qh1;mAaq8pb2ma2fzGks|feEOTK1%4^ID4In@oK*|x z-s80poVet$R0V|a41|kUE2w|)ow{))IY z8-{7LviH23iRv~iT-bslt__Ef7#c#KKNfO6f;ft}s#XvOKCK&<3YM~f5WWI2y|-4p zlPUZgbmK}ze20nV)nRl+n^p%byHoY&E1q}v=JjOA!!S+V-L?by<_0`D*oQjWb=OnI ziJwgj2$e*|OY}Oq6J{!>pR>|+=+{Z8bRL4YU0&8OXb?SPnmEHmWdI8s2HCks*?H|< zocjO(AOJ~3K~#Ty+FzZ1K0$KRY;JPD%EI64#-#+~vLFAOZd+=gCI0uZaDkpt1^ZaI z{ehcr{gIxr((sa_N6<8Q5~cn7{@|IB@sEzCrrJ42mWU_WiyRoCH66V3O2$zvVr+aI z?|SuXaiB4V`%fN26V1NTPe34JC4wfKmzcff2xm)sQAs!|*%b6V)%ID=LD>cNT4z}k zd+X{ySRZfx!kJQ}AU0K8Sdg(^mtL%p6|6Z%JYUP_NnPT;b28*tN0UW|X}IfxidcGX4VY@|9< zxta1R!AtyJF(6cHqmo!uvMI>CB8!Ag`)F4v{O$lk-$^7(;=xo444PtmlzD-#-?$O) z+EXj1l*1R0RMDJQO2Qw6(V5 zo@5HS96iq3$4Z3cpxaTqc+fAJo<_Lj#e=Y1JP?Hsv+zFMI0Nor;XTX~S&@ICH~jiD zC=MFP94q|6WM=B4>0Gwm**t>;gB^@gQ4*&Z5lJMI*wECBm%rlW_}0Kl7}>nol~xx6 z9o58PHt-6BH?E-DDwWsER6>Qa^ciFd1$2ZXw3GW|$!zYOebJ7e=YovTi;MH~pwGQO zk-*zFtj8zUt<|&73f}`++F;^A(;7dC*^PUAgoQuXjY}2F#RF0JAjCq$0S+PY-daIl z+I+6G1vQ;bZjh(~!d(*w8=H*a8z=I)j};2VcCqZdD2TPB2F@v2L^_j23nQ%CnD_C$sS#w7DcEWNfXeIS zOsHh9W+POx>$Xbp3c=aRS8G$d2D-za$Yl{UEnME*&O{`Kr^iPTwE|B>1I9b!cH>WN zMA_%FI35UrHhVn4ypTWIupV#Syh+cV5xxhqbiurjKVpZEu~6#_3F@-C9JN2zVo6}R zc_0M(fPYIKYXNZ^Fk+dy{t;>?RcTLSqZAX`^L(TWM_dd6l8bz1L+jjMB{j2 z=NcsPIXpHx%!`IhqtsvpOK50By15bA=H^8U`KBgxu3Clf<_k6dpnWWDNUkC8qgL^t zul^Q!Tvk|)9*Dw?5KrX_>KRo)(|i9f^F$Wy0rYc?TmJR0keq5V#s(+fKAB5?C|4*p zac(8ggQ$|b9%3vco6jS_!s}jfD}IR#Mwo!mo%uB4_LA{Tpr#?nx}tzovn%L!{d|>d zIy5n%YoWC;BbhYfb^zCPtVSF2xb7bwz@f=;)CYom!a$uJ{P}9zerL#Tcr0rK-5F?$ z1bSY`!N~;Pwq`Y6GYc=o_du2&n0UO59X^WMr|V`}co7Rf)iag@ma~8m=n;^!>6*Hq zh4(QLS(aaxjyFH~c@&P-HJ&&z`GJ#@L;pLI&s%)MKqVZIO9@%LZ)6m|by5chY z`>}&)t+wuiP>H;Co1RwC?dl}Dty*1zURFV`BikV}t*aQzWq7yMm91U4puP#cQwiKN za1v960vdy1E-tj@BW_t=j|L*|O&20(iUoQ?VbxD!!7#{#U{^;w{^8<_YQ7`#1!QS~ zi3i=((jYjk->4PT)kPa6E=w$T0U^-hoY`zNb`J}G&P0U7WLe{-&m2e7k;giRdJcc| z_{7BTXL2;73gT{D2?&c9iUs78Y5dMDzlBG_CVGd55vE7hDk85&=n8s%C8D1RdU?G) z1^s#|mGju>kZ136EGvZL^43m1)=|i2@$=r3czkRK4NN$~wuO=@wvn_EUre`cCy!4@cFpodcG11%e@xDar4Ya=%=T_oFK7dYl*9Hd1 zMsfYN9oTs7bMf61N6~Br#1s1}5p*T!gs#_{Ng(vH3VIzcD)G6e97QvwBj7XBEh!>om{_-I6Aq-N5N5`z;=zT-6Lje1 zt3kD|+Njo+x16`U%JT#|5Z%+Ps=ic;dr+_3uods!c?q5yZ^C0eNAa15euaBZ9;2;F z&_E)YFQ8Z`qEr-t`nk*^r1Z=Zk*mCi?y`E*Dz&#FJ2!el;& z9gVGc`>u;{`?kH(8^Fh2Z#Yz*2R^(H==%;n$6NfMHIi^3zB7#qVYZ+;%mbhY5{ zKpztjx$ABvP*t7mbz;|{m($Z;sP?_*(ZJWOu)GZO9ukEd_oTX`b-1j(3l}!EA(GFd zXJ7!oIDQxp_nii<;AoD<5wK}HdRCt=j5O&#@3Jy@+@L4FBWPLK=1BOHO~Kg50%%T( zow1e<=pz|m-qi(6>_2r0^@_|4zYA;ez{G>rq5TDfCs8ZtAuw0U7{d4}m-p z5|IOX#!|%#{^jGC91C?PCMG_a&gWiBTb1(}sU^DKHZULD(qNffq5u}CfojSLp=V8eABvAkvudK+$9G3 zX!b zhz~8Nf%OgRBUl}acZLF?ZoXwZpN=ZnIgv_XOIH`{RqZ%5GK9Di4}zD>b%Iw-sJKG4 zd|enS)saVjDt3*jVje@8G)A%+-lcZK>a}?HMOWa1mt2LHx2{I|vQ^%f~kIA|RiK!N)pipuE5XWSS-r4z@FC1jJcxr{juj{#gq7-nD9~UPP4TUDZ5Dyb z|J8Ds;`@rn_aV6Nz8g;r41R8KDzS&STig*C7#kVEi>|&JiH&P;pr3gk-mwpz_$xsd z6(ux;N_KBP!P7p8Te?7=MxL*_?qXiV&XzV@(y7=s#BUBCWMXj?r`fer z{rY$ukzkN{62i-%F%467NzvelDLoBK*i?6w$?PQ-=X%ESn#0jU8>5l;=9*jo{b=)A z{y;5}yEJhso5d|nO}KOYIz6ilz6Y{!kW+PMJ77+$%&GirHh^7LSm^>nAW!6*EX*)^ zJPq`Pe|V`cHhjhZ`~>O42W}c18@*#Znc71gG9)0$bQ;~UIQHCdEgncuBAoX;D@37^ zi0A@wHs}H(K~Y-Zmn`I&aO4p(EUaQev8S~idpo+&9f}}7nZS_~C-A_bgLs5_7^jAZ zK+iOZN27>_BT@uN6NGq(fpO}VQUc-%iLjZDkkIsjqDgB$EHuSpPp+sOATMobz?V0y*R#st3&_GiE)t|I)@L(Sm-=O2&BDLy87m1ZwF}D& z`T~Ckvzv2GKa>y4tqGPaQucl%(wS0@uZI%@#e^Iako6lkU?^mxkfEEPD&V*1o-{S! zCDuwe>B{Ck$~v@d`gktOr`)EQx3Ml>kJ~oy!27Sb4)4G8D!izn4dc%o!ry)Kn|SA) zpU0nm%PjfW~z%n5tIFs7P9 z;cs_@LbrE?gZ~t>!=*xr)`5uGX?&685)SrKR=D#Bk^^SDNRYUOIA=wR2jP71Kon@k z#6Lo;T(1@6fqZnSZonA($IoHsaQennK66JVo4tVX4l<0u+k;{3x$bH_UPvQA;{-Fo z>vdG}N)+@wna(oera^E<`Dn0%*wE03i#k_hS92ShOC~0VhVayp!?^$H{dkgj8fRFV zt}`AJo`yx9hU$`%-h}9$QiI~IharNn^Kup~ij>_~EKOcZ(6)2YaPWz`Nch`!B>v5i zZ5-bi4x-U+!#+EUBW>LX6i93T-0N8QhMut!aXtwM z;Wie&j@fl*(JsCpVsTCJ>t-_YNMntm(44yfICl4ONgU>vL zr;i`Qz{m&}g*qD32!%NL^QpH|G{pFY5(d>hCE{E#xTv@SB1A)o2u;jdx zj|T(4jE3re)X*6E&1u`n8kr(4hy>B>3y6im?LGT#N$tj%bIf;j!eu{E2c4z|Ijm5GR{W< zA-t4@Z?izpgRK?xWJ7wsF$u|%m}B|+?|s4OJ8u8(>B;_&rwjS6$%%1Xx@$L#om+5X zWEf$!5KR||YLJ{t9M1>A^I{M@%*c98T|F*jg0Zu?4ef@7%*ZH?GwxSSPX$cKsF~%&QI^YlnDrVBIJ=Muc9Oc!(i7>-BNU9VpL$B#zerjdu=<^ z6AcCrN1~Af;h?oY5Q-ickJO);noOd(a}{EN5bXRA`b$%=GQNQLs128kXPA?4ya%&e zLq=0|U&X@Rdd5n}`6?iU8zJr%>hz4W;0_i($wZ`2&sb=@{@(8e#`hh5*O7^_4~!?1 z(RxO<+poS7#{vc;PU(GA^D=alNHoN=!!yj=s0#+Mxw#b=ws&G{T@&hZc}(>6x8(ag;b=a^{F<6h|zuq{jk zwzqa*4-0DoVFVIW=s$HD`wt$#BhNg8XPCz^J~;tK?o2RZh{zS;N-TtMxPFIzE;z`A z`7R)Y9W4Bqh1Gh-SwM9@!$jmqdd5QG#_xVHm^_rYeKb4uJ~Nw(ZoJ|$^v8lQ)1Ilj z9syB2o@HJ`A}1C@bk@~lS8F@A);FQGWFkK@iry0^@#KL6c=XT#oajA+Oge*bB#bz9 zP039Q#Rl?HFiO-ER|gq~@GR(@hBF!tMRz!|&_vUK0)O*^Z%!Ndy&{dyp*@xTirgmew>hVn=g3)`g>pGqFhz z4dLYR9z1s7Aod?SioT&iz7`=Sr`mFHa5|l&GeP4QEJjcGGYl)micA@nHEdf}Do{di zJ`@^^gsllXRq83kBcpWzb2y*PpNzT+l)|i65$i$ z=-t?jo%^4_zU|M&ruH+)CF_x})*?4`4B7f9f{7$@kpSw0rY|7AfSfa!c)S5ZJZ3Y~ zitsdq=h35QoNw?2#0BkK_n$0Wt!JDCBM{>vcQ7HD(lh51>p%C&U}HAx>6^taqX7P01HhWFe?ki;rr|ozs$!ZOR zvQuLg>M~PxxrsG{Lxoe3Zj@q!xOo34j&HjHY35mMd2k<|zW4@gN*-du*Mwp>Pn7m#xU6OI_fSOv zhp8LRW6%$R+}PPFD*XWeiiJDa4|BF2%(KGUrg{T*Fc9zTFjKJz3fT-F2v0K6$XX`4 znwoLVsRZ}FXslkm$vNPy_@Xg`^|j4nVg%M z&dxpe+jGwUk!*}ajt6S|N2`5Rd#e34J41n*&7rE`U3CpDceKuKzok7?|HIbktZQ02 z<}7M#YFIS4IdpZnrR}<=%HYkOiptf&z{tZbFCN@B81#0}iuLu$a{~kYwedv#K(7oP z8Idv1xRj3!Nm*=Mkh7Ag@QMco52aj^2;aqSm=)$rNG`DED8BGv&N?*@)XBp;g63gC z14(66Oe{AZFsFP?jEP)gAIKH0{%~D$Yr~vGBvdt&j8EoC1giZq&mWWvyng8%)NkP3 zd*$gzACr4GZj|*~ABpYQ`=8O6NN-0=+n&x@?N2s`!w-fc;q{Ta(5<1m;Ehe~txH>? z^;gx0Lsv!`8n3ErsJ*r=nY^wgQF&9vyp~n1Z9^M^1Mw|mud98gWn$0XiIIwa@3@Sg zJUSq;$}y?zKPIv9m?S-D*Q7R~|E=)~pOhoQYNBk?G$u_Ve-{9xNU`Q7<~HW4Q}B04 zM8-RUSkORT4N4I#Qe7b?v(yPVR9mhO>bLC!xggR|8}J3g%@e*#3Fy1JIX)qc11F@a zr|)>*?q?5e-?eMs<6XPA9~>UuTpx|D>uhda-q|sCSxbF%X(U+py+#;BU377Kjekiv z(s*OEI=H;y$k?i}M&G9SqX%{*dq%s4Bjbk}d!8K(cJ&O82dl*E?-$>}0f|?5BpDx* zvay&XCKJQ;pQIW@rFSxE5W%}RP3L-o%INJK>v?UjEsK2 zF50-bsj2C^&AOtftqm@ziqzfE8ZY~4WgxIN+CKb1!;wSVChEd_W)Jkd6c~&RddqzY zdH#U(d&Z?Yeo|y;RMe9sSze~{NLdWM#l31072-)u=t=_pD`*iUf59BYT+|EShrQv0)rqpzp+sU~K*|=zD{HQa z_ygC6Dt$k%J+Ezze`5IlllApGTW6Pdc?Wx6jx{$7Hyk=XCL=NN)SeXI;L*vQq(m|< zp17_g5NTEAm5QWC;>aVJ+;+lllUYp=Qb<^HZ-tn-==1?bduz;nyaUJ?U=&t*gjDOq zSxM(95bAdawDaQ2M(l%x5O-1I@ayGUmd+l^c6!hc2<6z1*#}4}T!Ewq9;8cEH;MD( zUp&C5q4f)Wu+giX5RxOTIfkOAm~&3e19N+sn7K~#NCO&3`XKTYUCBNxrm&(@zO1@a zAMmf+2M8hAW6iBQ#mqIQU`}Ih|3J)KCuzVftjxe+96q@7?E`6mhZ6_%s|um-IwASa zg{EIQ%;Ou9*_Yzos!yw)vk#E7lgWoo%!7t5WovD}PX~PF2n$@P5B^u|gM^UuvE~q> zq%fy4d7rHnGnZ)|8Nd}t_FS&IU4?@?ry#EUSCFno{$U>^gq$8Vj<@UOtCpO!sh$D> zEelm^>;oiyXdv!zu9zOkC<~nlC<_lGS*=EL(mqHCF{p7=>jkS07)Lhq?Q^Pb`v7r9 zCQCl@YVaUp8H|{7r%_q}69Ip_Mkk2VveJZ<1lHWZiUD&a6Z62_#BKrRD$T z{?xoJZ~E#q~uWJn5UNomS&|4rVol2W7Se}ZD(@{4J0?zi;1+l z%s$|N$5p?E@}&nmA=Al)rbjtKa-sLwhMj;ax`@y^Vjm#c!7Z%ZfCm*}feR$FoDqNt zgL9F)bt0iA7a=8s^~~QbW)5U(9+-Oz#LPvSM-Jc$B==y+y-G}B#!SJ(k3Q_b(bdQk z_CZ351vQQf#PlYIu#(S|hs5NDU`v?f2pY)rfn_*)3WV(g4nQl-dmuHEefB{@3Kcbu zbM*2BORu*LI{_7R(P$zl5-A%%h(2YT^--V&mt zvf=k)3Mls42S{$9fy@ja7h@!|?E?-$sp$=n8cC*SErd)vY8*i^-9MoZ*@m6+Ulkfg zJzyUoxrGKYbJVJC5Ywvw(I(mOu$(BdNR13b3XC!1MvCcSf=7&&PH>xb)d}Fbg(m|P2eIPDE1IaJ2t%ZIB_-2Kg zKiTqE)%_5&+R1ccWsiT-(z|WLnSdH`SgE6_8@H?S1R6+wg2VM6i&>R8?d5zr(C^?6 z5Uc)@Tw+zp{e-3SZNr&>RR&fY*NQnTCwT-7B)>seBU*E2nu%-YfS5>?2h~Ve6NtEm z8pp@<0wKb%)i#_dSV3PcCTyMLAvBP}0232S_cz%GvH%A1N7W`Z6MnNJj#1OVO8F8o z1w`?Tx&>Cu*ve&CZk|H}DI8F@49Qjq{l)&WTXczu-g-!lWUGCU5Ibrd9}p8s1-;QW zoDDdqLr5-?WZ9Rz0HA>s9+hIsqAXQ)qz+}pnCefeKSOFJZ1G86K}}=6UOsH;BPw6& z9a*towMLpGiKkSLs<6GaRm}vwq)CyYrs3BMwy2;F zs@|G3 z-luv$ewA{Admx(XC#sFYGmfHw22z~hWq^{_FqB+14SP~dnB}C@OjrSWU#6U@!Y`mbR;z zVB3r28EP8Xj(V5sB1>+cot+A5vE8LwAtt(t6d^Q_(g5ax$gL|>Z?KKI4WhaJE@rz6 z+NFlFKjjWGEvR91=;a;w(b7A`-RP;)@o&{iF$d!;=vm~@KuQnnbHhkb;0__dxd!cc zQ9k7fG232Gsi9!SLR>}-11k!wGO!(m*03lml1*FKbV2CtePWCQ=VPQqpn;SwjjAt- z+1_%aW>LBfs{Uo^X-i#dDkzpm(nQSy#Ws<|hw22-n=RFydS8w~#yGaA)~OEJ#z+Z3 z10ew4Ru_orM~&G3=>~h`&xqOnK!_*Qt)?=Ra#x9>W)aZKxnjb!A#6jQC+=1xNEhS; z-J@D7W>rZ_7#avU73`0rOB_n3AcD({lJc2?!jH&?hxUpw8R!Ky7OY~54mAp_9@opv_XdnDYH|EQMeBgP8@ZKNQ^DAf{z9f+Gk?fd)d-0a0A2 zwu*yy6wpJqa=rrdI4EXM9tZdkwp}2sT<~og!V41jBC{SE74wqBw`*iaC)9{0lil>i zk6fB^FM+| z6udA|;sS<(GTyUNhe?6aBc`lBv_*`G5Rw)&5RwfZ)my}@N>HU0Novy(8cZ?=D=d^0 zLDl6=s(%W5i<1nYfe<&r_6+h&P`MSW6oi?=WXQ|`b3lX}3Sz=Ekf)KCXGEm%pn;HF z5*1Tt38sR!yjZPNq})N=CN3t&26d-k7N}KrH02ILT!IEdrjr^mIVY$V4575fOopcx z1Bg6B=@@KFLCDP*PPv1S96TFqD8np-Pwp&Mu(7 zQ*R<J}o4yRA8&4pw{Bpjk-IT8?Y?tnx^WXj_@ mB{bSPYzgNTjDR9V!~XzB%rJgMHNZar0000{%-7Kla0+An>QQVwr%Ul?|*n+%*Y$0us7~r@w0^3`;lk5A>*MrX=k1Iy&iagDb?jkvx@CX!Z>s{{` zV;x?cF@(c3nf7)6U$@nDTRc`7?mSzj`_p)3p5+U(ide5ISl16R+WmdX&g3*G*@XP1 z>#>wv`8|azC?IwxG6Tm(*vwN*A(gu*y>c{FWU>@6J3)cLbyj}f#xN^?WafikG)vQ> zXzEg#Dsm1TnB5g&F!>p&xnG?d;Gcy}E2KP9zb!b`j5>|)sCeU%!(z{#3v7c!s_NWbD7TB=qHtE7G3M*wI;Yr zM>NE=KHN%&v?MG^)vnaCaJ8OX%WSt^jupy*EiNxYYkWzN`z85#-<(+A-LT#R(y*jo z3;-M+z(ia4$YhpzYIWwK4nhRms2or=5`|6%`b&9$0Tch* z+7vkUC~LXLOZ1=j|Lo}^pOMQs&@|W#gGV&xnUb##ti;WcWlH!>k}Vrp_oh0718>+PdeyDL*EYh6*jD!B)jh5JMZscW% zpJ-)Tsxj2!ZKAyN1kX!nlvu(6jP!I?VHfHDCLXJG_&x_!O?o+qEu~Z(?-i3=^nrq- zhp3jKFV)^Uz7h%n3Phh^|Qce-Cibv9iV`3sT2 z#9*=;HKqJ5(O<3vwHce>P6n;e0ua>z*)h~at4Y}3N>}`xk zEM$9eD;*O+)#8^nn2=}fs2E!ecMHp#BU+Z}tJD&k!3D-yh67}hPVf}+gB9q;j(j4o z_k}o52ofus>C*!WH_X}Y!N3-0Ac=(bfniCYYF^&%cRIx!s71{Ew>0~@`FY2z)n&rS z{D_cm{)n1|CE)Q{?l}#%G0{A9HEI{GhE?&tHmy0=3}q)XZ|K37Wm1)UR63-MwD0V9 zor6zms%PTl1d6R{byrk}HmQd{TUh~qgaSt2aF%lt>h5ZD6iLtg^9_Ise7stj{HS~`be}Gelw1FVBWs9UWk(W|+bGlfUz{u#yZEr_`4LTW$Fm9!^56HxK z-1~geBpP_PK~JC?gznof6SiMM&4_X?$T|WpS>aoYw-Z3m_c1!)S{_|~+1#lN&$7Mk zNMdP|TE>|YL!BsX3O~VIW}6NAjcGd28F^@#>{$5@pws;iEFqz`t`*M#TRr@DG2@0Q zer?ib=$)(+_xP?iK}Wgz@Nm}Ig)-UliM?o;q|ivVZdm&g&hod$7q&UJxX74pDQ{np zY6lyy4euA$d>m&(BqztusLq`NAbG+<7LQ}Z6v|5U!)T#YbP~(gAd0!})yo!>?CX9z za>J@K%X$`PE;l$_HgLLy?m!g=W>UNOJ`&aY~dNKAzLhnDaxqqepEU)!$*sSa=W@Cu1MrboN zZ+_%D&_~>(y#{!a46Y&adJCLtf2j^zE!yj2g3Fmv$ciPkQ~+yyiVgDzCs`sV%7#cV ziO+D>6+;flw7A6B5_g|EKrt<8rSRb0uK4yztVH*g-d?AHJ`YBj-odB{FcRl$@Z?i9 zo1+vwK7S4K-N_85K!XG7cqVtyKujit-zd!-eg=;Xl!HEZh$D%9&y;^vuc@`5GtoK$ z>Ek7=(s(kB#MN*aa03DDxkK+(wO-RFXOP!(x5Zp@1cE*z9 zARe}XOtlG5Qd%Bnr?+fK3#`JlA~n2TxD}zU^`cBJ$Zh;TxT1ng~BcldlQd zbwF$Iw|_cB+8M#=*0~&TEH8E=zT}5ZkTs->$3IWBF4b{qmp5BH4K}ort4s+(edq8M zG)Uy6AL5*E?Hk39A|hN_FJWoS5$8Pi`NKUFUhJNS<>NaCp+DX{xr8`7(U8wqi&bi@ zB_!L5l`|!7561JPqj0CnwHU2eo0xwcO+gB{oxm8jyN8hqdy9dLI&)QXL@Hk%&XJ(u zkWJ>h0|FiX&^Ds`rCGS}vkSsSgcvMS$au|K9944h3TxY@!}wb+y&Y_UlLupT`~_nM{OOCK?}- zQa09t+jfp_{L+r`&Fjha`VftP0|pL-@Lw=0MFiW~S}SLR-C}GQVV6p1>BsAr9T5=C zOk}TNEp!MWgLwtPVUk8_B;3ED)0g5o(EZ5!&BRYQ*Z3!9_^34xjHptU8409M zbS6fB_=Jp&(L{fH_b2=at8bTn*+*>Lf+sCiFfzdDN+G2tyG;i~<% z85%F)1V<4_iWzLW)e}UBPZ2s-&KQ02ZGABagp~K2T+#`ZB0QVG+hU-jHakln%+>5@ z4-~a5A)+&Hf$4hsvYcxA9+Mo_`yfYqVd+6mUNq@@72h%%z=052S({ zyLx=`N4LPY{T7Nb&@mZktCq8H1+MJ6nmjbm6Pi;sS)#)R(qJoZr@VYSb9*TLi&-bl5-x0)+Bk!DcslyKZ~4)X;=_Qj)i(w0$ZY)Y^qZ-=RA`u_M>*x*VUa{;`{fIkb}#BClCqI^e8;~mTM+^2C6RE6?>sf@tkPr3rci#j3_e!` zn*`svnu%{rk3x)KBuB+_JhJAGOLGM?IECgN%XZ4I{L`(#XrAb9*dsxw$SAw-A>XWSBR81}%z_@;=B!)3+y6 z#ROwlC#ad5M6hYGp1%z%5FvgCx+$Ba^vm8sINf?t|5a+9V$|l zx5Yt@=y&fhxExZyoJ|D}Ut5QzQ%V@pZ=x;d@lZ$4Gb}kB=lh45|I|glmg=~Loj;Tz zF`Ox;JQvgDehpH?JaIT#|-)@~k|w*~@(Z=1Q9?g^1LE-i9*trC=?R84l3>|v^X zDgMo^6rJEUW!+#=@WP)<2!`2$bDdxjJF5YyGLo-pu%osgUh>>AV7ezWWc-Y zxOEL#wCoS12!Gv_m}mMjCn>!JL^38%TL@tmn8gt*IB+Am6M3y!@MxO1zA99!J3{Ws z9GO}Mo5W0}49_YN_CGG_$T2;&6l0Tk-R_noqBuw8E(Op!YcPXX1d)>4x$Qy$ShB-2 zS?YvHReL>@hysB{NN=j$PI0N$ohv!wB~t$beSZ{XP>rgXU78(>s>9EszDQjDrw`D} z7H5smZ~zHX5i98LJ7hWxq!onn9ks05{>6PDb=+fwc&C2mU1`k*ydoA`L;TB+B1!popUFr7|n8m(+m_=-I0w)OUtd<_S8B!f8P@0d!`Z!#XjYFQ$DP@bx z0SySffeTUY;xq6!UOb2clJQI&r*0TSXwaQQKRb|F-+57fl<(=dIa&AD#p4Kw|A&>W6tjYh^w3I!|vqkMl{Vg$e82NZvI*?-CZe9;yqRu#Mp zhG}9GX7F7qDM`nRKUW!*(|(9ieDGdcXIc$n070wfGD1t+<)I(s6UlL;>I# zOz_F?$0;hd0ZBLSJ|3Z}Mg(v=s6Kkfmd^w_cYb1Zo1OBJV1F3t@3c0TBFmK=biYrf zs}G9^iR*_y!%yoCkw5@JMkXI`h+oG`YZj^uXTMqQ$H`A8(7pAAeSSg5O=soOEx|9v zqAWm+gvz~O2F|2cC2j=PA@UZ}IdIj~l8-#I;kKZRoV&KiABqi{ z+||s0Qo8u=Xf>dqyUi~~yeQ)6DVTKrpUdg@6KU4diG``WzFa3zby0c&%?pG=l zrhQWnv55LUgk3ViUlsmiF)A^GP7xRZ)GeB2i=Xz?MyNRRXn`Kn2A2yAkTrowQ2cxv z%u1@bX0Ws?Mh9&zep55~9B(%BGWq;O$2L2bY-o&^c)pPW;%$Z^3A(ex*4|v0N^%ra zxsjKREf=9c-!8Gm4;yOO>7Kt?L=S8CBQUlah->?ms^)ZE?G(J{J(c32`&lCfVyj|w z>EfskrSvT3vH`1SZ4tie3h#vSH8zpTpFtK?5KU;!DK%h7bjAY|3m;m9NajrCWFIo4P)wj63~O^gAlzP@C<3z^-&q9G1Ky=`@-+n$Zzj^mU<>Uf&vV;&UMAm`xM_6s z)$k!|q&j=%yFJ6f`;c8xC6m=r1i0ibm7m=b1B$#uMSYyqoi3Ns?S9DsgPS&O=(0ezeIH63E3Y35fyPyrW{O;=wt#pGl zNijVXaY=Zz&_EQdE$x=Ll=zu6G_ivb*Adsx=#)E|E*)g-<2W%bBLbby?9pSeaSzo5 zE*w3HuJp$ag2rEzNfkxG1k5GMPd_=d&A z^w|K^ga^m2(W+v)BD^xbl%g=4_eMTI`d*1!2P0?v3?lS&JqKKcOt~rg&;7Q_@L~+j ziQS04=}Y1usqbhEh6zLR5PFyIH`B7ZKj<=#zN`X1zWgs0uneif`b1B-n8COPnW6FK z;})V_+#wna&|e!d&8-Zt#GnlC%X2bd5*tMaR;t)a=f4FNR;@uicQ>cr9dxZK=@Dd}x?IS&s`|yYk6s)roHZ^2j6f*W;oeE1UUH~!inQ21^bTkof zDyY_c2_&c%Gs855@v|z;f^AF0=ggGby8+tA54rkJ>_9ZZxRJiwsNK7ru_(xe>d9wW za_5pXw*eFQvMFgs%0$f`Hy#*pFqECDD>E{aL!HvP$W;TT^4U1l_R=c7aTfL5#@LNW z?;q0JmS}9Q4}mXv?o&j{2}j%ThW&W_IKA4>NU6E5(7M{?B?BAlckLa=Dd+T|83!N` zEmj3LR;2d6G8%_VPYOelI(H3IOi6v~UQiyq-)oPNLhOnwm^Z6} zE{_}gFO6$|VF*1hNp4-77+g+)*ZU%91bbRLv&Eu=Mvx1iHV;v#z>m7)h@ZWQ8+#s6 z;x-HqjpbYWRTFQ80zWBglI1EAl>B=+9WMT*xS&QT%w3ge%_Ld7w1+(!1S*e`T}}U>hCQ^_k3%;F&b|y(`Pr z)e|93juS%T40conCqp)T^R-RClAoN1c^#c9j}bThfdx$H%oeFlCe)?p2$IjX!>P0_ zeemVS{mRwNxR5J3E04?u(XW2Ely6IbG?`6=SVH-m!B}F|B!yG!XnQw~v*7M-cNjT! zDlspbw+?sIdx)a$+Dn=3``d?KA**4-GSy_A?v~4UZ6xqNEpwjjil>dpVT10x2kXj^ z`up*pte-V1c{KwrO{siePGIN+Pnhx52*YfoRbFt}O#L|vJ8v)5C?oHVxv({@Z?rvU ztvW5;65n$s2gNR{!wvDAGh*=Fv{@#wOg|@L!d3S;Uc4tA;1Zhxy+db%e&>{*P+ltT z(<*tAa`+2`zVDz4dp{&d_IXcTZBuTwdc{q{_tAG!PzUu`ut3vXo6fsod5-IDJOB53 z+?Xj3`us*G)Cw^mFn8HV#BEFE+xiPiQy-CDq^6^`iLr_1AE>>-f;Sc97*Z3b-_ZNLj`NqOip+zalm|PalO&@FUb~E)}g%g`g-bA($Ut z-OXc+xhqV!&1wpyTwBlfftK1b}(_q~ye55zF+3bm>s`5aps`xyfpdFKfHFBycS{KnBn zqPNc81bCp214xt#@O=OMA*26qOHHG8;9ndWFYZkK*x*q5tCPR} zLR$)cNt+Jfd*=^LIuDd6%46?L#*xNZtp!I9eBlOWpZAknY*>lYgjeF+opjKA?o5dG zN>#z5TYMrc%7&cFigoEo=h&$JzMm;hrK7ZJ@O)G_ept%V`{JPx2MI&7KY73an=h1l6C6h`T{_M+0aMi>2Ngwmi596D{Wz~D)yZX z(%YR~sm|kgMtY8x2-nU3x*Mk_+3FUn@p|^3{?XlL_WC8_7v(wM5%*&}W4H%X@5!s{ z_8`h01&97OJdHywUHp#MJK{&pxul@=N+Emuw#MeAO+$$A*_$oR+~2>pkeWs`(kk9M zbdrAiA9@4P$;BdH{4Emq1`cXGIw4@dd1U<*lGI#~a2=yEE>np6XI#?-pt)z#w`AP! zzuKwe$(5@EgpgETv#^G`hMU`K2umB9_&TP)`IT*OZXwBCGav3@7g-tgt#a(QrNw)v z$1tYdlRA)c_=TPlmrQH4#42lx#u8jyLKQ60cJL{!&mD%ne?Jj}lfNsJACnp`)9O+R z>(0wUiwJ@9n3QJ`;W-240~%40)}3p0WS)X1LsdE?bndW=x>~=00-Bj+kL;p1BvXjJ zD?dn~>W0nuN>f-((Br~Bq&!wRgt{(DbJJ}>!4j)L4=D=BXyve%JSH0 zYZ?xvlI2o|8GkfaVm&r{EOyVEVi<{;*u}D1J0o8C&D(d{Nx<+Xv$}uayhYLoBjyxxZJg@#t76gK~NU?_AhIAmxS<=%g3oD+zJR_?iDc{CYfgP34UJ z7uD`$+B`0eSo6qHyO7_UI3Ym7x4cmB#t4RMA2lB_+d^@*%9%VrbE>`P=IFcBoOx0^ zvy}!oC^zcd0y$F6h3hv-R+=0~M3fvbaPw<+|6Ll7!&4vB!$2q)hoYeQeN>BFEUE%^ z63+ELn7g;oG*z+)Vg73rt=}w>$vVsfhjsg!b`;eP!iA)7@5l7Jg-ec2!ini z=5?g`jNYhO$BN>I(~+p_IP!NarXvp?Su_Fs4gJ=!V>l- z=Z&V7iCl?*p?HeK%{ho(1wJG}xNd*Ucu$yV2(w?062KPvgue%pVxJir@}0qQMn@l< zOyx;-iZlwX8E)Ahu%Dj}I5;=`F(JWgiY0de2yr*kUivNH*!Z&AC4y+Fq%X|Lq?A4c z+7{kUkm>wVvaZ4|?!=?e7Qg89rMvg%=N3un6P-Ep8w?owgV0#?@1{m6^Mig7^8cZ( zuEr>`JLEC&YWU3NYsJ<^4D}k-))>m2`}QfN{zF43ZXJS-p!)mj?; zT)Nu6x~Q|-{_$2p93L&NK&C11EsriI26Lyc2`+MvMlGWWq5LK#!+kK#9jSZkm&@My zEyQcD1ByHBsgD4s(b?o@b8y#zh5$AGUE`oK7OO?BG196~LRvR?m+$5x*C7asZt}|tMqc}28XRWy$0IOq?NdIWL{ba zclo`pya}7FFY7Djgb*PzD*5OQDo2Hfm!$NHJjw%7Ug|P+FrBT~bOaH&d*u>JkE494 zd!iQc$`cr-9ixz9deZq!g)|L+AMS(Fxv~UEFeJkDF}kiw$+~Tgs~yv1+}+*Le;%QI z0pOjCcTC9wiT1Rwp}-E}tZnYIud-Xu91&YF@ znPtY$G{m_$W)27r>meC9_S}TgxFl`O>O5t`gUdBaRCokeu6BY;mb^k%eun?|JrwZ( z&ueHB%QRjE&3lcc!A;_ec)b%@sPqn5?H`yDJw6tIRxsw)%(R}HlEa~w+m_$`d>&xD z-5w|#?}2I0giQ`oshMgkL%wlI#%41kqE|VV?W{mnz5uB9(F!pu;9xzviYS60%(#ZFU|JulT+tm0*s5_XRV$-?vNrwvFM zUBj$%fk+^)5qG?%Z1hp0LV@9};|t`VPe%wEvs6pDV}^97sQZBq|0yJDZhDRA#eG*{F2-mwHNEPW5*GH?BV`aJ z1wFAnAMe&Zl+3r&K3$wZ(vQ@UrzKuf(BE)S^eh?$uHfFz^#q+|3Iy-VI{`5Q+^l(Q zV~cYWy{}&GdM_&Lp%SG86nggLznq%;9IYhSWiidK$r~Ixb#ag>%<`DF2J49tM5J0t z+^gqMVCENJz{O9cYwid`KpPVV{l?lVh=FD$>4ZkcTw-EbD{4#b8_ z3NEOt{=`TNY(~}9^5{r|jofoo`=gQ9x;*JrfHx#N6{BQ^>;b247I#ut2!Ht)k%+{; z;*8FVjG2SY4Vl@zNU|n#%ZqdJYEZ~z3O<&TeXu{6Ay|Ubx6sXVZg$Q)VdD}hrSbvw zMf7o;SZd`wk9wm;G1J^f4!>EcU?C=G_=MCw{g6udAk?8NS7@Rg$MK~!M!Dm-sihVBhA`zaZwwfi5c`EvJ`r4R^Ez-zdEVQfM;~L^wP`^%;hS)XLO!;o|*GNmyTgOvqAoWX4B1pEh zAw)|c+P}~6L`p4Zn!__V6TIq)_Cn?ln0F2(ovhwmaOI?9Jq;t*Cl4)BGX^-Wd&a!a`svxS}&y zp7P=RL^n*VrWR!JoD=+?E-E1E`XqZ{$PYnX(m^*3EI!Ii1q3GM&Vz{YbkH$ zR5~JDg!n~Nk}oj^!2~q16eVPPXys%{#n=o@drS?&gp=l{a*taC%=8 z|JP?9gVQ~5(l6!7QrOaHF$Gz%#n08-7L@dd^Hs$Yn_b}=i)jt#(>oRui3=9X@ z<_t3Nrb$}P=9lKXun|UzEU7gEMPw)ey>dV>(Pq(#R#YZET{QUW=wBRGuA$wzmw-LU z>=X!>oEA}Go1EtE5x?jAO@*&?Vng>WB0~}wHW#nI%FyURl0tf$vOFPX_$@V3#M1L6>mxDz$36^it zE=tEi5k&_P{-FEv%C4A+(EF28i+X$|thNhw{NCXSGQHvaRG2`as@=wGioi6(Xh%3I z3EXOc;ULLuTTPPD>g&m#@-=oZV$!9m@^%K_4wC}?t*$3)N0TSZS{os>0wFGgTb?Bh z(7Ol9GJX&VGk>T~T-sd`_{T@(G^G*;xe^Ip7&*3N3u|Bj54rhQ_v;BXA!_zacnIDH zRD}opcqrnLGU!Gh)k?dl4Tjmtw*|2A*NsjoiW78zC@_uM0!P_K^{kQc;|GK$_&y=lE`4qU(CWqns)*q|Vf<}?2CH3$TMyu&<)?5@NkOs_hYf^R%`GDo)tQJeL&PFihIO>tOmMp`c`{K#m7#z&GBY z9n&Ui4@^#n>mTpxxfzB|I)Lr%Ml| zIm#_|7dspZ>ou1y7l?-t{=t{cJA&j9YHx_oSn*(Iu|Ff7%QU{DV3>c&8>-1H-v77o z3h5D2qT6cSPLk_9xp0%86!MTG*t+n#lU$8Hgb!oP4Yu{NrE#%+8^r)tdcd>ArAe!Quz1yT3Y?3+MR}D3(U=Gk!y+QcV#YfLkGC5FI#v?6{cHIFiX!MQ zO#+LQzZqKiRc@H3K!&02!0x4K_ae8aK7^O@4cXCz-d)z2Vuz`X2v+|4B|x8oR=6Tq z`JAGNh-0hip6ihXjzn|+Z9c0Y!b&NuPSM4Hb8zkcuI*)UBxy%n0nGq5Vr~0+c%5kM zI6?asBBDcP`kNa7LO-rx&TS$*KrN4(9yKk zjWc@C{aeQ}L`sWbDbNMGQ!L32o*rv;NxfSsH1GZUZHIiT$7>d)JHy@DvNP7G(G?rl z0$u+YHUzzKL3T1lWryB;s8^rIXhTw7(L+zC@Lvk%pS)~;azZ$!q|qzY#@KoDg$`7m$!s{KE6FM+(v+hF1dnj%Fvzi`h^VG5(w(y7_PqFIFb3 zr)C8n^40qM0}+YB0r4S6%tgRK{nW?JY497H&NsSJ2^T1fx0BA&sdrEVN;nPgarbh@ zog!l<9%_+D9OojULy@AnVL12Lf1+_xJL!U8gY08a-i^V*dLE3sLNgLIQMK*c3GDy8 zcN{xUN)1^d1C{WNnj-?+W>4gF|p~A!@!6a^UL@bT~$PsB($lxK!OF)YzcX9aUJf)Q1wpGf@cXa0< zyQmWhox`{D9|}D8Gb79;sR^23loqyJfN+CjrFaf21qhAy@$IGWJDmv8aCjvjZJd_0 zVX_ZAovcAhh1&>&3tEl6qnri`K z6BkgHxk+p$ux7eP{uKf}@09ceMeGpP$cwieEulUlZ1k)M8y|6>>%Y^w6Z26xZ0mCH zEC!B4LzZUv&5HmsJJ_(=a6Wx?gRj?t)E3Ej;WT-&O=Tt-b`oBHYpl}P%Rak=CdVeN zErd+&yh119IRDuqmZ|x9UH@{4Lu!fMSqW3*heGC#v>iN9 zg^V;;I;@34>37z;gfHAn9uUJ=g=KJMSY9cb!6uX$M~7jo?0)foM&K!1l5>OhI9pOr zM7rL%!E1G}9ltPPVsnX$)NYMd-MACYGC5QGz$RC`=T47!v3a*u+d;`kqa&udE_q>Gu)d#3Ci3V zh$!W*_MFz*$<{x~m1Zc|W#(lO{lY=jaDYm^oxq|^Bk9PWaAPRv@2C1E*ni4t>HNsj z&}J5oSdldknrc;TT?s!cYa>#}pT}RAn7dxz{Ilw$1}^{%YZqFj5pM0z=X?GyTb?nsf;mPr2EjSfIBUeYYkG}mFu;QMGPf0%+wAs^Bf{?7 z5(rGFu2)v>TS=xK2+|rIv6POdZCSDrECUeihq;-i)yIYWux%>u#+UcfhRymOcw!Wm zJY_Z^kW4;D0Hi3^!Z<=r8t|A44Ff_UMbw{d)R6C>EN z$IvEZWn6k!yT?E~MwLjK`K4MqMnAQ{tlZRrUPkVpC=ND^wAk5=n+U9E%@gPufuwQC z14tEP))ZU#<}FTzos})h;|!+$@iBaYQI1_JSl=1E{d3r?j{iIwpGXMQKD(NS1-^jS zC3M=|gBMi&MmHC;DiHV@)!8a_Sx?h_WRwHjLo9lrq*n||`TA=HbyYrL;MVb!nG}ev zxV+^AH)8)(^@-anHM!ptVI%zcN*?0$q?FkI@PU+D;@d|FGPoVad_V^>UfYLTmxr*; zNN(OE1wcH4i-+~&__hel!^WUwnL%O5uairU$Np#ha|h#@ir)C%Yr61sV<^RF)55vP z4|u4RR4(M=iX?sU04;gzkLC9SRdS4Zt1rFb79a#x6yuIVo`4k{TRC5uZ`eu3fE(svj-dh zn=#2HLs}+RbdEy^Trzh&CZ&txp6N_H)}aK%S8ecDNLP#0CB%j$i@Pf6%VSg5-Wo1Q zUdUr0X+GTQzqkQYAL~|7DvUPwSL@}p^OdN3Fak{|)*&Hm@&}Z($$OJGwo}yR0+~p7 z2rIKMp`+PS5uA1}qKVlT4+BysJ%aRWYph|=d7QeVSMz3`Z}>7VK5 z`TF+ZH%aI{c4n-T5XTx)W*?Sca33ym99s!i1O+MV>^-l?r`17e+G4yo1$Q+>XftQj z*vXgQz$xhqar+2-@wc#v%{a-j#9@#~j2qDF4{4vfR<9en*xKvc-u`et^*O5wcyF4s z7hMw)oj3>3oSh9MGDUojTYG#MBP>$K5K&Oyb`7;Y6#m9<^BDTZJ>T?+E9SA1{t~G< zh0nq;pY!Q#ss8|r*9w(+Ul-f{Nx~!o-lr#V0O*9}j!#EO@$i>(PIXu7tyJX$!)_k$ z1M_F|#8^o3dVXTUFojnvN4Dc^P4^!3eCwB&wC3~77WPSNhD4s&_@i4IY2xHeTvqim z0PxT!JNo;$#{>vNM%63@%MnIR7DTNmHiY>fi|XKW2a1l2&gjY8fAeIxu8H+XK~chm zE$ca!obd*JlN`x#22uC`zlka6GzYJlW=~jHm$@UY8_xZ9&j8~Qat7U0NMk%beJk-}|3nJ89Tck1p$de0&zxqgYF|jUS zj4Q~TWkeBnbz?%#0mvE3Pe|Zjxy@T-03}|K7t5Q;9yfnl4 z%D5UUWG=US(h))XLBOddTT?hB66+!5X9UsRz~y2UY`ZD-JOUfMkKljEPdE_z<5EJD z__}j_3}uMFNX%VL*rjV#CA{3ZSBof2t1V5+aP7cOu~T_fO*T2q`ris@dB0kZ)>xG0 zppXokp~hr)O=Zh(U8mq+&Q&4ql_>y%|~V-A^FP&7z7 zMYC3WBJvQ_PD|@Hqq(#w2JRH_0ya*{e>G%$5lY^A-POd!!;p&80t6m(0iQM~NK9}( z=7_M`xpr>j7|r}&+hF-to9pz*sz7eXGkkY3 z=wzEt#-HAthLxoG%!7v}0qGhts=q)j8?0h-*ts%o_yW$mC!cpP4TQXX{&)H2zh24NOX&V0>n{iS_VW5KO$voTE*(#acq0}M z6+j=|@9Z`XKbm{<9ROchFB&4wAHodoY-_T^U|ee-P5O#2*s6D%s)UQ`v)|ViqziR@ zJ5Q?8j`~D#hMqffk#Beq>0@GBYKl;}n0yxxdV=fr0(4DqWSo&EnJQbPqofNea>#m+ zQtY|OF@^u`gIFyN%WVSPjv+cR$grLAW-s~MXAxH#9Y-qm@V;AxpF6sLG(natmOXlS zhXB|xFR$ih34)Q!R>T!#p9H!LInraaLsg71HJ$?fZs!jn6p~uMGo6XpLIK-=^JZ1` z!Zp~xX?0Bu1x?{}-})7gVy-jF^F#ouS*y1CxT0H|0Uy!l(Ia3$AGm`|%QT2Dii9zN zmz8Ybw)#r=`z@jH+TX27GSR@qCy%^vFqF?`l4k%`hP{zXTgE?~N`ij;B(f4~*BkC? zI?l+slsGnNT})nny?F5bzGW$!aF}ym_rYYI!6ZXITD>>Km$adYm^mP^h&oP102yxQ zcC6?cL>~+PlRCZ2J)k~!23A`+aFr($I*Ja6^)+XaLU<;uMlM=@6XBhrs*iycDt(-o zp9LKccAXV7Tqc;t?2wf!!ZD+9EkTF){+AUi$qptuvheNOY%Qw#SNN-t#e5#q8dj^L z@~Q(}+O%$%s2m@A4}7jym{4?#r{o&p1QC0s7x{m8DOYWaCeU~2D^*5 z5p7OTd#K2+fL=;8t|F+Li!5?d`e+YiW=(hZpPc@(L23N^pw!W9O2ASp%OTZQ)BJ#l zuv|eoNCnuDUlY$+|NZJ<GWenknWb1mMY{oR_;myW)RZJ8eB2^_-zSKWk^b$y=!Hq8L0vcXBdC;4Ocv ze4KzC0rbYxH-uFGpg)X+6M3yLOf}M^Lvv6T%1o;#SBT_N8^DHUcTKjH|5w^MFjU%o zZ9JcByP52oY}-89wl#UOU6ZXdb#jwklWp6^#QFEUU*Ww!!M?HAeXX^A>)LRsureo+ zg(K%&j=%N=4N~o!p+u=o4MCn^C(dQ_7-wzt zX+e(x&f#pPmUb!_^dOMr;Y`Imp?be?dx|MhvsOB(CZ8p8vk=MFg<4>S<0(~2dKXHWM|FSar$5*!LZvLZ% zwHMa=`&XL&-?8L1YUK9u#>Q;H%qO!DNJ!Fmf$Suhrx&OcU@4T(fXf0>%!9*@&Tvzz zz`Q(J|B(-_4DYEDKe&B1P}=5D)0+(1Ov4W4G?)GQo%IBfe^n`)kHFQ`b2efRP$p^t zTM!%fL%5|M@#MV(H-3bF42mI-KhJI8w+R%(H!MQ+EBa7}spQvRq+o^lHGIf) zCaF0ykf7(dbww-w1Y~t8)Y+^FA}O~jLq>4`K9cxr<7@}_I!S5~l#W(^QfF?JLE;yJ z%w;^<0s+ut5o25k%hnY#i^36H+p;fACN2=6M?z@JIoRXET18zg$v>K8JF$V3G5%5u z`iznccr3K^6cOD+C>%hnVGyr*fvRSF;8d3Af(5H#8|Kds2lq5fI$XywD!;hFB4FKp z(w+bbPMdiS6d||``fS8bL3IR7!)|6ylzy?-S&IC8fM3&(2T|~V*7`D$JugEX;QMH( zhu|=_K>xrBPz0wZvWDrJ3D=HNXJ4Zxw$!BuRBAx3;<>V!iMP?O2r7#y2OSh~aau4} zKqq2>KwK_C4`rt$#l9|$$O%$#lfLE}t$9&vW)&wGN}rt&6+EuNb_P9WdAD#3+mVh} zMvp%MN9__tn>hRH*YEoTtkyL9By9AtJ@tOy>TgIN`or4%t_U5(6aWEWj6V~ER3ynV&6?i?OFI&n&J3~N&WYsw^V)L zzmMcC*7}mPls%Y8!RA~NzELF$zILQkX~8pOx{VW#3@_e30~=ZQsTqSic}6D>gpZq znFeJM(E!>95n8bGMede#@PPrh%t_pg+y)1()WeeJ^&pg*9;Dr2=u>Yg$SghB1IQ5m zP+tO}WusQ5V@ztgLwTkovQBqV&#l2U>(>jO=yS*$|mHD z9^>DUQrvJl#z;)@PK3rm0&y6#ch_JQAWL*R9qg@ILeVlZHzRUjf-GL`}9a z3Yru2A7m?VfljY*0sl_EEw?)2*uR~I@=IK8HNBW@06D9)fcVT~y~R*@mLc>#=+D12|9Yr*VY_l{B6=O-w0S966!B@!`9XATFmVV@W!J#Z%9&qbJ4oD}q}#69i#jOTda_ixIrr8hRr%^YFkn~ z+{NCMdSDYVJ4$9w{_={$dC}lNwG@XTG8a_#iGK{r!gj_;X8J0a~|@m*w8 zGGb?lE_Qa5WKT)mBnrNeF3R9f~b-D5z+wENG6lPc*H`gE+iZJw+jba^-|^ zO$dOP^9M}AP;Mc@~{Lddh7Lrh&{q=lybeF8T7DC&!Em47HU;%Il>HT zM-z4Wf^qg=(kFsp!*<4&O;C?MFi}CyPJiDwFwU8Ei=~?FSc-8!jEug&QFH%1mP4mi z{=4+G;ywn-rH;>S;>D$$b|j_x4_i5T-F~5_u^^p@_GR-7h9JQ!p|T@&$xC~G4c{}K zHqTu-)?a>4D}D=jgL3b$-QBwu#&XFVn>fDYqs0M5L2?@tce{^K9ilYASF15oi}jr4 z`W=5%AS}kcp|1=+IG*QQ3z{73kC5Nq=8<towb2cj{K|zK(km`(|6Qi?PqP3sq@~ zXm-0r*+LHN>wUj}47y`T3RK#jsTw6>)^3(f#;hx>t@8aDk55$e7|F?r9hqNh8vWS^AgaBV@La_kXw9B#Wk8bwjT~%IChfb+g2fT4aUfmOq%Iz$mVNSP9flYALN0cKv>e+K*A zN&JxRz)%Kqwy5pP0UCn8ot?2$%Z<$BVPJyfepLh3jprdQ`=zwkwA9_)AI{f5`%(l| zgZCxKbOdTr!A+I{!lc;F)1kkM6u#qs{GFgb?WD2m@BJ1Se3Rwh)b5$t82>MTgTn^o zZvd~ZSEi-%A3GCUv9Vrrx)ONudX0T(0^6ov!F$d(f7oNnOnfX!&tCugGWP>&$igL* zbQEf%*GI!ou}I~3T!<|!LM>+Uhgr{t|zi1Uwk?*7_M zJC}_2%`z4`M^>Q+zQ+1i|o@xMt<9Vm$ncv9V1_HAsob%N;FC>45 z8Zki-=rnXv@KY4?ygJdSP*Ry4@VL4Dgf;fDEt_2zI)qH{_E=zqI=3~xt8BWr!3G~$ zkwo;?uhZMg9B* zU{oe8@$Q#8S=tPcJG0%>0{sdO`|~GkN(hy^)OCv>i%~!O`;u%(w0r)jX&^Hq8IONZ>t<%`YWDa*O!(~&{!YQ_ z%?Rjayau8om>0GW9)i_~=!AabR?&i!4O;}*;o#!E2PbM*);=Y5O)Ws8`;=ibES=igz-faf3~tC^au ziO|XGA5Pk&GIeoDzpnBN`@?%{j24}DSn|FOR8Bz!mkR8*$*~)Yy6lTJ+X}cbJ%BpG zP^e0)kewqONq*W9#;*`+(Yo&l|Jy<&_ZE5Bg`5MZU(N6PhzF%=7GUn$L}A@#;dI`3 z2C}YK6)EV;FFVB{0W@(gm&88fRF?M$tN2-6NDiWwY42RVF-8y84 zkM)rh%7EP#m6!ih(f<6_{)!>_o%}Z;vci5bR5|UQQXw8FZ_7ws!1j#Zpb0#-Pg9-l z;vYlnp4R)}MO#4`lB&6x3ZGbI*J`z6#d?1gU^KZ!GVqqh%M!lfk|!*^08)kp$w!F# zn1)*~p^ib0KJke?#ZUZ#vhhDjgLQ)#RsS6|<$ZpfSX{s<24#SzN#=a=l>nT2LbN&q z^oKTvv|RtPu*`S|R!dmqyROWoM$M@D$IIMIm-1cY&*Hd*3kk(lWX^ooScyjnZDCA3lgRlo1>27 z)EiPe$1eJuf!uNRWc7p0JiiJuN@Els<&z-@O&dw90;p7a_`G_9=Xi@FHq%O1vTB%> z(6Qd|YNIHKQ0v<*clFzeUUQL08Ntt`*iYk$6yiI}fx@mRXe?x~)c0(kOR)pff^ju2 zAFMxHRnwVn?Sh5u5ki_>vykaYQKP=0@=kDV;{Pt0IHSBOgTj5OP->22Hwt>_6ixEX&UxNo z2f0hxnhd^nytdih0-GJ<3afEySzrdkWIUI|eN6fAuM9L265GsN)!JC=Ve0sxq!hLh zR2Bl`S$$QANU>Kxr!71Ub}t_vnT&$!X;raMlik`+6dBLS!RRI)ufYk@*SZwNM>LXi z5O0iSN{>N5`+$?h;~$3Tpv-=dBmEP3U5KD4a$Mu<&m7*&|x+evT6nyb( z=O;`#Hl7F*8H<-p!YVX&N6!FD`)em%^=E4#f)7fL(WxpvXcnh%bHNG;?%H@kriTt$ zpeQ-xyG(XBy(}#Ci9foU1RXvwm>Imw_6ZQj%9OM!vl_J=<__w25`=dlIL%E>&Frq4 z1mkSy#DEgxHTa~kT_R+6WR3gE^kC9zlAB{Am@j@?2B;-?{(DMzfUu}MpN2nB-SS&c zX?vw8MS;!T86o69p06Q5L-bx=(Wk+<=Mq@A$y7%#|0eU5GI)*nULK#x0y7 z)SdNf$Bi~wTwK?$J-A{hZI9Xsq3rI>6Uj&3)3^zYiR5?>J1P~t_7d)F^E!aAkw1M~ zI+f7W8rk_&z}2O36^!vh;>CcAp+F^Pk6{U(#vxL}?_jh>$Cde>_Ihko(}u1kqrBQG zX*I2e~&^{uY1=iz}vweto_Ak3LcjTq-MTBPk%Qx{5fv3rtzqGQ4=jh1LEI%{h*$* zd{h-(PNBc8zxKGd2;I9~AWV90eAkmd51uKN8dLH6|5G-`y5+Q$mhGb7ksA39>Cn^<(*Evrh&O7oqmUrz8#-iMHPE_C*A zUoM(nJRN)4lA&+-gjrqMsMsB_sUmH3odeF-gX{fAhJ~L=MOc%f80k-Z`WpQ<_*6-R zRY*|S%x3``i>W;Fcat4IjaW5qU%S+N`L*D`h6guKb}l5)NSLK@X-YTWIMkW)U#E@> zKjW-#wD1O>ex3Jm0w#niaIO&y?YSoDRkTV~4XUR|yXPDjj{0#H(m`w(cM}m|O$vEt zUAA}Z0m@&owcgBtvC1k6Rl9uyG=h#&$B1VkDlbMEn*2LfQT+4X@4sZt$<~{a9A6q=J1AI8$esdf!)N_^#HXc@!*B|pW5CS$X-Cg3eq0KbdpsCTSKp(e_X%FDsl+1rRg$>x@v_+`k8dX8_43JUBn9eDjy;u^Jtt{aOar2oV>s50ZL_;0X0Lz(0#8ls;R4_56Hb?m*aJumoG zRa~ke7-znqPwhEf?#` z8Si*L{0Z9nZIGXuAh}Vdb#@z%z*-f^pvXhJAeL&;DV5+E6hk0d)jw&Qu;-7|ZZUK# zVEGXbW%rTlC~zfL1qX@m@n8MMp_3r5MR1oI9;guXtx{-PKwg(Vi_K#7C^za$WnziH zH6~CF>*c99X}a3YjqBO|%x1c+@5^khuz$8*;?W0e!v?lphd_X}T^^*gA#{R1TVfUc2@Lgr(}vM+|-1Mdo)0Xu}@E7|#lo8qP_W^ziL| zKUfToY9>3eh!eFrXLEJLW9{9FEz90@E)Hiq?IN%~RzxXNUx?X*K-; zPs2X`BAq;}V|Aj@9M=5w8A_ST2N@34I!^sdslf;o^`R4Ox1Dc~eqPM;(tx+aF7=Ik zef1F;{X@bC0=tJI1j;#oL_?iL4)E05kCz5f6+{9K_Zk0#{&AB6Zu&&5*CUA(C@g@- zpF>dPE+H)8VNqA`Yws9eawYxjy0MUtCl^d**|JsBANmYcTqyWGq9tv3@Sn;Cb5awt z^{li}HZvDu@K8;E$6#OKk!_NJydhHuZ>mloJ2{9sv^HwKJ_Ngt8<9BcQZmKC;JdwS z)s+a8hDQa4g^VmPe$II10heE9rVAC-AEUll7!Gf4lA@l!kwW;H=awl?Lzt+GGKxlf z=~GO@TKah|+H1@Ee;Z|Ixv$aBArW<9)<**EQmW)-R^Ia1erAUo%SYB=ep*dwL;iME zXXhhd%{psLR-G*%Od2ZKaf#TyIVD{R>Rf95bwb8O12g503BU*mR;zZ;M{13?rSS*y ze1~BS_>i4^7-o~|MVlv3fs4uVbr5DIsF3ZD&uU4bvRCYAvQJXtk#X8(pgHz%|Akd> z@AUZhie#C#IBD{-pp-h~fyxODuQe5?01;rOv2YPD1vz*Y)a&ze2M0isEhqmqSc>^G zRm?!6Pb)?nNL3GZ+sy#5Uw(6M)O zp@8`8EtXVxQSH8-G&eDt+~)72EZvGX?ihBd@F^V{~r zd{hkZYhiI~qKei3tH*EjGOP{Xc>?NkM580Pnv-?j&h5z&)42bToUh zjG>pCtyS?OPyH4|-h>6#uwR-1o7WT>-~o!S2AqUx&j&4=-T$rZJxZol1f8`})TF%CMvuNHdY7)Cmc};@kRhaXIaUV8?Ct z`rHz6E!E?V+&=M|bJRaAzVFo&5q@Ht^?qLz@JGYK)S6I}EDT%uGo8gWV@lw(#;e1h zt93t%N7=6=CS`V3q~H?TE77ab4GXB$d^Am}wc?;Cqe9qpI+5yLqU{`Ax9Pf_E7Vh> zKO3{@*gtBhes6`cFKe@cRDe|7|HZr-&ZT0Rs<7y&VU~{;DExJdHf-zO6iie)0~6A- zK|q@wZpC+nauXYvh5tNO`rgo)z+l1an}~7o(b09S&BeNNpH(To_E5Fh+xp_5^*&TN zO`jAiFBd>NYzJDi*DFQ2=6ImeEQlF>Yyw%~qe(b7mMqy{#%_t!P|7pB08E?-6rR?gTWt=YpQt7G zCQr$#c*fn__ZN#%(p(8U9=;ioy`Fk<{?svj9>ANUnU3r`l_f2hQRN=)V1Pyf>=`$e zS;yYeGw!E`y6qdayfcNhxU7!J>2Aaxc!5Jhefv zV10}`)j2@1Wl>WKJ6>sVAb~k)*{$#I<#!pSWyv)=Iw7WmZS9;ObvL-dmEy zK^dt{*d+Nr#tGf@E_C*Kf70mIrmRKVa|e_RT?Spf-}EysT;TTh*|5Qe$;8hytf)Nc zKv&#=-f3B!B0{Z?kSvwMyHkoU!k$$DxfjurgMY`36-m+#h6EFxqywcU)tgWkaB0;% zON^8^zKT6q(f42}3l!=ypFJ$C_OJZyJpa=#6?EW%Wgyd~Yv)X_MLWEDR>3P6`7Qfr z5H8s64%2t*S9@qwf@AG&i3){_;qE?n{?yMP!?IYu;tsIv)_q!MYpR=Q)C+S$2 z!+8!|khD{k9gYDHUu>DnZ+%4gGz0AS5(aK{NeetZx(bF)>=p!YY z^04oBUeCCC*$xL(1na7r(N>JZ7(Ip*em1>*qr)KcSw32=V4aR@eww3r(ml`76FHN_i1^A}NrsD^@~ZO>x$L~Aas zskY`VXuoKHWmeS63>UT2NyIrj7&$fzL_}q~OtBiEp-Gh6_-;5*vkb^=1@wXmm|2`u z^7*-$3JoJlNfG8Cy_b0@dmKW-xa!{3KR@mB^&N+`JZ`t-(xbFe*{z+z>k%`aM+ygB zDe!h}O`A9TZD(u#{tr517G0kh4W-T1LP*7Tnyie{@SEM6*w%O9X)wCgw0~|OX@6M9 z&=o(_HfP|$wOy0#f`$>eG%L6Wj@gV?eDRYZPZSp?HXMn+o=o^)Z4LFmdaTl{_I=

n)d3@oZpYFsmbJyGIDGW; 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 R3jP~ZQC3Z+PRcy&{{SdSemwvH diff --git a/openpype/resources/app_icons/nukestudio.png b/openpype/resources/app_icons/nukestudio.png index 99c95f59ff858d67fb92263f594f4b71bda87a66..601d4a591d7fd21a0c9c6a1850e569ca05e523ef 100644 GIT binary patch literal 101945 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 literal 46080 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 HIsgA3TR*cj diff --git a/openpype/resources/app_icons/nukex.png b/openpype/resources/app_icons/nukex.png index 1c5a83c8ab2e22da3e6afe8a9561441c4e0e4022..980f150124faae3715eb4d0018d3368f1091a60f 100644 GIT binary patch literal 99787 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≶y*UWJeRW_RcYBCht7M?Kk$4b?RkwBCiuA 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 a`-EZgF*J|OX($H!`pHTvNz{oM2mc>0LFUT< literal 44709 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

=26e?*z3RuFR6Ga0 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 CH}}2( literal 0 HcmV?d00001 From 2487c1f1cd8e759977d1ced49e4ed78a91d4dace Mon Sep 17 00:00:00 2001 From: pberto Date: Fri, 13 May 2022 13:28:35 +0900 Subject: [PATCH 141/350] cosmetics: removed two trailing whitespaces --- .../hosts/maya/plugins/publish/extract_multiverse_usd_comp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py index c686b2a600..0e5074f127 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py @@ -122,12 +122,12 @@ class ExtractMultiverseUsdComposition(openpype.api.Extractor): comp_write_opts = multiverse.CompositionWriteOptions() - """ + """ OP tells MV to write to a staging directory, and then moves the file to it's final publish directory. By default, MV write relative paths, but these paths will break when the referencing file moves. This option forces writes to absolute paths, which is ok within OP - because all published assets have static paths, and MV can only + because all published assets have static paths, and MV can only reference published assets. When a proper UsdAssetResolver is used, this won't be needed. """ From ababf4053e8de157b9edcc9227d662e476f3e497 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 13 May 2022 11:24:36 +0200 Subject: [PATCH 142/350] flame: splitting function into smaller parts --- .../publish/extract_subset_resources.py | 80 +++++++++---------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index 0e04336211..9ad3b21687 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -60,12 +60,7 @@ class ExtractSubsetResources(openpype.api.Extractor): export_presets_mapping = {} def process(self, instance): - if ( - self.keep_original_representation - and "representations" not in instance.data - or not self.keep_original_representation - ): - instance.data["representations"] = [] + self._make_representation_data(instance) # flame objects segment = instance.data["item"] @@ -92,7 +87,6 @@ class ExtractSubsetResources(openpype.api.Extractor): handles = max(handle_start, handle_end) # get media source range with handles - source_end_handles = instance.data["sourceEndH"] source_start_handles = instance.data["sourceStartH"] source_end_handles = instance.data["sourceEndH"] @@ -109,27 +103,7 @@ class ExtractSubsetResources(openpype.api.Extractor): for unique_name, preset_config in export_presets.items(): modify_xml_data = {} - # get activating attributes - activated_preset = preset_config["active"] - filter_path_regex = preset_config.get("filter_path_regex") - - self.log.info( - "Preset `{}` is active `{}` with filter `{}`".format( - unique_name, activated_preset, filter_path_regex - ) - ) - self.log.debug( - "__ clip_path: `{}`".format(clip_path)) - - # skip if not activated presete - if not activated_preset: - continue - - # exclude by regex filter if any - if ( - filter_path_regex - and not re.search(filter_path_regex, clip_path) - ): + if self._should_skip(preset_config, clip_path, unique_name): continue # get all presets attributes @@ -147,18 +121,10 @@ class ExtractSubsetResources(openpype.api.Extractor): ) ) - # get attribures related loading in integrate_batch_group - load_to_batch_group = preset_config.get( - "load_to_batch_group") - batch_group_loader_name = preset_config.get( - "batch_group_loader_name") - - # convert to None if empty string - if batch_group_loader_name == "": - batch_group_loader_name = None - # get frame range with handles for representation range frame_start_handle = frame_start - handle_start + + # calculate duration with handles source_duration_handles = ( source_end_handles - source_start_handles) @@ -272,8 +238,10 @@ class ExtractSubsetResources(openpype.api.Extractor): "data": { "colorspace": color_out }, - "load_to_batch_group": load_to_batch_group, - "batch_group_loader_name": batch_group_loader_name + "load_to_batch_group": preset_config.get( + "load_to_batch_group"), + "batch_group_loader_name": preset_config.get( + "batch_group_loader_name") or None } # collect all available content of export dir @@ -328,6 +296,38 @@ class ExtractSubsetResources(openpype.api.Extractor): self.log.debug("All representations: {}".format( pformat(instance.data["representations"]))) + def _should_skip(self, preset_config, clip_path, unique_name): + # get activating attributes + activated_preset = preset_config["active"] + filter_path_regex = preset_config.get("filter_path_regex") + + self.log.info( + "Preset `{}` is active `{}` with filter `{}`".format( + unique_name, activated_preset, filter_path_regex + ) + ) + self.log.debug( + "__ clip_path: `{}`".format(clip_path)) + + # skip if not activated presete + if not activated_preset: + return True + + # exclude by regex filter if any + if ( + filter_path_regex + and not re.search(filter_path_regex, clip_path) + ): + return True + + def _make_representation_data(self, instance): + if ( + self.keep_original_representation + and "representations" not in instance.data + or not self.keep_original_representation + ): + instance.data["representations"] = [] + def _unfolds_nested_folders(self, stage_dir, files_list, ext): """Unfolds nested folders From 0ae531d4cec91870774169f51ce373bb73e7261f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 13 May 2022 11:25:29 +0200 Subject: [PATCH 143/350] flame: fixing small hickups removing frame range input form reference --- openpype/hosts/flame/otio/flame_export.py | 7 ++++--- openpype/lib/editorial.py | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/flame/otio/flame_export.py b/openpype/hosts/flame/otio/flame_export.py index 08478d4b98..ffb82b97c2 100644 --- a/openpype/hosts/flame/otio/flame_export.py +++ b/openpype/hosts/flame/otio/flame_export.py @@ -205,8 +205,9 @@ def create_otio_markers(otio_item, item): otio_item.markers.append(otio_marker) -def create_otio_reference(clip_data, duration, fps=None): +def create_otio_reference(clip_data, fps=None): metadata = _get_metadata(clip_data) + duration = int(clip_data["source_duration"]) # get file info for path and start frame frame_start = 0 @@ -307,7 +308,7 @@ def create_otio_clip(clip_data): # secondly check if any change of speed if source_duration != _clip_record_duration: - retime_speed = float(source_duration / _clip_record_duration) + retime_speed = float(source_duration) / float(_clip_record_duration) log.debug("_ retime_speed: {}".format(retime_speed)) speed *= retime_speed @@ -319,7 +320,7 @@ def create_otio_clip(clip_data): # create media reference media_reference = create_otio_reference( - clip_data, source_duration, media_fps) + clip_data, media_fps) # creatae source range source_range = create_otio_time_range( diff --git a/openpype/lib/editorial.py b/openpype/lib/editorial.py index 1ee21deedc..4979bac159 100644 --- a/openpype/lib/editorial.py +++ b/openpype/lib/editorial.py @@ -269,16 +269,16 @@ def get_media_range_with_retimes(otio_clip, handle_start, handle_end): "retime": True, "speed": time_scalar, "timewarps": time_warp_nodes, - "handleStart": handle_start, - "handleEnd": handle_end + "handleStart": round(handle_start), + "handleEnd": round(handle_end) } } returning_dict = { "mediaIn": media_in_trimmed, "mediaOut": media_out_trimmed, - "handleStart": handle_start, - "handleEnd": handle_end + "handleStart": round(handle_start), + "handleEnd": round(handle_end) } # add version data only if retime From 43aee1989c197b74ce692b64581b233371aa8003 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 13 May 2022 11:55:03 +0200 Subject: [PATCH 144/350] flame: fixing padding if it is higher then needed --- openpype/hosts/flame/api/lib.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/flame/api/lib.py b/openpype/hosts/flame/api/lib.py index f2f5db184b..6dc7d3d887 100644 --- a/openpype/hosts/flame/api/lib.py +++ b/openpype/hosts/flame/api/lib.py @@ -855,22 +855,24 @@ class MediaInfoFile(object): # add `[` in front to make sure it want capture # shot name with the same number - number_from_path = "[" + self._separate_number(feed_basename, feed_ext) + number_from_path = self._separate_number(feed_basename, feed_ext) + search_number_pattern = "[" + number_from_path # convert to multiple collections _continues_colls = collection.separate() for _coll in _continues_colls: - coll_to_text = self._format_collection(_coll) + coll_to_text = self._format_collection(_coll, len(number_from_path)) self.log.debug("__ coll_to_text: {}".format(coll_to_text)) - if number_from_path in coll_to_text: + if search_number_pattern in coll_to_text: return coll_to_text @staticmethod - def _format_collection(collection): + def _format_collection(collection, padding=None): + padding = padding or collection.padding # if no holes then return collection head = collection.format("{head}") tail = collection.format("{tail}") range_template = "[{{:0{0}d}}-{{:0{0}d}}]".format( - len(str(max(collection.indexes)))) + padding) ranges = range_template.format( min(collection.indexes), max(collection.indexes) From 30123edb55ddbda74259318c6b85e0df19da0cd8 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 13 May 2022 20:10:51 +0200 Subject: [PATCH 145/350] flame: adding xml element if it is missing and its path possible --- openpype/hosts/flame/api/render_utils.py | 41 +++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/flame/api/render_utils.py b/openpype/hosts/flame/api/render_utils.py index 473fb2f985..9957550af9 100644 --- a/openpype/hosts/flame/api/render_utils.py +++ b/openpype/hosts/flame/api/render_utils.py @@ -1,5 +1,8 @@ import os from xml.etree import ElementTree as ET +import openpype.api as openpype + +log = openpype.Logger.get_logger(__name__) def export_clip(export_path, clip, preset_path, **kwargs): @@ -143,10 +146,40 @@ def modify_preset_file(xml_path, staging_dir, data): # change xml following data keys with open(xml_path, "r") as datafile: - tree = ET.parse(datafile) + _root = ET.parse(datafile) + for key, value in data.items(): - for element in tree.findall(".//{}".format(key)): - element.text = str(value) - tree.write(temp_path) + try: + if "/" in key: + if not key.startswith("./"): + key = ".//" + key + + split_key_path = key.split("/") + element_key = split_key_path[-1] + parent_obj_path = "/".join(split_key_path[:-1]) + + parent_obj = _root.find(parent_obj_path) + element_obj = parent_obj.find(element_key) + if not element_obj: + append_element(parent_obj, element_key, value) + else: + finds = _root.findall(".//{}".format(key)) + if not finds: + raise AttributeError + for element in finds: + element.text = str(value) + except AttributeError: + log.warning( + "Cannot create attribute: {}: {}. Skipping".format( + key, value + )) + _root.write(temp_path) return temp_path + + +def append_element(root_element_obj, key, value): + new_element_obj = ET.Element(key) + log.debug("__ new_element_obj: {}".format(new_element_obj)) + new_element_obj.text = str(value) + root_element_obj.insert(0, new_element_obj) From 851df8155f43d4fd6639ee71ab3a3f023e06c7a5 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 13 May 2022 20:11:20 +0200 Subject: [PATCH 146/350] flame: treat thumbnail as poster frame --- .../publish/extract_subset_resources.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index 9ad3b21687..eea575ea88 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -168,10 +168,6 @@ class ExtractSubsetResources(openpype.api.Extractor): # add any xml overrides collected form segment.comment modify_xml_data.update(instance.data["xml_overrides"]) - self.log.debug("__ modify_xml_data: {}".format(pformat( - modify_xml_data - ))) - export_kwargs = {} # validate xml preset file is filled if preset_file == "": @@ -198,11 +194,13 @@ class ExtractSubsetResources(openpype.api.Extractor): preset_dir, preset_file )) - preset_path = opfapi.modify_preset_file( - preset_orig_xml_path, staging_dir, modify_xml_data) - # define kwargs based on preset type if "thumbnail" in unique_name: + modify_xml_data.update({ + "video/posterFrame": True, + "video/useFrameAsPoster": 1, + "namePattern": "__thumbnail" + }) thumb_frame_number = int(in_mark + ( source_duration_handles / 2)) @@ -218,6 +216,12 @@ class ExtractSubsetResources(openpype.api.Extractor): "out_mark": out_mark }) + self.log.debug("__ modify_xml_data: {}".format( + pformat(modify_xml_data) + )) + preset_path = opfapi.modify_preset_file( + preset_orig_xml_path, staging_dir, modify_xml_data) + # get and make export dir paths export_dir_path = str(os.path.join( staging_dir, unique_name From d7454044c92f54392b3c8108a466bb6a5758b830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Marinov?= Date: Fri, 13 May 2022 21:02:44 +0200 Subject: [PATCH 147/350] Nuke: add pointcache and animation to loader --- openpype/hosts/nuke/plugins/load/load_model.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/plugins/load/load_model.py b/openpype/hosts/nuke/plugins/load/load_model.py index 9788bb25d2..89b58585ef 100644 --- a/openpype/hosts/nuke/plugins/load/load_model.py +++ b/openpype/hosts/nuke/plugins/load/load_model.py @@ -15,13 +15,13 @@ from openpype.hosts.nuke.api import ( class AlembicModelLoader(load.LoaderPlugin): """ - This will load alembic model into script. + This will load alembic model or anim into script. """ - families = ["model"] + families = ["model","pointcache","animation"] representations = ["abc"] - label = "Load Alembic Model" + label = "Load Alembic Model or Anim" icon = "cube" color = "orange" node_color = "0x4ecd91ff" From dfb3e53743b3bc4229b1c82beb1ff0ecbffc7323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Marinov?= Date: Fri, 13 May 2022 21:07:45 +0200 Subject: [PATCH 148/350] fix missing whitespaces --- openpype/hosts/nuke/plugins/load/load_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/load/load_model.py b/openpype/hosts/nuke/plugins/load/load_model.py index 89b58585ef..8aaa7221eb 100644 --- a/openpype/hosts/nuke/plugins/load/load_model.py +++ b/openpype/hosts/nuke/plugins/load/load_model.py @@ -18,7 +18,7 @@ class AlembicModelLoader(load.LoaderPlugin): This will load alembic model or anim into script. """ - families = ["model","pointcache","animation"] + families = ["model", "pointcache", "animation"] representations = ["abc"] label = "Load Alembic Model or Anim" From 631ccf6318916d9c7ad98830dba3007c073e70db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Mon, 16 May 2022 10:24:39 +0200 Subject: [PATCH 149/350] Update openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../kitsu/plugins/publish/integrate_kitsu_review.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py index 57e0286b00..a036f5f9cc 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py @@ -25,12 +25,9 @@ class IntegrateKitsuReview(pyblish.api.InstancePlugin): return # Add review representations as preview of comment - for representation in [ - r - for r in instance.data.get("representations", []) - if "review" in r.get("tags", []) - ]: - + for representation in instance.data.get("representations", []): + if "review" not in r.get("tags", []): + continue review_path = representation.get("published_path") self.log.debug("Found review at: {}".format(review_path)) From 15aa5709ae18c3cca83e73fef9eaa557684a0a5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Mon, 16 May 2022 10:25:41 +0200 Subject: [PATCH 150/350] cleaning --- .../modules/kitsu/plugins/publish/integrate_kitsu_review.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py index a036f5f9cc..bf80095225 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_review.py @@ -26,8 +26,10 @@ class IntegrateKitsuReview(pyblish.api.InstancePlugin): # Add review representations as preview of comment for representation in instance.data.get("representations", []): - if "review" not in r.get("tags", []): + # Skip if not tagged as review + if "review" not in representation.get("tags", []): continue + review_path = representation.get("published_path") self.log.debug("Found review at: {}".format(review_path)) From 7d13de97f694ee735ffc4de63749c285c898b7e0 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 16 May 2022 11:14:02 +0200 Subject: [PATCH 151/350] Flame: add handles including to settings --- openpype/settings/defaults/project_settings/flame.json | 3 ++- .../schemas/projects_schema/schema_project_flame.json | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/flame.json b/openpype/settings/defaults/project_settings/flame.json index dd8c05d460..a7836b9c1f 100644 --- a/openpype/settings/defaults/project_settings/flame.json +++ b/openpype/settings/defaults/project_settings/flame.json @@ -16,7 +16,8 @@ "vSyncOn": false, "workfileFrameStart": 1001, "handleStart": 5, - "handleEnd": 5 + "handleEnd": 5, + "includeHandles": false } }, "publish": { diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_flame.json b/openpype/settings/entities/schemas/projects_schema/schema_project_flame.json index ace404b47a..ca62679b3d 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_flame.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_flame.json @@ -123,6 +123,11 @@ "type": "number", "key": "handleEnd", "label": "Handle end (tail)" + }, + { + "type": "boolean", + "key": "includeHandles", + "label": "Enable handles including" } ] } From 3895008eae62c2ebba2afe60b0f0320bc7604cc0 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 16 May 2022 11:26:14 +0200 Subject: [PATCH 152/350] flame: implementing handles include switch --- openpype/hosts/flame/api/plugin.py | 3 +++ openpype/version.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/flame/api/plugin.py b/openpype/hosts/flame/api/plugin.py index 11108ba49f..efbabb6a55 100644 --- a/openpype/hosts/flame/api/plugin.py +++ b/openpype/hosts/flame/api/plugin.py @@ -360,6 +360,7 @@ class PublishableClip: driving_layer_default = "" index_from_segment_default = False use_shot_name_default = False + include_handles_default = False def __init__(self, segment, **kwargs): self.rename_index = kwargs["rename_index"] @@ -493,6 +494,8 @@ class PublishableClip: "reviewTrack", {}).get("value") or self.review_track_default self.audio = self.ui_inputs.get( "audio", {}).get("value") or False + self.include_handles = self.ui_inputs.get( + "includeHandles", {}).get("value") or self.include_handles_default # build subset name from layer name if self.subset_name == "[ track name ]": diff --git a/openpype/version.py b/openpype/version.py index 662adf28ca..fe2a90bdd1 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.10.0-nightly.2" +__version__ = "3.10.0-nightly.2-upp220513-1+staging" From 5c4541ca0ae6af1561ecd2e405d840579d4264ae Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 16 May 2022 11:31:06 +0200 Subject: [PATCH 153/350] flame: implementing handles including --- openpype/hosts/flame/api/plugin.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/hosts/flame/api/plugin.py b/openpype/hosts/flame/api/plugin.py index 11108ba49f..efbabb6a55 100644 --- a/openpype/hosts/flame/api/plugin.py +++ b/openpype/hosts/flame/api/plugin.py @@ -360,6 +360,7 @@ class PublishableClip: driving_layer_default = "" index_from_segment_default = False use_shot_name_default = False + include_handles_default = False def __init__(self, segment, **kwargs): self.rename_index = kwargs["rename_index"] @@ -493,6 +494,8 @@ class PublishableClip: "reviewTrack", {}).get("value") or self.review_track_default self.audio = self.ui_inputs.get( "audio", {}).get("value") or False + self.include_handles = self.ui_inputs.get( + "includeHandles", {}).get("value") or self.include_handles_default # build subset name from layer name if self.subset_name == "[ track name ]": From 45c445d438106b1ed3d989224778884f7796974b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 16 May 2022 11:33:35 +0200 Subject: [PATCH 154/350] removing version change by excident --- openpype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/version.py b/openpype/version.py index fe2a90bdd1..662adf28ca 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.10.0-nightly.2-upp220513-1+staging" +__version__ = "3.10.0-nightly.2" From e6286166fba934945756357ee08b5d6d89f95cde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Mon, 16 May 2022 11:33:35 +0200 Subject: [PATCH 155/350] remove default intent effect on review integration --- .../modules/kitsu/plugins/publish/integrate_kitsu_note.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py index 980589365d..9e067a8ecb 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py @@ -11,11 +11,6 @@ class IntegrateKitsuNote(pyblish.api.ContextPlugin): # families = ["kitsu"] def process(self, context): - # Check if work version for user - is_work_version = bool(context.data.get("intent", {}).get("value")) - if is_work_version: - self.log.info("Work version, nothing pushed to Kitsu.") - return # Get comment text body publish_comment = context.data.get("comment") From 5e68cfad86cb3781f3acdc66f681651a11b84945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Marinov?= Date: Mon, 16 May 2022 11:43:44 +0200 Subject: [PATCH 156/350] More straightforward label --- openpype/hosts/nuke/plugins/load/load_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/load/load_model.py b/openpype/hosts/nuke/plugins/load/load_model.py index 8aaa7221eb..2f54595cb0 100644 --- a/openpype/hosts/nuke/plugins/load/load_model.py +++ b/openpype/hosts/nuke/plugins/load/load_model.py @@ -21,7 +21,7 @@ class AlembicModelLoader(load.LoaderPlugin): families = ["model", "pointcache", "animation"] representations = ["abc"] - label = "Load Alembic Model or Anim" + label = "Load Alembic" icon = "cube" color = "orange" node_color = "0x4ecd91ff" From 3b15167adb602394ad32dcdbeec7f8f0bbb242a3 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 16 May 2022 11:54:29 +0200 Subject: [PATCH 157/350] Flame: adding new attribute to ui includeHandles --- openpype/hosts/flame/plugins/create/create_shot_clip.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openpype/hosts/flame/plugins/create/create_shot_clip.py b/openpype/hosts/flame/plugins/create/create_shot_clip.py index 11c00dab42..fa239ea420 100644 --- a/openpype/hosts/flame/plugins/create/create_shot_clip.py +++ b/openpype/hosts/flame/plugins/create/create_shot_clip.py @@ -268,6 +268,14 @@ class CreateShotClip(opfapi.Creator): "target": "tag", "toolTip": "Handle at end of clip", # noqa "order": 2 + }, + "includeHandles": { + "value": False, + "type": "QCheckBox", + "label": "Include handles", + "target": "tag", + "toolTip": "By default handles are excluded", # noqa + "order": 3 } } } From 3484d57a7633af9eea4f380b270f361e19eb075d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Mon, 16 May 2022 12:29:34 +0200 Subject: [PATCH 158/350] add support for PxrTexture --- .../maya/plugins/publish/collect_look.py | 27 ++++++++++++------- .../maya/plugins/publish/extract_look.py | 6 +++-- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_look.py b/openpype/hosts/maya/plugins/publish/collect_look.py index b6a76f1e21..70265a160f 100644 --- a/openpype/hosts/maya/plugins/publish/collect_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_look.py @@ -77,9 +77,14 @@ def node_uses_image_sequence(node): node_path = get_file_node_path(node).lower() # The following tokens imply a sequence - patterns = ["", "", "", "u_v", "", "", "", + "u_v", ""] + try: + extension = cmds.getAttr('%s.useFrameExtension' % node) + except ValueError: + extension = None - return (cmds.getAttr('%s.useFrameExtension' % node) or + return (extension or any(pattern in node_path for pattern in patterns)) @@ -165,7 +170,7 @@ def get_file_node_path(node): if any(pattern in lower for pattern in patterns): return texture_pattern - if cmds.nodeType(node) == 'aiImage': + if cmds.nodeType(node) in ['aiImage', 'PxrTexture']: return cmds.getAttr('{0}.filename'.format(node)) if cmds.nodeType(node) == 'RedshiftNormalMap': return cmds.getAttr('{}.tex0'.format(node)) @@ -326,7 +331,10 @@ class CollectLook(pyblish.api.InstancePlugin): "volumeShader", "displacementShader", "aiSurfaceShader", - "aiVolumeShader"] + "aiVolumeShader", + "rman__surface", + "rman__displacement" + ] if look_sets: materials = [] @@ -376,6 +384,7 @@ class CollectLook(pyblish.api.InstancePlugin): files = cmds.ls(history, type="file", long=True) files.extend(cmds.ls(history, type="aiImage", long=True)) + files.extend(cmds.ls(history, type="PxrTexture", long=True)) files.extend(cmds.ls(history, type="RedshiftNormalMap", long=True)) self.log.info("Collected file nodes:\n{}".format(files)) @@ -510,23 +519,21 @@ class CollectLook(pyblish.api.InstancePlugin): Returns: dict """ - self.log.debug("processing: {}".format(node)) - if cmds.nodeType(node) not in ["file", "aiImage", "RedshiftNormalMap"]: + if cmds.nodeType(node) not in [ + "file", "aiImage", "RedshiftNormalMap", "PxrTexture"]: self.log.error( "Unsupported file node: {}".format(cmds.nodeType(node))) raise AssertionError("Unsupported file node") + self.log.debug(" - got {}".format(cmds.nodeType(node))) if cmds.nodeType(node) == 'file': - self.log.debug(" - file node") attribute = "{}.fileTextureName".format(node) computed_attribute = "{}.computedFileTextureNamePattern".format(node) - elif cmds.nodeType(node) == 'aiImage': - self.log.debug("aiImage node") + elif cmds.nodeType(node) in ['aiImage', 'PxrTexture']: attribute = "{}.filename".format(node) computed_attribute = attribute elif cmds.nodeType(node) == 'RedshiftNormalMap': - self.log.debug("RedshiftNormalMap node") attribute = "{}.tex0".format(node) computed_attribute = attribute diff --git a/openpype/hosts/maya/plugins/publish/extract_look.py b/openpype/hosts/maya/plugins/publish/extract_look.py index 881705b92c..81d7c31ae7 100644 --- a/openpype/hosts/maya/plugins/publish/extract_look.py +++ b/openpype/hosts/maya/plugins/publish/extract_look.py @@ -372,10 +372,12 @@ class ExtractLook(openpype.api.Extractor): if mode == COPY: transfers.append((source, destination)) - self.log.info('copying') + self.log.info('file will be copied {} -> {}'.format( + source, destination)) elif mode == HARDLINK: hardlinks.append((source, destination)) - self.log.info('hardlinking') + self.log.info('file will be hardlinked {} -> {}'.format( + source, destination)) # Store the hashes from hash to destination to include in the # database From 3ef846b1623dabfdbcb6cb464c097ec6b19bd473 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 16 May 2022 12:59:55 +0200 Subject: [PATCH 159/350] flame: fixing head and tail calculation --- .../publish/collect_timeline_instances.py | 45 ++++++++++++------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/collect_timeline_instances.py b/openpype/hosts/flame/plugins/publish/collect_timeline_instances.py index 5174f9db48..306d2da203 100644 --- a/openpype/hosts/flame/plugins/publish/collect_timeline_instances.py +++ b/openpype/hosts/flame/plugins/publish/collect_timeline_instances.py @@ -58,12 +58,16 @@ class CollectTimelineInstances(pyblish.api.ContextPlugin): clip_name = clip_data["segment_name"] self.log.debug("clip_name: {}".format(clip_name)) + # get otio clip data + otio_data = self._get_otio_clip_instance_data(clip_data) or {} + self.log.debug("__ otio_data: {}".format(pformat(otio_data))) + # get file path file_path = clip_data["fpath"] first_frame = opfapi.get_frame_from_filename(file_path) or 0 - head, tail = self._get_head_tail(clip_data, first_frame) + head, tail = self._get_head_tail(clip_data, otio_data["otioClip"]) # solve handles length marker_data["handleStart"] = min( @@ -76,6 +80,9 @@ class CollectTimelineInstances(pyblish.api.ContextPlugin): # add marker data to instance data inst_data = dict(marker_data.items()) + # add ocio_data to instance data + inst_data.update(otio_data) + asset = marker_data["asset"] subset = marker_data["subset"] @@ -105,13 +112,6 @@ class CollectTimelineInstances(pyblish.api.ContextPlugin): task["name"]: {"type": task["type"]} for task in self.add_tasks} }) - - # get otio clip data - otio_data = self._get_otio_clip_instance_data(clip_data) or {} - self.log.debug("__ otio_data: {}".format(pformat(otio_data))) - - # add to instance data - inst_data.update(otio_data) self.log.debug("__ inst_data: {}".format(pformat(inst_data))) # add resolution @@ -236,20 +236,31 @@ class CollectTimelineInstances(pyblish.api.ContextPlugin): return split_comments - def _get_head_tail(self, clip_data, first_frame): + def _get_head_tail(self, clip_data, otio_clip): # calculate head and tail with forward compatibility head = clip_data.get("segment_head") tail = clip_data.get("segment_tail") + self.log.debug("__ head: `{}`".format(head)) + self.log.debug("__ tail: `{}`".format(tail)) # HACK: it is here to serve for versions bellow 2021.1 - if not head: - head = int(clip_data["source_in"]) - int(first_frame) - if not tail: - tail = int( - clip_data["source_duration"] - ( - head + clip_data["record_duration"] - ) - ) + if not any([head, tail]): + otio_source_range = otio_clip.source_range + otio_avalable_range = otio_clip.available_range() + range_convert = openpype.lib.otio_range_to_frame_range + src_start, src_end = range_convert(otio_source_range) + av_start, av_end = range_convert(otio_avalable_range) + av_range = av_end - av_start + av_tail = av_range - src_end + + self.log.debug("__ src_start: `{}`".format(src_start)) + self.log.debug("__ src_end: `{}`".format(src_end)) + self.log.debug("__ av_range: `{}`".format(av_range)) + self.log.debug("__ av_tail: `{}`".format(av_tail)) + + head = src_start + tail = av_tail + return head, tail def _get_resolution_to_data(self, data, context): From 05cb2e4bd938ee1c533bb39625f4d3bbb7b2dad4 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Mon, 16 May 2022 13:49:39 +0200 Subject: [PATCH 160/350] waiting approval status can be set in project settings --- .../plugins/publish/integrate_kitsu_note.py | 9 ++++--- .../defaults/project_settings/kitsu.json | 5 ++++ .../projects_schema/schema_project_kitsu.json | 25 +++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py index 9e067a8ecb..876eb6bf29 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py @@ -9,6 +9,7 @@ class IntegrateKitsuNote(pyblish.api.ContextPlugin): order = pyblish.api.IntegratorOrder label = "Kitsu Note and Status" # families = ["kitsu"] + waiting_for_approval_status = "wfa" def process(self, context): @@ -20,11 +21,13 @@ class IntegrateKitsuNote(pyblish.api.ContextPlugin): self.log.debug("Comment is `{}`".format(publish_comment)) # Get Waiting for Approval status - kitsu_status = gazu.task.get_task_status_by_short_name("wfa") + kitsu_status = gazu.task.get_task_status_by_short_name( + self.waiting_for_approval_status + ) if not kitsu_status: self.log.info( - "Cannot find 'Waiting For Approval' status." - "The status will not be changed" + "Cannot find {} status. The status will not be " + "changed!".format(self.waiting_for_approval_status) ) kitsu_status = context.data["kitsu_task"].get("task_status") self.log.debug("Kitsu status: {}".format(kitsu_status)) diff --git a/openpype/settings/defaults/project_settings/kitsu.json b/openpype/settings/defaults/project_settings/kitsu.json index a37146e1d2..2f1566d89a 100644 --- a/openpype/settings/defaults/project_settings/kitsu.json +++ b/openpype/settings/defaults/project_settings/kitsu.json @@ -7,5 +7,10 @@ "episode": "E##", "sequence": "SQ##", "shot": "SH##" + }, + "publish": { + "IntegrateKitsuNote": { + "waiting_for_approval_status": "wfa" + } } } \ No newline at end of file diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json b/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json index 8d71d0ecd6..cffd7ff578 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json @@ -43,6 +43,31 @@ "label": "Shot:" } ] + }, + { + "type": "dict", + "collapsible": true, + "key": "publish", + "label": "Publish plugins", + "children": [ + { + "type": "label", + "label": "Integrator" + }, + { + "type": "dict", + "collapsible": true, + "key": "IntegrateKitsuNote", + "label": "Integrate Kitsu Note", + "children": [ + { + "type": "text", + "key": "waiting_for_approval_status", + "label": "Waiting for Aproval Status:" + } + ] + } + ] } ] } From 0699906344a8399eeb0f7c10c6b61963ce3eb3e2 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 16 May 2022 15:20:57 +0200 Subject: [PATCH 161/350] Flame: implementing handles inclusion to publishing --- .../plugins/publish/collect_timeline_instances.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/openpype/hosts/flame/plugins/publish/collect_timeline_instances.py b/openpype/hosts/flame/plugins/publish/collect_timeline_instances.py index 306d2da203..4bca0dcf93 100644 --- a/openpype/hosts/flame/plugins/publish/collect_timeline_instances.py +++ b/openpype/hosts/flame/plugins/publish/collect_timeline_instances.py @@ -36,6 +36,7 @@ class CollectTimelineInstances(pyblish.api.ContextPlugin): for segment in selected_segments: # get openpype tag data marker_data = opfapi.get_segment_data_marker(segment) + self.log.debug("__ marker_data: {}".format( pformat(marker_data))) @@ -75,6 +76,8 @@ class CollectTimelineInstances(pyblish.api.ContextPlugin): marker_data["handleEnd"] = min( marker_data["handleEnd"], abs(tail)) + workfile_start = self._set_workfile_start(marker_data) + with_audio = bool(marker_data.pop("audio")) # add marker data to instance data @@ -105,6 +108,7 @@ class CollectTimelineInstances(pyblish.api.ContextPlugin): "families": families, "publish": marker_data["publish"], "fps": self.fps, + "workfileFrameStart": workfile_start, "sourceFirstFrame": int(first_frame), "path": file_path, "flameAddTasks": self.add_tasks, @@ -145,6 +149,17 @@ class CollectTimelineInstances(pyblish.api.ContextPlugin): if marker_data.get("reviewTrack") is not None: instance.data["reviewAudio"] = True + @staticmethod + def _set_workfile_start(data): + include_handles = data.get("includeHandles") + workfile_start = data["workfileFrameStart"] + handle_start = data["handleStart"] + + if include_handles: + workfile_start += handle_start + + return workfile_start + def _get_comment_attributes(self, segment): comment = segment.comment.get_value() From 0b0a9ca2815251ba423f543e376a38e5805c0aba Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Mon, 16 May 2022 15:46:47 +0200 Subject: [PATCH 162/350] by default use task status if not specified in config --- .../plugins/publish/integrate_kitsu_note.py | 34 ++++++++++++------- .../defaults/project_settings/kitsu.json | 3 +- .../projects_schema/schema_project_kitsu.json | 9 +++-- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py index 876eb6bf29..ae559e660e 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from distutils.log import debug import gazu import pyblish.api @@ -9,7 +10,8 @@ class IntegrateKitsuNote(pyblish.api.ContextPlugin): order = pyblish.api.IntegratorOrder label = "Kitsu Note and Status" # families = ["kitsu"] - waiting_for_approval_status = "wfa" + set_status_note = False + note_status_shortname = "wfa" def process(self, context): @@ -20,21 +22,29 @@ class IntegrateKitsuNote(pyblish.api.ContextPlugin): self.log.debug("Comment is `{}`".format(publish_comment)) - # Get Waiting for Approval status - kitsu_status = gazu.task.get_task_status_by_short_name( - self.waiting_for_approval_status - ) - if not kitsu_status: - self.log.info( - "Cannot find {} status. The status will not be " - "changed!".format(self.waiting_for_approval_status) + # Get note status, by default uses the task status for the note + # if it is not specified in the configuration + note_status = context.data["kitsu_task"]["task_status_id"] + if self.set_status_note: + kitsu_status = gazu.task.get_task_status_by_short_name( + self.note_status_shortname ) - kitsu_status = context.data["kitsu_task"].get("task_status") - self.log.debug("Kitsu status: {}".format(kitsu_status)) + if not kitsu_status: + self.log.info( + "Cannot find {} status. The status will not be " + "changed!".format(self.note_status_shortname) + ) + else: + note_status = kitsu_status + self.log.info("Note Kitsu status: {}".format(note_status)) # Add comment to kitsu task + self.log.debug("Add new note in taks id {}".format( + context.data["kitsu_task"]['id'])) kitsu_comment = gazu.task.add_comment( - context.data["kitsu_task"], kitsu_status, comment=publish_comment + context.data["kitsu_task"], + note_status, + comment=publish_comment ) context.data["kitsu_comment"] = kitsu_comment diff --git a/openpype/settings/defaults/project_settings/kitsu.json b/openpype/settings/defaults/project_settings/kitsu.json index 2f1566d89a..ba02d8d259 100644 --- a/openpype/settings/defaults/project_settings/kitsu.json +++ b/openpype/settings/defaults/project_settings/kitsu.json @@ -10,7 +10,8 @@ }, "publish": { "IntegrateKitsuNote": { - "waiting_for_approval_status": "wfa" + "set_status_note": false, + "note_status_shortname": "wfa" } } } \ No newline at end of file diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json b/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json index cffd7ff578..014a1b7886 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_kitsu.json @@ -60,10 +60,15 @@ "key": "IntegrateKitsuNote", "label": "Integrate Kitsu Note", "children": [ + { + "type": "boolean", + "key": "set_status_note", + "label": "Set status on note" + }, { "type": "text", - "key": "waiting_for_approval_status", - "label": "Waiting for Aproval Status:" + "key": "note_status_shortname", + "label": "Note shortname" } ] } From 694c3654764034e1a3f84b4e082b58c0899c8c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Mon, 16 May 2022 18:26:45 +0200 Subject: [PATCH 163/350] list to sets and var name change --- openpype/hosts/maya/plugins/publish/collect_look.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_look.py b/openpype/hosts/maya/plugins/publish/collect_look.py index 70265a160f..9697d0884f 100644 --- a/openpype/hosts/maya/plugins/publish/collect_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_look.py @@ -60,6 +60,7 @@ def get_look_attrs(node): def node_uses_image_sequence(node): + # type: (str) -> bool """Return whether file node uses an image sequence or single image. Determine if a node uses an image sequence or just a single image, @@ -80,11 +81,11 @@ def node_uses_image_sequence(node): patterns = ["", "", "", "u_v", ""] try: - extension = cmds.getAttr('%s.useFrameExtension' % node) + use_frame_extension = cmds.getAttr('%s.useFrameExtension' % node) except ValueError: - extension = None + use_frame_extension = False - return (extension or + return (use_frame_extension or any(pattern in node_path for pattern in patterns)) @@ -170,7 +171,7 @@ def get_file_node_path(node): if any(pattern in lower for pattern in patterns): return texture_pattern - if cmds.nodeType(node) in ['aiImage', 'PxrTexture']: + if cmds.nodeType(node) in {'aiImage', 'PxrTexture'}: return cmds.getAttr('{0}.filename'.format(node)) if cmds.nodeType(node) == 'RedshiftNormalMap': return cmds.getAttr('{}.tex0'.format(node)) @@ -520,8 +521,8 @@ class CollectLook(pyblish.api.InstancePlugin): dict """ self.log.debug("processing: {}".format(node)) - if cmds.nodeType(node) not in [ - "file", "aiImage", "RedshiftNormalMap", "PxrTexture"]: + if cmds.nodeType(node) not in { + "file", "aiImage", "RedshiftNormalMap", "PxrTexture"}: self.log.error( "Unsupported file node: {}".format(cmds.nodeType(node))) raise AssertionError("Unsupported file node") From 196182f5c5ffdc5bb02d86dedf46fb27b704f64e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 16 May 2022 20:57:51 +0200 Subject: [PATCH 164/350] general: expose lib editorial function to lib init --- openpype/lib/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/lib/__init__.py b/openpype/lib/__init__.py index 3c1d71ecd5..8d4e733b7d 100644 --- a/openpype/lib/__init__.py +++ b/openpype/lib/__init__.py @@ -203,6 +203,7 @@ from .editorial import ( is_overlapping_otio_ranges, otio_range_to_frame_range, otio_range_with_handles, + get_media_range_with_retimes, convert_to_padded_path, trim_media_range, range_from_frames, @@ -382,6 +383,7 @@ __all__ = [ "otio_range_with_handles", "convert_to_padded_path", "otio_range_to_frame_range", + "get_media_range_with_retimes", "trim_media_range", "range_from_frames", "frames_to_secons", From 6ee42b1d19b890ee583f4a10f8efab81ebec043e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 16 May 2022 20:58:20 +0200 Subject: [PATCH 165/350] flame: make head and tail with retimed value --- .../publish/collect_timeline_instances.py | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/collect_timeline_instances.py b/openpype/hosts/flame/plugins/publish/collect_timeline_instances.py index 4bca0dcf93..012cb110ec 100644 --- a/openpype/hosts/flame/plugins/publish/collect_timeline_instances.py +++ b/openpype/hosts/flame/plugins/publish/collect_timeline_instances.py @@ -1,8 +1,8 @@ import re import pyblish -import openpype import openpype.hosts.flame.api as opfapi from openpype.hosts.flame.otio import flame_export +import openpype.lib as oplib # # developer reload modules from pprint import pformat @@ -68,7 +68,12 @@ class CollectTimelineInstances(pyblish.api.ContextPlugin): first_frame = opfapi.get_frame_from_filename(file_path) or 0 - head, tail = self._get_head_tail(clip_data, otio_data["otioClip"]) + head, tail = self._get_head_tail( + clip_data, + otio_data["otioClip"], + marker_data["handleStart"], + marker_data["handleEnd"] + ) # solve handles length marker_data["handleStart"] = min( @@ -251,7 +256,7 @@ class CollectTimelineInstances(pyblish.api.ContextPlugin): return split_comments - def _get_head_tail(self, clip_data, otio_clip): + def _get_head_tail(self, clip_data, otio_clip, handle_start, handle_end): # calculate head and tail with forward compatibility head = clip_data.get("segment_head") tail = clip_data.get("segment_tail") @@ -260,21 +265,14 @@ class CollectTimelineInstances(pyblish.api.ContextPlugin): # HACK: it is here to serve for versions bellow 2021.1 if not any([head, tail]): - otio_source_range = otio_clip.source_range - otio_avalable_range = otio_clip.available_range() - range_convert = openpype.lib.otio_range_to_frame_range - src_start, src_end = range_convert(otio_source_range) - av_start, av_end = range_convert(otio_avalable_range) - av_range = av_end - av_start - av_tail = av_range - src_end + retimed_attributes = oplib.get_media_range_with_retimes( + otio_clip, handle_start, handle_end) + self.log.debug( + ">> retimed_attributes: {}".format(retimed_attributes)) - self.log.debug("__ src_start: `{}`".format(src_start)) - self.log.debug("__ src_end: `{}`".format(src_end)) - self.log.debug("__ av_range: `{}`".format(av_range)) - self.log.debug("__ av_tail: `{}`".format(av_tail)) - - head = src_start - tail = av_tail + # retimed head and tail + head = int(retimed_attributes["handleStart"]) + tail = int(retimed_attributes["handleEnd"]) return head, tail @@ -366,7 +364,7 @@ class CollectTimelineInstances(pyblish.api.ContextPlugin): continue if otio_clip.name not in segment.name.get_value(): continue - if openpype.lib.is_overlapping_otio_ranges( + if oplib.is_overlapping_otio_ranges( parent_range, timeline_range, strict=True): # add pypedata marker to otio_clip metadata From 257c58988181a9dcd39bf85e143a08eb686115a7 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 16 May 2022 20:58:44 +0200 Subject: [PATCH 166/350] flame: change editorial function to lib --- openpype/plugins/publish/collect_otio_subset_resources.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/openpype/plugins/publish/collect_otio_subset_resources.py b/openpype/plugins/publish/collect_otio_subset_resources.py index 7c11462ef0..53d327a51d 100644 --- a/openpype/plugins/publish/collect_otio_subset_resources.py +++ b/openpype/plugins/publish/collect_otio_subset_resources.py @@ -10,8 +10,7 @@ import os import clique import opentimelineio as otio import pyblish.api -import openpype -from openpype.lib import editorial +import openpype.lib as oplib class CollectOtioSubsetResources(pyblish.api.InstancePlugin): @@ -43,7 +42,7 @@ class CollectOtioSubsetResources(pyblish.api.InstancePlugin): available_duration = otio_avalable_range.duration.value # get available range trimmed with processed retimes - retimed_attributes = editorial.get_media_range_with_retimes( + retimed_attributes = oplib.get_media_range_with_retimes( otio_clip, handle_start, handle_end) self.log.debug( ">> retimed_attributes: {}".format(retimed_attributes)) @@ -145,7 +144,7 @@ class CollectOtioSubsetResources(pyblish.api.InstancePlugin): # in case it is file sequence but not new OTIO schema # `ImageSequenceReference` path = media_ref.target_url - collection_data = openpype.lib.make_sequence_collection( + collection_data = oplib.make_sequence_collection( path, trimmed_media_range_h, metadata) self.staging_dir, collection = collection_data From 056b92599ec28afb7de04d5c53021f716f056dfe Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 16 May 2022 21:09:00 +0200 Subject: [PATCH 167/350] global: fixing false editorial namespace --- openpype/plugins/publish/collect_otio_subset_resources.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/collect_otio_subset_resources.py b/openpype/plugins/publish/collect_otio_subset_resources.py index 53d327a51d..78e2a6428c 100644 --- a/openpype/plugins/publish/collect_otio_subset_resources.py +++ b/openpype/plugins/publish/collect_otio_subset_resources.py @@ -64,7 +64,7 @@ class CollectOtioSubsetResources(pyblish.api.InstancePlugin): a_frame_end_h = media_out + handle_end # create trimmed otio time range - trimmed_media_range_h = editorial.range_from_frames( + trimmed_media_range_h = oplib.range_from_frames( a_frame_start_h, (a_frame_end_h - a_frame_start_h + 1), media_fps ) From 5059c0cedff88d33f7c0044f0020fa03d1cdca48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Hector?= Date: Tue, 17 May 2022 11:43:28 +0200 Subject: [PATCH 168/350] Update openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Félix David --- .../modules/kitsu/plugins/publish/integrate_kitsu_note.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py index ae559e660e..78c5170856 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py @@ -29,14 +29,14 @@ class IntegrateKitsuNote(pyblish.api.ContextPlugin): kitsu_status = gazu.task.get_task_status_by_short_name( self.note_status_shortname ) - if not kitsu_status: + if kitsu_status: + note_status = kitsu_status + self.log.info("Note Kitsu status: {}".format(note_status)) + else: self.log.info( "Cannot find {} status. The status will not be " "changed!".format(self.note_status_shortname) ) - else: - note_status = kitsu_status - self.log.info("Note Kitsu status: {}".format(note_status)) # Add comment to kitsu task self.log.debug("Add new note in taks id {}".format( From 667cff319d70ea699ded5d009872588f5d5ffee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Tue, 17 May 2022 11:49:54 +0200 Subject: [PATCH 169/350] black --- .../kitsu/plugins/publish/integrate_kitsu_note.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py index 78c5170856..3cd1f450ca 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py @@ -22,7 +22,7 @@ class IntegrateKitsuNote(pyblish.api.ContextPlugin): self.log.debug("Comment is `{}`".format(publish_comment)) - # Get note status, by default uses the task status for the note + # Get note status, by default uses the task status for the note # if it is not specified in the configuration note_status = context.data["kitsu_task"]["task_status_id"] if self.set_status_note: @@ -39,12 +39,13 @@ class IntegrateKitsuNote(pyblish.api.ContextPlugin): ) # Add comment to kitsu task - self.log.debug("Add new note in taks id {}".format( - context.data["kitsu_task"]['id'])) + self.log.debug( + "Add new note in taks id {}".format( + context.data["kitsu_task"]["id"] + ) + ) kitsu_comment = gazu.task.add_comment( - context.data["kitsu_task"], - note_status, - comment=publish_comment + context.data["kitsu_task"], note_status, comment=publish_comment ) context.data["kitsu_comment"] = kitsu_comment From 6976546505590a59072095f675778c9e8a71fe03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20David?= Date: Tue, 17 May 2022 11:51:58 +0200 Subject: [PATCH 170/350] cleaning --- openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py index 3cd1f450ca..ea98e0b7cc 100644 --- a/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py +++ b/openpype/modules/kitsu/plugins/publish/integrate_kitsu_note.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -from distutils.log import debug import gazu import pyblish.api From ea00dc0c6a41c21d7744b996c40a4eca84e1dcb8 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Tue, 17 May 2022 17:07:33 +0200 Subject: [PATCH 171/350] fix support for plugin location --- openpype/hosts/unreal/__init__.py | 3 ++- openpype/hosts/unreal/hooks/pre_workfile_preparation.py | 8 +++++++- openpype/hosts/unreal/lib.py | 6 +++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/unreal/__init__.py b/openpype/hosts/unreal/__init__.py index 533f315df3..bedf5a29f7 100644 --- a/openpype/hosts/unreal/__init__.py +++ b/openpype/hosts/unreal/__init__.py @@ -9,7 +9,8 @@ def add_implementation_envs(env, _app): os.path.dirname(os.path.abspath(openpype.hosts.__file__)), "unreal", "integration" ) - env["OPENPYPE_UNREAL_PLUGIN"] = unreal_plugin_path + if not env.get("OPENPYPE_UNREAL_PLUGIN"): + env["OPENPYPE_UNREAL_PLUGIN"] = unreal_plugin_path # Set default environments if are not set via settings defaults = { diff --git a/openpype/hosts/unreal/hooks/pre_workfile_preparation.py b/openpype/hosts/unreal/hooks/pre_workfile_preparation.py index f07e96551c..fa0562a3a0 100644 --- a/openpype/hosts/unreal/hooks/pre_workfile_preparation.py +++ b/openpype/hosts/unreal/hooks/pre_workfile_preparation.py @@ -25,7 +25,7 @@ class UnrealPrelaunchHook(PreLaunchHook): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.signature = "( {} )".format(self.__class__.__name__) + self.signature = f"( {self.__class__.__name__} )" def _get_work_filename(self): # Use last workfile if was found @@ -99,6 +99,7 @@ class UnrealPrelaunchHook(PreLaunchHook): f"character ({unreal_project_name}). Appending 'P'" )) unreal_project_name = f"P{unreal_project_name}" + unreal_project_filename = f'{unreal_project_name}.uproject' project_path = Path(os.path.join(workdir, unreal_project_name)) @@ -138,6 +139,11 @@ class UnrealPrelaunchHook(PreLaunchHook): )) # Set "OPENPYPE_UNREAL_PLUGIN" to current process environment for # execution of `create_unreal_project` + if self.launch_context.env.get("OPENPYPE_UNREAL_PLUGIN"): + self.log.info(( + f"{self.signature} using OpenPype plugin from " + f"{self.launch_context.env.get('OPENPYPE_UNREAL_PLUGIN')}" + )) env_key = "OPENPYPE_UNREAL_PLUGIN" if self.launch_context.env.get(env_key): os.environ[env_key] = self.launch_context.env[env_key] diff --git a/openpype/hosts/unreal/lib.py b/openpype/hosts/unreal/lib.py index 906002b38f..fdf3acb37b 100644 --- a/openpype/hosts/unreal/lib.py +++ b/openpype/hosts/unreal/lib.py @@ -280,7 +280,7 @@ def create_unreal_project(project_name: str, python_path = None if platform.system().lower() == "windows": python_path = engine_path / ("Engine/Binaries/ThirdParty/" - "Python3/Win64/pythonw.exe") + "Python3/Win64/python.exe") if platform.system().lower() == "linux": python_path = engine_path / ("Engine/Binaries/ThirdParty/" @@ -294,8 +294,8 @@ def create_unreal_project(project_name: str, raise NotImplementedError("Unsupported platform") if not python_path.exists(): raise RuntimeError(f"Unreal Python not found at {python_path}") - subprocess.run( - [python_path.as_posix(), "-m", "pip", "install", "pyside2"]) + out = subprocess.check_call( + [python_path.as_posix(), "-m", "pip", "install", "--user", "pyside2"]) if dev_mode or preset["dev_mode"]: _prepare_cpp_project(project_file, engine_path) From 8e1cc8cef675b909223db7c5d5d39d5aac7deb13 Mon Sep 17 00:00:00 2001 From: DMO Date: Wed, 18 May 2022 16:58:59 +0900 Subject: [PATCH 172/350] Added mvLook publish. This extracts the look information from the UsdCompoundShape - it generates "OP look" compatible data structures and lets the rest of the OP publish as normal. It also generates a .usda file with the overrides containing material assignments as needed. --- .../plugins/create/create_multiverse_look.py | 14 + .../publish/collect_multiverse_look.py | 323 ++++++++++++++++++ .../maya/plugins/publish/extract_look.py | 2 +- .../publish/extract_multiverse_look.py | 134 ++++++++ .../plugins/publish/collect_resources_path.py | 1 + openpype/plugins/publish/integrate_new.py | 1 + 6 files changed, 474 insertions(+), 1 deletion(-) create mode 100644 openpype/hosts/maya/plugins/create/create_multiverse_look.py create mode 100644 openpype/hosts/maya/plugins/publish/collect_multiverse_look.py create mode 100644 openpype/hosts/maya/plugins/publish/extract_multiverse_look.py diff --git a/openpype/hosts/maya/plugins/create/create_multiverse_look.py b/openpype/hosts/maya/plugins/create/create_multiverse_look.py new file mode 100644 index 0000000000..b2b9b5bb29 --- /dev/null +++ b/openpype/hosts/maya/plugins/create/create_multiverse_look.py @@ -0,0 +1,14 @@ +from openpype.hosts.maya.api import plugin, lib + + +class CreateMultiverseLook(plugin.Creator): + """Create Multiverse Look""" + + name = "mvLook" + label = "Multiverse Look" + family = "mvLook" + icon = "cubes" + + def __init__(self, *args, **kwargs): + super(CreateMultiverseLook, self).__init__(*args, **kwargs) + self.data["fileFormat"] = ["usda", "usd"] diff --git a/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py b/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py new file mode 100644 index 0000000000..9c1569e216 --- /dev/null +++ b/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py @@ -0,0 +1,323 @@ +import glob +import os +import re + +from maya import cmds +import pyblish.api +from openpype.hosts.maya.api import lib + +def get_look_attrs(node): + """Returns attributes of a node that are important for the look. + + These are the "changed" attributes (those that have edits applied + in the current scene). + + Returns: + list: Attribute names to extract + + """ + # When referenced get only attributes that are "changed since file open" + # which includes any reference edits, otherwise take *all* user defined + # attributes + is_referenced = cmds.referenceQuery(node, isNodeReferenced=True) + result = cmds.listAttr(node, userDefined=True, + changedSinceFileOpen=is_referenced) or [] + + # `cbId` is added when a scene is saved, ignore by default + if "cbId" in result: + result.remove("cbId") + + # For shapes allow render stat changes + if cmds.objectType(node, isAType="shape"): + attrs = cmds.listAttr(node, changedSinceFileOpen=True) or [] + for attr in attrs: + if attr in SHAPE_ATTRS: + result.append(attr) + elif attr.startswith('ai'): + result.append(attr) + + return result + + +def node_uses_image_sequence(node): + """Return whether file node uses an image sequence or single image. + + Determine if a node uses an image sequence or just a single image, + not always obvious from its file path alone. + + Args: + node (str): Name of the Maya node + + Returns: + bool: True if node uses an image sequence + + """ + + # useFrameExtension indicates an explicit image sequence + node_path = get_file_node_path(node).lower() + + # The following tokens imply a sequence + patterns = ["", "", "", "u_v", ".tif will return as /path/to/texture.*.tif. + + Args: + path (str): the image sequence path + + Returns: + str: Return glob string that matches the filename pattern. + + """ + + if path is None: + return path + + # If any of the patterns, convert the pattern + patterns = { + "": "", + "": "", + "": "", + "#": "#", + "u_v": "|", + "", + "": "" + } + + lower = path.lower() + has_pattern = False + for pattern, regex_pattern in patterns.items(): + if pattern in lower: + path = re.sub(regex_pattern, "*", path, flags=re.IGNORECASE) + has_pattern = True + + if has_pattern: + return path + + base = os.path.basename(path) + matches = list(re.finditer(r'\d+', base)) + if matches: + match = matches[-1] + new_base = '{0}*{1}'.format(base[:match.start()], + base[match.end():]) + head = os.path.dirname(path) + return os.path.join(head, new_base) + else: + return path + + +def get_file_node_path(node): + """Get the file path used by a Maya file node. + + Args: + node (str): Name of the Maya file node + + Returns: + str: the file path in use + + """ + # if the path appears to be sequence, use computedFileTextureNamePattern, + # this preserves the <> tag + if cmds.attributeQuery('computedFileTextureNamePattern', + node=node, + exists=True): + plug = '{0}.computedFileTextureNamePattern'.format(node) + texture_pattern = cmds.getAttr(plug) + + patterns = ["", + "", + "u_v", + "", + ""] + lower = texture_pattern.lower() + if any(pattern in lower for pattern in patterns): + return texture_pattern + + if cmds.nodeType(node) == 'aiImage': + return cmds.getAttr('{0}.filename'.format(node)) + if cmds.nodeType(node) == 'RedshiftNormalMap': + return cmds.getAttr('{}.tex0'.format(node)) + + # otherwise use fileTextureName + return cmds.getAttr('{0}.fileTextureName'.format(node)) + + +def get_file_node_files(node): + """Return the file paths related to the file node + + Note: + Will only return existing files. Returns an empty list + if not valid existing files are linked. + + Returns: + list: List of full file paths. + + """ + + path = get_file_node_path(node) + path = cmds.workspace(expandName=path) + if node_uses_image_sequence(node): + glob_pattern = seq_to_glob(path) + return glob.glob(glob_pattern) + elif os.path.exists(path): + return [path] + else: + return [] + + +class CollectMultiverseLookData(pyblish.api.InstancePlugin): + """Collect Multiverse Look + + """ + + order = pyblish.api.CollectorOrder + 0.2 + label = 'Collect Multiverse Look' + families = ["mvLook"] + + def process(self, instance): + # Load plugin first + cmds.loadPlugin("MultiverseForMaya", quiet=True) + import multiverse + + self.log.info("Processing mvLook for '{}' / '{}'".format( + instance, instance.data['name'])) + + nodes = set() + for node in instance: + # We want only mvUsdCompoundShape nodes. + nodes_of_interest = cmds.ls(node, + dag=True, + shapes=False, + type="mvUsdCompoundShape", + noIntermediate=True, + long=True) + nodes.update(nodes_of_interest) + + files = [] + sets = {} + instance.data["resources"] = [] + + for node in nodes: + self.log.info("Getting resources for '{}'".format(node)) + + # We know what nodes + overrides = multiverse.ListMaterialOverridePrims(node) + for override in overrides: + matOver = multiverse.GetMaterialOverride(node, override) + + if isinstance(matOver, multiverse.MaterialSourceShadingGroup): + shadingGroup = matOver.shadingGroupName + self.log.debug("ShadingGroup = '{}'".format(shadingGroup)) + sets[shadingGroup] = {"uuid": lib.get_id(shadingGroup), "members": list()} + + history = cmds.listHistory(shadingGroup) + files = cmds.ls(history, type="file", long=True) + + for f in files: + resources = self.collect_resource(f) + instance.data["resources"].append(resources) + + elif isinstance(matOver, multiverse.MaterialSourceUsdPath): + # TODO: Handle this later. + pass + else: + # TODO: What to do here? + pass + + # Store data on the instance + instance.data["lookData"] = { + "attributes": [], + "relationships": sets + } + + self.log.info("-------------------------") + self.log.info("Instance: {},{}".format(type(instance),instance)) + self.log.info("Instance.data: {},{}".format(type(instance.data),instance.data)) + for k in instance.data.keys(): + v = instance.data[k] + self.log.info(" data: {},{}".format(k,v)) + self.log.info("-------------------------") + + + def collect_resource(self, node): + """Collect the link to the file(s) used (resource) + Args: + node (str): name of the node + + Returns: + dict + """ + + self.log.debug("processing: {}".format(node)) + if cmds.nodeType(node) not in ["file", "aiImage", "RedshiftNormalMap"]: + self.log.error( + "Unsupported file node: {}".format(cmds.nodeType(node))) + raise AssertionError("Unsupported file node") + + if cmds.nodeType(node) == 'file': + self.log.debug(" - file node") + attribute = "{}.fileTextureName".format(node) + computed_attribute = "{}.computedFileTextureNamePattern".format(node) + elif cmds.nodeType(node) == 'aiImage': + self.log.debug("aiImage node") + attribute = "{}.filename".format(node) + computed_attribute = attribute + elif cmds.nodeType(node) == 'RedshiftNormalMap': + self.log.debug("RedshiftNormalMap node") + attribute = "{}.tex0".format(node) + computed_attribute = attribute + + source = cmds.getAttr(attribute) + self.log.info(" - file source: {}".format(source)) + color_space_attr = "{}.colorSpace".format(node) + try: + color_space = cmds.getAttr(color_space_attr) + except ValueError: + # node doesn't have colorspace attribute + color_space = "Raw" + # Compare with the computed file path, e.g. the one with the + # pattern in it, to generate some logging information about this + # difference + # computed_attribute = "{}.computedFileTextureNamePattern".format(node) + computed_source = cmds.getAttr(computed_attribute) + if source != computed_source: + self.log.debug("Detected computed file pattern difference " + "from original pattern: {0} " + "({1} -> {2})".format(node, + source, + computed_source)) + + # We replace backslashes with forward slashes because V-Ray + # can't handle the UDIM files with the backslashes in the + # paths as the computed patterns + source = source.replace("\\", "/") + + files = get_file_node_files(node) + if len(files) == 0: + self.log.error("No valid files found from node `%s`" % node) + + self.log.info("collection of resource done:") + self.log.info(" - node: {}".format(node)) + self.log.info(" - attribute: {}".format(attribute)) + self.log.info(" - source: {}".format(source)) + self.log.info(" - file: {}".format(files)) + self.log.info(" - color space: {}".format(color_space)) + + # Define the resource + return {"node": node, + "attribute": attribute, + "source": source, # required for resources + "files": files, + "color_space": color_space} # required for resources \ No newline at end of file diff --git a/openpype/hosts/maya/plugins/publish/extract_look.py b/openpype/hosts/maya/plugins/publish/extract_look.py index 881705b92c..c427eacd98 100644 --- a/openpype/hosts/maya/plugins/publish/extract_look.py +++ b/openpype/hosts/maya/plugins/publish/extract_look.py @@ -146,7 +146,7 @@ class ExtractLook(openpype.api.Extractor): label = "Extract Look (Maya Scene + JSON)" hosts = ["maya"] - families = ["look"] + families = ["look","mvLook"] order = pyblish.api.ExtractorOrder + 0.2 scene_type = "ma" look_data_type = "json" diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_look.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_look.py new file mode 100644 index 0000000000..34c72f0915 --- /dev/null +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_look.py @@ -0,0 +1,134 @@ +import os +import six + +from maya import cmds + +import openpype.api +from openpype.hosts.maya.api.lib import maintained_selection + + +class ExtractMultiverseLook(openpype.api.Extractor): + """Extractor for Multiverse USD look data into a Maya Scene.""" + + label = "Extract Multiverse USD Look" + hosts = ["maya"] + families = ["mvLook"] + scene_type = "usda" + file_formats = ["usda", "usd"] + + @property + def options(self): + """Overridable options for Multiverse USD Export + + Given in the following format + - {NAME: EXPECTED TYPE} + + If the overridden option's type does not match, + the option is not included and a warning is logged. + + """ + + return { + "writeAll": bool, + "writeTransforms": bool, + "writeVisibility": bool, + "writeAttributes": bool, + "writeMaterials": bool, + "writeVariants": bool, + "writeVariantsDefinition": bool, + "writeActiveState": bool, + "writeNamespaces": bool, + "numTimeSamples": int, + "timeSamplesSpan": float + } + + @property + def default_options(self): + """The default options for Multiverse USD extraction.""" + + return { + "writeAll": False, + "writeTransforms": False, + "writeVisibility": False, + "writeAttributes": False, + "writeMaterials": True, + "writeVariants": False, + "writeVariantsDefinition": False, + "writeActiveState": False, + "writeNamespaces": False, + "numTimeSamples": 1, + "timeSamplesSpan": 0.0 + } + + def get_file_format(self, instance): + fileFormat = instance.data["fileFormat"] + if fileFormat in range(len(self.file_formats)): + self.scene_type = self.file_formats[fileFormat] + + def process(self, instance): + # Load plugin first + cmds.loadPlugin("MultiverseForMaya", quiet=True) + + # Define output file path + staging_dir = self.staging_dir(instance) + self.get_file_format(instance) + file_name = "{0}.{1}".format(instance.name, self.scene_type) + file_path = os.path.join(staging_dir, file_name) + file_path = file_path.replace('\\', '/') + + # Parse export options + options = self.default_options + self.log.info("Export options: {0}".format(options)) + + # Perform extraction + self.log.info("Performing extraction ...") + + with maintained_selection(): + members = instance.data("setMembers") + members = cmds.ls(members, + dag=True, + shapes=False, + type="mvUsdCompoundShape", + noIntermediate=True, + long=True) + self.log.info('Collected object {}'.format(members)) + if len(members) > 1: + self.log.error('More than one member: {}'.format(members)) + + import multiverse + + over_write_opts = multiverse.OverridesWriteOptions() + options_discard_keys = { + "numTimeSamples", + "timeSamplesSpan", + "frameStart", + "frameEnd", + "handleStart", + "handleEnd", + "step", + "fps" + } + for key, value in options.items(): + if key in options_discard_keys: + continue + setattr(over_write_opts, key, value) + + for member in members: + # @TODO: Make sure there is only one here. + + self.log.debug("Writing Override for '{}'".format(member)) + multiverse.WriteOverrides(file_path, member, over_write_opts) + + if "representations" not in instance.data: + instance.data["representations"] = [] + + representation = { + 'name': self.scene_type, + 'ext': self.scene_type, + 'files': file_name, + 'stagingDir': staging_dir + } + instance.data["representations"].append(representation) + + self.log.info("Extracted instance {} to {}".format( + instance.name, file_path)) diff --git a/openpype/plugins/publish/collect_resources_path.py b/openpype/plugins/publish/collect_resources_path.py index 89df031fb0..8bdf70b529 100644 --- a/openpype/plugins/publish/collect_resources_path.py +++ b/openpype/plugins/publish/collect_resources_path.py @@ -41,6 +41,7 @@ class CollectResourcesPath(pyblish.api.InstancePlugin): "rig", "plate", "look", + "mvLook", "yetiRig", "yeticache", "nukenodes", diff --git a/openpype/plugins/publish/integrate_new.py b/openpype/plugins/publish/integrate_new.py index bf13a4050e..4712c2e6bb 100644 --- a/openpype/plugins/publish/integrate_new.py +++ b/openpype/plugins/publish/integrate_new.py @@ -106,6 +106,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): "effect", "xgen", "hda", + "mvLook", "usd", "staticMesh", "skeletalMesh", From b62627bf558e09f7e8e2b127a82486517a608488 Mon Sep 17 00:00:00 2001 From: DMO Date: Wed, 18 May 2022 17:08:17 +0900 Subject: [PATCH 173/350] Change the default of composition/override to usda. --- .../hosts/maya/plugins/create/create_multiverse_usd_comp.py | 3 ++- .../hosts/maya/plugins/create/create_multiverse_usd_over.py | 3 ++- .../hosts/maya/plugins/publish/extract_multiverse_usd_comp.py | 3 ++- .../hosts/maya/plugins/publish/extract_multiverse_usd_over.py | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/plugins/create/create_multiverse_usd_comp.py b/openpype/hosts/maya/plugins/create/create_multiverse_usd_comp.py index accdffad46..0a8219938b 100644 --- a/openpype/hosts/maya/plugins/create/create_multiverse_usd_comp.py +++ b/openpype/hosts/maya/plugins/create/create_multiverse_usd_comp.py @@ -15,7 +15,8 @@ class CreateMultiverseUsdComp(plugin.Creator): # Add animation data first, since it maintains order. self.data.update(lib.collect_animation_data(True)) - self.data["fileFormat"] = ["usd", "usda"] + # Order of `fileFormat` must match extract_multiverse_usd_comp.py + self.data["fileFormat"] = ["usda", "usd"] self.data["stripNamespaces"] = False self.data["mergeTransformAndShape"] = False self.data["flattenContent"] = False diff --git a/openpype/hosts/maya/plugins/create/create_multiverse_usd_over.py b/openpype/hosts/maya/plugins/create/create_multiverse_usd_over.py index 25892f68bb..9477cd7fed 100644 --- a/openpype/hosts/maya/plugins/create/create_multiverse_usd_over.py +++ b/openpype/hosts/maya/plugins/create/create_multiverse_usd_over.py @@ -15,7 +15,8 @@ class CreateMultiverseUsdOver(plugin.Creator): # Add animation data first, since it maintains order. self.data.update(lib.collect_animation_data(True)) - self.data["fileFormat"] = ["usd", "usda"] + # Order of `fileFormat` must match extract_multiverse_usd_over.py + self.data["fileFormat"] = ["usda", "usd"] self.data["writeAll"] = False self.data["writeTransforms"] = True self.data["writeVisibility"] = True diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py index c686b2a600..695ea9a33f 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py @@ -13,7 +13,8 @@ class ExtractMultiverseUsdComposition(openpype.api.Extractor): hosts = ["maya"] families = ["usdComposition"] scene_type = "usd" - file_formats = ["usd", "usda"] + # Order of `fileFormat` must match create_multiverse_usd_comp.py + file_formats = ["usda", "usd"] @property def options(self): diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py index be0a7be52f..3b101ab6cf 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py @@ -13,7 +13,8 @@ class ExtractMultiverseUsdOverride(openpype.api.Extractor): hosts = ["maya"] families = ["usdOverride"] scene_type = "usd" - file_formats = ["usd", "usda"] + # Order of `fileFormat` must match create_multiverse_usd_over.py + file_formats = ["usda", "usd"] @property def options(self): From 229852dfb52187ee22282427fd0282b81a65edba Mon Sep 17 00:00:00 2001 From: DMO Date: Wed, 18 May 2022 18:27:21 +0900 Subject: [PATCH 174/350] Adding new asset/composition options to the creators. --- openpype/hosts/maya/plugins/create/create_multiverse_usd.py | 1 + .../hosts/maya/plugins/create/create_multiverse_usd_comp.py | 1 + openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py | 2 ++ .../hosts/maya/plugins/publish/extract_multiverse_usd_comp.py | 2 ++ 4 files changed, 6 insertions(+) diff --git a/openpype/hosts/maya/plugins/create/create_multiverse_usd.py b/openpype/hosts/maya/plugins/create/create_multiverse_usd.py index 1d53328760..a82a73cbdb 100644 --- a/openpype/hosts/maya/plugins/create/create_multiverse_usd.py +++ b/openpype/hosts/maya/plugins/create/create_multiverse_usd.py @@ -46,6 +46,7 @@ class CreateMultiverseUsd(plugin.Creator): self.data["writeShadingNetworks"] = False self.data["writeTransformMatrix"] = True self.data["writeUsdAttributes"] = False + self.data["writeInstancesAsReferences"] = False self.data["timeVaryingTopology"] = False self.data["customMaterialNamespace"] = '' self.data["numTimeSamples"] = 1 diff --git a/openpype/hosts/maya/plugins/create/create_multiverse_usd_comp.py b/openpype/hosts/maya/plugins/create/create_multiverse_usd_comp.py index 0a8219938b..9d00ad1cfa 100644 --- a/openpype/hosts/maya/plugins/create/create_multiverse_usd_comp.py +++ b/openpype/hosts/maya/plugins/create/create_multiverse_usd_comp.py @@ -20,6 +20,7 @@ class CreateMultiverseUsdComp(plugin.Creator): self.data["stripNamespaces"] = False self.data["mergeTransformAndShape"] = False self.data["flattenContent"] = False + self.data["writeAsCompoundLayers"] = False self.data["writePendingOverrides"] = False self.data["numTimeSamples"] = 1 self.data["timeSamplesSpan"] = 0.0 diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py index 1748dd00dc..4bc0322fa8 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py @@ -59,6 +59,7 @@ class ExtractMultiverseUsd(openpype.api.Extractor): "writeShadingNetworks": bool, "writeTransformMatrix": bool, "writeUsdAttributes": bool, + "writeInstancesAsReferences": bool, "timeVaryingTopology": bool, "customMaterialNamespace": str, "numTimeSamples": int, @@ -100,6 +101,7 @@ class ExtractMultiverseUsd(openpype.api.Extractor): "writeShadingNetworks": False, "writeTransformMatrix": True, "writeUsdAttributes": False, + "writeInstancesAsReferences": False, "timeVaryingTopology": False, "customMaterialNamespace": str(), "numTimeSamples": 1, diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py index 695ea9a33f..54f23ae774 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py @@ -32,6 +32,7 @@ class ExtractMultiverseUsdComposition(openpype.api.Extractor): "stripNamespaces": bool, "mergeTransformAndShape": bool, "flattenContent": bool, + "writeAsCompoundLayers": bool, "writePendingOverrides": bool, "numTimeSamples": int, "timeSamplesSpan": float @@ -45,6 +46,7 @@ class ExtractMultiverseUsdComposition(openpype.api.Extractor): "stripNamespaces": True, "mergeTransformAndShape": False, "flattenContent": False, + "writeAsCompoundLayers": False, "writePendingOverrides": False, "numTimeSamples": 1, "timeSamplesSpan": 0.0 From 9fc70adfffeb0569f8c0f32f52eb80c722f923b7 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 18 May 2022 13:07:33 +0200 Subject: [PATCH 175/350] flame: abs number only if not 0 --- .../plugins/publish/collect_timeline_instances.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/collect_timeline_instances.py b/openpype/hosts/flame/plugins/publish/collect_timeline_instances.py index 012cb110ec..0aca7c38d5 100644 --- a/openpype/hosts/flame/plugins/publish/collect_timeline_instances.py +++ b/openpype/hosts/flame/plugins/publish/collect_timeline_instances.py @@ -75,11 +75,17 @@ class CollectTimelineInstances(pyblish.api.ContextPlugin): marker_data["handleEnd"] ) + # make sure value is absolute + if head != 0: + head = abs(head) + if tail != 0: + tail = abs(tail) + # solve handles length marker_data["handleStart"] = min( - marker_data["handleStart"], abs(head)) + marker_data["handleStart"], head) marker_data["handleEnd"] = min( - marker_data["handleEnd"], abs(tail)) + marker_data["handleEnd"], tail) workfile_start = self._set_workfile_start(marker_data) From 43f7ad57ce3b3d9c289002f311855b031f1f7f05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Wed, 18 May 2022 15:08:09 +0200 Subject: [PATCH 176/350] support for other renderman nodes --- .../maya/plugins/publish/collect_look.py | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_look.py b/openpype/hosts/maya/plugins/publish/collect_look.py index 9697d0884f..692ecdcde1 100644 --- a/openpype/hosts/maya/plugins/publish/collect_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_look.py @@ -25,6 +25,32 @@ RENDERER_NODE_TYPES = [ SHAPE_ATTRS = set(SHAPE_ATTRS) +DEFAULT_FILE_NODES = frozenset( + ["file"] +) + +ARNOLD_FILE_NODES = frozenset( + ["aiImage"] +) + +REDSHIFT_FILE_NODES = frozenset( + ["RedshiftNormalMap"] +) + +RENDERMAN_FILE_NODES = frozenset( + [ + "PxrBump", + "PxrNormalMap", + # PxrMultiTexture (need to handle multiple filename0 attrs) + "PxrPtexture", + "PxrTexture", + ] +) + +NODES_WITH_FILENAME = frozenset().union( + DEFAULT_FILE_NODES, ARNOLD_FILE_NODES, RENDERMAN_FILE_NODES +) + def get_look_attrs(node): """Returns attributes of a node that are important for the look. @@ -171,7 +197,7 @@ def get_file_node_path(node): if any(pattern in lower for pattern in patterns): return texture_pattern - if cmds.nodeType(node) in {'aiImage', 'PxrTexture'}: + if cmds.nodeType(node) in NODES_WITH_FILENAME: return cmds.getAttr('{0}.filename'.format(node)) if cmds.nodeType(node) == 'RedshiftNormalMap': return cmds.getAttr('{}.tex0'.format(node)) @@ -383,10 +409,13 @@ class CollectLook(pyblish.api.InstancePlugin): or [] ) - files = cmds.ls(history, type="file", long=True) - files.extend(cmds.ls(history, type="aiImage", long=True)) - files.extend(cmds.ls(history, type="PxrTexture", long=True)) - files.extend(cmds.ls(history, type="RedshiftNormalMap", long=True)) + all_supported_nodes = set().union( + DEFAULT_FILE_NODES, ARNOLD_FILE_NODES, REDSHIFT_FILE_NODES, + RENDERMAN_FILE_NODES + ) + files = [] + for node_type in all_supported_nodes: + files.extend(cmds.ls(history, type=node_type, long=True)) self.log.info("Collected file nodes:\n{}".format(files)) # Collect textures if any file nodes are found From 5ceba8cad4ee59c662fbf172041821d6f4d5fa62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Wed, 18 May 2022 17:52:59 +0200 Subject: [PATCH 177/350] fix supported nodes --- .../maya/plugins/publish/collect_look.py | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_look.py b/openpype/hosts/maya/plugins/publish/collect_look.py index 692ecdcde1..123e2637cb 100644 --- a/openpype/hosts/maya/plugins/publish/collect_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_look.py @@ -22,21 +22,16 @@ RENDERER_NODE_TYPES = [ # redshift "RedshiftMeshParameters" ] - SHAPE_ATTRS = set(SHAPE_ATTRS) - DEFAULT_FILE_NODES = frozenset( ["file"] ) - ARNOLD_FILE_NODES = frozenset( ["aiImage"] ) - REDSHIFT_FILE_NODES = frozenset( ["RedshiftNormalMap"] ) - RENDERMAN_FILE_NODES = frozenset( [ "PxrBump", @@ -46,9 +41,14 @@ RENDERMAN_FILE_NODES = frozenset( "PxrTexture", ] ) - +NODES_WITH_FILE = frozenset().union( + DEFAULT_FILE_NODES +) NODES_WITH_FILENAME = frozenset().union( - DEFAULT_FILE_NODES, ARNOLD_FILE_NODES, RENDERMAN_FILE_NODES + ARNOLD_FILE_NODES, RENDERMAN_FILE_NODES +) +NODES_WITH_TEX = frozenset().union( + REDSHIFT_FILE_NODES ) @@ -550,20 +550,23 @@ class CollectLook(pyblish.api.InstancePlugin): dict """ self.log.debug("processing: {}".format(node)) - if cmds.nodeType(node) not in { - "file", "aiImage", "RedshiftNormalMap", "PxrTexture"}: + all_supported_nodes = set().union( + DEFAULT_FILE_NODES, ARNOLD_FILE_NODES, REDSHIFT_FILE_NODES, + RENDERMAN_FILE_NODES + ) + if cmds.nodeType(node) not in all_supported_nodes: self.log.error( "Unsupported file node: {}".format(cmds.nodeType(node))) raise AssertionError("Unsupported file node") self.log.debug(" - got {}".format(cmds.nodeType(node))) - if cmds.nodeType(node) == 'file': + if cmds.nodeType(node) in NODES_WITH_FILE: attribute = "{}.fileTextureName".format(node) computed_attribute = "{}.computedFileTextureNamePattern".format(node) - elif cmds.nodeType(node) in ['aiImage', 'PxrTexture']: + elif cmds.nodeType(node) in NODES_WITH_FILENAME: attribute = "{}.filename".format(node) computed_attribute = attribute - elif cmds.nodeType(node) == 'RedshiftNormalMap': + elif cmds.nodeType(node) in NODES_WITH_TEX: attribute = "{}.tex0".format(node) computed_attribute = attribute From 6b9983fdede5e7e086e62798abddabdec3afcb85 Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Thu, 19 May 2022 14:19:30 +0100 Subject: [PATCH 178/350] Added support for both UE4 and 5 Plugin won't compile in UE4 yet. UE5 needs different modules, not available in UE4. --- .../unreal/hooks/pre_workfile_preparation.py | 12 ++--- openpype/hosts/unreal/lib.py | 48 ++++++++++++------- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/openpype/hosts/unreal/hooks/pre_workfile_preparation.py b/openpype/hosts/unreal/hooks/pre_workfile_preparation.py index fa0562a3a0..5be04fc841 100644 --- a/openpype/hosts/unreal/hooks/pre_workfile_preparation.py +++ b/openpype/hosts/unreal/hooks/pre_workfile_preparation.py @@ -71,7 +71,7 @@ class UnrealPrelaunchHook(PreLaunchHook): if int(engine_version.split(".")[0]) < 4 and \ int(engine_version.split(".")[1]) < 26: raise ApplicationLaunchFailed(( - f"{self.signature} Old unsupported version of UE4 " + f"{self.signature} Old unsupported version of UE " f"detected - {engine_version}")) except ValueError: # there can be string in minor version and in that case @@ -104,14 +104,14 @@ class UnrealPrelaunchHook(PreLaunchHook): project_path = Path(os.path.join(workdir, unreal_project_name)) self.log.info(( - f"{self.signature} requested UE4 version: " + f"{self.signature} requested UE version: " f"[ {engine_version} ]" )) detected = unreal_lib.get_engine_versions(self.launch_context.env) detected_str = ', '.join(detected.keys()) or 'none' self.log.info(( - f"{self.signature} detected UE4 versions: " + f"{self.signature} detected UE versions: " f"[ {detected_str} ]" )) if not detected: @@ -124,10 +124,10 @@ class UnrealPrelaunchHook(PreLaunchHook): f"detected [ {engine_version} ]" )) - ue4_path = unreal_lib.get_editor_executable_path( - Path(detected[engine_version])) + ue_path = unreal_lib.get_editor_executable_path( + Path(detected[engine_version]), engine_version) - self.launch_context.launch_args = [ue4_path.as_posix()] + self.launch_context.launch_args = [ue_path.as_posix()] project_path.mkdir(parents=True, exist_ok=True) project_file = project_path / unreal_project_filename diff --git a/openpype/hosts/unreal/lib.py b/openpype/hosts/unreal/lib.py index fdf3acb37b..f220d8dedf 100644 --- a/openpype/hosts/unreal/lib.py +++ b/openpype/hosts/unreal/lib.py @@ -70,19 +70,22 @@ def get_engine_versions(env=None): return OrderedDict() -def get_editor_executable_path(engine_path: Path) -> Path: - """Get UE4 Editor executable path.""" - ue4_path = engine_path / "Engine/Binaries" +def get_editor_executable_path(engine_path: Path, engine_version: str) -> Path: + """Get UE Editor executable path.""" + ue_path = engine_path / "Engine/Binaries" if platform.system().lower() == "windows": - ue4_path /= "Win64/UnrealEditor.exe" + if engine_version.split(".")[0] == "4": + ue_path /= "Win64/UE4Editor.exe" + elif engine_version.split(".")[0] == "5": + ue_path /= "Win64/UnrealEditor.exe" elif platform.system().lower() == "linux": - ue4_path /= "Linux/UE4Editor" + ue_path /= "Linux/UE4Editor" elif platform.system().lower() == "darwin": - ue4_path /= "Mac/UE4Editor" + ue_path /= "Mac/UE4Editor" - return ue4_path + return ue_path def _win_get_engine_versions(): @@ -208,22 +211,26 @@ def create_unreal_project(project_name: str, # created in different UE4 version. When user convert such project # to his UE4 version, Engine ID is replaced in uproject file. If some # other user tries to open it, it will present him with similar error. - ue4_modules = Path() + ue_modules = Path() if platform.system().lower() == "windows": - ue4_modules = Path(os.path.join(engine_path, "Engine", "Binaries", - "Win64", "UE4Editor.modules")) + ue_modules_path = engine_path / "Engine/Binaries/Win64" + if ue_version.split(".")[0] == "4": + ue_modules_path /= "UE4Editor.modules" + elif ue_version.split(".")[0] == "5": + ue_modules_path /= "UnrealEditor.modules" + ue_modules = Path(ue_modules_path) if platform.system().lower() == "linux": - ue4_modules = Path(os.path.join(engine_path, "Engine", "Binaries", + ue_modules = Path(os.path.join(engine_path, "Engine", "Binaries", "Linux", "UE4Editor.modules")) if platform.system().lower() == "darwin": - ue4_modules = Path(os.path.join(engine_path, "Engine", "Binaries", + ue_modules = Path(os.path.join(engine_path, "Engine", "Binaries", "Mac", "UE4Editor.modules")) - if ue4_modules.exists(): + if ue_modules.exists(): print("--- Loading Engine ID from modules file ...") - with open(ue4_modules, "r") as mp: + with open(ue_modules, "r") as mp: loaded_modules = json.load(mp) if loaded_modules.get("BuildId"): @@ -298,10 +305,11 @@ def create_unreal_project(project_name: str, [python_path.as_posix(), "-m", "pip", "install", "--user", "pyside2"]) if dev_mode or preset["dev_mode"]: - _prepare_cpp_project(project_file, engine_path) + _prepare_cpp_project(project_file, engine_path, ue_version) -def _prepare_cpp_project(project_file: Path, engine_path: Path) -> None: +def _prepare_cpp_project( + project_file: Path, engine_path: Path, ue_version: str) -> None: """Prepare CPP Unreal Project. This function will add source files needed for project to be @@ -420,8 +428,12 @@ class {1}_API A{0}GameModeBase : public AGameModeBase with open(sources_dir / f"{project_name}GameModeBase.h", mode="w") as f: f.write(game_mode_h) - u_build_tool = Path( - engine_path / "Engine/Binaries/DotNET/UnrealBuildTool/UnrealBuildTool.exe") + u_build_tool_path = engine_path / "Engine/Binaries/DotNET" + if ue_version.split(".")[0] == "4": + u_build_tool_path /= "UnrealBuildTool.exe" + elif ue_version.split(".")[0] == "5": + u_build_tool_path /= "UnrealBuildTool/UnrealBuildTool.exe" + u_build_tool = Path(u_build_tool_path) u_header_tool = None arch = "Win64" From 13b4b18d162ed4307408e9d2f64869403c740724 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 19 May 2022 17:05:55 +0200 Subject: [PATCH 179/350] OP-2787 - WIP implementation --- openpype/api.py | 2 + openpype/hosts/maya/api/pipeline.py | 7 + .../maya/plugins/create/create_animation.py | 4 + .../maya/plugins/create/create_pointcache.py | 4 + .../maya/plugins/publish/collect_animation.py | 3 + .../plugins/publish/collect_pointcache.py | 14 ++ .../maya/plugins/publish/extract_animation.py | 8 + .../plugins/publish/extract_pointcache.py | 8 + openpype/lib/remote_publish.py | 2 +- .../submit_maya_remote_publish_deadline.py | 137 ++++++++++++++++++ openpype/plugin.py | 12 ++ openpype/plugins/publish/integrate_new.py | 3 + openpype/scripts/remote_publish.py | 11 ++ 13 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 openpype/hosts/maya/plugins/publish/collect_pointcache.py create mode 100644 openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py create mode 100644 openpype/scripts/remote_publish.py diff --git a/openpype/api.py b/openpype/api.py index 9ce745b653..e049a683c6 100644 --- a/openpype/api.py +++ b/openpype/api.py @@ -44,6 +44,7 @@ from . import resources from .plugin import ( Extractor, + Integrator, ValidatePipelineOrder, ValidateContentsOrder, @@ -86,6 +87,7 @@ __all__ = [ # plugin classes "Extractor", + "Integrator", # ordering "ValidatePipelineOrder", "ValidateContentsOrder", diff --git a/openpype/hosts/maya/api/pipeline.py b/openpype/hosts/maya/api/pipeline.py index b0e8fac635..b75af29523 100644 --- a/openpype/hosts/maya/api/pipeline.py +++ b/openpype/hosts/maya/api/pipeline.py @@ -71,8 +71,15 @@ def install(): if lib.IS_HEADLESS: log.info(("Running in headless mode, skipping Maya " "save/open/new callback installation..")) + + # Register default "local" target + print("Registering pyblish target: farm") + pyblish.api.register_target("farm") return + print("Registering pyblish target: local") + pyblish.api.register_target("local") + _set_project() _register_callbacks() diff --git a/openpype/hosts/maya/plugins/create/create_animation.py b/openpype/hosts/maya/plugins/create/create_animation.py index 11a668cfc8..5cd1f7090a 100644 --- a/openpype/hosts/maya/plugins/create/create_animation.py +++ b/openpype/hosts/maya/plugins/create/create_animation.py @@ -38,3 +38,7 @@ class CreateAnimation(plugin.Creator): # Default to exporting world-space self.data["worldSpace"] = True + + # Default to not send to farm. + self.data["farm"] = False + self.data["priority"] = 50 diff --git a/openpype/hosts/maya/plugins/create/create_pointcache.py b/openpype/hosts/maya/plugins/create/create_pointcache.py index ede152f1ef..e876015adb 100644 --- a/openpype/hosts/maya/plugins/create/create_pointcache.py +++ b/openpype/hosts/maya/plugins/create/create_pointcache.py @@ -28,3 +28,7 @@ class CreatePointCache(plugin.Creator): # Add options for custom attributes self.data["attr"] = "" self.data["attrPrefix"] = "" + + # Default to not send to farm. + self.data["farm"] = False + self.data["priority"] = 50 diff --git a/openpype/hosts/maya/plugins/publish/collect_animation.py b/openpype/hosts/maya/plugins/publish/collect_animation.py index 9b1e38fd0a..b442113fbc 100644 --- a/openpype/hosts/maya/plugins/publish/collect_animation.py +++ b/openpype/hosts/maya/plugins/publish/collect_animation.py @@ -55,3 +55,6 @@ class CollectAnimationOutputGeometry(pyblish.api.InstancePlugin): # Store data in the instance for the validator instance.data["out_hierarchy"] = hierarchy + + if instance.data.get("farm"): + instance.data["families"].append("deadline") diff --git a/openpype/hosts/maya/plugins/publish/collect_pointcache.py b/openpype/hosts/maya/plugins/publish/collect_pointcache.py new file mode 100644 index 0000000000..b55babe372 --- /dev/null +++ b/openpype/hosts/maya/plugins/publish/collect_pointcache.py @@ -0,0 +1,14 @@ +import pyblish.api + + +class CollectPointcache(pyblish.api.InstancePlugin): + """Collect pointcache data for instance.""" + + order = pyblish.api.CollectorOrder + 0.4 + families = ["pointcache"] + label = "Collect Pointcache" + hosts = ["maya"] + + def process(self, instance): + if instance.data.get("farm"): + instance.data["families"].append("deadline") \ No newline at end of file diff --git a/openpype/hosts/maya/plugins/publish/extract_animation.py b/openpype/hosts/maya/plugins/publish/extract_animation.py index 8a8bd67cd8..87f2d35192 100644 --- a/openpype/hosts/maya/plugins/publish/extract_animation.py +++ b/openpype/hosts/maya/plugins/publish/extract_animation.py @@ -23,6 +23,14 @@ class ExtractAnimation(openpype.api.Extractor): families = ["animation"] def process(self, instance): + if instance.data.get("farm"): + path = os.path.join( + os.path.dirname(instance.context.data["currentFile"]), + "cache", + instance.data["name"] + ".abc" + ) + instance.data["expectedFiles"] = [os.path.normpath(path)] + return # Collect the out set nodes out_sets = [node for node in instance if node.endswith("out_SET")] diff --git a/openpype/hosts/maya/plugins/publish/extract_pointcache.py b/openpype/hosts/maya/plugins/publish/extract_pointcache.py index 60502fdde1..7ad4c6dfa9 100644 --- a/openpype/hosts/maya/plugins/publish/extract_pointcache.py +++ b/openpype/hosts/maya/plugins/publish/extract_pointcache.py @@ -25,6 +25,14 @@ class ExtractAlembic(openpype.api.Extractor): "vrayproxy"] def process(self, instance): + if instance.data.get("farm"): + path = os.path.join( + os.path.dirname(instance.context.data["currentFile"]), + "cache", + instance.data["name"] + ".abc" + ) + instance.data["expectedFiles"] = [os.path.normpath(path)] + return nodes = instance[:] diff --git a/openpype/lib/remote_publish.py b/openpype/lib/remote_publish.py index 8a42daf4e9..da2497e1a5 100644 --- a/openpype/lib/remote_publish.py +++ b/openpype/lib/remote_publish.py @@ -228,7 +228,7 @@ def _get_close_plugin(close_plugin_name, log): if plugin.__name__ == close_plugin_name: return plugin - log.warning("Close plugin not found, app might not close.") + log.debug("Close plugin not found, app might not close.") def get_task_data(batch_dir): diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py new file mode 100644 index 0000000000..761bc8cc95 --- /dev/null +++ b/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py @@ -0,0 +1,137 @@ +import os +import requests + +from maya import cmds + +from openpype.pipeline import legacy_io + +import pyblish.api + + +class MayaSubmitRemotePublishDeadline(pyblish.api.ContextPlugin): + """Submit Maya scene to perform a local publish in Deadline. + + Publishing in Deadline can be helpful for scenes that publish very slow. + This way it can process in the background on another machine without the + Artist having to wait for the publish to finish on their local machine. + + Submission is done through the Deadline Web Service. + + Different from `ProcessSubmittedJobOnFarm` which creates publish job + depending on metadata json containing context and instance data of + rendered files. + """ + + label = "Submit Scene to Deadline" + order = pyblish.api.IntegratorOrder + hosts = ["maya"] + families = ["deadline"] + + # custom deadline attributes + deadline_department = "" + deadline_pool = "" + deadline_pool_secondary = "" + deadline_group = "" + deadline_chunk_size = 1 + deadline_priority = 50 + + def process(self, context): + + # Ensure no errors so far + assert all(result["success"] for result in context.data["results"]), ( + "Errors found, aborting integration..") + + # Note that `publish` data member might change in the future. + # See: https://github.com/pyblish/pyblish-base/issues/307 + actives = [i for i in context if i.data["publish"]] + instance_names = sorted(instance.name for instance in actives) + + if not instance_names: + self.log.warning("No active instances found. " + "Skipping submission..") + return + + scene = context.data["currentFile"] + scenename = os.path.basename(scene) + + # Get project code + project_name = legacy_io.Session["AVALON_PROJECT"] + + job_name = "{scene} [PUBLISH]".format(scene=scenename) + batch_name = "{code} - {scene}".format(code=project_name, + scene=scenename) + + # Generate the payload for Deadline submission + payload = { + "JobInfo": { + "Plugin": "MayaBatch", + "BatchName": batch_name, + "Priority": 50, + "Name": job_name, + "UserName": context.data["user"], + # "Comment": instance.context.data.get("comment", ""), + # "InitialStatus": state + "Department": self.deadline_department, + "ChunkSize": self.deadline_chunk_size, + "Priority": self.deadline_priority, + + "Group": self.deadline_group, + + }, + "PluginInfo": { + + "Build": None, # Don't force build + "StrictErrorChecking": True, + "ScriptJob": True, + + # Inputs + "SceneFile": scene, + "ScriptFilename": "{OPENPYPE_ROOT}/scripts/remote_publish.py", + + # Mandatory for Deadline + "Version": cmds.about(version=True), + + # Resolve relative references + "ProjectPath": cmds.workspace(query=True, + rootDirectory=True), + + }, + + # Mandatory for Deadline, may be empty + "AuxFiles": [] + } + + # Include critical environment variables with submission + api.Session + keys = [ + "FTRACK_API_USER", + "FTRACK_API_KEY", + "FTRACK_SERVER" + ] + environment = dict({key: os.environ[key] for key in keys + if key in os.environ}, **legacy_io.Session) + + # TODO replace legacy_io with context.data ? + environment["AVALON_PROJECT"] = legacy_io.Session["AVALON_PROJECT"] + environment["AVALON_ASSET"] = legacy_io.Session["AVALON_ASSET"] + environment["AVALON_TASK"] = legacy_io.Session["AVALON_TASK"] + environment["AVALON_APP_NAME"] = os.environ.get("AVALON_APP_NAME") + environment["OPENPYPE_LOG_NO_COLORS"] = "1" + environment["OPENPYPE_USERNAME"] = context.data["user"] + environment["OPENPYPE_PUBLISH_JOB"] = "1" + environment["OPENPYPE_RENDER_JOB"] = "0" + environment["PYBLISH_ACTIVE_INSTANCES"] = ",".join(instance_names) + + payload["JobInfo"].update({ + "EnvironmentKeyValue%d" % index: "{key}={value}".format( + key=key, + value=environment[key] + ) for index, key in enumerate(environment) + }) + + self.log.info("Submitting Deadline job ...") + deadline_url = context.data["defaultDeadline"] + assert deadline_url, "Requires Deadline Webservice URL" + url = "{}/api/jobs".format(deadline_url) + response = requests.post(url, json=payload, timeout=10) + if not response.ok: + raise Exception(response.text) diff --git a/openpype/plugin.py b/openpype/plugin.py index bb9bc2ff85..f1ee626ffb 100644 --- a/openpype/plugin.py +++ b/openpype/plugin.py @@ -18,6 +18,16 @@ class InstancePlugin(pyblish.api.InstancePlugin): super(InstancePlugin, cls).process(cls, *args, **kwargs) +class Integrator(InstancePlugin): + """Integrator base class. + + Wraps pyblish instance plugin. Targets set to "local" which means all + integrators should run on "local" publishes, by default. + "farm" targets could be used for integrators that should run on a farm. + """ + targets = ["local"] + + class Extractor(InstancePlugin): """Extractor base class. @@ -28,6 +38,8 @@ class Extractor(InstancePlugin): """ + targets = ["local"] + order = 2.0 def staging_dir(self, instance): diff --git a/openpype/plugins/publish/integrate_new.py b/openpype/plugins/publish/integrate_new.py index bf13a4050e..1a4112107a 100644 --- a/openpype/plugins/publish/integrate_new.py +++ b/openpype/plugins/publish/integrate_new.py @@ -139,6 +139,9 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): ef, instance.data["family"], instance.data["families"])) return + if "deadline" in instance.data["families"]: + return + self.integrated_file_sizes = {} try: self.register(instance) diff --git a/openpype/scripts/remote_publish.py b/openpype/scripts/remote_publish.py new file mode 100644 index 0000000000..b54c8d931b --- /dev/null +++ b/openpype/scripts/remote_publish.py @@ -0,0 +1,11 @@ +try: + from openpype.api import Logger + import openpype.lib.remote_publish +except ImportError as exc: + # Ensure Deadline fails by output an error that contains "Fatal Error:" + raise ImportError("Fatal Error: %s" % exc) + +if __name__ == "__main__": + # Perform remote publish with thorough error checking + log = Logger.get_logger(__name__) + openpype.lib.remote_publish.publish(log) From 0b7e3b6606a5e369e7aa2d9d4ae465d218f38016 Mon Sep 17 00:00:00 2001 From: DMO Date: Fri, 20 May 2022 10:34:53 +0900 Subject: [PATCH 180/350] Fixed formatting errors, removed unneeded code, added comments. --- .../publish/collect_multiverse_look.py | 46 ++++++++----------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py b/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py index 9c1569e216..643a3eae61 100644 --- a/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py @@ -6,6 +6,7 @@ from maya import cmds import pyblish.api from openpype.hosts.maya.api import lib + def get_look_attrs(node): """Returns attributes of a node that are important for the look. @@ -191,20 +192,19 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): cmds.loadPlugin("MultiverseForMaya", quiet=True) import multiverse - self.log.info("Processing mvLook for '{}' / '{}'".format( - instance, instance.data['name'])) + self.log.info("Processing mvLook for '{}'".format(instance)) nodes = set() for node in instance: # We want only mvUsdCompoundShape nodes. nodes_of_interest = cmds.ls(node, - dag=True, - shapes=False, - type="mvUsdCompoundShape", - noIntermediate=True, - long=True) + dag=True, + shapes=False, + type="mvUsdCompoundShape", + noIntermediate=True, + long=True) nodes.update(nodes_of_interest) - + files = [] sets = {} instance.data["resources"] = [] @@ -212,16 +212,21 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): for node in nodes: self.log.info("Getting resources for '{}'".format(node)) - # We know what nodes + # We know what nodes need to be collected, now we need to + # extract the materials overrides. overrides = multiverse.ListMaterialOverridePrims(node) for override in overrides: matOver = multiverse.GetMaterialOverride(node, override) if isinstance(matOver, multiverse.MaterialSourceShadingGroup): + # We now need to grab the shadingGroup so add it to the + # sets we pass down the pipe. shadingGroup = matOver.shadingGroupName self.log.debug("ShadingGroup = '{}'".format(shadingGroup)) - sets[shadingGroup] = {"uuid": lib.get_id(shadingGroup), "members": list()} + sets[shadingGroup] = {"uuid": lib.get_id( + shadingGroup), "members": list()} + # The SG may reference files, add those too! history = cmds.listHistory(shadingGroup) files = cmds.ls(history, type="file", long=True) @@ -229,28 +234,16 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): resources = self.collect_resource(f) instance.data["resources"].append(resources) - elif isinstance(matOver, multiverse.MaterialSourceUsdPath): + elif isinstance(matOver, multiverse.MaterialSourceUsdPath): # TODO: Handle this later. pass - else: - # TODO: What to do here? - pass - # Store data on the instance + # Store data on the instance for validators, extractos, etc. instance.data["lookData"] = { "attributes": [], "relationships": sets } - self.log.info("-------------------------") - self.log.info("Instance: {},{}".format(type(instance),instance)) - self.log.info("Instance.data: {},{}".format(type(instance.data),instance.data)) - for k in instance.data.keys(): - v = instance.data[k] - self.log.info(" data: {},{}".format(k,v)) - self.log.info("-------------------------") - - def collect_resource(self, node): """Collect the link to the file(s) used (resource) Args: @@ -269,7 +262,8 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): if cmds.nodeType(node) == 'file': self.log.debug(" - file node") attribute = "{}.fileTextureName".format(node) - computed_attribute = "{}.computedFileTextureNamePattern".format(node) + computed_attribute = "{}.computedFileTextureNamePattern".format( + node) elif cmds.nodeType(node) == 'aiImage': self.log.debug("aiImage node") attribute = "{}.filename".format(node) @@ -320,4 +314,4 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): "attribute": attribute, "source": source, # required for resources "files": files, - "color_space": color_space} # required for resources \ No newline at end of file + "color_space": color_space} # required for resources From fe40624135dae296d0f4099edbdaf8be38742b79 Mon Sep 17 00:00:00 2001 From: DMO Date: Fri, 20 May 2022 10:38:45 +0900 Subject: [PATCH 181/350] Minor cleanup. --- .../maya/plugins/publish/collect_multiverse_look.py | 13 ++++++++++++- openpype/hosts/maya/plugins/publish/extract_look.py | 2 +- .../maya/plugins/publish/extract_multiverse_look.py | 1 - 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py b/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py index 643a3eae61..c5ea6a2253 100644 --- a/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py @@ -6,6 +6,17 @@ from maya import cmds import pyblish.api from openpype.hosts.maya.api import lib +SHAPE_ATTRS = ["castsShadows", + "receiveShadows", + "motionBlur", + "primaryVisibility", + "smoothShading", + "visibleInReflections", + "visibleInRefractions", + "doubleSided", + "opposite"] + +SHAPE_ATTRS = set(SHAPE_ATTRS) def get_look_attrs(node): """Returns attributes of a node that are important for the look. @@ -92,7 +103,7 @@ def seq_to_glob(path): "": "", "#": "#", "u_v": "|", - "", + "", #noqa - copied from collect_look.py "": "" } diff --git a/openpype/hosts/maya/plugins/publish/extract_look.py b/openpype/hosts/maya/plugins/publish/extract_look.py index c427eacd98..afb2c3b3d6 100644 --- a/openpype/hosts/maya/plugins/publish/extract_look.py +++ b/openpype/hosts/maya/plugins/publish/extract_look.py @@ -146,7 +146,7 @@ class ExtractLook(openpype.api.Extractor): label = "Extract Look (Maya Scene + JSON)" hosts = ["maya"] - families = ["look","mvLook"] + families = ["look", "mvLook"] order = pyblish.api.ExtractorOrder + 0.2 scene_type = "ma" look_data_type = "json" diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_look.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_look.py index 34c72f0915..5ba840f2b7 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_look.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_look.py @@ -1,5 +1,4 @@ import os -import six from maya import cmds From d46c919281145a7d07ffb5aca1ef16f7407c6e46 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 12 May 2022 11:46:55 +0200 Subject: [PATCH 182/350] general: calculation of duration should not exclude one frame From ddfee503677c3ad6e653c9346cd742520667d0d9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 12 May 2022 11:47:23 +0200 Subject: [PATCH 183/350] hiero: fitting new duration calculation From f4ebcdb27856888794c59c142c43806b863cb61b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 12:22:35 +0200 Subject: [PATCH 184/350] Hiero: small bugs - track name was not equal and was catching similar names too - publish action in timeline submenu was broken - parse_container was returning false data even it should not --- openpype/hosts/hiero/api/lib.py | 7 ++++--- openpype/hosts/hiero/api/pipeline.py | 5 +++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/hiero/api/lib.py b/openpype/hosts/hiero/api/lib.py index 2a4cd03b76..be02c7c793 100644 --- a/openpype/hosts/hiero/api/lib.py +++ b/openpype/hosts/hiero/api/lib.py @@ -118,7 +118,7 @@ def get_current_track(sequence, name, audio=False): # get track by name track = None for _track in tracks: - if _track.name() in name: + if _track.name() == name: track = _track if not track: @@ -126,6 +126,7 @@ def get_current_track(sequence, name, audio=False): track = hiero.core.VideoTrack(name) else: track = hiero.core.AudioTrack(name) + sequence.addTrack(track) return track @@ -497,7 +498,7 @@ class PyblishSubmission(hiero.exporters.FnSubmission.Submission): from . import publish # Add submission to Hiero module for retrieval in plugins. hiero.submission = self - publish() + publish(hiero.ui.mainWindow()) def add_submission(): @@ -527,7 +528,7 @@ class PublishAction(QtWidgets.QAction): # from getting picked up when not using the "Export" dialog. if hasattr(hiero, "submission"): del hiero.submission - publish() + publish(hiero.ui.mainWindow()) def eventHandler(self, event): # Add the Menu to the right-click menu diff --git a/openpype/hosts/hiero/api/pipeline.py b/openpype/hosts/hiero/api/pipeline.py index 8025ebff05..9b628ec70b 100644 --- a/openpype/hosts/hiero/api/pipeline.py +++ b/openpype/hosts/hiero/api/pipeline.py @@ -143,6 +143,11 @@ def parse_container(track_item, validate=True): """ # convert tag metadata to normal keys names data = lib.get_track_item_pype_data(track_item) + if ( + not data + or data.get("id") != "pyblish.avalon.container" + ): + return if validate and data and data.get("schema"): schema.validate(data) From c09038984190085b6182cf075455d503692e10ca Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 19:46:34 +0200 Subject: [PATCH 185/350] Hiero: add new `get_timeline_selection` function --- openpype/hosts/hiero/api/__init__.py | 2 ++ openpype/hosts/hiero/api/lib.py | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/openpype/hosts/hiero/api/__init__.py b/openpype/hosts/hiero/api/__init__.py index f3c32b268c..fc2d017f04 100644 --- a/openpype/hosts/hiero/api/__init__.py +++ b/openpype/hosts/hiero/api/__init__.py @@ -27,6 +27,7 @@ from .lib import ( get_track_items, get_current_project, get_current_sequence, + get_timeline_selection, get_current_track, get_track_item_pype_tag, set_track_item_pype_tag, @@ -80,6 +81,7 @@ __all__ = [ "get_track_items", "get_current_project", "get_current_sequence", + "get_timeline_selection", "get_current_track", "get_track_item_pype_tag", "set_track_item_pype_tag", diff --git a/openpype/hosts/hiero/api/lib.py b/openpype/hosts/hiero/api/lib.py index be02c7c793..115a926d84 100644 --- a/openpype/hosts/hiero/api/lib.py +++ b/openpype/hosts/hiero/api/lib.py @@ -96,6 +96,12 @@ def get_current_sequence(name=None, new=False): return sequence +def get_timeline_selection(): + active_sequence = hiero.ui.activeSequence() + timeline_editor = hiero.ui.getTimelineEditor(active_sequence) + return list(timeline_editor.selection()) + + def get_current_track(sequence, name, audio=False): """ Get current track in context of active project. From 9dd13425c36511873aeefb46f88f721381d91cc6 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 19:47:15 +0200 Subject: [PATCH 186/350] Hiero: removing event slowing down work with timeline --- openpype/hosts/hiero/api/events.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/hiero/api/events.py b/openpype/hosts/hiero/api/events.py index 7fab3edfc8..59fd278a81 100644 --- a/openpype/hosts/hiero/api/events.py +++ b/openpype/hosts/hiero/api/events.py @@ -109,8 +109,9 @@ def register_hiero_events(): # hiero.core.events.registerInterest("kShutdown", shutDown) # hiero.core.events.registerInterest("kStartup", startupCompleted) - hiero.core.events.registerInterest( - ("kSelectionChanged", "kTimeline"), selection_changed_timeline) + # INFO: was disabled because it was slowing down timeline operations + # hiero.core.events.registerInterest( + # ("kSelectionChanged", "kTimeline"), selection_changed_timeline) # workfiles try: From c70c6d99110dce5f7d880cc0d285e2a03dfbf583 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 19:48:12 +0200 Subject: [PATCH 187/350] Hiero: fixing one frame difference otio clip and media --- openpype/hosts/hiero/api/otio/hiero_export.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/hiero/api/otio/hiero_export.py b/openpype/hosts/hiero/api/otio/hiero_export.py index 64fb81aed4..46e1204324 100644 --- a/openpype/hosts/hiero/api/otio/hiero_export.py +++ b/openpype/hosts/hiero/api/otio/hiero_export.py @@ -151,7 +151,7 @@ def create_otio_reference(clip): padding = media_source.filenamePadding() file_head = media_source.filenameHead() is_sequence = not media_source.singleFile() - frame_duration = media_source.duration() - 1 + frame_duration = media_source.duration() fps = utils.get_rate(clip) or self.project_fps extension = os.path.splitext(path)[-1] @@ -277,7 +277,7 @@ def create_otio_clip(track_item): # flip if speed is in minus source_in = track_item.sourceIn() if speed > 0 else track_item.sourceOut() - duration = int(track_item.duration()) + duration = int(track_item.duration()) - 1 fps = utils.get_rate(track_item) or self.project_fps name = track_item.name() From cf6ea949acca41fcd04a0155134252c21816939a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 19:48:40 +0200 Subject: [PATCH 188/350] global: hierarchy fps should be taken from instance.data --- openpype/plugins/publish/collect_hierarchy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/collect_hierarchy.py b/openpype/plugins/publish/collect_hierarchy.py index a96d444be6..8398a2815a 100644 --- a/openpype/plugins/publish/collect_hierarchy.py +++ b/openpype/plugins/publish/collect_hierarchy.py @@ -62,7 +62,7 @@ class CollectHierarchy(pyblish.api.ContextPlugin): "frameEnd": instance.data["frameEnd"], "clipIn": instance.data["clipIn"], "clipOut": instance.data["clipOut"], - 'fps': instance.context.data["fps"], + "fps": instance.data["fps"], "resolutionWidth": instance.data["resolutionWidth"], "resolutionHeight": instance.data["resolutionHeight"], "pixelAspect": instance.data["pixelAspect"] From 191444167c025f0f1bf20b6d15dbd480eff1243e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 19:49:52 +0200 Subject: [PATCH 189/350] Hiero: moving order bit lower under core plugins --- openpype/hosts/hiero/plugins/publish/precollect_workfile.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/hiero/plugins/publish/precollect_workfile.py b/openpype/hosts/hiero/plugins/publish/precollect_workfile.py index b9f58c15f6..c9bfb86810 100644 --- a/openpype/hosts/hiero/plugins/publish/precollect_workfile.py +++ b/openpype/hosts/hiero/plugins/publish/precollect_workfile.py @@ -16,7 +16,7 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin): """Inject the current working file into context""" label = "Precollect Workfile" - order = pyblish.api.CollectorOrder - 0.5 + order = pyblish.api.CollectorOrder - 0.491 def process(self, context): @@ -84,6 +84,7 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin): "colorspace": self.get_colorspace(project), "fps": fps } + self.log.debug("__ context_data: {}".format(pformat(context_data))) context.data.update(context_data) self.log.info("Creating instance: {}".format(instance)) From b55bf81d352790c46ba748a7781bc75cda88afb1 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 19:50:50 +0200 Subject: [PATCH 190/350] Hiero: adding timeline selected to precollector --- .../hosts/hiero/plugins/publish/precollect_instances.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/hiero/plugins/publish/precollect_instances.py b/openpype/hosts/hiero/plugins/publish/precollect_instances.py index 46f0b2440e..1ef7e5f538 100644 --- a/openpype/hosts/hiero/plugins/publish/precollect_instances.py +++ b/openpype/hosts/hiero/plugins/publish/precollect_instances.py @@ -19,9 +19,12 @@ class PrecollectInstances(pyblish.api.ContextPlugin): def process(self, context): self.otio_timeline = context.data["otioTimeline"] - + timeline_selection = phiero.get_timeline_selection() selected_timeline_items = phiero.get_track_items( - selected=True, check_tagged=True, check_enabled=True) + selection=timeline_selection, + check_tagged=True, + check_enabled=True + ) # only return enabled track items if not selected_timeline_items: From 68439301dc5f24372ccd69202bcea3a3040ce733 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 19:51:21 +0200 Subject: [PATCH 191/350] Hiero: one frame diff fix, with code improvements --- .../hosts/hiero/plugins/publish/precollect_instances.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/hiero/plugins/publish/precollect_instances.py b/openpype/hosts/hiero/plugins/publish/precollect_instances.py index 1ef7e5f538..e54d050f0d 100644 --- a/openpype/hosts/hiero/plugins/publish/precollect_instances.py +++ b/openpype/hosts/hiero/plugins/publish/precollect_instances.py @@ -295,9 +295,9 @@ class PrecollectInstances(pyblish.api.ContextPlugin): for otio_clip in self.otio_timeline.each_clip(): track_name = otio_clip.parent().name parent_range = otio_clip.range_in_parent() - if ti_track_name not in track_name: + if ti_track_name != track_name: continue - if otio_clip.name not in track_item.name(): + if otio_clip.name != track_item.name(): continue self.log.debug("__ parent_range: {}".format(parent_range)) self.log.debug("__ timeline_range: {}".format(timeline_range)) @@ -317,7 +317,7 @@ class PrecollectInstances(pyblish.api.ContextPlugin): speed = track_item.playbackSpeed() timeline = phiero.get_current_sequence() frame_start = int(track_item.timelineIn()) - frame_duration = int(track_item.sourceDuration() / speed) + frame_duration = int((track_item.duration() - 1) / speed) fps = timeline.framerate().toFloat() return hiero_export.create_otio_time_range( From 2798469e36c3f915692cb0cfdea5e0cb5f16900a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 19:54:17 +0200 Subject: [PATCH 192/350] Hiero: refactory of get_track_items with better validation --- openpype/hosts/hiero/api/lib.py | 140 ++++++++++++++++++++------------ 1 file changed, 89 insertions(+), 51 deletions(-) diff --git a/openpype/hosts/hiero/api/lib.py b/openpype/hosts/hiero/api/lib.py index 115a926d84..15142daa09 100644 --- a/openpype/hosts/hiero/api/lib.py +++ b/openpype/hosts/hiero/api/lib.py @@ -1,7 +1,10 @@ """ Host specific functions where host api is connected """ + +import contextlib import os +from pprint import pformat import re import sys import platform @@ -139,7 +142,7 @@ def get_current_track(sequence, name, audio=False): def get_track_items( - selected=False, + selection=False, sequence_name=None, track_item_name=None, track_name=None, @@ -150,7 +153,7 @@ def get_track_items( """Get all available current timeline track items. Attribute: - selected (bool)[optional]: return only selected items on timeline + selection (list)[optional]: list of selected track items sequence_name (str)[optional]: return only clips from input sequence track_item_name (str)[optional]: return only item with input name track_name (str)[optional]: return only items from track name @@ -162,32 +165,33 @@ def get_track_items( Return: list or hiero.core.TrackItem: list of track items or single track item """ - return_list = list() - track_items = list() + track_type = track_type or "video" + selection = selection or [] + return_list = [] # get selected track items or all in active sequence - if selected: - try: - selected_items = list(hiero.selection) - for item in selected_items: - if track_name and track_name in item.parent().name(): - # filter only items fitting input track name - track_items.append(item) - elif not track_name: - # or add all if no track_name was defined - track_items.append(item) - except AttributeError: - pass + if selection: + with contextlib.suppress(AttributeError): + for track_item in selection: + log.info("___ track_item: {}".format(track_item)) + # make sure only trackitems are selected + if not isinstance(track_item, hiero.core.TrackItem): + continue + + if _validate_all_atrributes( + track_item, + track_item_name, + track_name, + track_type, + check_enabled, + check_tagged + ): + log.info("___ valid trackitem: {}".format(track_item)) + return_list.append(track_item) - # check if any collected track items are - # `core.Hiero.Python.TrackItem` instance - if track_items: - any_track_item = track_items[0] - if not isinstance(any_track_item, hiero.core.TrackItem): - selected_items = [] # collect all available active sequence track items - if not track_items: + if not return_list: sequence = get_current_sequence(name=sequence_name) # get all available tracks from sequence tracks = list(sequence.audioTracks()) + list(sequence.videoTracks()) @@ -198,42 +202,76 @@ def get_track_items( if check_enabled and not track.isEnabled(): continue # and all items in track - for item in track.items(): - if check_tagged and not item.tags(): + for track_item in track.items(): + # make sure no subtrackitem is also track items + if not isinstance(track_item, hiero.core.TrackItem): continue - # check if track item is enabled - if check_enabled: - if not item.isEnabled(): - continue - if track_item_name: - if track_item_name in item.name(): - return item - # make sure only track items with correct track names are added - if track_name and track_name in track.name(): - # filter out only defined track_name items - track_items.append(item) - elif not track_name: - # or add all if no track_name is defined - track_items.append(item) + if not _validate_all_atrributes( + track_item, + track_item_name, + track_name, + track_type, + check_enabled, + check_tagged + ): + return_list.append(track_item) - # filter out only track items with defined track_type - for track_item in track_items: - if track_type and track_type == "video" and isinstance( + return return_list + + +def _validate_all_atrributes( + track_item, + track_item_name, + track_name, + track_type, + check_enabled, + check_tagged +): + def _validate_correct_name_track_item(): + if track_item_name and track_item_name in track_item.name(): + return True + elif not track_item_name: + return True + + def _validate_tagged_track_item(): + if check_tagged and track_item.tags(): + return True + elif not check_tagged: + return True + + def _validate_enabled_track_item(): + if check_enabled and track_item.isEnabled(): + return True + elif not check_enabled: + return True + + def _validate_parent_track_item(): + if track_name and track_name in track_item.parent().name(): + # filter only items fitting input track name + return True + elif not track_name: + # or add all if no track_name was defined + return True + + def _validate_type_track_item(): + if track_type == "video" and isinstance( track_item.parent(), hiero.core.VideoTrack): # only video track items are allowed - return_list.append(track_item) - elif track_type and track_type == "audio" and isinstance( + return True + elif track_type == "audio" and isinstance( track_item.parent(), hiero.core.AudioTrack): # only audio track items are allowed - return_list.append(track_item) - elif not track_type: - # add all if no track_type is defined - return_list.append(track_item) + return True - # return output list but make sure all items are TrackItems - return [_i for _i in return_list - if type(_i) == hiero.core.TrackItem] + # check if track item is enabled + return all([ + _validate_enabled_track_item(), + _validate_type_track_item(), + _validate_tagged_track_item(), + _validate_parent_track_item(), + _validate_correct_name_track_item() + ]) def get_track_item_pype_tag(track_item): From 13599837176687e49a57762414aad97e56e9125a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 19:55:16 +0200 Subject: [PATCH 193/350] Hiero: fixing events --- openpype/hosts/hiero/api/lib.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/openpype/hosts/hiero/api/lib.py b/openpype/hosts/hiero/api/lib.py index 15142daa09..d3e6441705 100644 --- a/openpype/hosts/hiero/api/lib.py +++ b/openpype/hosts/hiero/api/lib.py @@ -1027,7 +1027,7 @@ def sync_clip_name_to_data_asset(track_items_list): print("asset was changed in clip: {}".format(ti_name)) -def check_inventory_versions(): +def check_inventory_versions(track_items=None): """ Actual version color idetifier of Loaded containers @@ -1038,14 +1038,15 @@ def check_inventory_versions(): """ from . import parse_container + track_item = track_items or get_track_items() # presets clip_color_last = "green" clip_color = "red" # get all track items from current timeline - for track_item in get_track_items(): + for track_item in track_item: container = parse_container(track_item) - + log.info("___> container: {}".format(pformat(container))) if container: # get representation from io representation = legacy_io.find_one({ @@ -1083,29 +1084,31 @@ def selection_changed_timeline(event): timeline_editor = event.sender selection = timeline_editor.selection() - selection = [ti for ti in selection - if isinstance(ti, hiero.core.TrackItem)] + track_items = get_track_items( + selection=selection, + track_type="video", + check_enabled=True, + check_locked=True, + check_tagged=True + ) # run checking function - sync_clip_name_to_data_asset(selection) - - # also mark old versions of loaded containers - check_inventory_versions() + sync_clip_name_to_data_asset(track_items) def before_project_save(event): track_items = get_track_items( - selected=False, track_type="video", check_enabled=True, check_locked=True, - check_tagged=True) + check_tagged=True + ) # run checking function sync_clip_name_to_data_asset(track_items) # also mark old versions of loaded containers - check_inventory_versions() + check_inventory_versions(track_items) def get_main_window(): From 733ad125b5798d01fe9dac9d3d24e6256d614386 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 19:56:15 +0200 Subject: [PATCH 194/350] Hiero: one frame diff during loading --- openpype/hosts/hiero/api/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/hiero/api/plugin.py b/openpype/hosts/hiero/api/plugin.py index 54e66bf99a..35e9d54810 100644 --- a/openpype/hosts/hiero/api/plugin.py +++ b/openpype/hosts/hiero/api/plugin.py @@ -500,7 +500,7 @@ class ClipLoader: track_item.setSource(clip) track_item.setSourceIn(self.handle_start) track_item.setTimelineIn(self.timeline_in) - track_item.setSourceOut(self.media_duration - self.handle_end) + track_item.setSourceOut((self.media_duration + 1) - self.handle_end) track_item.setTimelineOut(self.timeline_out) track_item.setPlaybackSpeed(1) self.active_track.addTrackItem(track_item) From 91af28612e367d412e70a20ece03481ed4b976e9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 20 May 2022 11:21:16 +0200 Subject: [PATCH 195/350] Hiero: poping found clip --- openpype/hosts/hiero/plugins/load/load_clip.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/hiero/plugins/load/load_clip.py b/openpype/hosts/hiero/plugins/load/load_clip.py index da4326c8c1..a3365253b3 100644 --- a/openpype/hosts/hiero/plugins/load/load_clip.py +++ b/openpype/hosts/hiero/plugins/load/load_clip.py @@ -3,10 +3,6 @@ from openpype.pipeline import ( get_representation_path, ) import openpype.hosts.hiero.api as phiero -# from openpype.hosts.hiero.api import plugin, lib -# reload(lib) -# reload(plugin) -# reload(phiero) class LoadClip(phiero.SequenceLoader): @@ -106,7 +102,7 @@ class LoadClip(phiero.SequenceLoader): name = container['name'] namespace = container['namespace'] track_item = phiero.get_track_items( - track_item_name=namespace) + track_item_name=namespace).pop() version = legacy_io.find_one({ "type": "version", "_id": representation["parent"] @@ -157,7 +153,7 @@ class LoadClip(phiero.SequenceLoader): # load clip to timeline and get main variables namespace = container['namespace'] track_item = phiero.get_track_items( - track_item_name=namespace) + track_item_name=namespace).pop() track = track_item.parent() # remove track item from track From 053287bc616f1370602383f2aa4891fe80358599 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 20:00:01 +0200 Subject: [PATCH 196/350] Hiero: better logging and improving code --- openpype/hosts/hiero/api/plugin.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/hiero/api/plugin.py b/openpype/hosts/hiero/api/plugin.py index 35e9d54810..174a25102f 100644 --- a/openpype/hosts/hiero/api/plugin.py +++ b/openpype/hosts/hiero/api/plugin.py @@ -1,4 +1,5 @@ import os +from pprint import pformat import re from copy import deepcopy @@ -400,7 +401,8 @@ class ClipLoader: # inject asset data to representation dict self._get_asset_data() - log.debug("__init__ self.data: `{}`".format(self.data)) + log.info("__init__ self.data: `{}`".format(pformat(self.data))) + log.info("__init__ options: `{}`".format(pformat(options))) # add active components to class if self.new_sequence: @@ -482,7 +484,9 @@ class ClipLoader: """ asset_name = self.context["representation"]["context"]["asset"] - self.data["assetData"] = openpype.get_asset(asset_name)["data"] + asset_doc = openpype.get_asset(asset_name) + log.debug("__ asset_doc: {}".format(pformat(asset_doc))) + self.data["assetData"] = asset_doc["data"] def _make_track_item(self, source_bin_item, audio=False): """ Create track item with """ @@ -527,7 +531,8 @@ class ClipLoader: if self.sequencial_load: last_track_item = lib.get_track_items( sequence_name=self.active_sequence.name(), - track_name=self.active_track.name()) + track_name=self.active_track.name() + ) if len(last_track_item) == 0: last_timeline_out = 0 else: @@ -541,6 +546,8 @@ class ClipLoader: self.timeline_in = int(self.data["assetData"]["clipIn"]) self.timeline_out = int(self.data["assetData"]["clipOut"]) + log.debug("__ self.timeline_in: {}".format(self.timeline_in)) + log.debug("__ self.timeline_out: {}".format(self.timeline_out)) # check if slate is included # either in version data families or by calculating frame diff slate_on = next( @@ -553,6 +560,7 @@ class ClipLoader: (self.timeline_out - self.timeline_in + 1) + self.handle_start + self.handle_end) < self.media_duration) + log.debug("__ slate_on: {}".format(slate_on)) # if slate is on then remove the slate frame from beginning if slate_on: self.media_duration -= 1 @@ -599,8 +607,8 @@ class Creator(LegacyCreator): rename_index = None def __init__(self, *args, **kwargs): - import openpype.hosts.hiero.api as phiero super(Creator, self).__init__(*args, **kwargs) + import openpype.hosts.hiero.api as phiero self.presets = openpype.get_current_project_settings()[ "hiero"]["create"].get(self.__class__.__name__, {}) @@ -609,7 +617,10 @@ class Creator(LegacyCreator): self.sequence = phiero.get_current_sequence() if (self.options or {}).get("useSelection"): - self.selected = phiero.get_track_items(selected=True) + timeline_selection = phiero.get_timeline_selection() + self.selected = phiero.get_track_items( + selection=timeline_selection + ) else: self.selected = phiero.get_track_items() @@ -716,6 +727,10 @@ class PublishClip: else: self.tag_data.update({"reviewTrack": None}) + log.debug("___ self.tag_data: {}".format( + pformat(self.tag_data) + )) + # create pype tag on track_item and add data lib.imprint(self.track_item, self.tag_data) From d27448e7e36d751f16b458bde328065706378092 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 20:42:29 +0200 Subject: [PATCH 197/350] Hiero: handles and slate detection - handles should be int - slate only if in families on version --- openpype/hosts/hiero/api/plugin.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/hiero/api/plugin.py b/openpype/hosts/hiero/api/plugin.py index 174a25102f..e3ec6f3cf1 100644 --- a/openpype/hosts/hiero/api/plugin.py +++ b/openpype/hosts/hiero/api/plugin.py @@ -524,9 +524,12 @@ class ClipLoader: self.handle_start = self.data["versionData"].get("handleStart") self.handle_end = self.data["versionData"].get("handleEnd") if self.handle_start is None: - self.handle_start = int(self.data["assetData"]["handleStart"]) + self.handle_start = self.data["assetData"]["handleStart"] if self.handle_end is None: - self.handle_end = int(self.data["assetData"]["handleEnd"]) + self.handle_end = self.data["assetData"]["handleEnd"] + + self.handle_start = int(self.handle_start) + self.handle_end = int(self.handle_end) if self.sequencial_load: last_track_item = lib.get_track_items( @@ -556,9 +559,7 @@ class ClipLoader: if "slate" in f), # if nothing was found then use default None # so other bool could be used - None) or bool(int( - (self.timeline_out - self.timeline_in + 1) - + self.handle_start + self.handle_end) < self.media_duration) + None) log.debug("__ slate_on: {}".format(slate_on)) # if slate is on then remove the slate frame from beginning From cac79e69031f5c9a0e082ad0b4117ce3b5339a78 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 20:42:53 +0200 Subject: [PATCH 198/350] Hiero: fix timewarp lookup to be list --- openpype/lib/editorial.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/lib/editorial.py b/openpype/lib/editorial.py index 1ee21deedc..5fe498bf6a 100644 --- a/openpype/lib/editorial.py +++ b/openpype/lib/editorial.py @@ -218,6 +218,7 @@ def get_media_range_with_retimes(otio_clip, handle_start, handle_end): "name": name } tw_node.update(metadata) + tw_node["lookup"] = list(lookup) # get first and last frame offsets offset_in += lookup[0] From ffe1bff6599e0de5c0e07b30b4878714bd26e91a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 21:06:11 +0200 Subject: [PATCH 199/350] Hiero: fix by reversing validation --- openpype/hosts/hiero/api/lib.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openpype/hosts/hiero/api/lib.py b/openpype/hosts/hiero/api/lib.py index d3e6441705..4dc8d26c2a 100644 --- a/openpype/hosts/hiero/api/lib.py +++ b/openpype/hosts/hiero/api/lib.py @@ -207,7 +207,7 @@ def get_track_items( if not isinstance(track_item, hiero.core.TrackItem): continue - if not _validate_all_atrributes( + if _validate_all_atrributes( track_item, track_item_name, track_name, @@ -1046,7 +1046,6 @@ def check_inventory_versions(track_items=None): # get all track items from current timeline for track_item in track_item: container = parse_container(track_item) - log.info("___> container: {}".format(pformat(container))) if container: # get representation from io representation = legacy_io.find_one({ From 15726cfef92bb465a794d7ccd3acb8cdc3e828bd Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 21:06:42 +0200 Subject: [PATCH 200/350] Hiero: simplify code for slate detection --- openpype/hosts/hiero/api/plugin.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/hiero/api/plugin.py b/openpype/hosts/hiero/api/plugin.py index e3ec6f3cf1..8c61baa04b 100644 --- a/openpype/hosts/hiero/api/plugin.py +++ b/openpype/hosts/hiero/api/plugin.py @@ -551,17 +551,11 @@ class ClipLoader: log.debug("__ self.timeline_in: {}".format(self.timeline_in)) log.debug("__ self.timeline_out: {}".format(self.timeline_out)) - # check if slate is included - # either in version data families or by calculating frame diff - slate_on = next( - # check iterate if slate is in families - (f for f in self.context["version"]["data"]["families"] - if "slate" in f), - # if nothing was found then use default None - # so other bool could be used - None) + # check if slate is included + slate_on = "slate" in self.context["version"]["data"]["families"] log.debug("__ slate_on: {}".format(slate_on)) + # if slate is on then remove the slate frame from beginning if slate_on: self.media_duration -= 1 @@ -581,7 +575,7 @@ class ClipLoader: # there were some cases were hiero was not creating it source_bin_item = None for item in self.active_bin.items(): - if self.data["clip_name"] in item.name(): + if self.data["clip_name"] == item.name(): source_bin_item = item if not source_bin_item: log.warning("Problem with created Source clip: `{}`".format( From 38d4c3fa67effbc25847ee8706c7a1714cfa54a8 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 21:17:14 +0200 Subject: [PATCH 201/350] Hiero: lib code refactory --- openpype/hosts/hiero/api/lib.py | 37 +++++++++++++-------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/openpype/hosts/hiero/api/lib.py b/openpype/hosts/hiero/api/lib.py index 4dc8d26c2a..758df43968 100644 --- a/openpype/hosts/hiero/api/lib.py +++ b/openpype/hosts/hiero/api/lib.py @@ -4,7 +4,6 @@ Host specific functions where host api is connected import contextlib import os -from pprint import pformat import re import sys import platform @@ -92,7 +91,7 @@ def get_current_sequence(name=None, new=False): if not sequence: # if nothing found create new with input name sequence = get_current_sequence(name, True) - elif not name and not new: + else: # if name is none and new is False then return current open sequence sequence = hiero.ui.activeSequence() @@ -189,7 +188,6 @@ def get_track_items( log.info("___ valid trackitem: {}".format(track_item)) return_list.append(track_item) - # collect all available active sequence track items if not return_list: sequence = get_current_sequence(name=sequence_name) @@ -311,7 +309,7 @@ def set_track_item_pype_tag(track_item, data=None): "editable": "0", "note": "OpenPype data container", "icon": "openpype_icon.png", - "metadata": {k: v for k, v in data.items()} + "metadata": dict(data.items()) } # get available pype tag if any _tag = get_track_item_pype_tag(track_item) @@ -369,7 +367,7 @@ def get_track_item_pype_data(track_item): log.warning(msg) value = v - data.update({key: value}) + data[key] = value return data @@ -938,32 +936,32 @@ def apply_colorspace_clips(): def is_overlapping(ti_test, ti_original, strict=False): - covering_exp = bool( + covering_exp = ( (ti_test.timelineIn() <= ti_original.timelineIn()) and (ti_test.timelineOut() >= ti_original.timelineOut()) ) - inside_exp = bool( + inside_exp = ( (ti_test.timelineIn() >= ti_original.timelineIn()) and (ti_test.timelineOut() <= ti_original.timelineOut()) ) - overlaying_right_exp = bool( + overlaying_right_exp = ( (ti_test.timelineIn() < ti_original.timelineOut()) and (ti_test.timelineOut() >= ti_original.timelineOut()) ) - overlaying_left_exp = bool( + overlaying_left_exp = ( (ti_test.timelineOut() > ti_original.timelineIn()) and (ti_test.timelineIn() <= ti_original.timelineIn()) ) - if not strict: + if strict: + return covering_exp + else: return any(( covering_exp, inside_exp, overlaying_right_exp, overlaying_left_exp )) - else: - return covering_exp def get_sequence_pattern_and_padding(file): @@ -981,17 +979,12 @@ def get_sequence_pattern_and_padding(file): """ foundall = re.findall( r"(#+)|(%\d+d)|(?<=[^a-zA-Z0-9])(\d+)(?=\.\w+$)", file) - if foundall: - found = sorted(list(set(foundall[0])))[-1] - - if "%" in found: - padding = int(re.findall(r"\d+", found)[-1]) - else: - padding = len(found) - - return found, padding - else: + if not foundall: return None, None + found = sorted(list(set(foundall[0])))[-1] + + padding = int(re.findall(r"\d+", found)[-1]) if "%" in found else len(found) + return found, padding def sync_clip_name_to_data_asset(track_items_list): From 90948931b08dba9e4698ffc45f6a3be307996853 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 19 May 2022 19:49:08 +0200 Subject: [PATCH 202/350] Hiero: removing old code From 61be6857603c8061283bcbed938f07c5bd525eee Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 20 May 2022 12:35:46 +0200 Subject: [PATCH 203/350] replaced persistent editors with added ability of any edit trigger --- .../tools/project_manager/project_manager/view.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/openpype/tools/project_manager/project_manager/view.py b/openpype/tools/project_manager/project_manager/view.py index 25174232bc..6f5b9dc3f7 100644 --- a/openpype/tools/project_manager/project_manager/view.py +++ b/openpype/tools/project_manager/project_manager/view.py @@ -139,6 +139,7 @@ class HierarchyView(QtWidgets.QTreeView): self.setAlternatingRowColors(True) self.setSelectionMode(HierarchyView.ExtendedSelection) self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) + self.setEditTriggers(HierarchyView.AllEditTriggers) column_delegates = {} column_key_to_index = {} @@ -301,16 +302,6 @@ class HierarchyView(QtWidgets.QTreeView): def rowsInserted(self, parent_index, start, end): super(HierarchyView, self).rowsInserted(parent_index, start, end) - for row in range(start, end + 1): - for key, column in self._column_key_to_index.items(): - if key not in self.persistent_columns: - continue - col_index = self._source_model.index(row, column, parent_index) - if bool( - self._source_model.flags(col_index) - & QtCore.Qt.ItemIsEditable - ): - self.openPersistentEditor(col_index) # Expand parent on insert if not self.isExpanded(parent_index): From 7c3fdcc633f80b73084b0fbf4ba6f51d4c8c8a71 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 20 May 2022 12:59:38 +0200 Subject: [PATCH 204/350] Hiero: tag should use deepcopy for metadata --- openpype/hosts/hiero/api/lib.py | 7 ++++--- openpype/hosts/hiero/api/tags.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/hiero/api/lib.py b/openpype/hosts/hiero/api/lib.py index 758df43968..5b2f6c814d 100644 --- a/openpype/hosts/hiero/api/lib.py +++ b/openpype/hosts/hiero/api/lib.py @@ -3,6 +3,7 @@ Host specific functions where host api is connected """ import contextlib +from copy import deepcopy import os import re import sys @@ -288,7 +289,7 @@ def get_track_item_pype_tag(track_item): return None for tag in _tags: # return only correct tag defined by global name - if tag.name() in self.pype_tag_name: + if tag.name() == self.pype_tag_name: return tag @@ -344,9 +345,9 @@ def get_track_item_pype_data(track_item): return None # get tag metadata attribute - tag_data = tag.metadata() + tag_data = deepcopy(dict(tag.metadata())) # convert tag metadata to normal keys names and values to correct types - for k, v in dict(tag_data).items(): + for k, v in tag_data.items(): key = k.replace("tag.", "") try: diff --git a/openpype/hosts/hiero/api/tags.py b/openpype/hosts/hiero/api/tags.py index 8877b92b9d..8c6ff2a77b 100644 --- a/openpype/hosts/hiero/api/tags.py +++ b/openpype/hosts/hiero/api/tags.py @@ -86,7 +86,7 @@ def update_tag(tag, data): # due to hiero bug we have to make sure keys which are not existent in # data are cleared of value by `None` - for _mk in mtd.keys(): + for _mk in mtd.dict().keys(): if _mk.replace("tag.", "") not in data_mtd.keys(): mtd.setValue(_mk, str(None)) From be9f6cf5c5ddd7e833f5dd5c31e690706767e493 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 20 May 2022 15:08:56 +0200 Subject: [PATCH 205/350] Hiero: frame difference issue --- openpype/hosts/hiero/api/otio/hiero_export.py | 2 +- openpype/hosts/hiero/api/plugin.py | 2 +- openpype/lib/editorial.py | 2 +- openpype/plugins/publish/collect_otio_frame_ranges.py | 8 ++++---- openpype/plugins/publish/collect_otio_subset_resources.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/hiero/api/otio/hiero_export.py b/openpype/hosts/hiero/api/otio/hiero_export.py index 46e1204324..1e4088d9c0 100644 --- a/openpype/hosts/hiero/api/otio/hiero_export.py +++ b/openpype/hosts/hiero/api/otio/hiero_export.py @@ -277,7 +277,7 @@ def create_otio_clip(track_item): # flip if speed is in minus source_in = track_item.sourceIn() if speed > 0 else track_item.sourceOut() - duration = int(track_item.duration()) - 1 + duration = int(track_item.duration()) fps = utils.get_rate(track_item) or self.project_fps name = track_item.name() diff --git a/openpype/hosts/hiero/api/plugin.py b/openpype/hosts/hiero/api/plugin.py index 8c61baa04b..add416d04e 100644 --- a/openpype/hosts/hiero/api/plugin.py +++ b/openpype/hosts/hiero/api/plugin.py @@ -504,7 +504,7 @@ class ClipLoader: track_item.setSource(clip) track_item.setSourceIn(self.handle_start) track_item.setTimelineIn(self.timeline_in) - track_item.setSourceOut((self.media_duration + 1) - self.handle_end) + track_item.setSourceOut((self.media_duration) - self.handle_end) track_item.setTimelineOut(self.timeline_out) track_item.setPlaybackSpeed(1) self.active_track.addTrackItem(track_item) diff --git a/openpype/lib/editorial.py b/openpype/lib/editorial.py index 5fe498bf6a..2c877b9d0d 100644 --- a/openpype/lib/editorial.py +++ b/openpype/lib/editorial.py @@ -255,7 +255,7 @@ def get_media_range_with_retimes(otio_clip, handle_start, handle_end): media_in + source_in + offset_in) media_out_trimmed = ( media_in + source_in + ( - (source_range.duration.value * abs( + ((source_range.duration.value - 1) * abs( time_scalar)) + offset_out)) # calculate available handles diff --git a/openpype/plugins/publish/collect_otio_frame_ranges.py b/openpype/plugins/publish/collect_otio_frame_ranges.py index ee7b7957ad..8eaf9d6f29 100644 --- a/openpype/plugins/publish/collect_otio_frame_ranges.py +++ b/openpype/plugins/publish/collect_otio_frame_ranges.py @@ -55,13 +55,13 @@ class CollectOtioFrameRanges(pyblish.api.InstancePlugin): "frameStart": frame_start, "frameEnd": frame_end, "clipIn": tl_start, - "clipOut": tl_end, + "clipOut": tl_end - 1, "clipInH": tl_start_h, - "clipOutH": tl_end_h, + "clipOutH": tl_end_h - 1, "sourceStart": src_starting_from + src_start, - "sourceEnd": src_starting_from + src_end, + "sourceEnd": src_starting_from + src_end - 1, "sourceStartH": src_starting_from + src_start_h, - "sourceEndH": src_starting_from + src_end_h, + "sourceEndH": src_starting_from + src_end_h - 1, } instance.data.update(data) self.log.debug( diff --git a/openpype/plugins/publish/collect_otio_subset_resources.py b/openpype/plugins/publish/collect_otio_subset_resources.py index 7c11462ef0..b89a076a44 100644 --- a/openpype/plugins/publish/collect_otio_subset_resources.py +++ b/openpype/plugins/publish/collect_otio_subset_resources.py @@ -66,7 +66,7 @@ class CollectOtioSubsetResources(pyblish.api.InstancePlugin): # create trimmed otio time range trimmed_media_range_h = editorial.range_from_frames( - a_frame_start_h, (a_frame_end_h - a_frame_start_h + 1), + a_frame_start_h, (a_frame_end_h - a_frame_start_h) + 1, media_fps ) trimmed_duration = trimmed_media_range_h.duration.value From 4c4c824d8084247c2b0ed550579849fe9b503247 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 20 May 2022 15:22:23 +0200 Subject: [PATCH 206/350] :recycle: refactored work with attributes --- .../maya/plugins/publish/collect_look.py | 153 +++++++++--------- 1 file changed, 81 insertions(+), 72 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_look.py b/openpype/hosts/maya/plugins/publish/collect_look.py index 123e2637cb..fb2ce04cad 100644 --- a/openpype/hosts/maya/plugins/publish/collect_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_look.py @@ -23,33 +23,43 @@ RENDERER_NODE_TYPES = [ "RedshiftMeshParameters" ] SHAPE_ATTRS = set(SHAPE_ATTRS) -DEFAULT_FILE_NODES = frozenset( - ["file"] -) -ARNOLD_FILE_NODES = frozenset( - ["aiImage"] -) -REDSHIFT_FILE_NODES = frozenset( - ["RedshiftNormalMap"] -) -RENDERMAN_FILE_NODES = frozenset( - [ - "PxrBump", - "PxrNormalMap", - # PxrMultiTexture (need to handle multiple filename0 attrs) - "PxrPtexture", - "PxrTexture", - ] -) -NODES_WITH_FILE = frozenset().union( - DEFAULT_FILE_NODES -) -NODES_WITH_FILENAME = frozenset().union( - ARNOLD_FILE_NODES, RENDERMAN_FILE_NODES -) -NODES_WITH_TEX = frozenset().union( - REDSHIFT_FILE_NODES -) + + +def get_pxr_multitexture_file_attrs(node): + attrs = [] + for i in range(9): + if cmds.attributeQuery("filename{}".format(i), node): + file = cmds.getAttr("{}.filename{}".format(node, i)) + if file: + attrs.append("filename{}".format(i)) + return attrs + + +FILE_NODES = { + "file": "fileTextureName", + + "aiImage": "filename", + + "RedshiftNormalMap": "text0", + + "PxrBump": "filename", + "PxrNormalMap": "filename", + "PxrMultiTexture": get_pxr_multitexture_file_attrs, + "PxrPtexture": "filename", + "PxrTexture": "filename" +} + + +def get_attributes(dictionary, attr): + # type: (dict, str) -> list + if callable(dictionary[attr]): + val = dictionary[attr]() + else: + val = dictionary.get(attr, []) + + if not isinstance(val, list): + return [val] + return val def get_look_attrs(node): @@ -77,15 +87,13 @@ def get_look_attrs(node): if cmds.objectType(node, isAType="shape"): attrs = cmds.listAttr(node, changedSinceFileOpen=True) or [] for attr in attrs: - if attr in SHAPE_ATTRS: + if attr in SHAPE_ATTRS or \ + attr not in SHAPE_ATTRS and attr.startswith('ai'): result.append(attr) - elif attr.startswith('ai'): - result.append(attr) - return result -def node_uses_image_sequence(node): +def node_uses_image_sequence(node, node_path): # type: (str) -> bool """Return whether file node uses an image sequence or single image. @@ -101,8 +109,6 @@ def node_uses_image_sequence(node): """ # useFrameExtension indicates an explicit image sequence - node_path = get_file_node_path(node).lower() - # The following tokens imply a sequence patterns = ["", "", "", "u_v", ""] @@ -169,14 +175,15 @@ def seq_to_glob(path): return path -def get_file_node_path(node): +def get_file_node_paths(node): + # type: (str) -> list """Get the file path used by a Maya file node. Args: node (str): Name of the Maya file node Returns: - str: the file path in use + list: the file paths in use """ # if the path appears to be sequence, use computedFileTextureNamePattern, @@ -195,15 +202,19 @@ def get_file_node_path(node): ""] lower = texture_pattern.lower() if any(pattern in lower for pattern in patterns): - return texture_pattern + return [texture_pattern] - if cmds.nodeType(node) in NODES_WITH_FILENAME: - return cmds.getAttr('{0}.filename'.format(node)) - if cmds.nodeType(node) == 'RedshiftNormalMap': - return cmds.getAttr('{}.tex0'.format(node)) + try: + file_attributes = get_attributes(FILE_NODES, cmds.nodeType(node)) + except AttributeError: + file_attributes = "fileTextureName" - # otherwise use fileTextureName - return cmds.getAttr('{0}.fileTextureName'.format(node)) + files = [] + for file_attr in file_attributes: + if cmds.attributeQuery(file_attr, node=node, exists=True): + files.append(cmds.getAttr("{}.{}".format(node, file_attr))) + + return files def get_file_node_files(node): @@ -217,16 +228,21 @@ def get_file_node_files(node): list: List of full file paths. """ + paths = get_file_node_paths(node) + sequences = [] + replaces = [] + for index, path in enumerate(paths): + if node_uses_image_sequence(node, path): + glob_pattern = seq_to_glob(path) + sequences.extend(glob.glob(glob_pattern)) + replaces.append(index) - path = get_file_node_path(node) - path = cmds.workspace(expandName=path) - if node_uses_image_sequence(node): - glob_pattern = seq_to_glob(path) - return glob.glob(glob_pattern) - elif os.path.exists(path): - return [path] - else: - return [] + for index in replaces: + paths.pop(index) + + paths.extend(sequences) + + return [p for p in paths if os.path.exists(p)] class CollectLook(pyblish.api.InstancePlugin): @@ -270,13 +286,13 @@ class CollectLook(pyblish.api.InstancePlugin): "for %s" % instance.data['name']) # Discover related object sets - self.log.info("Gathering sets..") + self.log.info("Gathering sets ...") sets = self.collect_sets(instance) # Lookup set (optimization) instance_lookup = set(cmds.ls(instance, long=True)) - self.log.info("Gathering set relations..") + self.log.info("Gathering set relations ...") # Ensure iteration happen in a list so we can remove keys from the # dict within the loop @@ -409,10 +425,7 @@ class CollectLook(pyblish.api.InstancePlugin): or [] ) - all_supported_nodes = set().union( - DEFAULT_FILE_NODES, ARNOLD_FILE_NODES, REDSHIFT_FILE_NODES, - RENDERMAN_FILE_NODES - ) + all_supported_nodes = FILE_NODES.keys() files = [] for node_type in all_supported_nodes: files.extend(cmds.ls(history, type=node_type, long=True)) @@ -550,27 +563,23 @@ class CollectLook(pyblish.api.InstancePlugin): dict """ self.log.debug("processing: {}".format(node)) - all_supported_nodes = set().union( - DEFAULT_FILE_NODES, ARNOLD_FILE_NODES, REDSHIFT_FILE_NODES, - RENDERMAN_FILE_NODES - ) + all_supported_nodes = FILE_NODES.keys() if cmds.nodeType(node) not in all_supported_nodes: self.log.error( "Unsupported file node: {}".format(cmds.nodeType(node))) raise AssertionError("Unsupported file node") self.log.debug(" - got {}".format(cmds.nodeType(node))) - if cmds.nodeType(node) in NODES_WITH_FILE: - attribute = "{}.fileTextureName".format(node) - computed_attribute = "{}.computedFileTextureNamePattern".format(node) - elif cmds.nodeType(node) in NODES_WITH_FILENAME: - attribute = "{}.filename".format(node) - computed_attribute = attribute - elif cmds.nodeType(node) in NODES_WITH_TEX: - attribute = "{}.tex0".format(node) - computed_attribute = attribute - source = cmds.getAttr(attribute) + attribute = FILE_NODES.get(cmds.nodeType(node)) + source = cmds.getAttr("{}.{}".format( + node, + attribute + )) + computed_attribute = "{}.{}".format(node, attribute) + if attribute == "fileTextureName": + computed_attribute = node + ".computedFileTextureNamePattern" + self.log.info(" - file source: {}".format(source)) color_space_attr = "{}.colorSpace".format(node) try: From f35079aaed7eb74ccca74645c800d20d8f225801 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 20 May 2022 16:18:39 +0200 Subject: [PATCH 207/350] global: remove exclude family for `clip` --- openpype/plugins/publish/integrate_new.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/integrate_new.py b/openpype/plugins/publish/integrate_new.py index bf13a4050e..353314fff2 100644 --- a/openpype/plugins/publish/integrate_new.py +++ b/openpype/plugins/publish/integrate_new.py @@ -113,7 +113,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): "usdOverride", "simpleUnrealTexture" ] - exclude_families = ["clip", "render.farm"] + exclude_families = ["render.farm"] db_representation_context_keys = [ "project", "asset", "task", "subset", "version", "representation", "family", "hierarchy", "task", "username" From 87182f5a3e66cbae791f49c2f8cc0692f8dff3bf Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 20 May 2022 17:00:48 +0200 Subject: [PATCH 208/350] global: otio duration is one frame longer --- openpype/plugins/publish/extract_otio_trimming_video.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/extract_otio_trimming_video.py b/openpype/plugins/publish/extract_otio_trimming_video.py index 30b57e2c69..e8e2994f36 100644 --- a/openpype/plugins/publish/extract_otio_trimming_video.py +++ b/openpype/plugins/publish/extract_otio_trimming_video.py @@ -80,7 +80,7 @@ class ExtractOTIOTrimmingVideo(openpype.api.Extractor): video_path = input_file_path frame_start = otio_range.start_time.value input_fps = otio_range.start_time.rate - frame_duration = (otio_range.duration.value + 1) + frame_duration = otio_range.duration.value - 1 sec_start = openpype.lib.frames_to_secons(frame_start, input_fps) sec_duration = openpype.lib.frames_to_secons(frame_duration, input_fps) From 7b65184389640165d7268996dc069600722fe60f Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 20 May 2022 17:45:15 +0200 Subject: [PATCH 209/350] OP-2787 - replaced target farm with remote Target farm is being used for rendering, this should better differentiate it. --- openpype/hosts/maya/api/pipeline.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/api/pipeline.py b/openpype/hosts/maya/api/pipeline.py index b75af29523..c2fe8a95a5 100644 --- a/openpype/hosts/maya/api/pipeline.py +++ b/openpype/hosts/maya/api/pipeline.py @@ -73,8 +73,8 @@ def install(): "save/open/new callback installation..")) # Register default "local" target - print("Registering pyblish target: farm") - pyblish.api.register_target("farm") + print("Registering pyblish target: remote") + pyblish.api.register_target("remote") return print("Registering pyblish target: local") From c3e13a9e198a7082439588d6b3f6550bbdf98675 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 20 May 2022 18:07:26 +0200 Subject: [PATCH 210/350] modules have ability to modify environments before launch --- openpype/lib/applications.py | 33 ++++++++++++++++++++++++++++----- openpype/modules/base.py | 19 +++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index 6ade33b59c..a81bdeca0f 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -1282,7 +1282,13 @@ class EnvironmentPrepData(dict): def get_app_environments_for_context( - project_name, asset_name, task_name, app_name, env_group=None, env=None + project_name, + asset_name, + task_name, + app_name, + env_group=None, + env=None, + modules_manager=None ): """Prepare environment variables by context. Args: @@ -1293,10 +1299,12 @@ def get_app_environments_for_context( by ApplicationManager. env (dict): Initial environment variables. `os.environ` is used when not passed. + modules_manager (ModulesManager): Initialized modules manager. Returns: dict: Environments for passed context and application. """ + from openpype.pipeline import AvalonMongoDB # Avalon database connection @@ -1311,6 +1319,11 @@ def get_app_environments_for_context( "name": asset_name }) + if modules_manager is None: + from openpype.modules import ModulesManager + + modules_manager = ModulesManager() + # Prepare app object which can be obtained only from ApplciationManager app_manager = ApplicationManager() app = app_manager.applications[app_name] @@ -1334,7 +1347,7 @@ def get_app_environments_for_context( "env": env }) - prepare_app_environments(data, env_group) + prepare_app_environments(data, env_group, modules_manager) prepare_context_environments(data, env_group) # Discard avalon connection @@ -1355,9 +1368,12 @@ def _merge_env(env, current_env): return result -def _add_python_version_paths(app, env, logger): +def _add_python_version_paths(app, env, logger, modules_manager): """Add vendor packages specific for a Python version.""" + for module in modules_manager.get_enabled_modules(): + module.modify_application_launch_arguments(app, env) + # Skip adding if host name is not set if not app.host_name: return @@ -1390,7 +1406,9 @@ def _add_python_version_paths(app, env, logger): env["PYTHONPATH"] = os.pathsep.join(python_paths) -def prepare_app_environments(data, env_group=None, implementation_envs=True): +def prepare_app_environments( + data, env_group=None, implementation_envs=True, modules_manager=None +): """Modify launch environments based on launched app and context. Args: @@ -1403,7 +1421,12 @@ def prepare_app_environments(data, env_group=None, implementation_envs=True): log = data["log"] source_env = data["env"].copy() - _add_python_version_paths(app, source_env, log) + if modules_manager is None: + from openpype.modules import ModulesManager + + modules_manager = ModulesManager() + + _add_python_version_paths(app, source_env, log, modules_manager) # Use environments from local settings filtered_local_envs = {} diff --git a/openpype/modules/base.py b/openpype/modules/base.py index 5b49649359..d591df6768 100644 --- a/openpype/modules/base.py +++ b/openpype/modules/base.py @@ -370,6 +370,7 @@ def _load_modules(): class _OpenPypeInterfaceMeta(ABCMeta): """OpenPypeInterface meta class to print proper string.""" + def __str__(self): return "<'OpenPypeInterface.{}'>".format(self.__name__) @@ -388,6 +389,7 @@ class OpenPypeInterface: OpenPype modules which means they have to have implemented methods defined in the interface. By default interface does not have any abstract parts. """ + pass @@ -432,10 +434,12 @@ class OpenPypeModule: It is not recommended to override __init__ that's why specific method was implemented. """ + pass def connect_with_modules(self, enabled_modules): """Connect with other enabled modules.""" + pass def get_global_environments(self): @@ -443,8 +447,22 @@ class OpenPypeModule: Environment variables that can be get only from system settings. """ + return {} + def modify_application_launch_arguments(self, app, env): + """Give option to modify launch environments before application launch. + + Implementation is optional. To change environments modify passed + dictionary of environments. + + Args: + app (Application): Application that is launcher. + env (dict): Current environemnt variables. + """ + + pass + def cli(self, module_click_group): """Add commands to click group. @@ -465,6 +483,7 @@ class OpenPypeModule: def mycommand(): print("my_command") """ + pass From 6fc240734c799a37c349f7a6e8945f7feea50ab5 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 20 May 2022 18:10:40 +0200 Subject: [PATCH 211/350] ftrack module modify application launch environments in module instead of in prelaunch hook --- openpype/modules/base.py | 4 +- openpype/modules/ftrack/ftrack_module.py | 34 +++++++++++++++ .../ftrack/launch_hooks/pre_python2_vendor.py | 43 ------------------- 3 files changed, 36 insertions(+), 45 deletions(-) delete mode 100644 openpype/modules/ftrack/launch_hooks/pre_python2_vendor.py diff --git a/openpype/modules/base.py b/openpype/modules/base.py index d591df6768..96c1b84a54 100644 --- a/openpype/modules/base.py +++ b/openpype/modules/base.py @@ -450,14 +450,14 @@ class OpenPypeModule: return {} - def modify_application_launch_arguments(self, app, env): + def modify_application_launch_arguments(self, application, env): """Give option to modify launch environments before application launch. Implementation is optional. To change environments modify passed dictionary of environments. Args: - app (Application): Application that is launcher. + application (Application): Application that is launched. env (dict): Current environemnt variables. """ diff --git a/openpype/modules/ftrack/ftrack_module.py b/openpype/modules/ftrack/ftrack_module.py index 5c38df2e03..f99e189082 100644 --- a/openpype/modules/ftrack/ftrack_module.py +++ b/openpype/modules/ftrack/ftrack_module.py @@ -88,6 +88,40 @@ class FtrackModule( """Implementation of `ILaunchHookPaths`.""" return os.path.join(FTRACK_MODULE_DIR, "launch_hooks") + def modify_application_launch_arguments(self, application, env): + if not application.use_python_2: + return + + self.log.info("Adding Ftrack Python 2 packages to PYTHONPATH.") + + # Prepare vendor dir path + python_2_vendor = os.path.join(FTRACK_MODULE_DIR, "python2_vendor") + + # Add Python 2 modules + python_paths = [ + # `python-ftrack-api` + os.path.join(python_2_vendor, "ftrack-python-api", "source"), + # `arrow` + os.path.join(python_2_vendor, "arrow"), + # `builtins` from `python-future` + # - `python-future` is strict Python 2 module that cause crashes + # of Python 3 scripts executed through OpenPype + # (burnin script etc.) + os.path.join(python_2_vendor, "builtins"), + # `backports.functools_lru_cache` + os.path.join( + python_2_vendor, "backports.functools_lru_cache" + ) + ] + + # Load PYTHONPATH from current launch context + python_path = env.get("PYTHONPATH") + if python_path: + python_paths.append(python_path) + + # Set new PYTHONPATH to launch context environments + env["PYTHONPATH"] = os.pathsep.join(python_paths) + def connect_with_modules(self, enabled_modules): for module in enabled_modules: if not hasattr(module, "get_ftrack_event_handler_paths"): diff --git a/openpype/modules/ftrack/launch_hooks/pre_python2_vendor.py b/openpype/modules/ftrack/launch_hooks/pre_python2_vendor.py deleted file mode 100644 index 0dd894bebf..0000000000 --- a/openpype/modules/ftrack/launch_hooks/pre_python2_vendor.py +++ /dev/null @@ -1,43 +0,0 @@ -import os -from openpype.lib import PreLaunchHook -from openpype_modules.ftrack import FTRACK_MODULE_DIR - - -class PrePython2Support(PreLaunchHook): - """Add python ftrack api module for Python 2 to PYTHONPATH. - - Path to vendor modules is added to the beggining of PYTHONPATH. - """ - - def execute(self): - if not self.application.use_python_2: - return - - self.log.info("Adding Ftrack Python 2 packages to PYTHONPATH.") - - # Prepare vendor dir path - python_2_vendor = os.path.join(FTRACK_MODULE_DIR, "python2_vendor") - - # Add Python 2 modules - python_paths = [ - # `python-ftrack-api` - os.path.join(python_2_vendor, "ftrack-python-api", "source"), - # `arrow` - os.path.join(python_2_vendor, "arrow"), - # `builtins` from `python-future` - # - `python-future` is strict Python 2 module that cause crashes - # of Python 3 scripts executed through OpenPype (burnin script etc.) - os.path.join(python_2_vendor, "builtins"), - # `backports.functools_lru_cache` - os.path.join( - python_2_vendor, "backports.functools_lru_cache" - ) - ] - - # Load PYTHONPATH from current launch context - python_path = self.launch_context.env.get("PYTHONPATH") - if python_path: - python_paths.append(python_path) - - # Set new PYTHONPATH to launch context environments - self.launch_context.env["PYTHONPATH"] = os.pathsep.join(python_paths) From 38d58182fc9f7d908eca61ab573b7562d1e8af97 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 20 May 2022 18:44:11 +0200 Subject: [PATCH 212/350] OP-2787 - added updating of script url Remote publish requires path to script which is known only on DL node. Injection of env var is required for remote publish. --- .../repository/custom/plugins/GlobalJobPreLoad.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py b/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py index eeb1f7744c..bcd853f374 100644 --- a/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py +++ b/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py @@ -87,6 +87,13 @@ def inject_openpype_environment(deadlinePlugin): for key, value in contents.items(): deadlinePlugin.SetProcessEnvironmentVariable(key, value) + script_url = job.GetJobPluginInfoKeyValue("ScriptFilename") + if script_url: + + script_url = script_url.format(**contents).replace("\\", "/") + print(">>> Setting script path {}".format(script_url)) + job.SetJobPluginInfoKeyValue("ScriptFilename", script_url) + print(">>> Removing temporary file") os.remove(export_url) @@ -196,16 +203,19 @@ def __main__(deadlinePlugin): job.GetJobEnvironmentKeyValue('OPENPYPE_RENDER_JOB') or '0' openpype_publish_job = \ job.GetJobEnvironmentKeyValue('OPENPYPE_PUBLISH_JOB') or '0' + openpype_remote_job = \ + job.GetJobEnvironmentKeyValue('OPENPYPE_REMOTE_JOB') or '0' print("--- Job type - render {}".format(openpype_render_job)) print("--- Job type - publish {}".format(openpype_publish_job)) + print("--- Job type - remote {}".format(openpype_remote_job)) if openpype_publish_job == '1' and openpype_render_job == '1': raise RuntimeError("Misconfiguration. Job couldn't be both " + "render and publish.") if openpype_publish_job == '1': inject_render_job_id(deadlinePlugin) - elif openpype_render_job == '1': + elif openpype_render_job == '1' or openpype_remote_job == '1': inject_openpype_environment(deadlinePlugin) else: pype(deadlinePlugin) # backward compatibility with Pype2 From 529c31c4f912d66bece87a17eb597c1ec5dd86ad Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 20 May 2022 19:02:17 +0200 Subject: [PATCH 213/350] OP-2787 - updated validator Checks for exactly 1 out set. --- .../hosts/maya/plugins/publish/validate_animation_content.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openpype/hosts/maya/plugins/publish/validate_animation_content.py b/openpype/hosts/maya/plugins/publish/validate_animation_content.py index bcea761a01..7638c44b87 100644 --- a/openpype/hosts/maya/plugins/publish/validate_animation_content.py +++ b/openpype/hosts/maya/plugins/publish/validate_animation_content.py @@ -30,6 +30,10 @@ class ValidateAnimationContent(pyblish.api.InstancePlugin): assert 'out_hierarchy' in instance.data, "Missing `out_hierarchy` data" + out_sets = [node for node in instance if node.endswith("out_SET")] + msg = "Couldn't find exactly one out_SET: {0}".format(out_sets) + assert len(out_sets) == 1, msg + # All nodes in the `out_hierarchy` must be among the nodes that are # in the instance. The nodes in the instance are found from the top # group, as such this tests whether all nodes are under that top group. From 62ac633da95772488f94ea4b9d53c2c5a74e9b9c Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 20 May 2022 19:05:35 +0200 Subject: [PATCH 214/350] OP-2787 - used settings from ProcessSubmittedJobOnFarm --- .../submit_maya_remote_publish_deadline.py | 67 +++++++++---------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py index 761bc8cc95..b11698f8e8 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py @@ -4,18 +4,22 @@ import requests from maya import cmds from openpype.pipeline import legacy_io +from openpype.settings import get_project_settings import pyblish.api -class MayaSubmitRemotePublishDeadline(pyblish.api.ContextPlugin): +class MayaSubmitRemotePublishDeadline(pyblish.api.InstancePlugin): """Submit Maya scene to perform a local publish in Deadline. Publishing in Deadline can be helpful for scenes that publish very slow. This way it can process in the background on another machine without the Artist having to wait for the publish to finish on their local machine. - Submission is done through the Deadline Web Service. + Submission is done through the Deadline Web Service. DL then triggers + `openpype/scripts/remote_publish.py`. + + Each publishable instance creates its own full publish job. Different from `ProcessSubmittedJobOnFarm` which creates publish job depending on metadata json containing context and instance data of @@ -27,31 +31,24 @@ class MayaSubmitRemotePublishDeadline(pyblish.api.ContextPlugin): hosts = ["maya"] families = ["deadline"] - # custom deadline attributes - deadline_department = "" - deadline_pool = "" - deadline_pool_secondary = "" - deadline_group = "" - deadline_chunk_size = 1 - deadline_priority = 50 - - def process(self, context): + def process(self, instance): + settings = get_project_settings(os.getenv("AVALON_PROJECT")) + # use setting for publish job on farm, no reason to have it separately + deadline_publish_job_sett = (settings["deadline"] + ["publish"] + ["ProcessSubmittedJobOnFarm"]) # Ensure no errors so far - assert all(result["success"] for result in context.data["results"]), ( - "Errors found, aborting integration..") + assert (all(result["success"] + for result in instance.context.data["results"]), + ("Errors found, aborting integration..")) - # Note that `publish` data member might change in the future. - # See: https://github.com/pyblish/pyblish-base/issues/307 - actives = [i for i in context if i.data["publish"]] - instance_names = sorted(instance.name for instance in actives) - - if not instance_names: + if not instance.data["publish"]: self.log.warning("No active instances found. " "Skipping submission..") return - scene = context.data["currentFile"] + scene = instance.context.data["currentFile"] scenename = os.path.basename(scene) # Get project code @@ -66,17 +63,15 @@ class MayaSubmitRemotePublishDeadline(pyblish.api.ContextPlugin): "JobInfo": { "Plugin": "MayaBatch", "BatchName": batch_name, - "Priority": 50, "Name": job_name, - "UserName": context.data["user"], - # "Comment": instance.context.data.get("comment", ""), + "UserName": instance.context.data["user"], + "Comment": instance.context.data.get("comment", ""), # "InitialStatus": state - "Department": self.deadline_department, - "ChunkSize": self.deadline_chunk_size, - "Priority": self.deadline_priority, - - "Group": self.deadline_group, - + "Department": deadline_publish_job_sett["deadline_department"], + "ChunkSize": deadline_publish_job_sett["deadline_chunk_size"], + "Priority": deadline_publish_job_sett["deadline_priority"], + "Group": deadline_publish_job_sett["deadline_group"], + "Pool": deadline_publish_job_sett["deadline_pool"], }, "PluginInfo": { @@ -86,7 +81,7 @@ class MayaSubmitRemotePublishDeadline(pyblish.api.ContextPlugin): # Inputs "SceneFile": scene, - "ScriptFilename": "{OPENPYPE_ROOT}/scripts/remote_publish.py", + "ScriptFilename": "{OPENPYPE_REPOS_ROOT}/openpype/scripts/remote_publish.py", # noqa # Mandatory for Deadline "Version": cmds.about(version=True), @@ -116,10 +111,9 @@ class MayaSubmitRemotePublishDeadline(pyblish.api.ContextPlugin): environment["AVALON_TASK"] = legacy_io.Session["AVALON_TASK"] environment["AVALON_APP_NAME"] = os.environ.get("AVALON_APP_NAME") environment["OPENPYPE_LOG_NO_COLORS"] = "1" - environment["OPENPYPE_USERNAME"] = context.data["user"] - environment["OPENPYPE_PUBLISH_JOB"] = "1" - environment["OPENPYPE_RENDER_JOB"] = "0" - environment["PYBLISH_ACTIVE_INSTANCES"] = ",".join(instance_names) + environment["OPENPYPE_REMOTE_JOB"] = "1" + environment["OPENPYPE_USERNAME"] = instance.context.data["user"] + environment["OPENPYPE_PUBLISH_SUBSET"] = instance.data["subset"] payload["JobInfo"].update({ "EnvironmentKeyValue%d" % index: "{key}={value}".format( @@ -129,7 +123,10 @@ class MayaSubmitRemotePublishDeadline(pyblish.api.ContextPlugin): }) self.log.info("Submitting Deadline job ...") - deadline_url = context.data["defaultDeadline"] + deadline_url = instance.context.data["defaultDeadline"] + # if custom one is set in instance, use that + if instance.data.get("deadlineUrl"): + deadline_url = instance.data.get("deadlineUrl") assert deadline_url, "Requires Deadline Webservice URL" url = "{}/api/jobs".format(deadline_url) response = requests.post(url, json=payload, timeout=10) From bf75d18a7b6852415cbb71b69a8a6a05c0ea3754 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 20 May 2022 19:07:21 +0200 Subject: [PATCH 215/350] OP-2787 - added collector for remote publishable instances Filters instances from a workfile and marks only these that should be published on a farm. --- .../publish/collect_publishable_instances.py | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 openpype/modules/deadline/plugins/publish/collect_publishable_instances.py diff --git a/openpype/modules/deadline/plugins/publish/collect_publishable_instances.py b/openpype/modules/deadline/plugins/publish/collect_publishable_instances.py new file mode 100644 index 0000000000..9a467428fd --- /dev/null +++ b/openpype/modules/deadline/plugins/publish/collect_publishable_instances.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +"""Collect instances that should be processed and published on DL. + +""" +import os + +import pyblish.api + + +class CollectDeadlinePublishableInstances(pyblish.api.InstancePlugin): + """Collect instances that should be processed and published on DL. + + Some long running publishes (not just renders) could be offloaded to DL, + this plugin compares theirs name against env variable, marks only + publishable by farm. + + Triggered only when running only in headless mode, eg on a farm. + """ + + order = pyblish.api.CollectorOrder + 0.499 + label = "Collect Deadline Publishable Instance" + targets = ["remote"] + + def process(self, instance): + self.log.debug("CollectDeadlinePublishableInstances") + publish_inst = os.environ.get("OPENPYPE_PUBLISH_SUBSET", '') + assert (publish_inst, + "OPENPYPE_PUBLISH_SUBSET env var required for " + "remote publishing") + + subset_name = instance.data["subset"] + if subset_name == publish_inst: + self.log.debug("Publish {}".format(subset_name)) + instance.data["publish"] = True + instance.data["farm"] = False + instance.data["families"].remove("deadline") + else: + self.log.debug("Skipping {}".format(subset_name)) + instance.data["publish"] = False From 72d8633266048ba19b78d425c879aa0325ba042b Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 20 May 2022 19:09:35 +0200 Subject: [PATCH 216/350] OP-2787 - changed flag from family to farm It probably makes more sense to check specific flag than a family. --- openpype/plugins/publish/integrate_new.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/plugins/publish/integrate_new.py b/openpype/plugins/publish/integrate_new.py index 1a4112107a..b5a7f11904 100644 --- a/openpype/plugins/publish/integrate_new.py +++ b/openpype/plugins/publish/integrate_new.py @@ -139,7 +139,8 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): ef, instance.data["family"], instance.data["families"])) return - if "deadline" in instance.data["families"]: + # instance should be published on a farm + if instance.data["farm"]: return self.integrated_file_sizes = {} From 6b71ff1909c3d32e5bebc0595580f1dcde1c1180 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 20 May 2022 19:25:55 +0200 Subject: [PATCH 217/350] OP-2787 - removed deadline family deadline family is not used anymore anywhere, filtering on integrate is being done on instance.data["farm"] flag. --- .../maya/plugins/publish/collect_animation.py | 3 --- .../maya/plugins/publish/collect_pointcache.py | 14 -------------- 2 files changed, 17 deletions(-) delete mode 100644 openpype/hosts/maya/plugins/publish/collect_pointcache.py diff --git a/openpype/hosts/maya/plugins/publish/collect_animation.py b/openpype/hosts/maya/plugins/publish/collect_animation.py index b442113fbc..9b1e38fd0a 100644 --- a/openpype/hosts/maya/plugins/publish/collect_animation.py +++ b/openpype/hosts/maya/plugins/publish/collect_animation.py @@ -55,6 +55,3 @@ class CollectAnimationOutputGeometry(pyblish.api.InstancePlugin): # Store data in the instance for the validator instance.data["out_hierarchy"] = hierarchy - - if instance.data.get("farm"): - instance.data["families"].append("deadline") diff --git a/openpype/hosts/maya/plugins/publish/collect_pointcache.py b/openpype/hosts/maya/plugins/publish/collect_pointcache.py deleted file mode 100644 index b55babe372..0000000000 --- a/openpype/hosts/maya/plugins/publish/collect_pointcache.py +++ /dev/null @@ -1,14 +0,0 @@ -import pyblish.api - - -class CollectPointcache(pyblish.api.InstancePlugin): - """Collect pointcache data for instance.""" - - order = pyblish.api.CollectorOrder + 0.4 - families = ["pointcache"] - label = "Collect Pointcache" - hosts = ["maya"] - - def process(self, instance): - if instance.data.get("farm"): - instance.data["families"].append("deadline") \ No newline at end of file From a176228396083c4eefc1de798c579c67ff65fd4d Mon Sep 17 00:00:00 2001 From: Jiri Sindelar <45896205+jrsndl@users.noreply.github.com> Date: Mon, 23 May 2022 13:19:53 +0200 Subject: [PATCH 218/350] Update openpype/plugins/publish/extract_review_slate.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/plugins/publish/extract_review_slate.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 832799601c..52d988a6b0 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -130,8 +130,9 @@ class ExtractReviewSlate(openpype.api.Extractor): input_audio = True break # Get duration of one frame in micro seconds - one_frame_duration = "40000us" - if input_frame_rate: + if not input_frame_rate: + one_frame_duration = "40000us" + else: items = input_frame_rate.split("/") if len(items) == 1: one_frame_duration = float(1.0) / float(items[0]) From bf80eee17816bf1876d32d0d37c486ec9db54aa3 Mon Sep 17 00:00:00 2001 From: Jiri Sindelar <45896205+jrsndl@users.noreply.github.com> Date: Mon, 23 May 2022 13:20:10 +0200 Subject: [PATCH 219/350] Update openpype/plugins/publish/extract_review_slate.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/plugins/publish/extract_review_slate.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 52d988a6b0..3bf7d00f7b 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -138,6 +138,8 @@ class ExtractReviewSlate(openpype.api.Extractor): one_frame_duration = float(1.0) / float(items[0]) elif len(items) == 2: one_frame_duration = float(items[1]) / float(items[0]) + else: + one_frame_duration = 0 one_frame_duration *= 1000000 one_frame_duration = str(int(one_frame_duration)) + "us" self.log.debug( From 9244389b585b654f92dbf76a8e5ed2692ac4cb3b Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 23 May 2022 17:16:44 +0200 Subject: [PATCH 220/350] OP-2790 - safer querying of farm flag --- openpype/plugins/publish/integrate_new.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/integrate_new.py b/openpype/plugins/publish/integrate_new.py index b5a7f11904..fa0582c65a 100644 --- a/openpype/plugins/publish/integrate_new.py +++ b/openpype/plugins/publish/integrate_new.py @@ -140,7 +140,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): return # instance should be published on a farm - if instance.data["farm"]: + if instance.data.get("farm"): return self.integrated_file_sizes = {} From 5d6ce5592dfcb02444e9d7f86e9feab6eaebf53d Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 23 May 2022 17:47:54 +0200 Subject: [PATCH 221/350] Hiero: rolled back py3 compatible code make it py27 working --- openpype/hosts/hiero/api/lib.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/hiero/api/lib.py b/openpype/hosts/hiero/api/lib.py index 5b2f6c814d..ae0aef9e9b 100644 --- a/openpype/hosts/hiero/api/lib.py +++ b/openpype/hosts/hiero/api/lib.py @@ -171,7 +171,7 @@ def get_track_items( # get selected track items or all in active sequence if selection: - with contextlib.suppress(AttributeError): + try: for track_item in selection: log.info("___ track_item: {}".format(track_item)) # make sure only trackitems are selected @@ -188,6 +188,8 @@ def get_track_items( ): log.info("___ valid trackitem: {}".format(track_item)) return_list.append(track_item) + except AttributeError: + pass # collect all available active sequence track items if not return_list: From 2e5acf6221e5063517870c93046979e79b243e49 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 23 May 2022 17:50:09 +0200 Subject: [PATCH 222/350] hound --- openpype/hosts/hiero/api/lib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/hiero/api/lib.py b/openpype/hosts/hiero/api/lib.py index ae0aef9e9b..d19cefd2da 100644 --- a/openpype/hosts/hiero/api/lib.py +++ b/openpype/hosts/hiero/api/lib.py @@ -2,7 +2,6 @@ Host specific functions where host api is connected """ -import contextlib from copy import deepcopy import os import re @@ -986,7 +985,8 @@ def get_sequence_pattern_and_padding(file): return None, None found = sorted(list(set(foundall[0])))[-1] - padding = int(re.findall(r"\d+", found)[-1]) if "%" in found else len(found) + padding = int( + re.findall(r"\d+", found)[-1]) if "%" in found else len(found) return found, padding From d4b6d6552caf6ebaef179a1f1519731746dad28e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Mon, 23 May 2022 18:34:03 +0200 Subject: [PATCH 223/350] :bug: get resolution from overrides --- .../hosts/maya/plugins/publish/collect_render.py | 12 +++++++++--- .../hosts/maya/plugins/publish/collect_vrayscene.py | 12 +++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_render.py b/openpype/hosts/maya/plugins/publish/collect_render.py index e66983780e..b19572ab37 100644 --- a/openpype/hosts/maya/plugins/publish/collect_render.py +++ b/openpype/hosts/maya/plugins/publish/collect_render.py @@ -339,9 +339,15 @@ class CollectMayaRender(pyblish.api.ContextPlugin): "source": filepath, "expectedFiles": full_exp_files, "publishRenderMetadataFolder": common_publish_meta_path, - "resolutionWidth": cmds.getAttr("defaultResolution.width"), - "resolutionHeight": cmds.getAttr("defaultResolution.height"), - "pixelAspect": cmds.getAttr("defaultResolution.pixelAspect"), + "resolutionWidth": lib.get_attr_in_layer( + "defaultResolution.height", layer=layer + ), + "resolutionHeight": lib.get_attr_in_layer( + "defaultResolution.width", layer=layer + ), + "pixelAspect": lib.get_attr_in_layer( + "defaultResolution.pixelAspect", layer=layer + ), "tileRendering": render_instance.data.get("tileRendering") or False, # noqa: E501 "tilesX": render_instance.data.get("tilesX") or 2, "tilesY": render_instance.data.get("tilesY") or 2, diff --git a/openpype/hosts/maya/plugins/publish/collect_vrayscene.py b/openpype/hosts/maya/plugins/publish/collect_vrayscene.py index afdb570cbc..6a0c2332fe 100644 --- a/openpype/hosts/maya/plugins/publish/collect_vrayscene.py +++ b/openpype/hosts/maya/plugins/publish/collect_vrayscene.py @@ -124,9 +124,15 @@ class CollectVrayScene(pyblish.api.InstancePlugin): # Add source to allow tracing back to the scene from # which was submitted originally "source": context.data["currentFile"].replace("\\", "/"), - "resolutionWidth": cmds.getAttr("defaultResolution.width"), - "resolutionHeight": cmds.getAttr("defaultResolution.height"), - "pixelAspect": cmds.getAttr("defaultResolution.pixelAspect"), + "resolutionWidth": lib.get_attr_in_layer( + "defaultResolution.height", layer=layer + ), + "resolutionHeight": lib.get_attr_in_layer( + "defaultResolution.width", layer=layer + ), + "pixelAspect": lib.get_attr_in_layer( + "defaultResolution.pixelAspect", layer=layer + ), "priority": instance.data.get("priority"), "useMultipleSceneFiles": instance.data.get( "vraySceneMultipleFiles") From c0ee519dba5f24c8040bc08f910c7024697b621d Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 24 May 2022 12:59:33 +0200 Subject: [PATCH 224/350] Hound --- openpype/hosts/flame/api/lib.py | 12 +++++++----- openpype/hosts/hiero/api/lib.py | 3 ++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/flame/api/lib.py b/openpype/hosts/flame/api/lib.py index 6dc7d3d887..d59308ad6c 100644 --- a/openpype/hosts/flame/api/lib.py +++ b/openpype/hosts/flame/api/lib.py @@ -779,7 +779,6 @@ class MediaInfoFile(object): feed_dir = os.path.dirname(path) feed_ext = os.path.splitext(feed_basename)[1][1:].lower() - with maintained_temp_file_path(".clip") as tmp_path: self.log.info("Temp File: {}".format(tmp_path)) self._generate_media_info_file(tmp_path, feed_ext, feed_dir) @@ -827,9 +826,11 @@ class MediaInfoFile(object): # make sure partial input basename is having correct extensoon if not partialname: - raise AttributeError("Wrong input attributes. Basename - {}, Ext - {}".format( - feed_basename, feed_ext - )) + raise AttributeError( + "Wrong input attributes. Basename - {}, Ext - {}".format( + feed_basename, feed_ext + ) + ) # get all related files files = [ @@ -860,7 +861,8 @@ class MediaInfoFile(object): # convert to multiple collections _continues_colls = collection.separate() for _coll in _continues_colls: - coll_to_text = self._format_collection(_coll, len(number_from_path)) + coll_to_text = self._format_collection( + _coll, len(number_from_path)) self.log.debug("__ coll_to_text: {}".format(coll_to_text)) if search_number_pattern in coll_to_text: return coll_to_text diff --git a/openpype/hosts/hiero/api/lib.py b/openpype/hosts/hiero/api/lib.py index 5b2f6c814d..5a9f38bf92 100644 --- a/openpype/hosts/hiero/api/lib.py +++ b/openpype/hosts/hiero/api/lib.py @@ -984,7 +984,8 @@ def get_sequence_pattern_and_padding(file): return None, None found = sorted(list(set(foundall[0])))[-1] - padding = int(re.findall(r"\d+", found)[-1]) if "%" in found else len(found) + padding = int( + re.findall(r"\d+", found)[-1]) if "%" in found else len(found) return found, padding From 0e0bbd56992a8ee8e7c32d90e56606623bb3781c Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Tue, 24 May 2022 15:31:01 +0100 Subject: [PATCH 225/350] Fix camera in UE5 --- .../hosts/unreal/plugins/load/load_camera.py | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/unreal/plugins/load/load_camera.py b/openpype/hosts/unreal/plugins/load/load_camera.py index b33e45b6e9..0072dd9e73 100644 --- a/openpype/hosts/unreal/plugins/load/load_camera.py +++ b/openpype/hosts/unreal/plugins/load/load_camera.py @@ -57,6 +57,33 @@ class CameraLoader(plugin.Loader): min_frame_j, max_frame_j + 1) + def _import_camera( + self, world, sequence, bindings, import_fbx_settings, import_filename + ): + ue_version = unreal.SystemLibrary.get_engine_version().split('.') + ue_major = int(ue_version[0]) + ue_minor = int(ue_version[1]) + + if ue_major == 4 and ue_minor <= 26: + unreal.SequencerTools.import_fbx( + world, + sequence, + bindings, + import_fbx_settings, + import_filename + ) + elif (ue_major == 4 and ue_minor >= 27) or ue_major == 5: + unreal.SequencerTools.import_level_sequence_fbx( + world, + sequence, + bindings, + import_fbx_settings, + import_filename + ) + else: + raise NotImplementedError( + f"Unreal version {ue_major} not supported") + def load(self, context, name, namespace, data): """ Load and containerise representation into Content Browser. @@ -228,7 +255,7 @@ class CameraLoader(plugin.Loader): settings.set_editor_property('reduce_keys', False) if cam_seq: - unreal.SequencerTools.import_fbx( + self._import_camera( EditorLevelLibrary.get_editor_world(), cam_seq, cam_seq.get_bindings(), @@ -388,7 +415,7 @@ class CameraLoader(plugin.Loader): sub_scene.set_sequence(new_sequence) - unreal.SequencerTools.import_fbx( + self._import_camera( EditorLevelLibrary.get_editor_world(), new_sequence, new_sequence.get_bindings(), From 9c72873a9a8ac462abf463cc86c1c04dcfecaf8b Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Tue, 24 May 2022 15:32:29 +0100 Subject: [PATCH 226/350] Fix animations in UE5 --- openpype/hosts/unreal/plugins/load/load_animation.py | 12 ++++++++---- openpype/hosts/unreal/plugins/load/load_layout.py | 6 ++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/unreal/plugins/load/load_animation.py b/openpype/hosts/unreal/plugins/load/load_animation.py index 60c1526d3d..54b43c500c 100644 --- a/openpype/hosts/unreal/plugins/load/load_animation.py +++ b/openpype/hosts/unreal/plugins/load/load_animation.py @@ -77,13 +77,15 @@ class AnimationFBXLoader(plugin.Loader): task.options.anim_sequence_import_data.set_editor_property( 'import_meshes_in_bone_hierarchy', False) task.options.anim_sequence_import_data.set_editor_property( - 'use_default_sample_rate', True) + 'use_default_sample_rate', False) + task.options.anim_sequence_import_data.set_editor_property( + 'custom_sample_rate', 25.0) # TODO: get from database task.options.anim_sequence_import_data.set_editor_property( 'import_custom_attribute', True) task.options.anim_sequence_import_data.set_editor_property( 'import_bone_tracks', True) task.options.anim_sequence_import_data.set_editor_property( - 'remove_redundant_keys', True) + 'remove_redundant_keys', False) task.options.anim_sequence_import_data.set_editor_property( 'convert_scene', True) @@ -279,13 +281,15 @@ class AnimationFBXLoader(plugin.Loader): task.options.anim_sequence_import_data.set_editor_property( 'import_meshes_in_bone_hierarchy', False) task.options.anim_sequence_import_data.set_editor_property( - 'use_default_sample_rate', True) + 'use_default_sample_rate', False) + task.options.anim_sequence_import_data.set_editor_property( + 'custom_sample_rate', 25.0) # TODO: get from database task.options.anim_sequence_import_data.set_editor_property( 'import_custom_attribute', True) task.options.anim_sequence_import_data.set_editor_property( 'import_bone_tracks', True) task.options.anim_sequence_import_data.set_editor_property( - 'remove_redundant_keys', True) + 'remove_redundant_keys', False) task.options.anim_sequence_import_data.set_editor_property( 'convert_scene', True) diff --git a/openpype/hosts/unreal/plugins/load/load_layout.py b/openpype/hosts/unreal/plugins/load/load_layout.py index 412f77e3a9..49611c6c05 100644 --- a/openpype/hosts/unreal/plugins/load/load_layout.py +++ b/openpype/hosts/unreal/plugins/load/load_layout.py @@ -262,13 +262,15 @@ class LayoutLoader(plugin.Loader): task.options.anim_sequence_import_data.set_editor_property( 'import_meshes_in_bone_hierarchy', False) task.options.anim_sequence_import_data.set_editor_property( - 'use_default_sample_rate', True) + 'use_default_sample_rate', False) + task.options.anim_sequence_import_data.set_editor_property( + 'custom_sample_rate', 25.0) # TODO: get from database task.options.anim_sequence_import_data.set_editor_property( 'import_custom_attribute', True) task.options.anim_sequence_import_data.set_editor_property( 'import_bone_tracks', True) task.options.anim_sequence_import_data.set_editor_property( - 'remove_redundant_keys', True) + 'remove_redundant_keys', False) task.options.anim_sequence_import_data.set_editor_property( 'convert_scene', True) From 1b76f86d6691b0106ce2ae9022666979103cf57d Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Tue, 24 May 2022 15:35:47 +0100 Subject: [PATCH 227/350] Fix render create in UE5 --- openpype/hosts/unreal/plugins/create/create_render.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/unreal/plugins/create/create_render.py b/openpype/hosts/unreal/plugins/create/create_render.py index 3b6c7a9f1e..a3e125a94e 100644 --- a/openpype/hosts/unreal/plugins/create/create_render.py +++ b/openpype/hosts/unreal/plugins/create/create_render.py @@ -22,17 +22,24 @@ class CreateRender(Creator): ar = unreal.AssetRegistryHelpers.get_asset_registry() + # The asset name is the the third element of the path which contains + # the map. + # The index of the split path is 3 because the first element is an + # empty string, as the path begins with "/Content". + a = unreal.EditorUtilityLibrary.get_selected_assets()[0] + asset_name = a.get_path_name().split("/")[3] + # Get the master sequence and the master level. # There should be only one sequence and one level in the directory. filter = unreal.ARFilter( class_names=["LevelSequence"], - package_paths=[f"/Game/OpenPype/{self.data['asset']}"], + package_paths=[f"/Game/OpenPype/{asset_name}"], recursive_paths=False) sequences = ar.get_assets(filter) ms = sequences[0].get_editor_property('object_path') filter = unreal.ARFilter( class_names=["World"], - package_paths=[f"/Game/OpenPype/{self.data['asset']}"], + package_paths=[f"/Game/OpenPype/{asset_name}"], recursive_paths=False) levels = ar.get_assets(filter) ml = levels[0].get_editor_property('object_path') From f57c22e4203b9d6441a05edabeda19742e4eda91 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Tue, 24 May 2022 22:20:00 +0200 Subject: [PATCH 228/350] :bug: fix layer names --- openpype/hosts/maya/plugins/publish/collect_render.py | 6 +++--- openpype/hosts/maya/plugins/publish/collect_vrayscene.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_render.py b/openpype/hosts/maya/plugins/publish/collect_render.py index b19572ab37..fbd2e81279 100644 --- a/openpype/hosts/maya/plugins/publish/collect_render.py +++ b/openpype/hosts/maya/plugins/publish/collect_render.py @@ -340,13 +340,13 @@ class CollectMayaRender(pyblish.api.ContextPlugin): "expectedFiles": full_exp_files, "publishRenderMetadataFolder": common_publish_meta_path, "resolutionWidth": lib.get_attr_in_layer( - "defaultResolution.height", layer=layer + "defaultResolution.height", layer=layer_name ), "resolutionHeight": lib.get_attr_in_layer( - "defaultResolution.width", layer=layer + "defaultResolution.width", layer=layer_name ), "pixelAspect": lib.get_attr_in_layer( - "defaultResolution.pixelAspect", layer=layer + "defaultResolution.pixelAspect", layer=layer_name ), "tileRendering": render_instance.data.get("tileRendering") or False, # noqa: E501 "tilesX": render_instance.data.get("tilesX") or 2, diff --git a/openpype/hosts/maya/plugins/publish/collect_vrayscene.py b/openpype/hosts/maya/plugins/publish/collect_vrayscene.py index 6a0c2332fe..0bae9656f3 100644 --- a/openpype/hosts/maya/plugins/publish/collect_vrayscene.py +++ b/openpype/hosts/maya/plugins/publish/collect_vrayscene.py @@ -125,13 +125,13 @@ class CollectVrayScene(pyblish.api.InstancePlugin): # which was submitted originally "source": context.data["currentFile"].replace("\\", "/"), "resolutionWidth": lib.get_attr_in_layer( - "defaultResolution.height", layer=layer + "defaultResolution.height", layer=layer_name ), "resolutionHeight": lib.get_attr_in_layer( - "defaultResolution.width", layer=layer + "defaultResolution.width", layer=layer_name ), "pixelAspect": lib.get_attr_in_layer( - "defaultResolution.pixelAspect", layer=layer + "defaultResolution.pixelAspect", layer=layer_name ), "priority": instance.data.get("priority"), "useMultipleSceneFiles": instance.data.get( From ac79f31a279fcbd50d04a571b2b3eb8270b761d7 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Tue, 24 May 2022 22:39:50 +0200 Subject: [PATCH 229/350] :bug: filter out display types without file output don't process renderman display type that are not producing any file output (like `d_it`) --- openpype/hosts/maya/api/lib_renderproducts.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openpype/hosts/maya/api/lib_renderproducts.py b/openpype/hosts/maya/api/lib_renderproducts.py index ff04fa7aa2..2d3bda5245 100644 --- a/openpype/hosts/maya/api/lib_renderproducts.py +++ b/openpype/hosts/maya/api/lib_renderproducts.py @@ -1093,6 +1093,11 @@ class RenderProductsRenderman(ARenderProducts): if not enabled: continue + # Skip display types not producing any file output. + # Is there a better way to do it? + if not display_types.get(display["driverNode"]["type"]): + continue + aov_name = name if aov_name == "rmanDefaultDisplay": aov_name = "beauty" From d019e5d7c22ace4d64bdbd8f73d09592b912e315 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Wed, 25 May 2022 03:48:50 +0000 Subject: [PATCH 230/350] [Automated] Bump version --- CHANGELOG.md | 23 +++++++++++------------ openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8cec29df7..3dd410391a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [3.10.0-nightly.4](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.10.0-nightly.5](https://github.com/pypeclub/OpenPype/tree/HEAD) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.9.8...HEAD) @@ -14,12 +14,16 @@ **🚀 Enhancements** +- Project Manager: Allow to paste Tasks into multiple assets at the same time [\#3226](https://github.com/pypeclub/OpenPype/pull/3226) - Project manager: Sped up project load [\#3216](https://github.com/pypeclub/OpenPype/pull/3216) +- Loader UI: Speed issues of loader with sync server [\#3199](https://github.com/pypeclub/OpenPype/pull/3199) - Maya: added clean\_import option to Import loader [\#3181](https://github.com/pypeclub/OpenPype/pull/3181) - Maya: add maya 2023 to default applications [\#3167](https://github.com/pypeclub/OpenPype/pull/3167) +- Compressed bgeo publishing in SAP and Houdini loader [\#3153](https://github.com/pypeclub/OpenPype/pull/3153) - General: Add 'dataclasses' to required python modules [\#3149](https://github.com/pypeclub/OpenPype/pull/3149) - Hooks: Tweak logging grammar [\#3147](https://github.com/pypeclub/OpenPype/pull/3147) - Nuke: settings for reformat node in CreateWriteRender node [\#3143](https://github.com/pypeclub/OpenPype/pull/3143) +- Houdini: Add loader for alembic through Alembic Archive node [\#3140](https://github.com/pypeclub/OpenPype/pull/3140) - Publisher: UI Modifications and fixes [\#3139](https://github.com/pypeclub/OpenPype/pull/3139) - General: Simplified OP modules/addons import [\#3137](https://github.com/pypeclub/OpenPype/pull/3137) - Terminal: Tweak coloring of TrayModuleManager logging enabled states [\#3133](https://github.com/pypeclub/OpenPype/pull/3133) @@ -28,18 +32,19 @@ - Unreal: Layout and Camera update and remove functions reimplemented and improvements [\#3116](https://github.com/pypeclub/OpenPype/pull/3116) - Settings: Remove environment groups from settings [\#3115](https://github.com/pypeclub/OpenPype/pull/3115) - TVPaint: Match renderlayer key with other hosts [\#3110](https://github.com/pypeclub/OpenPype/pull/3110) -- Ftrack: AssetVersion status on publish [\#3108](https://github.com/pypeclub/OpenPype/pull/3108) - Tray publisher: Simple families from settings [\#3105](https://github.com/pypeclub/OpenPype/pull/3105) **🐛 Bug fixes** +- Ftrack: Validate that the user exists on ftrack [\#3237](https://github.com/pypeclub/OpenPype/pull/3237) +- TVPaint: Look for more groups than 12 [\#3228](https://github.com/pypeclub/OpenPype/pull/3228) +- Project Manager: Fix persistent editors on project change [\#3218](https://github.com/pypeclub/OpenPype/pull/3218) - Deadline: instance data overwrite fix [\#3214](https://github.com/pypeclub/OpenPype/pull/3214) - Ftrack: Push hierarchical attributes action works [\#3210](https://github.com/pypeclub/OpenPype/pull/3210) - Standalone Publisher: Always create new representation for thumbnail [\#3203](https://github.com/pypeclub/OpenPype/pull/3203) - Photoshop: skip collector when automatic testing [\#3202](https://github.com/pypeclub/OpenPype/pull/3202) - Nuke: render/workfile version sync doesn't work on farm [\#3185](https://github.com/pypeclub/OpenPype/pull/3185) - Ftrack: Review image only if there are no mp4 reviews [\#3183](https://github.com/pypeclub/OpenPype/pull/3183) -- Ftrack: Locations deepcopy issue [\#3177](https://github.com/pypeclub/OpenPype/pull/3177) - General: Avoid creating multiple thumbnails [\#3176](https://github.com/pypeclub/OpenPype/pull/3176) - General/Hiero: better clip duration calculation [\#3169](https://github.com/pypeclub/OpenPype/pull/3169) - General: Oiio conversion for ffmpeg checks for invalid characters [\#3166](https://github.com/pypeclub/OpenPype/pull/3166) @@ -52,11 +57,10 @@ - TVPaint: Composite layers in reversed order [\#3135](https://github.com/pypeclub/OpenPype/pull/3135) - Nuke: fixing default settings for workfile builder loaders [\#3120](https://github.com/pypeclub/OpenPype/pull/3120) - Nuke: fix anatomy imageio regex default [\#3119](https://github.com/pypeclub/OpenPype/pull/3119) -- General: Python 3 compatibility in queries [\#3112](https://github.com/pypeclub/OpenPype/pull/3112) -- General: Collect loaded versions skips not existing representations [\#3095](https://github.com/pypeclub/OpenPype/pull/3095) **🔀 Refactored code** +- Avalon repo removed from Jobs workflow [\#3193](https://github.com/pypeclub/OpenPype/pull/3193) - General: Remove remaining imports from avalon [\#3130](https://github.com/pypeclub/OpenPype/pull/3130) **Merged pull requests:** @@ -72,6 +76,7 @@ **🚀 Enhancements** - nuke: generate publishing nodes inside render group node [\#3206](https://github.com/pypeclub/OpenPype/pull/3206) +- Loader UI: Speed issues of loader with sync server [\#3200](https://github.com/pypeclub/OpenPype/pull/3200) - Backport of fix for attaching renders to subsets [\#3195](https://github.com/pypeclub/OpenPype/pull/3195) **🐛 Bug fixes** @@ -79,6 +84,7 @@ - Standalone Publisher: Always create new representation for thumbnail [\#3204](https://github.com/pypeclub/OpenPype/pull/3204) - Nuke: render/workfile version sync doesn't work on farm [\#3184](https://github.com/pypeclub/OpenPype/pull/3184) - Ftrack: Review image only if there are no mp4 reviews [\#3182](https://github.com/pypeclub/OpenPype/pull/3182) +- Ftrack: Locations deepcopy issue [\#3177](https://github.com/pypeclub/OpenPype/pull/3177) - Ftrack: Locations deepcopy issue [\#3175](https://github.com/pypeclub/OpenPype/pull/3175) - General: Avoid creating multiple thumbnails [\#3174](https://github.com/pypeclub/OpenPype/pull/3174) - General: TemplateResult can be copied [\#3170](https://github.com/pypeclub/OpenPype/pull/3170) @@ -98,9 +104,7 @@ **🚀 Enhancements** - Deadline output dir issue to 3.9x [\#3155](https://github.com/pypeclub/OpenPype/pull/3155) -- Compressed bgeo publishing in SAP and Houdini loader [\#3153](https://github.com/pypeclub/OpenPype/pull/3153) - nuke: removing redundant code from startup [\#3142](https://github.com/pypeclub/OpenPype/pull/3142) -- Houdini: Add loader for alembic through Alembic Archive node [\#3140](https://github.com/pypeclub/OpenPype/pull/3140) **🐛 Bug fixes** @@ -137,11 +141,6 @@ [Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.10.0-nightly.2...3.9.5) -**🐛 Bug fixes** - -- Ftrack: Update Create Folders action [\#3092](https://github.com/pypeclub/OpenPype/pull/3092) -- General: Extract review sequence is not converted with same names [\#3075](https://github.com/pypeclub/OpenPype/pull/3075) - ## [3.9.4](https://github.com/pypeclub/OpenPype/tree/3.9.4) (2022-04-15) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.9.4-nightly.2...3.9.4) diff --git a/openpype/version.py b/openpype/version.py index 1cc854cfd1..eee776fd2c 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.10.0-nightly.4" +__version__ = "3.10.0-nightly.5" diff --git a/pyproject.toml b/pyproject.toml index a2614b24b5..50cdefe1bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.10.0-nightly.4" # OpenPype +version = "3.10.0-nightly.5" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From 73a0d6fc70c847ab6114b1985dd0013282fb9a9a Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 25 May 2022 12:08:01 +0200 Subject: [PATCH 231/350] extracted some functionality into separated functions --- .../plugins/publish/extract_review_slate.py | 275 +++++++++++------- 1 file changed, 171 insertions(+), 104 deletions(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index 7b2df4dc5f..a42fbbbfe1 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -78,76 +78,26 @@ class ExtractReviewSlate(openpype.api.Extractor): input_path, self.log ) # Get video metadata - for stream in streams: - input_timecode = "" - input_width = None - input_height = None - input_frame_rate = None - if "codec_type" in stream: - if stream["codec_type"] == "video": - self.log.debug("__Ffprobe Video: {}".format(stream)) - tags = stream.get("tags") or {} - input_timecode = tags.get("timecode") or "" - if "width" in stream and "height" in stream: - input_width = int(stream.get("width")) - input_height = int(stream.get("height")) - if "r_frame_rate" in stream: - # get frame rate in a form of - # x/y, like 24000/1001 for 23.976 - input_frame_rate = stream.get("r_frame_rate") - if ( - input_width - and input_height - and input_frame_rate - ): - input_frame_rate = str(input_frame_rate) - break + ( + input_width, + input_height, + input_timecode, + input_frame_rate + ) = self._get_video_metadata(streams) + # Raise exception of any stream didn't define input resolution if input_width is None: raise AssertionError(( "FFprobe couldn't read resolution from input file: \"{}\"" ).format(input_path)) - # Get audio metadata - for stream in streams: - audio_channels = None - audio_sample_rate = None - audio_channel_layout = None - input_audio = False - if stream["codec_type"] == "audio": - self.log.debug("__Ffprobe Audio: {}".format(stream)) - if stream["channels"]: - audio_channels = str(stream.get("channels")) - if stream["sample_rate"]: - audio_sample_rate = str(stream.get("sample_rate")) - if stream["channel_layout"]: - audio_channel_layout = str( - stream.get("channel_layout")) - if stream["codec_name"]: - audio_codec = str( - stream.get("codec_name")) - if ( - audio_channels - and audio_sample_rate - and audio_channel_layout - and audio_codec - ): - input_audio = str(input_audio) - audio_sample_rate = str(audio_sample_rate) - audio_channel_layout = str(audio_channel_layout) - audio_codec = str(audio_codec) - break - # Get duration of one frame in micro seconds - one_frame_duration = "40000us" - if input_frame_rate: - items = input_frame_rate.split("/") - if len(items) == 1: - one_frame_duration = float(1.0) / float(items[0]) - elif len(items) == 2: - one_frame_duration = float(items[1]) / float(items[0]) - one_frame_duration *= 1000000 - one_frame_duration = str(int(one_frame_duration)) + "us" - self.log.debug( - "One frame duration is {}".format(one_frame_duration)) + + ( + audio_codec, + audio_channels, + audio_sample_rate, + audio_channel_layout, + input_audio + ) = self._get_audio_metadata(streams) # values are set in ExtractReview if use_legacy_code: @@ -205,14 +155,16 @@ class ExtractReviewSlate(openpype.api.Extractor): else: input_args.extend(repre["outputDef"].get('input', [])) - input_args.append("-loop 1 -i {}".format( - openpype.lib.path_to_subprocess_arg(slate_path))) - input_args.extend(["-r {}".format(input_frame_rate)]) - input_args.extend(["-frames:v 1"]) + input_args.extend([ + "-loop", "1", + "-i", openpype.lib.path_to_subprocess_arg(slate_path), + "-r", str(input_frame_rate), + "-frames:v", "1", + ]) + # add timecode from source to the slate, substract one frame offset_timecode = "" if input_timecode: - offset_timecode = str(input_timecode) offset_timecode = self._tc_offset( str(input_timecode), framerate=fps, @@ -221,7 +173,8 @@ class ExtractReviewSlate(openpype.api.Extractor): self.log.debug("Slate Timecode: `{}`".format( offset_timecode )) - input_args.extend(["-timecode {}".format(offset_timecode)]) + input_args.extend(["-timecode", str(offset_timecode)]) + if use_legacy_code: format_args = [] codec_args = repre["_profile"].get('codec', []) @@ -236,10 +189,10 @@ class ExtractReviewSlate(openpype.api.Extractor): # make sure colors are correct output_args.extend([ - "-vf scale=out_color_matrix=bt709", - "-color_primaries bt709", - "-color_trc bt709", - "-colorspace bt709" + "-vf", "scale=out_color_matrix=bt709", + "-color_primaries", "bt709", + "-color_trc", "bt709", + "-colorspace", "bt709", ]) # scaling none square pixels and 1920 width @@ -275,13 +228,20 @@ class ExtractReviewSlate(openpype.api.Extractor): "__ height_half_pad: `{}`".format(height_half_pad) ) - scaling_arg = ("scale={0}x{1}:flags=lanczos," - "pad={2}:{3}:{4}:{5}:black,setsar=1").format( - width_scale, height_scale, to_width, to_height, - width_half_pad, height_half_pad + scaling_arg = ( + "scale={0}x{1}:flags=lanczos" + ",pad={2}:{3}:{4}:{5}:black" + ",setsar=1" + ",fps={6}" + ).format( + width_scale, + height_scale, + to_width, + to_height, + width_half_pad, + height_half_pad, + input_frame_rate ) - # add output frame rate as a filter, just in case - scaling_arg += ",fps={}".format(input_frame_rate) vf_back = self.add_video_filter_args(output_args, scaling_arg) # add it to output_args @@ -317,30 +277,14 @@ class ExtractReviewSlate(openpype.api.Extractor): slate_silent_path = "_silent".join( os.path.splitext(slate_v_path)) _remove_at_end.append(slate_silent_path) - - slate_silent_args = [ + self._create_silent_slate( ffmpeg_path, - "-i", slate_v_path, - "-f", "lavfi", "-i", - "anullsrc=r={}:cl={}:d={}".format( - audio_sample_rate, - audio_channel_layout, - one_frame_duration - ), - "-c:v", "copy", - "-c:a", audio_codec, - "-map", "0:v", - "-map", "1:a", - "-shortest", - "-y", - slate_silent_path - ] - # run slate generation subprocess - self.log.debug( - "Silent Slate Executing: {}".format( - " ".join(slate_silent_args))) - openpype.api.run_subprocess( - slate_silent_args, logger=self.log + slate_v_path, + slate_silent_path, + audio_codec, + audio_channels, + audio_sample_rate, + audio_channel_layout, ) # replace slate with silent slate for concat @@ -426,6 +370,129 @@ class ExtractReviewSlate(openpype.api.Extractor): self.log.debug(inst_data["representations"]) + def _get_video_metadata(self, streams): + input_timecode = "" + input_width = None + input_height = None + input_frame_rate = None + for stream in streams: + if stream.get("codec_type") != "video": + continue + self.log.debug("FFprobe Video: {}".format(stream)) + + if "width" not in stream or "height" not in stream: + continue + width = int(stream["width"]) + height = int(stream["height"]) + if not width or not height: + continue + + # Make sure that width and height are captured even if frame rate + # is not available + input_width = width + input_height = height + + tags = stream.get("tags") or {} + input_timecode = tags.get("timecode") or "" + + input_frame_rate = stream.get("r_frame_rate") + if input_frame_rate is not None: + break + return ( + input_width, + input_height, + input_timecode, + input_frame_rate + ) + + def _get_audio_metadata(self, streams): + # Get audio metadata + audio_codec = None + audio_channels = None + audio_sample_rate = None + audio_channel_layout = None + input_audio = False + + for stream in streams: + if stream.get("codec_type") != "audio": + continue + self.log.debug("__Ffprobe Audio: {}".format(stream)) + + if all( + stream.get(key) + for key in ( + "codec_name", + "channels", + "sample_rate", + "channel_layout", + ) + ): + audio_codec = stream["codec_name"] + audio_channels = stream["channels"] + audio_sample_rate = stream["sample_rate"] + audio_channel_layout = stream["channel_layout"] + input_audio = True + break + + return ( + audio_codec, + audio_channels, + audio_sample_rate, + audio_channel_layout, + input_audio, + ) + + def _create_silent_slate( + self, + ffmpeg_path, + src_path, + dst_path, + audio_codec, + audio_channels, + audio_sample_rate, + audio_channel_layout, + ): + # Get duration of one frame in micro seconds + items = audio_sample_rate.split("/") + if len(items) == 1: + one_frame_duration = 1.0 / float(items[0]) + elif len(items) == 2: + one_frame_duration = float(items[1]) / float(items[0]) + else: + one_frame_duration = None + + if one_frame_duration is None: + one_frame_duration = "40000us" + else: + one_frame_duration *= 1000000 + one_frame_duration = str(int(one_frame_duration)) + "us" + self.log.debug("One frame duration is {}".format(one_frame_duration)) + + slate_silent_args = [ + ffmpeg_path, + "-i", src_path, + "-f", "lavfi", "-i", + "anullsrc=r={}:cl={}:d={}".format( + audio_sample_rate, + audio_channel_layout, + one_frame_duration + ), + "-c:v", "copy", + "-c:a", audio_codec, + "-map", "0:v", + "-map", "1:a", + "-shortest", + "-y", + dst_path + ] + # run slate generation subprocess + self.log.debug("Silent Slate Executing: {}".format( + " ".join(slate_silent_args) + )) + openpype.api.run_subprocess( + slate_silent_args, logger=self.log + ) + def add_video_filter_args(self, args, inserting_arg): """ Fixing video filter argumets to be one long string From 4c3914c6c263efe68d466a542c26908a1e12739d Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 25 May 2022 12:12:46 +0200 Subject: [PATCH 232/350] fix double space --- openpype/plugins/publish/extract_review_slate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index a42fbbbfe1..a2cbc1b704 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -159,7 +159,7 @@ class ExtractReviewSlate(openpype.api.Extractor): "-loop", "1", "-i", openpype.lib.path_to_subprocess_arg(slate_path), "-r", str(input_frame_rate), - "-frames:v", "1", + "-frames:v", "1", ]) # add timecode from source to the slate, substract one frame From c9b0bb0e54cbd3390f06ee8ea3135ffd5e9413e5 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 25 May 2022 13:32:45 +0200 Subject: [PATCH 233/350] make sure chunk size is at least 1 --- openpype/modules/ftrack/lib/avalon_sync.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/openpype/modules/ftrack/lib/avalon_sync.py b/openpype/modules/ftrack/lib/avalon_sync.py index 124787e467..e4ba651bfd 100644 --- a/openpype/modules/ftrack/lib/avalon_sync.py +++ b/openpype/modules/ftrack/lib/avalon_sync.py @@ -143,14 +143,17 @@ def create_chunks(iterable, chunk_size=None): list: Chunked items. """ chunks = [] - if not iterable: - return chunks tupled_iterable = tuple(iterable) + if not tupled_iterable: + return chunks iterable_size = len(tupled_iterable) if chunk_size is None: chunk_size = 200 + if chunk_size < 1: + chunk_size = 1 + for idx in range(0, iterable_size, chunk_size): chunks.append(tupled_iterable[idx:idx + chunk_size]) return chunks From 93c4e3403aa0a26717ab47815940cb269e279c76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Wed, 25 May 2022 14:06:25 +0200 Subject: [PATCH 234/350] :bug: fix node attribute name --- .../hosts/maya/plugins/publish/collect_look.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_look.py b/openpype/hosts/maya/plugins/publish/collect_look.py index fb2ce04cad..d295492f9a 100644 --- a/openpype/hosts/maya/plugins/publish/collect_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_look.py @@ -616,11 +616,15 @@ class CollectLook(pyblish.api.InstancePlugin): self.log.info(" - color space: {}".format(color_space)) # Define the resource - return {"node": node, - "attribute": attribute, - "source": source, # required for resources - "files": files, - "color_space": color_space} # required for resources + return { + "node": node, + # here we are passing not only attribute, but with node again + # this should be simplified and changed extractor. + "attribute": "{}.{}".format(node, attribute), + "source": source, # required for resources + "files": files, + "color_space": color_space + } # required for resources class CollectModelRenderSets(CollectLook): From ce882641e7baec3c7edca957e2024331943ab9af Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 25 May 2022 17:27:40 +0200 Subject: [PATCH 235/350] Vendor: updating scriptmenu to 1.5.2 --- openpype/vendor/python/common/scriptsmenu/action.py | 3 ++- openpype/vendor/python/common/scriptsmenu/launchfornuke.py | 7 ++----- openpype/vendor/python/common/scriptsmenu/scriptsmenu.py | 3 +-- openpype/vendor/python/common/scriptsmenu/version.py | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/openpype/vendor/python/common/scriptsmenu/action.py b/openpype/vendor/python/common/scriptsmenu/action.py index dc4d775f6a..5e68628406 100644 --- a/openpype/vendor/python/common/scriptsmenu/action.py +++ b/openpype/vendor/python/common/scriptsmenu/action.py @@ -119,7 +119,8 @@ module.{module_name}()""" """ # get the current application and its linked keyboard modifiers - modifiers = QtWidgets.QApplication.keyboardModifiers() + app = QtWidgets.QApplication.instance() + modifiers = app.keyboardModifiers() # If the menu has a callback registered for the current modifier # we run the callback instead of the action itself. diff --git a/openpype/vendor/python/common/scriptsmenu/launchfornuke.py b/openpype/vendor/python/common/scriptsmenu/launchfornuke.py index 23e4ed1b4d..72302a79a6 100644 --- a/openpype/vendor/python/common/scriptsmenu/launchfornuke.py +++ b/openpype/vendor/python/common/scriptsmenu/launchfornuke.py @@ -8,7 +8,7 @@ def _nuke_main_window(): if (obj.inherits('QMainWindow') and obj.metaObject().className() == 'Foundry::UI::DockMainWindow'): return obj - raise RuntimeError('Could not find Nuke MainWindow instance') + raise RuntimeError('Could not find Nuke MainWindow instance') def _nuke_main_menubar(): @@ -22,9 +22,6 @@ def _nuke_main_menubar(): def main(title="Scripts"): - # Register control + shift callback to add to shelf (Nuke behavior) - # modifiers = QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier - # menu.register_callback(modifiers, to_shelf) nuke_main_bar = _nuke_main_menubar() for nuke_bar in nuke_main_bar.children(): if isinstance(nuke_bar, scriptsmenu.ScriptsMenu): @@ -33,4 +30,4 @@ def main(title="Scripts"): return menu menu = scriptsmenu.ScriptsMenu(title=title, parent=nuke_main_bar) - return menu \ No newline at end of file + return menu diff --git a/openpype/vendor/python/common/scriptsmenu/scriptsmenu.py b/openpype/vendor/python/common/scriptsmenu/scriptsmenu.py index e2b7ff96c7..9e7c094902 100644 --- a/openpype/vendor/python/common/scriptsmenu/scriptsmenu.py +++ b/openpype/vendor/python/common/scriptsmenu/scriptsmenu.py @@ -264,8 +264,7 @@ class ScriptsMenu(QtWidgets.QMenu): action.setVisible(True) else: for action in self._script_actions: - if not action.has_tag(search.lower()): - action.setVisible(False) + action.setVisible(action.has_tag(search.lower())) # Set visibility for all submenus for action in self.actions(): diff --git a/openpype/vendor/python/common/scriptsmenu/version.py b/openpype/vendor/python/common/scriptsmenu/version.py index 73f9426c2d..52ec49c845 100644 --- a/openpype/vendor/python/common/scriptsmenu/version.py +++ b/openpype/vendor/python/common/scriptsmenu/version.py @@ -1,6 +1,6 @@ VERSION_MAJOR = 1 VERSION_MINOR = 5 -VERSION_PATCH = 1 +VERSION_PATCH = 2 version = '{}.{}.{}'.format(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH) From d17ae6d6a588be1c700be664f3e746975661034a Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Wed, 25 May 2022 19:10:32 +0200 Subject: [PATCH 236/350] Change icon path and add nukestudio icon. --- openpype/resources/app_icons/nukestudio.png | Bin 0 -> 46080 bytes .../defaults/system_settings/applications.json | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 openpype/resources/app_icons/nukestudio.png diff --git a/openpype/resources/app_icons/nukestudio.png b/openpype/resources/app_icons/nukestudio.png new file mode 100644 index 0000000000000000000000000000000000000000..99c95f59ff858d67fb92263f594f4b71bda87a66 GIT binary patch literal 46080 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 HIsgA3TR*cj literal 0 HcmV?d00001 diff --git a/openpype/settings/defaults/system_settings/applications.json b/openpype/settings/defaults/system_settings/applications.json index 2b0de44fa9..29c8a1cccc 100644 --- a/openpype/settings/defaults/system_settings/applications.json +++ b/openpype/settings/defaults/system_settings/applications.json @@ -292,7 +292,7 @@ "nukex": { "enabled": true, "label": "Nuke X", - "icon": "{}/app_icons/nuke.png", + "icon": "{}/app_icons/nukex.png", "host_name": "nuke", "environment": { "NUKE_PATH": [ @@ -431,7 +431,7 @@ "nukestudio": { "enabled": true, "label": "Nuke Studio", - "icon": "{}/app_icons/nuke.png", + "icon": "{}/app_icons/nukestudio.png", "host_name": "hiero", "environment": { "WORKFILES_STARTUP": "0", From d9a9981fefacc42a9e9466f6af6769f1605d4396 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 25 May 2022 19:37:14 +0200 Subject: [PATCH 237/350] Fix - Harmony 21.1 messed up Javascript Qt API QDataStream is missing, different way to get codec used. QApplication.activeWindow() also returned null, replaced by topLevelWidgets --- openpype/hosts/harmony/api/TB_sceneOpened.js | 31 +++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/openpype/hosts/harmony/api/TB_sceneOpened.js b/openpype/hosts/harmony/api/TB_sceneOpened.js index 6a403fa65e..29473bcc93 100644 --- a/openpype/hosts/harmony/api/TB_sceneOpened.js +++ b/openpype/hosts/harmony/api/TB_sceneOpened.js @@ -279,19 +279,13 @@ function Client() { }; self._send = function(message) { - var data = new QByteArray(); - var outstr = new QDataStream(data, QIODevice.WriteOnly); - outstr.writeInt(0); - data.append('UTF-8'); - outstr.device().seek(0); - outstr.writeInt(data.size() - 4); - var codec = QTextCodec.codecForUtfText(data); - var msg = codec.fromUnicode(message); - var l = msg.size(); - var coded = new QByteArray('AH').append(self.pack(l)); - coded = coded.append(msg); - self.socket.write(new QByteArray(coded)); - self.logDebug('Sent.'); + var codec_name = new QByteArray().append("ISO-8859-1"); + var codec = QTextCodec.codecForName(codec_name); + var msg = codec.fromUnicode(message); + var l = msg.size(); + var coded = new QByteArray().append('AH').append(self.pack(l)).append(msg); + self.socket.write(new QByteArray(coded)); + self.logDebug('Sent.'); }; self.waitForLock = function() { @@ -343,6 +337,7 @@ function start() { var host = '127.0.0.1'; /** port of the server */ var port = parseInt(System.getenv('AVALON_HARMONY_PORT')); + MessageLog.trace("port " + port.toString()); // Attach the client to the QApplication to preserve. var app = QCoreApplication.instance(); @@ -351,7 +346,15 @@ function start() { app.avalonClient = new Client(); app.avalonClient.socket.connectToHost(host, port); } - var menuBar = QApplication.activeWindow().menuBar(); + var mainWindow = null; + var widgets = QApplication.topLevelWidgets(); + for (var i = 0 ; i < widgets.length; i++) { + if (widgets[i] instanceof QMainWindow){ + MessageLog.trace('(DEBUG): START Main window '); + mainWindow = widgets[i]; + } + } + var menuBar = mainWindow.menuBar(); var actions = menuBar.actions(); app.avalonMenu = null; From f213a33f130d336ca8345ab64bbc6d1105c3a379 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 25 May 2022 19:40:40 +0200 Subject: [PATCH 238/350] Fix - Harmony 21.1 messed up Javascript Qt API Removed missed logging --- openpype/hosts/harmony/api/TB_sceneOpened.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/hosts/harmony/api/TB_sceneOpened.js b/openpype/hosts/harmony/api/TB_sceneOpened.js index 29473bcc93..610b0a73bb 100644 --- a/openpype/hosts/harmony/api/TB_sceneOpened.js +++ b/openpype/hosts/harmony/api/TB_sceneOpened.js @@ -337,7 +337,6 @@ function start() { var host = '127.0.0.1'; /** port of the server */ var port = parseInt(System.getenv('AVALON_HARMONY_PORT')); - MessageLog.trace("port " + port.toString()); // Attach the client to the QApplication to preserve. var app = QCoreApplication.instance(); @@ -350,7 +349,6 @@ function start() { var widgets = QApplication.topLevelWidgets(); for (var i = 0 ; i < widgets.length; i++) { if (widgets[i] instanceof QMainWindow){ - MessageLog.trace('(DEBUG): START Main window '); mainWindow = widgets[i]; } } From 78ddd548287c00eb99aaeb99624d380314172052 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 26 May 2022 10:42:31 +0200 Subject: [PATCH 239/350] init file for tvpaint worker also has set path to not existing file in guidelines --- openpype/hosts/tvpaint/worker/init_file.tvpp | Bin 59333 -> 59973 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/openpype/hosts/tvpaint/worker/init_file.tvpp b/openpype/hosts/tvpaint/worker/init_file.tvpp index 572d278fdb49c619d3cf040f59238377d1062d6a..22170b45bc728d3d46193a35fa5216e5c739e8cf 100644 GIT binary patch delta 627 zcmZ`!&r94u6n-1o7WW`Zp|ppVoa$-UWMbA$V4$EB5B?|x5xnSZcA6b`HWPLdQ4j>h zOHVDi6%=}`g_aV$mEuM4=0(uIz|#H|eTnu`^ufFz-+SNt=AE7oon8#RfBgJU-PvFA zf4m&KJluxSm2XF1ptOhE7+!pzoHw4j-~)jsm|%g2xl?)qUjETIFe*;gsvbWYhFK7x zApr#g*n&FP*<97TgFJ;RY#`ZTb@2`sxrbE<>gYp z2h-361`&jaR)FL)4}MD{{hCeaH6xwNKj_^`O`pA5d@~QAPx5E!yS6drWS=k3t1J~A zmF-(*}bzUpvFib`vt6KY`^C@ER2Ikj&JHK3Mhla`6R;vxE0inyHZ ziKs)T5Rt6SC0$U7$v1J4h(c5JS;!mfaagof(A(jilGA5{5SKR*R_%2jpz5vFi};`W z*Td43?b!*s;r^1=F%9nU9TO){MXT^5Br`*cmR*T2%g@OG;2 delta 199 zcmX?lh56`t<_ThQ&(|8ahFa}$5WGIGhCv`|{i@XrV8A8p>0If=z3$r*`x>8X Date: Thu, 26 May 2022 10:42:37 +0200 Subject: [PATCH 240/350] OP-2787 - changed assert to PublishXmlValidationError --- .../help/submit_maya_remote_publish_deadline.xml | 16 ++++++++++++++++ .../submit_maya_remote_publish_deadline.py | 8 ++++---- 2 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 openpype/hosts/maya/plugins/publish/help/submit_maya_remote_publish_deadline.xml diff --git a/openpype/hosts/maya/plugins/publish/help/submit_maya_remote_publish_deadline.xml b/openpype/hosts/maya/plugins/publish/help/submit_maya_remote_publish_deadline.xml new file mode 100644 index 0000000000..e92320ccdc --- /dev/null +++ b/openpype/hosts/maya/plugins/publish/help/submit_maya_remote_publish_deadline.xml @@ -0,0 +1,16 @@ + + + +Errors found + +## Publish process has errors + +At least one plugin failed before this plugin, job won't be sent to Deadline for processing before all issues are fixed. + +### How to repair? + +Check all failing plugins (should be highlighted in red) and fix issues if possible. + + + + \ No newline at end of file diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py index b11698f8e8..be8c50d7b3 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py @@ -3,7 +3,7 @@ import requests from maya import cmds -from openpype.pipeline import legacy_io +from openpype.pipeline import legacy_io, PublishXmlValidationError from openpype.settings import get_project_settings import pyblish.api @@ -39,9 +39,9 @@ class MayaSubmitRemotePublishDeadline(pyblish.api.InstancePlugin): ["ProcessSubmittedJobOnFarm"]) # Ensure no errors so far - assert (all(result["success"] - for result in instance.context.data["results"]), - ("Errors found, aborting integration..")) + if not (all(result["success"] + for result in instance.context.data["results"])): + raise PublishXmlValidationError("Publish process has errors") if not instance.data["publish"]: self.log.warning("No active instances found. " From 4ca419f0b63c2782d8955b8012674ca131a57ad9 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 26 May 2022 11:36:49 +0200 Subject: [PATCH 241/350] Revert "OP-2787 - removed deadline family" This reverts commit 6b71ff19 --- .../maya/plugins/publish/collect_animation.py | 3 +++ .../maya/plugins/publish/collect_pointcache.py | 14 ++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 openpype/hosts/maya/plugins/publish/collect_pointcache.py diff --git a/openpype/hosts/maya/plugins/publish/collect_animation.py b/openpype/hosts/maya/plugins/publish/collect_animation.py index 9b1e38fd0a..b442113fbc 100644 --- a/openpype/hosts/maya/plugins/publish/collect_animation.py +++ b/openpype/hosts/maya/plugins/publish/collect_animation.py @@ -55,3 +55,6 @@ class CollectAnimationOutputGeometry(pyblish.api.InstancePlugin): # Store data in the instance for the validator instance.data["out_hierarchy"] = hierarchy + + if instance.data.get("farm"): + instance.data["families"].append("deadline") diff --git a/openpype/hosts/maya/plugins/publish/collect_pointcache.py b/openpype/hosts/maya/plugins/publish/collect_pointcache.py new file mode 100644 index 0000000000..b55babe372 --- /dev/null +++ b/openpype/hosts/maya/plugins/publish/collect_pointcache.py @@ -0,0 +1,14 @@ +import pyblish.api + + +class CollectPointcache(pyblish.api.InstancePlugin): + """Collect pointcache data for instance.""" + + order = pyblish.api.CollectorOrder + 0.4 + families = ["pointcache"] + label = "Collect Pointcache" + hosts = ["maya"] + + def process(self, instance): + if instance.data.get("farm"): + instance.data["families"].append("deadline") \ No newline at end of file From c96ea856425550835c7c5dfc42b1965a54ca0902 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 26 May 2022 11:40:19 +0200 Subject: [PATCH 242/350] OP-2787 - change families to more generic Not only Deadline could be used for remote publish. DL plugin will be picked only if DL module is enabled. --- openpype/hosts/maya/plugins/publish/collect_animation.py | 2 +- openpype/hosts/maya/plugins/publish/collect_pointcache.py | 2 +- .../plugins/publish/submit_maya_remote_publish_deadline.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_animation.py b/openpype/hosts/maya/plugins/publish/collect_animation.py index b442113fbc..549098863f 100644 --- a/openpype/hosts/maya/plugins/publish/collect_animation.py +++ b/openpype/hosts/maya/plugins/publish/collect_animation.py @@ -57,4 +57,4 @@ class CollectAnimationOutputGeometry(pyblish.api.InstancePlugin): instance.data["out_hierarchy"] = hierarchy if instance.data.get("farm"): - instance.data["families"].append("deadline") + instance.data["families"].append("publish.farm") diff --git a/openpype/hosts/maya/plugins/publish/collect_pointcache.py b/openpype/hosts/maya/plugins/publish/collect_pointcache.py index b55babe372..a841341f72 100644 --- a/openpype/hosts/maya/plugins/publish/collect_pointcache.py +++ b/openpype/hosts/maya/plugins/publish/collect_pointcache.py @@ -11,4 +11,4 @@ class CollectPointcache(pyblish.api.InstancePlugin): def process(self, instance): if instance.data.get("farm"): - instance.data["families"].append("deadline") \ No newline at end of file + instance.data["families"].append("publish.farm") diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py index be8c50d7b3..210fefb520 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py @@ -29,7 +29,7 @@ class MayaSubmitRemotePublishDeadline(pyblish.api.InstancePlugin): label = "Submit Scene to Deadline" order = pyblish.api.IntegratorOrder hosts = ["maya"] - families = ["deadline"] + families = ["publish.farm"] def process(self, instance): settings = get_project_settings(os.getenv("AVALON_PROJECT")) From 0d03e3e2f836476310b899a21aec5b49dbd2a7c8 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 26 May 2022 11:40:50 +0200 Subject: [PATCH 243/350] OP-2787 - removed obsolete part of code Doesn't do anything. --- openpype/hosts/maya/plugins/publish/extract_animation.py | 7 +------ openpype/hosts/maya/plugins/publish/extract_pointcache.py | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_animation.py b/openpype/hosts/maya/plugins/publish/extract_animation.py index 87f2d35192..1ccc8f5cfe 100644 --- a/openpype/hosts/maya/plugins/publish/extract_animation.py +++ b/openpype/hosts/maya/plugins/publish/extract_animation.py @@ -24,12 +24,7 @@ class ExtractAnimation(openpype.api.Extractor): def process(self, instance): if instance.data.get("farm"): - path = os.path.join( - os.path.dirname(instance.context.data["currentFile"]), - "cache", - instance.data["name"] + ".abc" - ) - instance.data["expectedFiles"] = [os.path.normpath(path)] + self.log.debug("Should be processed on farm, skipping.") return # Collect the out set nodes diff --git a/openpype/hosts/maya/plugins/publish/extract_pointcache.py b/openpype/hosts/maya/plugins/publish/extract_pointcache.py index 7ad4c6dfa9..ff3d97ded1 100644 --- a/openpype/hosts/maya/plugins/publish/extract_pointcache.py +++ b/openpype/hosts/maya/plugins/publish/extract_pointcache.py @@ -26,12 +26,7 @@ class ExtractAlembic(openpype.api.Extractor): def process(self, instance): if instance.data.get("farm"): - path = os.path.join( - os.path.dirname(instance.context.data["currentFile"]), - "cache", - instance.data["name"] + ".abc" - ) - instance.data["expectedFiles"] = [os.path.normpath(path)] + self.log.debug("Should be processed on farm, skipping.") return nodes = instance[:] From de161da68b4035c4fde2e376dc8da1ab2b79d093 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 26 May 2022 11:45:29 +0200 Subject: [PATCH 244/350] OP-2787 - created explicit env var HEADLESS_PUBLISH Env var created to differentiate launch of Maya on the farm. lib.IS_HEADLESS might be triggered locally, it is not precise enough. Added same env var to all commands to standardize it a bit. --- openpype/hosts/maya/api/pipeline.py | 5 ++++- .../submit_maya_remote_publish_deadline.py | 2 ++ openpype/pype_commands.py | 18 +++++++++++++----- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/maya/api/pipeline.py b/openpype/hosts/maya/api/pipeline.py index c2fe8a95a5..6fc93e864f 100644 --- a/openpype/hosts/maya/api/pipeline.py +++ b/openpype/hosts/maya/api/pipeline.py @@ -72,7 +72,10 @@ def install(): log.info(("Running in headless mode, skipping Maya " "save/open/new callback installation..")) - # Register default "local" target + return + + if os.environ.get("HEADLESS_PUBLISH"): + # Maya launched on farm, lib.IS_HEADLESS might be triggered locally too print("Registering pyblish target: remote") pyblish.api.register_target("remote") return diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py index 210fefb520..8f50878db4 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py @@ -114,6 +114,8 @@ class MayaSubmitRemotePublishDeadline(pyblish.api.InstancePlugin): environment["OPENPYPE_REMOTE_JOB"] = "1" environment["OPENPYPE_USERNAME"] = instance.context.data["user"] environment["OPENPYPE_PUBLISH_SUBSET"] = instance.data["subset"] + environment["HEADLESS_PUBLISH"] = "1" + payload["JobInfo"].update({ "EnvironmentKeyValue%d" % index: "{key}={value}".format( diff --git a/openpype/pype_commands.py b/openpype/pype_commands.py index d945a1f697..90c582a319 100644 --- a/openpype/pype_commands.py +++ b/openpype/pype_commands.py @@ -144,6 +144,7 @@ class PypeCommands: pyblish.api.register_target("farm") os.environ["OPENPYPE_PUBLISH_DATA"] = os.pathsep.join(paths) + os.environ["HEADLESS_PUBLISH"] = 'true' # to use in app lib log.info("Running publish ...") @@ -173,9 +174,11 @@ class PypeCommands: user_email, targets=None): """Opens installed variant of 'host' and run remote publish there. + Eventually should be yanked out to Webpublisher cli. + Currently implemented and tested for Photoshop where customer wants to process uploaded .psd file and publish collected layers - from there. + from there. Triggered by Webpublisher. Checks if no other batches are running (status =='in_progress). If so, it sleeps for SLEEP (this is separate process), @@ -273,7 +276,8 @@ class PypeCommands: def remotepublish(project, batch_path, user_email, targets=None): """Start headless publishing. - Used to publish rendered assets, workfiles etc. + Used to publish rendered assets, workfiles etc via Webpublisher. + Eventually should be yanked out to Webpublisher cli. Publish use json from passed paths argument. @@ -309,6 +313,7 @@ class PypeCommands: os.environ["AVALON_PROJECT"] = project os.environ["AVALON_APP"] = host_name os.environ["USER_EMAIL"] = user_email + os.environ["HEADLESS_PUBLISH"] = 'true' # to use in app lib pyblish.api.register_host(host_name) @@ -331,9 +336,12 @@ class PypeCommands: log.info("Publish finished.") @staticmethod - def extractenvironments( - output_json_path, project, asset, task, app, env_group - ): + def extractenvironments(output_json_path, project, asset, task, app, + env_group): + """Produces json file with environment based on project and app. + + Called by Deadline plugin to propagate environment into render jobs. + """ if all((project, asset, task, app)): from openpype.api import get_app_environments_for_context env = get_app_environments_for_context( From 8cda0ebbeef23ceccc7f1a9d9963eecc93219012 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 26 May 2022 12:09:13 +0200 Subject: [PATCH 245/350] OP-2787 - Hound --- .../plugins/publish/collect_publishable_instances.py | 7 ++++--- .../plugins/publish/submit_maya_remote_publish_deadline.py | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/collect_publishable_instances.py b/openpype/modules/deadline/plugins/publish/collect_publishable_instances.py index 9a467428fd..741a2a5af8 100644 --- a/openpype/modules/deadline/plugins/publish/collect_publishable_instances.py +++ b/openpype/modules/deadline/plugins/publish/collect_publishable_instances.py @@ -5,6 +5,7 @@ import os import pyblish.api +from openpype.pipeline import PublishValidationError class CollectDeadlinePublishableInstances(pyblish.api.InstancePlugin): @@ -24,9 +25,9 @@ class CollectDeadlinePublishableInstances(pyblish.api.InstancePlugin): def process(self, instance): self.log.debug("CollectDeadlinePublishableInstances") publish_inst = os.environ.get("OPENPYPE_PUBLISH_SUBSET", '') - assert (publish_inst, - "OPENPYPE_PUBLISH_SUBSET env var required for " - "remote publishing") + if not publish_inst: + raise PublishValidationError("OPENPYPE_PUBLISH_SUBSET env var " + "required for remote publishing") subset_name = instance.data["subset"] if subset_name == publish_inst: diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py index 8f50878db4..196adc5906 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_remote_publish_deadline.py @@ -116,7 +116,6 @@ class MayaSubmitRemotePublishDeadline(pyblish.api.InstancePlugin): environment["OPENPYPE_PUBLISH_SUBSET"] = instance.data["subset"] environment["HEADLESS_PUBLISH"] = "1" - payload["JobInfo"].update({ "EnvironmentKeyValue%d" % index: "{key}={value}".format( key=key, From 15822591793cb94ea730941358abb0a06dac211c Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 26 May 2022 14:07:30 +0200 Subject: [PATCH 246/350] :truck: split versions of integration plugin --- openpype/hosts/unreal/__init__.py | 10 +- .../integration/{ => UE_4.7}/.gitignore | 0 .../Content/Python/init_unreal.py | 0 .../integration/{ => UE_4.7}/OpenPype.uplugin | 0 .../unreal/integration/{ => UE_4.7}/README.md | 2 +- .../{ => UE_4.7}/Resources/openpype128.png | Bin .../{ => UE_4.7}/Resources/openpype40.png | Bin .../{ => UE_4.7}/Resources/openpype512.png | Bin .../UE_4.7/Source/OpenPype/OpenPype.Build.cs | 57 +++++++++ .../OpenPype/Private/AssetContainer.cpp | 0 .../Private/AssetContainerFactory.cpp | 0 .../Source/OpenPype/Private/OpenPype.cpp | 103 ++++++++++++++++ .../Source/OpenPype/Private/OpenPypeLib.cpp | 0 .../Private/OpenPypePublishInstance.cpp | 0 .../OpenPypePublishInstanceFactory.cpp | 0 .../OpenPype/Private/OpenPypePythonBridge.cpp | 0 .../Source/OpenPype/Private/OpenPypeStyle.cpp | 70 +++++++++++ .../Source/OpenPype/Public/AssetContainer.h | 0 .../OpenPype/Public/AssetContainerFactory.h | 0 .../UE_4.7/Source/OpenPype/Public/OpenPype.h | 21 ++++ .../Source/OpenPype/Public/OpenPypeLib.h | 0 .../OpenPype/Public/OpenPypePublishInstance.h | 0 .../Public/OpenPypePublishInstanceFactory.h | 0 .../OpenPype/Public/OpenPypePythonBridge.h | 0 .../Source/OpenPype/Public/OpenPypeStyle.h | 22 ++++ .../unreal/integration/UE_5.0/.gitignore | 35 ++++++ .../UE_5.0/Content/Python/__init__.py | 0 .../UE_5.0/Content/Python/init_unreal.py | 28 +++++ .../integration/UE_5.0/Content/__init__.py | 0 .../integration/UE_5.0/OpenPype.uplugin | 24 ++++ .../hosts/unreal/integration/UE_5.0/README.md | 11 ++ .../UE_5.0/Resources/openpype128.png | Bin 0 -> 14594 bytes .../UE_5.0/Resources/openpype40.png | Bin 0 -> 4884 bytes .../UE_5.0/Resources/openpype512.png | Bin 0 -> 85856 bytes .../Source/OpenPype/OpenPype.Build.cs | 0 .../OpenPype/Private/AssetContainer.cpp | 115 ++++++++++++++++++ .../Private/AssetContainerFactory.cpp | 20 +++ .../Source/OpenPype/Private/OpenPype.cpp | 0 .../OpenPype/Private/OpenPypeCommands.cpp | 0 .../Source/OpenPype/Private/OpenPypeLib.cpp | 48 ++++++++ .../Private/OpenPypePublishInstance.cpp | 108 ++++++++++++++++ .../OpenPypePublishInstanceFactory.cpp | 20 +++ .../OpenPype/Private/OpenPypePythonBridge.cpp | 13 ++ .../Source/OpenPype/Private/OpenPypeStyle.cpp | 0 .../Source/OpenPype/Public/AssetContainer.h | 39 ++++++ .../OpenPype/Public/AssetContainerFactory.h | 21 ++++ .../Source/OpenPype/Public/OpenPype.h | 0 .../Source/OpenPype/Public/OpenPypeCommands.h | 0 .../Source/OpenPype/Public/OpenPypeLib.h | 19 +++ .../OpenPype/Public/OpenPypePublishInstance.h | 21 ++++ .../Public/OpenPypePublishInstanceFactory.h | 19 +++ .../OpenPype/Public/OpenPypePythonBridge.h | 20 +++ .../Source/OpenPype/Public/OpenPypeStyle.h | 0 .../system_settings/applications.json | 12 +- repos/avalon-core | 1 - 55 files changed, 854 insertions(+), 5 deletions(-) rename openpype/hosts/unreal/integration/{ => UE_4.7}/.gitignore (100%) rename openpype/hosts/unreal/integration/{ => UE_4.7}/Content/Python/init_unreal.py (100%) rename openpype/hosts/unreal/integration/{ => UE_4.7}/OpenPype.uplugin (100%) rename openpype/hosts/unreal/integration/{ => UE_4.7}/README.md (91%) rename openpype/hosts/unreal/integration/{ => UE_4.7}/Resources/openpype128.png (100%) rename openpype/hosts/unreal/integration/{ => UE_4.7}/Resources/openpype40.png (100%) rename openpype/hosts/unreal/integration/{ => UE_4.7}/Resources/openpype512.png (100%) create mode 100644 openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/OpenPype.Build.cs rename openpype/hosts/unreal/integration/{ => UE_4.7}/Source/OpenPype/Private/AssetContainer.cpp (100%) rename openpype/hosts/unreal/integration/{ => UE_4.7}/Source/OpenPype/Private/AssetContainerFactory.cpp (100%) create mode 100644 openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp rename openpype/hosts/unreal/integration/{ => UE_4.7}/Source/OpenPype/Private/OpenPypeLib.cpp (100%) rename openpype/hosts/unreal/integration/{ => UE_4.7}/Source/OpenPype/Private/OpenPypePublishInstance.cpp (100%) rename openpype/hosts/unreal/integration/{ => UE_4.7}/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp (100%) rename openpype/hosts/unreal/integration/{ => UE_4.7}/Source/OpenPype/Private/OpenPypePythonBridge.cpp (100%) create mode 100644 openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeStyle.cpp rename openpype/hosts/unreal/integration/{ => UE_4.7}/Source/OpenPype/Public/AssetContainer.h (100%) rename openpype/hosts/unreal/integration/{ => UE_4.7}/Source/OpenPype/Public/AssetContainerFactory.h (100%) create mode 100644 openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPype.h rename openpype/hosts/unreal/integration/{ => UE_4.7}/Source/OpenPype/Public/OpenPypeLib.h (100%) rename openpype/hosts/unreal/integration/{ => UE_4.7}/Source/OpenPype/Public/OpenPypePublishInstance.h (100%) rename openpype/hosts/unreal/integration/{ => UE_4.7}/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h (100%) rename openpype/hosts/unreal/integration/{ => UE_4.7}/Source/OpenPype/Public/OpenPypePythonBridge.h (100%) create mode 100644 openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeStyle.h create mode 100644 openpype/hosts/unreal/integration/UE_5.0/.gitignore create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Content/Python/__init__.py create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Content/Python/init_unreal.py create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Content/__init__.py create mode 100644 openpype/hosts/unreal/integration/UE_5.0/OpenPype.uplugin create mode 100644 openpype/hosts/unreal/integration/UE_5.0/README.md create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Resources/openpype128.png create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Resources/openpype40.png create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Resources/openpype512.png rename openpype/hosts/unreal/integration/{ => UE_5.0}/Source/OpenPype/OpenPype.Build.cs (100%) create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/AssetContainer.cpp create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/AssetContainerFactory.cpp rename openpype/hosts/unreal/integration/{ => UE_5.0}/Source/OpenPype/Private/OpenPype.cpp (100%) rename openpype/hosts/unreal/integration/{ => UE_5.0}/Source/OpenPype/Private/OpenPypeCommands.cpp (100%) create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeLib.cpp create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstance.cpp create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePythonBridge.cpp rename openpype/hosts/unreal/integration/{ => UE_5.0}/Source/OpenPype/Private/OpenPypeStyle.cpp (100%) create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/AssetContainer.h create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/AssetContainerFactory.h rename openpype/hosts/unreal/integration/{ => UE_5.0}/Source/OpenPype/Public/OpenPype.h (100%) rename openpype/hosts/unreal/integration/{ => UE_5.0}/Source/OpenPype/Public/OpenPypeCommands.h (100%) create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeLib.h create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstance.h create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePythonBridge.h rename openpype/hosts/unreal/integration/{ => UE_5.0}/Source/OpenPype/Public/OpenPypeStyle.h (100%) delete mode 160000 repos/avalon-core diff --git a/openpype/hosts/unreal/__init__.py b/openpype/hosts/unreal/__init__.py index bedf5a29f7..ae9b113acd 100644 --- a/openpype/hosts/unreal/__init__.py +++ b/openpype/hosts/unreal/__init__.py @@ -1,13 +1,19 @@ import os import openpype.hosts +from openpype.lib.applications import Application -def add_implementation_envs(env, _app): +def add_implementation_envs(env: dict, _app: Application) -> None: """Modify environments to contain all required for implementation.""" # Set OPENPYPE_UNREAL_PLUGIN required for Unreal implementation + + engine_version = _app.name.split("/")[-1].replace("-", ".") + major_version = int(engine_version.split(".")[0]) + + ue_plugin = "UE_4.7" if major_version == 4 else "UE_5.0" unreal_plugin_path = os.path.join( os.path.dirname(os.path.abspath(openpype.hosts.__file__)), - "unreal", "integration" + "unreal", "integration", ue_plugin ) if not env.get("OPENPYPE_UNREAL_PLUGIN"): env["OPENPYPE_UNREAL_PLUGIN"] = unreal_plugin_path diff --git a/openpype/hosts/unreal/integration/.gitignore b/openpype/hosts/unreal/integration/UE_4.7/.gitignore similarity index 100% rename from openpype/hosts/unreal/integration/.gitignore rename to openpype/hosts/unreal/integration/UE_4.7/.gitignore diff --git a/openpype/hosts/unreal/integration/Content/Python/init_unreal.py b/openpype/hosts/unreal/integration/UE_4.7/Content/Python/init_unreal.py similarity index 100% rename from openpype/hosts/unreal/integration/Content/Python/init_unreal.py rename to openpype/hosts/unreal/integration/UE_4.7/Content/Python/init_unreal.py diff --git a/openpype/hosts/unreal/integration/OpenPype.uplugin b/openpype/hosts/unreal/integration/UE_4.7/OpenPype.uplugin similarity index 100% rename from openpype/hosts/unreal/integration/OpenPype.uplugin rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype.uplugin diff --git a/openpype/hosts/unreal/integration/README.md b/openpype/hosts/unreal/integration/UE_4.7/README.md similarity index 91% rename from openpype/hosts/unreal/integration/README.md rename to openpype/hosts/unreal/integration/UE_4.7/README.md index a32d89aab8..a08c1ada39 100644 --- a/openpype/hosts/unreal/integration/README.md +++ b/openpype/hosts/unreal/integration/UE_4.7/README.md @@ -1,4 +1,4 @@ -# OpenPype Unreal Integration plugin +# OpenPype Unreal Integration plugin - UE 4.x This is plugin for Unreal Editor, creating menu for [OpenPype](https://github.com/getavalon) tools to run. diff --git a/openpype/hosts/unreal/integration/Resources/openpype128.png b/openpype/hosts/unreal/integration/UE_4.7/Resources/openpype128.png similarity index 100% rename from openpype/hosts/unreal/integration/Resources/openpype128.png rename to openpype/hosts/unreal/integration/UE_4.7/Resources/openpype128.png diff --git a/openpype/hosts/unreal/integration/Resources/openpype40.png b/openpype/hosts/unreal/integration/UE_4.7/Resources/openpype40.png similarity index 100% rename from openpype/hosts/unreal/integration/Resources/openpype40.png rename to openpype/hosts/unreal/integration/UE_4.7/Resources/openpype40.png diff --git a/openpype/hosts/unreal/integration/Resources/openpype512.png b/openpype/hosts/unreal/integration/UE_4.7/Resources/openpype512.png similarity index 100% rename from openpype/hosts/unreal/integration/Resources/openpype512.png rename to openpype/hosts/unreal/integration/UE_4.7/Resources/openpype512.png diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/OpenPype.Build.cs b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/OpenPype.Build.cs new file mode 100644 index 0000000000..c30835b63d --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/OpenPype.Build.cs @@ -0,0 +1,57 @@ +// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class OpenPype : ModuleRules +{ + public OpenPype(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + + PublicIncludePaths.AddRange( + new string[] { + // ... add public include paths required here ... + } + ); + + + PrivateIncludePaths.AddRange( + new string[] { + // ... add other private include paths required here ... + } + ); + + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + // ... add other public dependencies that you statically link with here ... + } + ); + + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "Projects", + "InputCore", + "UnrealEd", + "LevelEditor", + "CoreUObject", + "Engine", + "Slate", + "SlateCore", + // ... add private dependencies that you statically link with here ... + } + ); + + + DynamicallyLoadedModuleNames.AddRange( + new string[] + { + // ... add any modules that your module loads dynamically here ... + } + ); + } +} diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Private/AssetContainer.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/AssetContainer.cpp similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Private/AssetContainer.cpp rename to openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/AssetContainer.cpp diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Private/AssetContainerFactory.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/AssetContainerFactory.cpp similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Private/AssetContainerFactory.cpp rename to openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/AssetContainerFactory.cpp diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp new file mode 100644 index 0000000000..15c46b3862 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp @@ -0,0 +1,103 @@ +#include "OpenPype.h" +#include "LevelEditor.h" +#include "OpenPypePythonBridge.h" +#include "OpenPypeStyle.h" + + +static const FName OpenPypeTabName("OpenPype"); + +#define LOCTEXT_NAMESPACE "FOpenPypeModule" + +// This function is triggered when the plugin is staring up +void FOpenPypeModule::StartupModule() +{ + + FOpenPypeStyle::Initialize(); + FOpenPypeStyle::SetIcon("Logo", "openpype40"); + + // Create the Extender that will add content to the menu + FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked("LevelEditor"); + + TSharedPtr MenuExtender = MakeShareable(new FExtender()); + TSharedPtr ToolbarExtender = MakeShareable(new FExtender()); + + MenuExtender->AddMenuExtension( + "LevelEditor", + EExtensionHook::After, + NULL, + FMenuExtensionDelegate::CreateRaw(this, &FOpenPypeModule::AddMenuEntry) + ); + ToolbarExtender->AddToolBarExtension( + "Settings", + EExtensionHook::After, + NULL, + FToolBarExtensionDelegate::CreateRaw(this, &FOpenPypeModule::AddToobarEntry)); + + + LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender); + LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender); + +} + +void FOpenPypeModule::ShutdownModule() +{ + FOpenPypeStyle::Shutdown(); +} + + +void FOpenPypeModule::AddMenuEntry(FMenuBuilder& MenuBuilder) +{ + // Create Section + MenuBuilder.BeginSection("OpenPype", TAttribute(FText::FromString("OpenPype"))); + { + // Create a Submenu inside of the Section + MenuBuilder.AddMenuEntry( + FText::FromString("Tools..."), + FText::FromString("Pipeline tools"), + FSlateIcon(FOpenPypeStyle::GetStyleSetName(), "OpenPype.Logo"), + FUIAction(FExecuteAction::CreateRaw(this, &FOpenPypeModule::MenuPopup)) + ); + + MenuBuilder.AddMenuEntry( + FText::FromString("Tools dialog..."), + FText::FromString("Pipeline tools dialog"), + FSlateIcon(FOpenPypeStyle::GetStyleSetName(), "OpenPype.Logo"), + FUIAction(FExecuteAction::CreateRaw(this, &FOpenPypeModule::MenuDialog)) + ); + + } + MenuBuilder.EndSection(); +} + +void FOpenPypeModule::AddToobarEntry(FToolBarBuilder& ToolbarBuilder) +{ + ToolbarBuilder.BeginSection(TEXT("OpenPype")); + { + ToolbarBuilder.AddToolBarButton( + FUIAction( + FExecuteAction::CreateRaw(this, &FOpenPypeModule::MenuPopup), + NULL, + FIsActionChecked() + + ), + NAME_None, + LOCTEXT("OpenPype_label", "OpenPype"), + LOCTEXT("OpenPype_tooltip", "OpenPype Tools"), + FSlateIcon(FOpenPypeStyle::GetStyleSetName(), "OpenPype.Logo") + ); + } + ToolbarBuilder.EndSection(); +} + + +void FOpenPypeModule::MenuPopup() { + UOpenPypePythonBridge* bridge = UOpenPypePythonBridge::Get(); + bridge->RunInPython_Popup(); +} + +void FOpenPypeModule::MenuDialog() { + UOpenPypePythonBridge* bridge = UOpenPypePythonBridge::Get(); + bridge->RunInPython_Dialog(); +} + +IMPLEMENT_MODULE(FOpenPypeModule, OpenPype) diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypeLib.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeLib.cpp similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypeLib.cpp rename to openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeLib.cpp diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypePublishInstance.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePublishInstance.cpp similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypePublishInstance.cpp rename to openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePublishInstance.cpp diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp rename to openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypePythonBridge.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePythonBridge.cpp similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypePythonBridge.cpp rename to openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePythonBridge.cpp diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeStyle.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeStyle.cpp new file mode 100644 index 0000000000..a51c2d6aa5 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeStyle.cpp @@ -0,0 +1,70 @@ +#include "OpenPypeStyle.h" +#include "Framework/Application/SlateApplication.h" +#include "Styling/SlateStyle.h" +#include "Styling/SlateStyleRegistry.h" + + +TUniquePtr< FSlateStyleSet > FOpenPypeStyle::OpenPypeStyleInstance = nullptr; + +void FOpenPypeStyle::Initialize() +{ + if (!OpenPypeStyleInstance.IsValid()) + { + OpenPypeStyleInstance = Create(); + FSlateStyleRegistry::RegisterSlateStyle(*OpenPypeStyleInstance); + } +} + +void FOpenPypeStyle::Shutdown() +{ + if (OpenPypeStyleInstance.IsValid()) + { + FSlateStyleRegistry::UnRegisterSlateStyle(*OpenPypeStyleInstance); + OpenPypeStyleInstance.Reset(); + } +} + +FName FOpenPypeStyle::GetStyleSetName() +{ + static FName StyleSetName(TEXT("OpenPypeStyle")); + return StyleSetName; +} + +FName FOpenPypeStyle::GetContextName() +{ + static FName ContextName(TEXT("OpenPype")); + return ContextName; +} + +#define IMAGE_BRUSH(RelativePath, ...) FSlateImageBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ ) + +const FVector2D Icon40x40(40.0f, 40.0f); + +TUniquePtr< FSlateStyleSet > FOpenPypeStyle::Create() +{ + TUniquePtr< FSlateStyleSet > Style = MakeUnique(GetStyleSetName()); + Style->SetContentRoot(FPaths::ProjectPluginsDir() / TEXT("OpenPype/Resources")); + + return Style; +} + +void FOpenPypeStyle::SetIcon(const FString& StyleName, const FString& ResourcePath) +{ + FSlateStyleSet* Style = OpenPypeStyleInstance.Get(); + + FString Name(GetContextName().ToString()); + Name = Name + "." + StyleName; + Style->Set(*Name, new FSlateImageBrush(Style->RootToContentDir(ResourcePath, TEXT(".png")), Icon40x40)); + + + FSlateApplication::Get().GetRenderer()->ReloadTextureResources(); +} + +#undef IMAGE_BRUSH + +const ISlateStyle& FOpenPypeStyle::Get() +{ + check(OpenPypeStyleInstance); + return *OpenPypeStyleInstance; + return *OpenPypeStyleInstance; +} diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Public/AssetContainer.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/AssetContainer.h similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Public/AssetContainer.h rename to openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/AssetContainer.h diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Public/AssetContainerFactory.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/AssetContainerFactory.h similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Public/AssetContainerFactory.h rename to openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/AssetContainerFactory.h diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPype.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPype.h new file mode 100644 index 0000000000..db3f299354 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPype.h @@ -0,0 +1,21 @@ +// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Engine.h" + + +class FOpenPypeModule : public IModuleInterface +{ +public: + virtual void StartupModule() override; + virtual void ShutdownModule() override; + +private: + + void AddMenuEntry(FMenuBuilder& MenuBuilder); + void AddToobarEntry(FToolBarBuilder& ToolbarBuilder); + void MenuPopup(); + void MenuDialog(); + +}; diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypeLib.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeLib.h similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypeLib.h rename to openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeLib.h diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypePublishInstance.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePublishInstance.h similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypePublishInstance.h rename to openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePublishInstance.h diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h rename to openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypePythonBridge.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePythonBridge.h similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypePythonBridge.h rename to openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePythonBridge.h diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeStyle.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeStyle.h new file mode 100644 index 0000000000..fbc8bcdd5b --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeStyle.h @@ -0,0 +1,22 @@ +#pragma once +#include "CoreMinimal.h" + +class FSlateStyleSet; +class ISlateStyle; + + +class FOpenPypeStyle +{ +public: + static void Initialize(); + static void Shutdown(); + static const ISlateStyle& Get(); + static FName GetStyleSetName(); + static FName GetContextName(); + + static void SetIcon(const FString& StyleName, const FString& ResourcePath); + +private: + static TUniquePtr< FSlateStyleSet > Create(); + static TUniquePtr< FSlateStyleSet > OpenPypeStyleInstance; +}; \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_5.0/.gitignore b/openpype/hosts/unreal/integration/UE_5.0/.gitignore new file mode 100644 index 0000000000..b32a6f55e5 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/.gitignore @@ -0,0 +1,35 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +/Binaries +/Intermediate diff --git a/openpype/hosts/unreal/integration/UE_5.0/Content/Python/__init__.py b/openpype/hosts/unreal/integration/UE_5.0/Content/Python/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openpype/hosts/unreal/integration/UE_5.0/Content/Python/init_unreal.py b/openpype/hosts/unreal/integration/UE_5.0/Content/Python/init_unreal.py new file mode 100644 index 0000000000..4bb03b07ed --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Content/Python/init_unreal.py @@ -0,0 +1,28 @@ +import unreal + +openpype_detected = True +try: + from openpype.pipeline import install_host + from openpype.hosts.unreal import api as openpype_host +except ImportError as exc: + openpype_host = None + openpype_detected = False + unreal.log_error("OpenPype: cannot load OpenPype [ {} ]".format(exc)) + +if openpype_detected: + install_host(openpype_host) + + +@unreal.uclass() +class OpenPypeIntegration(unreal.OpenPypePythonBridge): + @unreal.ufunction(override=True) + def RunInPython_Popup(self): + unreal.log_warning("OpenPype: showing tools popup") + if openpype_detected: + openpype_host.show_tools_popup() + + @unreal.ufunction(override=True) + def RunInPython_Dialog(self): + unreal.log_warning("OpenPype: showing tools dialog") + if openpype_detected: + openpype_host.show_tools_dialog() diff --git a/openpype/hosts/unreal/integration/UE_5.0/Content/__init__.py b/openpype/hosts/unreal/integration/UE_5.0/Content/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openpype/hosts/unreal/integration/UE_5.0/OpenPype.uplugin b/openpype/hosts/unreal/integration/UE_5.0/OpenPype.uplugin new file mode 100644 index 0000000000..4c7a74403c --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/OpenPype.uplugin @@ -0,0 +1,24 @@ +{ + "FileVersion": 3, + "Version": 1, + "VersionName": "1.0", + "FriendlyName": "OpenPype", + "Description": "OpenPype Integration", + "Category": "OpenPype.Integration", + "CreatedBy": "Ondrej Samohel", + "CreatedByURL": "https://openpype.io", + "DocsURL": "https://openpype.io/docs/artist_hosts_unreal", + "MarketplaceURL": "", + "SupportURL": "https://pype.club/", + "CanContainContent": true, + "IsBetaVersion": true, + "IsExperimentalVersion": false, + "Installed": false, + "Modules": [ + { + "Name": "OpenPype", + "Type": "Editor", + "LoadingPhase": "Default" + } + ] +} \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_5.0/README.md b/openpype/hosts/unreal/integration/UE_5.0/README.md new file mode 100644 index 0000000000..cf0aa622c2 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/README.md @@ -0,0 +1,11 @@ +# OpenPype Unreal Integration plugin - UE 5.x + +This is plugin for Unreal Editor, creating menu for [OpenPype](https://github.com/getavalon) tools to run. + +## How does this work + +Plugin is creating basic menu items in **Window/OpenPype** section of Unreal Editor main menu and a button +on the main toolbar with associated menu. Clicking on those menu items is calling callbacks that are +declared in C++ but needs to be implemented during Unreal Editor +startup in `Plugins/OpenPype/Content/Python/init_unreal.py` - this should be executed by Unreal Editor +automatically. diff --git a/openpype/hosts/unreal/integration/UE_5.0/Resources/openpype128.png b/openpype/hosts/unreal/integration/UE_5.0/Resources/openpype128.png new file mode 100644 index 0000000000000000000000000000000000000000..abe8a807ef40f00b75d7446d020a2437732c7583 GIT binary patch literal 14594 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 literal 0 HcmV?d00001 diff --git a/openpype/hosts/unreal/integration/UE_5.0/Resources/openpype512.png b/openpype/hosts/unreal/integration/UE_5.0/Resources/openpype512.png new file mode 100644 index 0000000000000000000000000000000000000000..97c4d4326bc16ba6dfb45d35c4362d8bc15900ae GIT binary patch literal 85856 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 bCJFu@j}?W0K?Ok;00000NkvXXu0mjf9`4Bp literal 0 HcmV?d00001 diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/OpenPype.Build.cs b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/OpenPype.Build.cs similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/OpenPype.Build.cs rename to openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/OpenPype.Build.cs diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/AssetContainer.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/AssetContainer.cpp new file mode 100644 index 0000000000..c766f87a8e --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/AssetContainer.cpp @@ -0,0 +1,115 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "AssetContainer.h" +#include "AssetRegistryModule.h" +#include "Misc/PackageName.h" +#include "Engine.h" +#include "Containers/UnrealString.h" + +UAssetContainer::UAssetContainer(const FObjectInitializer& ObjectInitializer) +: UAssetUserData(ObjectInitializer) +{ + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked("AssetRegistry"); + FString path = UAssetContainer::GetPathName(); + UE_LOG(LogTemp, Warning, TEXT("UAssetContainer %s"), *path); + FARFilter Filter; + Filter.PackagePaths.Add(FName(*path)); + + AssetRegistryModule.Get().OnAssetAdded().AddUObject(this, &UAssetContainer::OnAssetAdded); + AssetRegistryModule.Get().OnAssetRemoved().AddUObject(this, &UAssetContainer::OnAssetRemoved); + AssetRegistryModule.Get().OnAssetRenamed().AddUObject(this, &UAssetContainer::OnAssetRenamed); +} + +void UAssetContainer::OnAssetAdded(const FAssetData& AssetData) +{ + TArray split; + + // get directory of current container + FString selfFullPath = UAssetContainer::GetPathName(); + FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath); + + // get asset path and class + FString assetPath = AssetData.GetFullName(); + FString assetFName = AssetData.AssetClass.ToString(); + + // split path + assetPath.ParseIntoArray(split, TEXT(" "), true); + + FString assetDir = FPackageName::GetLongPackagePath(*split[1]); + + // take interest only in paths starting with path of current container + if (assetDir.StartsWith(*selfDir)) + { + // exclude self + if (assetFName != "AssetContainer") + { + assets.Add(assetPath); + assetsData.Add(AssetData); + UE_LOG(LogTemp, Log, TEXT("%s: asset added to %s"), *selfFullPath, *selfDir); + } + } +} + +void UAssetContainer::OnAssetRemoved(const FAssetData& AssetData) +{ + TArray split; + + // get directory of current container + FString selfFullPath = UAssetContainer::GetPathName(); + FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath); + + // get asset path and class + FString assetPath = AssetData.GetFullName(); + FString assetFName = AssetData.AssetClass.ToString(); + + // split path + assetPath.ParseIntoArray(split, TEXT(" "), true); + + FString assetDir = FPackageName::GetLongPackagePath(*split[1]); + + // take interest only in paths starting with path of current container + FString path = UAssetContainer::GetPathName(); + FString lpp = FPackageName::GetLongPackagePath(*path); + + if (assetDir.StartsWith(*selfDir)) + { + // exclude self + if (assetFName != "AssetContainer") + { + // UE_LOG(LogTemp, Warning, TEXT("%s: asset removed"), *lpp); + assets.Remove(assetPath); + assetsData.Remove(AssetData); + } + } +} + +void UAssetContainer::OnAssetRenamed(const FAssetData& AssetData, const FString& str) +{ + TArray split; + + // get directory of current container + FString selfFullPath = UAssetContainer::GetPathName(); + FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath); + + // get asset path and class + FString assetPath = AssetData.GetFullName(); + FString assetFName = AssetData.AssetClass.ToString(); + + // split path + assetPath.ParseIntoArray(split, TEXT(" "), true); + + FString assetDir = FPackageName::GetLongPackagePath(*split[1]); + if (assetDir.StartsWith(*selfDir)) + { + // exclude self + if (assetFName != "AssetContainer") + { + + assets.Remove(str); + assets.Add(assetPath); + assetsData.Remove(AssetData); + // UE_LOG(LogTemp, Warning, TEXT("%s: asset renamed %s"), *lpp, *str); + } + } +} + diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/AssetContainerFactory.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/AssetContainerFactory.cpp new file mode 100644 index 0000000000..b943150bdd --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/AssetContainerFactory.cpp @@ -0,0 +1,20 @@ +#include "AssetContainerFactory.h" +#include "AssetContainer.h" + +UAssetContainerFactory::UAssetContainerFactory(const FObjectInitializer& ObjectInitializer) + : UFactory(ObjectInitializer) +{ + SupportedClass = UAssetContainer::StaticClass(); + bCreateNew = false; + bEditorImport = true; +} + +UObject* UAssetContainerFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) +{ + UAssetContainer* AssetContainer = NewObject(InParent, Class, Name, Flags); + return AssetContainer; +} + +bool UAssetContainerFactory::ShouldShowInNewMenu() const { + return false; +} diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPype.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPype.cpp rename to openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypeCommands.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeCommands.cpp similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypeCommands.cpp rename to openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeCommands.cpp diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeLib.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeLib.cpp new file mode 100644 index 0000000000..5facab7b8b --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeLib.cpp @@ -0,0 +1,48 @@ +#include "OpenPypeLib.h" +#include "Misc/Paths.h" +#include "Misc/ConfigCacheIni.h" +#include "UObject/UnrealType.h" + +/** + * Sets color on folder icon on given path + * @param InPath - path to folder + * @param InFolderColor - color of the folder + * @warning This color will appear only after Editor restart. Is there a better way? + */ + +void UOpenPypeLib::CSetFolderColor(FString FolderPath, FLinearColor FolderColor, bool bForceAdd) +{ + auto SaveColorInternal = [](FString InPath, FLinearColor InFolderColor) + { + // Saves the color of the folder to the config + if (FPaths::FileExists(GEditorPerProjectIni)) + { + GConfig->SetString(TEXT("PathColor"), *InPath, *InFolderColor.ToString(), GEditorPerProjectIni); + } + + }; + + SaveColorInternal(FolderPath, FolderColor); + +} +/** + * Returns all poperties on given object + * @param cls - class + * @return TArray of properties + */ +TArray UOpenPypeLib::GetAllProperties(UClass* cls) +{ + TArray Ret; + if (cls != nullptr) + { + for (TFieldIterator It(cls); It; ++It) + { + FProperty* Property = *It; + if (Property->HasAnyPropertyFlags(EPropertyFlags::CPF_Edit)) + { + Ret.Add(Property->GetName()); + } + } + } + return Ret; +} diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstance.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstance.cpp new file mode 100644 index 0000000000..4f1e846c0b --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstance.cpp @@ -0,0 +1,108 @@ +#pragma once + +#include "OpenPypePublishInstance.h" +#include "AssetRegistryModule.h" + + +UOpenPypePublishInstance::UOpenPypePublishInstance(const FObjectInitializer& ObjectInitializer) + : UObject(ObjectInitializer) +{ + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked("AssetRegistry"); + FString path = UOpenPypePublishInstance::GetPathName(); + FARFilter Filter; + Filter.PackagePaths.Add(FName(*path)); + + AssetRegistryModule.Get().OnAssetAdded().AddUObject(this, &UOpenPypePublishInstance::OnAssetAdded); + AssetRegistryModule.Get().OnAssetRemoved().AddUObject(this, &UOpenPypePublishInstance::OnAssetRemoved); + AssetRegistryModule.Get().OnAssetRenamed().AddUObject(this, &UOpenPypePublishInstance::OnAssetRenamed); +} + +void UOpenPypePublishInstance::OnAssetAdded(const FAssetData& AssetData) +{ + TArray split; + + // get directory of current container + FString selfFullPath = UOpenPypePublishInstance::GetPathName(); + FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath); + + // get asset path and class + FString assetPath = AssetData.GetFullName(); + FString assetFName = AssetData.AssetClass.ToString(); + + // split path + assetPath.ParseIntoArray(split, TEXT(" "), true); + + FString assetDir = FPackageName::GetLongPackagePath(*split[1]); + + // take interest only in paths starting with path of current container + if (assetDir.StartsWith(*selfDir)) + { + // exclude self + if (assetFName != "OpenPypePublishInstance") + { + assets.Add(assetPath); + UE_LOG(LogTemp, Log, TEXT("%s: asset added to %s"), *selfFullPath, *selfDir); + } + } +} + +void UOpenPypePublishInstance::OnAssetRemoved(const FAssetData& AssetData) +{ + TArray split; + + // get directory of current container + FString selfFullPath = UOpenPypePublishInstance::GetPathName(); + FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath); + + // get asset path and class + FString assetPath = AssetData.GetFullName(); + FString assetFName = AssetData.AssetClass.ToString(); + + // split path + assetPath.ParseIntoArray(split, TEXT(" "), true); + + FString assetDir = FPackageName::GetLongPackagePath(*split[1]); + + // take interest only in paths starting with path of current container + FString path = UOpenPypePublishInstance::GetPathName(); + FString lpp = FPackageName::GetLongPackagePath(*path); + + if (assetDir.StartsWith(*selfDir)) + { + // exclude self + if (assetFName != "OpenPypePublishInstance") + { + // UE_LOG(LogTemp, Warning, TEXT("%s: asset removed"), *lpp); + assets.Remove(assetPath); + } + } +} + +void UOpenPypePublishInstance::OnAssetRenamed(const FAssetData& AssetData, const FString& str) +{ + TArray split; + + // get directory of current container + FString selfFullPath = UOpenPypePublishInstance::GetPathName(); + FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath); + + // get asset path and class + FString assetPath = AssetData.GetFullName(); + FString assetFName = AssetData.AssetClass.ToString(); + + // split path + assetPath.ParseIntoArray(split, TEXT(" "), true); + + FString assetDir = FPackageName::GetLongPackagePath(*split[1]); + if (assetDir.StartsWith(*selfDir)) + { + // exclude self + if (assetFName != "AssetContainer") + { + + assets.Remove(str); + assets.Add(assetPath); + // UE_LOG(LogTemp, Warning, TEXT("%s: asset renamed %s"), *lpp, *str); + } + } +} diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp new file mode 100644 index 0000000000..e61964c689 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp @@ -0,0 +1,20 @@ +#include "OpenPypePublishInstanceFactory.h" +#include "OpenPypePublishInstance.h" + +UOpenPypePublishInstanceFactory::UOpenPypePublishInstanceFactory(const FObjectInitializer& ObjectInitializer) + : UFactory(ObjectInitializer) +{ + SupportedClass = UOpenPypePublishInstance::StaticClass(); + bCreateNew = false; + bEditorImport = true; +} + +UObject* UOpenPypePublishInstanceFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) +{ + UOpenPypePublishInstance* OpenPypePublishInstance = NewObject(InParent, Class, Name, Flags); + return OpenPypePublishInstance; +} + +bool UOpenPypePublishInstanceFactory::ShouldShowInNewMenu() const { + return false; +} diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePythonBridge.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePythonBridge.cpp new file mode 100644 index 0000000000..8113231503 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePythonBridge.cpp @@ -0,0 +1,13 @@ +#include "OpenPypePythonBridge.h" + +UOpenPypePythonBridge* UOpenPypePythonBridge::Get() +{ + TArray OpenPypePythonBridgeClasses; + GetDerivedClasses(UOpenPypePythonBridge::StaticClass(), OpenPypePythonBridgeClasses); + int32 NumClasses = OpenPypePythonBridgeClasses.Num(); + if (NumClasses > 0) + { + return Cast(OpenPypePythonBridgeClasses[NumClasses - 1]->GetDefaultObject()); + } + return nullptr; +}; \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypeStyle.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeStyle.cpp similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Private/OpenPypeStyle.cpp rename to openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeStyle.cpp diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/AssetContainer.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/AssetContainer.h new file mode 100644 index 0000000000..3c2a360c78 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/AssetContainer.h @@ -0,0 +1,39 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/NoExportTypes.h" +#include "Engine/AssetUserData.h" +#include "AssetData.h" +#include "AssetContainer.generated.h" + +/** + * + */ +UCLASS(Blueprintable) +class OPENPYPE_API UAssetContainer : public UAssetUserData +{ + GENERATED_BODY() + +public: + + UAssetContainer(const FObjectInitializer& ObjectInitalizer); + // ~UAssetContainer(); + + UPROPERTY(EditAnywhere, BlueprintReadOnly) + TArray assets; + + // There seems to be no reflection option to expose array of FAssetData + /* + UPROPERTY(Transient, BlueprintReadOnly, Category = "Python", meta=(DisplayName="Assets Data")) + TArray assetsData; + */ +private: + TArray assetsData; + void OnAssetAdded(const FAssetData& AssetData); + void OnAssetRemoved(const FAssetData& AssetData); + void OnAssetRenamed(const FAssetData& AssetData, const FString& str); +}; + + diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/AssetContainerFactory.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/AssetContainerFactory.h new file mode 100644 index 0000000000..331ce6bb50 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/AssetContainerFactory.h @@ -0,0 +1,21 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Factories/Factory.h" +#include "AssetContainerFactory.generated.h" + +/** + * + */ +UCLASS() +class OPENPYPE_API UAssetContainerFactory : public UFactory +{ + GENERATED_BODY() + +public: + UAssetContainerFactory(const FObjectInitializer& ObjectInitializer); + virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; + virtual bool ShouldShowInNewMenu() const override; +}; \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPype.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPype.h similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPype.h rename to openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPype.h diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypeCommands.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeCommands.h similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypeCommands.h rename to openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeCommands.h diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeLib.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeLib.h new file mode 100644 index 0000000000..59e9c8bd76 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeLib.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Engine.h" +#include "OpenPypeLib.generated.h" + + +UCLASS(Blueprintable) +class OPENPYPE_API UOpenPypeLib : public UObject +{ + + GENERATED_BODY() + +public: + UFUNCTION(BlueprintCallable, Category = Python) + static void CSetFolderColor(FString FolderPath, FLinearColor FolderColor, bool bForceAdd); + + UFUNCTION(BlueprintCallable, Category = Python) + static TArray GetAllProperties(UClass* cls); +}; \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstance.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstance.h new file mode 100644 index 0000000000..0a27a078d7 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstance.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Engine.h" +#include "OpenPypePublishInstance.generated.h" + + +UCLASS(Blueprintable) +class OPENPYPE_API UOpenPypePublishInstance : public UObject +{ + GENERATED_BODY() + +public: + UOpenPypePublishInstance(const FObjectInitializer& ObjectInitalizer); + + UPROPERTY(EditAnywhere, BlueprintReadOnly) + TArray assets; +private: + void OnAssetAdded(const FAssetData& AssetData); + void OnAssetRemoved(const FAssetData& AssetData); + void OnAssetRenamed(const FAssetData& AssetData, const FString& str); +}; \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h new file mode 100644 index 0000000000..a2b3abe13e --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h @@ -0,0 +1,19 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Factories/Factory.h" +#include "OpenPypePublishInstanceFactory.generated.h" + +/** + * + */ +UCLASS() +class OPENPYPE_API UOpenPypePublishInstanceFactory : public UFactory +{ + GENERATED_BODY() + +public: + UOpenPypePublishInstanceFactory(const FObjectInitializer& ObjectInitializer); + virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; + virtual bool ShouldShowInNewMenu() const override; +}; \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePythonBridge.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePythonBridge.h new file mode 100644 index 0000000000..692aab2e5e --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePythonBridge.h @@ -0,0 +1,20 @@ +#pragma once +#include "Engine.h" +#include "OpenPypePythonBridge.generated.h" + +UCLASS(Blueprintable) +class UOpenPypePythonBridge : public UObject +{ + GENERATED_BODY() + +public: + UFUNCTION(BlueprintCallable, Category = Python) + static UOpenPypePythonBridge* Get(); + + UFUNCTION(BlueprintImplementableEvent, Category = Python) + void RunInPython_Popup() const; + + UFUNCTION(BlueprintImplementableEvent, Category = Python) + void RunInPython_Dialog() const; + +}; diff --git a/openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypeStyle.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeStyle.h similarity index 100% rename from openpype/hosts/unreal/integration/Source/OpenPype/Public/OpenPypeStyle.h rename to openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeStyle.h diff --git a/openpype/settings/defaults/system_settings/applications.json b/openpype/settings/defaults/system_settings/applications.json index 2b0de44fa9..d17674ea2c 100644 --- a/openpype/settings/defaults/system_settings/applications.json +++ b/openpype/settings/defaults/system_settings/applications.json @@ -1243,9 +1243,19 @@ "host_name": "unreal", "environment": {}, "variants": { - "4-26": { + "4-27": { "use_python_2": false, "environment": {} + }, + "5-0": { + "use_python_2": false, + "environment": { + "UE_PYTHONPATH": "{PYTHONPATH}" + } + }, + "__dynamic_keys_labels__": { + "4-27": "4.27", + "5-0": "5.0" } } }, diff --git a/repos/avalon-core b/repos/avalon-core deleted file mode 160000 index 2fa14cea6f..0000000000 --- a/repos/avalon-core +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2fa14cea6f6a9d86eec70bbb96860cbe4c75c8eb From 2b1079be32264ae78d4cb70a10e9c10960db7d6e Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 26 May 2022 14:10:46 +0200 Subject: [PATCH 247/350] :recycle: simplify version determination --- openpype/hosts/unreal/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/unreal/__init__.py b/openpype/hosts/unreal/__init__.py index ae9b113acd..9c0768b78e 100644 --- a/openpype/hosts/unreal/__init__.py +++ b/openpype/hosts/unreal/__init__.py @@ -10,7 +10,7 @@ def add_implementation_envs(env: dict, _app: Application) -> None: engine_version = _app.name.split("/")[-1].replace("-", ".") major_version = int(engine_version.split(".")[0]) - ue_plugin = "UE_4.7" if major_version == 4 else "UE_5.0" + ue_plugin = "UE_5.0" if _app.name[:1] == "5" else "UE_4.7" unreal_plugin_path = os.path.join( os.path.dirname(os.path.abspath(openpype.hosts.__file__)), "unreal", "integration", ue_plugin From 067058f5d344a9ab940cd33ff0f3ab4436e74dbb Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 26 May 2022 14:13:25 +0200 Subject: [PATCH 248/350] :recycle: hound fixes --- openpype/hosts/unreal/__init__.py | 1 - openpype/hosts/unreal/lib.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/unreal/__init__.py b/openpype/hosts/unreal/__init__.py index 9c0768b78e..e0e1f0bc3d 100644 --- a/openpype/hosts/unreal/__init__.py +++ b/openpype/hosts/unreal/__init__.py @@ -8,7 +8,6 @@ def add_implementation_envs(env: dict, _app: Application) -> None: # Set OPENPYPE_UNREAL_PLUGIN required for Unreal implementation engine_version = _app.name.split("/")[-1].replace("-", ".") - major_version = int(engine_version.split(".")[0]) ue_plugin = "UE_5.0" if _app.name[:1] == "5" else "UE_4.7" unreal_plugin_path = os.path.join( diff --git a/openpype/hosts/unreal/lib.py b/openpype/hosts/unreal/lib.py index f220d8dedf..8c453b38b9 100644 --- a/openpype/hosts/unreal/lib.py +++ b/openpype/hosts/unreal/lib.py @@ -301,8 +301,8 @@ def create_unreal_project(project_name: str, raise NotImplementedError("Unsupported platform") if not python_path.exists(): raise RuntimeError(f"Unreal Python not found at {python_path}") - out = subprocess.check_call( - [python_path.as_posix(), "-m", "pip", "install", "--user", "pyside2"]) + subprocess.check_call( + [python_path.as_posix(), "-m", "pip", "install", "pyside2"]) if dev_mode or preset["dev_mode"]: _prepare_cpp_project(project_file, engine_path, ue_version) From 9a5dce42af1d1d9befc021ca1326f2e2a3a2fdc7 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 26 May 2022 14:17:41 +0200 Subject: [PATCH 249/350] :recycle: hound fixes #2 :dog: --- openpype/hosts/unreal/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/hosts/unreal/__init__.py b/openpype/hosts/unreal/__init__.py index e0e1f0bc3d..10e9c5100e 100644 --- a/openpype/hosts/unreal/__init__.py +++ b/openpype/hosts/unreal/__init__.py @@ -7,8 +7,6 @@ def add_implementation_envs(env: dict, _app: Application) -> None: """Modify environments to contain all required for implementation.""" # Set OPENPYPE_UNREAL_PLUGIN required for Unreal implementation - engine_version = _app.name.split("/")[-1].replace("-", ".") - ue_plugin = "UE_5.0" if _app.name[:1] == "5" else "UE_4.7" unreal_plugin_path = os.path.join( os.path.dirname(os.path.abspath(openpype.hosts.__file__)), From e4878eac8aecf8993b5b690401539fba88bb182c Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 26 May 2022 14:25:51 +0200 Subject: [PATCH 250/350] Flame: make sure repre name is first segment from tokenizable str --- .../flame/plugins/publish/extract_subset_resources.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index eea575ea88..1bfe980a01 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -232,10 +232,14 @@ class ExtractSubsetResources(openpype.api.Extractor): opfapi.export_clip( export_dir_path, exporting_clip, preset_path, **export_kwargs) + # make sure only first segment is used if underscore in name + # HACK: `ftrackreview_withLUT` will result only in `ftrackreview` + repr_name = unique_name.split("_")[0] + # create representation data representation_data = { - "name": unique_name, - "outputName": unique_name, + "name": repr_name, + "outputName": repr_name, "ext": extension, "stagingDir": export_dir_path, "tags": repre_tags, From 4fbdefdb6c95b461cbe43e70a0e3de6c6ec7992e Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 26 May 2022 14:43:48 +0200 Subject: [PATCH 251/350] :recycle: fps from asset, few style changes --- .../unreal/plugins/load/load_animation.py | 25 +++++------- .../hosts/unreal/plugins/load/load_layout.py | 39 +++++++++---------- 2 files changed, 29 insertions(+), 35 deletions(-) diff --git a/openpype/hosts/unreal/plugins/load/load_animation.py b/openpype/hosts/unreal/plugins/load/load_animation.py index 54b43c500c..da2830bc52 100644 --- a/openpype/hosts/unreal/plugins/load/load_animation.py +++ b/openpype/hosts/unreal/plugins/load/load_animation.py @@ -14,6 +14,7 @@ from openpype.pipeline import ( ) from openpype.hosts.unreal.api import plugin from openpype.hosts.unreal.api import pipeline as unreal_pipeline +from openpype.api import get_asset class AnimationFBXLoader(plugin.Loader): @@ -79,7 +80,7 @@ class AnimationFBXLoader(plugin.Loader): task.options.anim_sequence_import_data.set_editor_property( 'use_default_sample_rate', False) task.options.anim_sequence_import_data.set_editor_property( - 'custom_sample_rate', 25.0) # TODO: get from database + 'custom_sample_rate', get_asset()["data"].get("fps")) task.options.anim_sequence_import_data.set_editor_property( 'import_custom_attribute', True) task.options.anim_sequence_import_data.set_editor_property( @@ -141,22 +142,18 @@ class AnimationFBXLoader(plugin.Loader): root = "/Game/OpenPype" asset = context.get('asset').get('name') suffix = "_CON" - if asset: - asset_name = "{}_{}".format(asset, name) - else: - asset_name = "{}".format(name) - + asset_name = f"{asset}_{name}" if asset else f"{name}" tools = unreal.AssetToolsHelpers().get_asset_tools() asset_dir, container_name = tools.create_unique_asset_name( f"{root}/Animations/{asset}/{name}", suffix="") ar = unreal.AssetRegistryHelpers.get_asset_registry() - filter = unreal.ARFilter( + _filter = unreal.ARFilter( class_names=["World"], package_paths=[f"{root}/{hierarchy[0]}"], recursive_paths=False) - levels = ar.get_assets(filter) + levels = ar.get_assets(_filter) master_level = levels[0].get_editor_property('object_path') hierarchy_dir = root @@ -164,11 +161,11 @@ class AnimationFBXLoader(plugin.Loader): hierarchy_dir = f"{hierarchy_dir}/{h}" hierarchy_dir = f"{hierarchy_dir}/{asset}" - filter = unreal.ARFilter( + _filter = unreal.ARFilter( class_names=["World"], package_paths=[f"{hierarchy_dir}/"], recursive_paths=True) - levels = ar.get_assets(filter) + levels = ar.get_assets(_filter) level = levels[0].get_editor_property('object_path') unreal.EditorLevelLibrary.save_all_dirty_levels() @@ -235,8 +232,7 @@ class AnimationFBXLoader(plugin.Loader): "parent": context["representation"]["parent"], "family": context["representation"]["context"]["family"] } - unreal_pipeline.imprint( - "{}/{}".format(asset_dir, container_name), data) + unreal_pipeline.imprint(f"{asset_dir}/{container_name}", data) imported_content = EditorAssetLibrary.list_assets( asset_dir, recursive=True, include_folder=False) @@ -283,7 +279,7 @@ class AnimationFBXLoader(plugin.Loader): task.options.anim_sequence_import_data.set_editor_property( 'use_default_sample_rate', False) task.options.anim_sequence_import_data.set_editor_property( - 'custom_sample_rate', 25.0) # TODO: get from database + 'custom_sample_rate', get_asset()["data"].get("fps")) task.options.anim_sequence_import_data.set_editor_property( 'import_custom_attribute', True) task.options.anim_sequence_import_data.set_editor_property( @@ -300,8 +296,7 @@ class AnimationFBXLoader(plugin.Loader): # do import fbx and replace existing data unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task]) - container_path = "{}/{}".format(container["namespace"], - container["objectName"]) + container_path = f'{container["namespace"]}/{container["objectName"]}' # update metadata unreal_pipeline.imprint( container_path, diff --git a/openpype/hosts/unreal/plugins/load/load_layout.py b/openpype/hosts/unreal/plugins/load/load_layout.py index 49611c6c05..0632c3c0b5 100644 --- a/openpype/hosts/unreal/plugins/load/load_layout.py +++ b/openpype/hosts/unreal/plugins/load/load_layout.py @@ -20,6 +20,7 @@ from openpype.pipeline import ( AVALON_CONTAINER_ID, legacy_io, ) +from openpype.api import get_asset from openpype.hosts.unreal.api import plugin from openpype.hosts.unreal.api import pipeline as unreal_pipeline @@ -87,7 +88,8 @@ class LayoutLoader(plugin.Loader): return None - def _get_data(self, asset_name): + @staticmethod + def _get_data(asset_name): asset_doc = legacy_io.find_one({ "type": "asset", "name": asset_name @@ -95,8 +97,9 @@ class LayoutLoader(plugin.Loader): return asset_doc.get("data") + @staticmethod def _set_sequence_hierarchy( - self, seq_i, seq_j, max_frame_i, min_frame_j, max_frame_j, map_paths + seq_i, seq_j, max_frame_i, min_frame_j, max_frame_j, map_paths ): # Get existing sequencer tracks or create them if they don't exist tracks = seq_i.get_master_tracks() @@ -165,8 +168,9 @@ class LayoutLoader(plugin.Loader): hid_section.set_row_index(index) hid_section.set_level_names(maps) + @staticmethod def _process_family( - self, assets, class_name, transform, sequence, inst_name=None + assets, class_name, transform, sequence, inst_name=None ): ar = unreal.AssetRegistryHelpers.get_asset_registry() @@ -264,7 +268,7 @@ class LayoutLoader(plugin.Loader): task.options.anim_sequence_import_data.set_editor_property( 'use_default_sample_rate', False) task.options.anim_sequence_import_data.set_editor_property( - 'custom_sample_rate', 25.0) # TODO: get from database + 'custom_sample_rate', get_asset()["data"].get("fps")) task.options.anim_sequence_import_data.set_editor_property( 'import_custom_attribute', True) task.options.anim_sequence_import_data.set_editor_property( @@ -313,11 +317,8 @@ class LayoutLoader(plugin.Loader): for binding in bindings: tracks = binding.get_tracks() track = None - if not tracks: - track = binding.add_track( - unreal.MovieSceneSkeletalAnimationTrack) - else: - track = tracks[0] + track = tracks[0] if tracks else binding.add_track( + unreal.MovieSceneSkeletalAnimationTrack) sections = track.get_sections() section = None @@ -337,11 +338,11 @@ class LayoutLoader(plugin.Loader): curr_anim.get_path_name()).parent ).replace('\\', '/') - filter = unreal.ARFilter( + _filter = unreal.ARFilter( class_names=["AssetContainer"], package_paths=[anim_path], recursive_paths=False) - containers = ar.get_assets(filter) + containers = ar.get_assets(_filter) if len(containers) > 0: return @@ -352,6 +353,7 @@ class LayoutLoader(plugin.Loader): sec_params = section.get_editor_property('params') sec_params.set_editor_property('animation', animation) + @staticmethod def _generate_sequence(self, h, h_dir): tools = unreal.AssetToolsHelpers().get_asset_tools() @@ -585,10 +587,7 @@ class LayoutLoader(plugin.Loader): hierarchy_dir_list.append(hierarchy_dir) asset = context.get('asset').get('name') suffix = "_CON" - if asset: - asset_name = "{}_{}".format(asset, name) - else: - asset_name = "{}".format(name) + asset_name = f"{asset}_{name}" if asset else asset_name = name tools = unreal.AssetToolsHelpers().get_asset_tools() asset_dir, container_name = tools.create_unique_asset_name( @@ -802,7 +801,7 @@ class LayoutLoader(plugin.Loader): lc for lc in layout_containers if asset in lc.get('loaded_assets')] - if len(layouts) == 0: + if not layouts: EditorAssetLibrary.delete_directory(str(Path(asset).parent)) # Remove the Level Sequence from the parent. @@ -812,17 +811,17 @@ class LayoutLoader(plugin.Loader): namespace = container.get('namespace').replace(f"{root}/", "") ms_asset = namespace.split('/')[0] ar = unreal.AssetRegistryHelpers.get_asset_registry() - filter = unreal.ARFilter( + _filter = unreal.ARFilter( class_names=["LevelSequence"], package_paths=[f"{root}/{ms_asset}"], recursive_paths=False) - sequences = ar.get_assets(filter) + sequences = ar.get_assets(_filter) master_sequence = sequences[0].get_asset() - filter = unreal.ARFilter( + _filter = unreal.ARFilter( class_names=["World"], package_paths=[f"{root}/{ms_asset}"], recursive_paths=False) - levels = ar.get_assets(filter) + levels = ar.get_assets(_filter) master_level = levels[0].get_editor_property('object_path') sequences = [master_sequence] From 0c2d0bdd75961d8a685c810c6cbbf6d36591669d Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 26 May 2022 14:45:17 +0200 Subject: [PATCH 252/350] :bug: fix wrong assignment --- openpype/hosts/unreal/plugins/load/load_layout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/unreal/plugins/load/load_layout.py b/openpype/hosts/unreal/plugins/load/load_layout.py index 0632c3c0b5..c65cd25ac8 100644 --- a/openpype/hosts/unreal/plugins/load/load_layout.py +++ b/openpype/hosts/unreal/plugins/load/load_layout.py @@ -587,7 +587,7 @@ class LayoutLoader(plugin.Loader): hierarchy_dir_list.append(hierarchy_dir) asset = context.get('asset').get('name') suffix = "_CON" - asset_name = f"{asset}_{name}" if asset else asset_name = name + asset_name = f"{asset}_{name}" if asset else name tools = unreal.AssetToolsHelpers().get_asset_tools() asset_dir, container_name = tools.create_unique_asset_name( From d3179847d266be44a96ab08e9b9b7fdffe5b3173 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 26 May 2022 14:59:08 +0200 Subject: [PATCH 253/350] General: editorial otio_range in collection was one frame longer --- openpype/lib/editorial.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/lib/editorial.py b/openpype/lib/editorial.py index 2c877b9d0d..7b2d22f738 100644 --- a/openpype/lib/editorial.py +++ b/openpype/lib/editorial.py @@ -168,7 +168,7 @@ def make_sequence_collection(path, otio_range, metadata): first, last = otio_range_to_frame_range(otio_range) collection = clique.Collection( head=head, tail=tail, padding=metadata["padding"]) - collection.indexes.update([i for i in range(first, (last + 1))]) + collection.indexes.update([i for i in range(first, last)]) return dir_path, collection From f96318cddd5e4cee2f66fa01ca85ccfb6bddb769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Thu, 26 May 2022 15:01:56 +0200 Subject: [PATCH 254/350] Update openpype/hosts/flame/otio/flame_export.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/hosts/flame/otio/flame_export.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/flame/otio/flame_export.py b/openpype/hosts/flame/otio/flame_export.py index ffb82b97c2..9756d0442e 100644 --- a/openpype/hosts/flame/otio/flame_export.py +++ b/openpype/hosts/flame/otio/flame_export.py @@ -94,7 +94,7 @@ def create_otio_time_range(start_frame, frame_duration, fps): def _get_metadata(item): if hasattr(item, 'metadata'): - return dict(dict(item.metadata)) if item.metadata else {} + return dict(item.metadata) if item.metadata else {} return {} From 95f836f41175128e548f9369d5e50c148e180e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Thu, 26 May 2022 15:02:17 +0200 Subject: [PATCH 255/350] Update openpype/hosts/flame/api/render_utils.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/hosts/flame/api/render_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/flame/api/render_utils.py b/openpype/hosts/flame/api/render_utils.py index 9957550af9..da22f117a7 100644 --- a/openpype/hosts/flame/api/render_utils.py +++ b/openpype/hosts/flame/api/render_utils.py @@ -1,8 +1,8 @@ import os from xml.etree import ElementTree as ET -import openpype.api as openpype +import openpype.api import Logger -log = openpype.Logger.get_logger(__name__) +log = Logger.get_logger(__name__) def export_clip(export_path, clip, preset_path, **kwargs): From 2d1f7b9873022ece16f822690a4269a15fb979c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Thu, 26 May 2022 15:02:41 +0200 Subject: [PATCH 256/350] Update openpype/hosts/flame/otio/flame_export.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/hosts/flame/otio/flame_export.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/hosts/flame/otio/flame_export.py b/openpype/hosts/flame/otio/flame_export.py index 9756d0442e..1e4ef866ed 100644 --- a/openpype/hosts/flame/otio/flame_export.py +++ b/openpype/hosts/flame/otio/flame_export.py @@ -280,9 +280,7 @@ def create_otio_clip(clip_data): segment = clip_data["PySegment"] # calculate source in - media_info = MediaInfoFile(clip_data["fpath"], **{ - "logger": log - }) + media_info = MediaInfoFile(clip_data["fpath"], logger=log) media_timecode_start = media_info.start_frame media_fps = media_info.fps From db5d85080a418ed8e78908bb72339a0a41011b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Thu, 26 May 2022 15:03:29 +0200 Subject: [PATCH 257/350] Update openpype/hosts/flame/plugins/publish/extract_subset_resources.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../hosts/flame/plugins/publish/extract_subset_resources.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index 1bfe980a01..6319f4b041 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -425,9 +425,7 @@ class ExtractSubsetResources(openpype.api.Extractor): Import clip from path """ dir_path = os.path.dirname(path) - media_info = MediaInfoFile(path, **{ - "logger": self.log - }) + media_info = MediaInfoFile(path, logger=self.log) file_pattern = media_info.file_pattern self.log.debug("__ file_pattern: {}".format(file_pattern)) From 024874b4f653725e56223fba8a2a7f47404c30f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Thu, 26 May 2022 15:06:16 +0200 Subject: [PATCH 258/350] Update openpype/hosts/flame/plugins/publish/extract_subset_resources.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../hosts/flame/plugins/publish/extract_subset_resources.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index 6319f4b041..9265d3517c 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -60,7 +60,8 @@ class ExtractSubsetResources(openpype.api.Extractor): export_presets_mapping = {} def process(self, instance): - self._make_representation_data(instance) + if "representations" not in instance.data: + instance.data["representations"] = [] # flame objects segment = instance.data["item"] From a2289429a850061484300e81eaed99413a87ef38 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 26 May 2022 15:57:52 +0200 Subject: [PATCH 259/350] :sparkles: added collector for FBX camera export --- .../plugins/publish/collect_fbx_camera.py | 20 +++++++++++++++++++ .../defaults/project_settings/maya.json | 3 +++ .../schemas/schema_maya_publish.json | 14 +++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 openpype/hosts/maya/plugins/publish/collect_fbx_camera.py diff --git a/openpype/hosts/maya/plugins/publish/collect_fbx_camera.py b/openpype/hosts/maya/plugins/publish/collect_fbx_camera.py new file mode 100644 index 0000000000..bfa5bccbb9 --- /dev/null +++ b/openpype/hosts/maya/plugins/publish/collect_fbx_camera.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from maya import cmds # noqa +import pyblish.api + + +class CollectFbxCamera(pyblish.api.InstancePlugin): + """Collect Camera for FBX export.""" + + order = pyblish.api.CollectorOrder + 0.2 + label = "Collect Camera for FBX export" + families = ["camera"] + + def process(self, instance): + if not instance.data.get("families"): + instance.data["families"] = [] + + if "fbx" not in instance.data["families"]: + instance.data["families"].append("fbx") + + instance.data["cameras"] = True diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index 4cdfe1ca5d..e03bdcecc3 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -165,6 +165,9 @@ "CollectMayaRender": { "sync_workfile_version": false }, + "CollectFbxCamera": { + "enabled": false + }, "ValidateInstanceInContext": { "enabled": true, "optional": true, diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json index 2e5bc64e1c..9877b5ff0d 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json @@ -21,6 +21,20 @@ } ] }, + { + "type": "dict", + "collapsible": true, + "key": "CollectFbxCamera", + "label": "Collect Camera for FBX export", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + } + ] + }, { "type": "splitter" }, From ab8068858cf62422b6838b7e526d723f1b81230a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 26 May 2022 16:32:25 +0200 Subject: [PATCH 260/350] flame: removing unneeded code --- .../flame/plugins/publish/extract_subset_resources.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index 9265d3517c..b91aec15c8 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -51,7 +51,6 @@ class ExtractSubsetResources(openpype.api.Extractor): "path_regex": ".*" } } - keep_original_representation = False # hide publisher during exporting hide_ui_on_process = True @@ -329,14 +328,6 @@ class ExtractSubsetResources(openpype.api.Extractor): ): return True - def _make_representation_data(self, instance): - if ( - self.keep_original_representation - and "representations" not in instance.data - or not self.keep_original_representation - ): - instance.data["representations"] = [] - def _unfolds_nested_folders(self, stage_dir, files_list, ext): """Unfolds nested folders From 24c289a0d5088c708d9e6754dd8ebbc033e0e491 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 26 May 2022 17:18:00 +0200 Subject: [PATCH 261/350] nuke: use framerange used as list but it is bool --- openpype/hosts/nuke/api/lib.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index ba8aa7a8db..f40425eefc 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -373,7 +373,7 @@ def add_write_node_legacy(name, **kwarg): Returns: node (obj): nuke write node """ - frame_range = kwarg.get("use_range_limit", None) + use_range_limit = kwarg.get("use_range_limit", None) w = nuke.createNode( "Write", @@ -391,10 +391,10 @@ def add_write_node_legacy(name, **kwarg): log.debug(e) continue - if frame_range: + if use_range_limit: w["use_limit"].setValue(True) - w["first"].setValue(frame_range[0]) - w["last"].setValue(frame_range[1]) + w["first"].setValue(kwarg["frame_range"][0]) + w["last"].setValue(kwarg["frame_range"][1]) return w @@ -409,7 +409,7 @@ def add_write_node(name, file_path, knobs, **kwarg): Returns: node (obj): nuke write node """ - frame_range = kwarg.get("use_range_limit", None) + use_range_limit = kwarg.get("use_range_limit", None) w = nuke.createNode( "Write", @@ -420,10 +420,10 @@ def add_write_node(name, file_path, knobs, **kwarg): # finally add knob overrides set_node_knobs_from_settings(w, knobs, **kwarg) - if frame_range: + if use_range_limit: w["use_limit"].setValue(True) - w["first"].setValue(frame_range[0]) - w["last"].setValue(frame_range[1]) + w["first"].setValue(kwarg["frame_range"][0]) + w["last"].setValue(kwarg["frame_range"][1]) return w From 693efa272fefee7c09aaa93eb78ffa07b3c198f2 Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Thu, 26 May 2022 16:23:50 +0100 Subject: [PATCH 262/350] Camera creates master level if layout is missing --- .../hosts/unreal/plugins/load/load_camera.py | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/openpype/hosts/unreal/plugins/load/load_camera.py b/openpype/hosts/unreal/plugins/load/load_camera.py index b33e45b6e9..c6061bc5c1 100644 --- a/openpype/hosts/unreal/plugins/load/load_camera.py +++ b/openpype/hosts/unreal/plugins/load/load_camera.py @@ -5,6 +5,7 @@ from pathlib import Path import unreal from unreal import EditorAssetLibrary from unreal import EditorLevelLibrary +from unreal import EditorLevelUtils from openpype.pipeline import ( AVALON_CONTAINER_ID, @@ -84,10 +85,10 @@ class CameraLoader(plugin.Loader): hierarchy = context.get('asset').get('data').get('parents') root = "/Game/OpenPype" hierarchy_dir = root - hierarchy_list = [] + hierarchy_dir_list = [] for h in hierarchy: hierarchy_dir = f"{hierarchy_dir}/{h}" - hierarchy_list.append(hierarchy_dir) + hierarchy_dir_list.append(hierarchy_dir) asset = context.get('asset').get('name') suffix = "_CON" if asset: @@ -121,27 +122,40 @@ class CameraLoader(plugin.Loader): asset_dir, container_name = tools.create_unique_asset_name( f"{hierarchy_dir}/{asset}/{name}_{unique_number:02d}", suffix="") + asset_path = Path(asset_dir) + asset_path_parent = str(asset_path.parent.as_posix()) + container_name += suffix - current_level = EditorLevelLibrary.get_editor_world().get_full_name() + EditorAssetLibrary.make_directory(asset_dir) + + # Create map for the shot, and create hierarchy of map. If the maps + # already exist, we will use them. + h_dir = hierarchy_dir_list[0] + h_asset = hierarchy[0] + master_level = f"{h_dir}/{h_asset}_map.{h_asset}_map" + if not EditorAssetLibrary.does_asset_exist(master_level): + EditorLevelLibrary.new_level(f"{h_dir}/{h_asset}_map") + + level = f"{asset_path_parent}/{asset}_map.{asset}_map" + if not EditorAssetLibrary.does_asset_exist(level): + EditorLevelLibrary.new_level(f"{asset_path_parent}/{asset}_map") + + EditorLevelLibrary.load_level(master_level) + EditorLevelUtils.add_level_to_world( + EditorLevelLibrary.get_editor_world(), + level, + unreal.LevelStreamingDynamic + ) EditorLevelLibrary.save_all_dirty_levels() - - ar = unreal.AssetRegistryHelpers.get_asset_registry() - filter = unreal.ARFilter( - class_names=["World"], - package_paths=[f"{hierarchy_dir}/{asset}/"], - recursive_paths=True) - maps = ar.get_assets(filter) - - # There should be only one map in the list - EditorLevelLibrary.load_level(maps[0].get_full_name()) + EditorLevelLibrary.load_level(level) # Get all the sequences in the hierarchy. It will create them, if # they don't exist. sequences = [] frame_ranges = [] i = 0 - for h in hierarchy_list: + for h in hierarchy_dir_list: root_content = EditorAssetLibrary.list_assets( h, recursive=False, include_folder=False) @@ -256,7 +270,7 @@ class CameraLoader(plugin.Loader): "{}/{}".format(asset_dir, container_name), data) EditorLevelLibrary.save_all_dirty_levels() - EditorLevelLibrary.load_level(current_level) + EditorLevelLibrary.load_level(master_level) asset_content = EditorAssetLibrary.list_assets( asset_dir, recursive=True, include_folder=True From c5787b899257433f0873f61c9aa1408cd68c0bee Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 26 May 2022 17:23:51 +0200 Subject: [PATCH 263/350] Flame: small bugs --- openpype/hosts/flame/api/render_utils.py | 2 +- openpype/plugins/publish/collect_otio_subset_resources.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/flame/api/render_utils.py b/openpype/hosts/flame/api/render_utils.py index da22f117a7..a29d6be695 100644 --- a/openpype/hosts/flame/api/render_utils.py +++ b/openpype/hosts/flame/api/render_utils.py @@ -1,6 +1,6 @@ import os from xml.etree import ElementTree as ET -import openpype.api import Logger +from openpype.api import Logger log = Logger.get_logger(__name__) diff --git a/openpype/plugins/publish/collect_otio_subset_resources.py b/openpype/plugins/publish/collect_otio_subset_resources.py index fb4cc6ee5e..40d4f35bdc 100644 --- a/openpype/plugins/publish/collect_otio_subset_resources.py +++ b/openpype/plugins/publish/collect_otio_subset_resources.py @@ -64,7 +64,7 @@ class CollectOtioSubsetResources(pyblish.api.InstancePlugin): a_frame_end_h = media_out + handle_end # create trimmed otio time range - trimmed_media_range_h = editorial.range_from_frames( + trimmed_media_range_h = oplib.range_from_frames( a_frame_start_h, (a_frame_end_h - a_frame_start_h) + 1, media_fps ) From ae233ce80cc9ecf549d2fdbebbc50d1ca29b8b98 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 26 May 2022 17:26:00 +0200 Subject: [PATCH 264/350] hiero: PR suggestion https://github.com/pypeclub/OpenPype/pull/3224#discussion_r882588237 --- openpype/hosts/hiero/api/lib.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/hiero/api/lib.py b/openpype/hosts/hiero/api/lib.py index 5a9f38bf92..999dae5488 100644 --- a/openpype/hosts/hiero/api/lib.py +++ b/openpype/hosts/hiero/api/lib.py @@ -941,6 +941,10 @@ def is_overlapping(ti_test, ti_original, strict=False): (ti_test.timelineIn() <= ti_original.timelineIn()) and (ti_test.timelineOut() >= ti_original.timelineOut()) ) + + if strict: + return covering_exp + inside_exp = ( (ti_test.timelineIn() >= ti_original.timelineIn()) and (ti_test.timelineOut() <= ti_original.timelineOut()) @@ -954,15 +958,12 @@ def is_overlapping(ti_test, ti_original, strict=False): and (ti_test.timelineIn() <= ti_original.timelineIn()) ) - if strict: - return covering_exp - else: - return any(( - covering_exp, - inside_exp, - overlaying_right_exp, - overlaying_left_exp - )) + return any(( + covering_exp, + inside_exp, + overlaying_right_exp, + overlaying_left_exp + )) def get_sequence_pattern_and_padding(file): From 4cd4124e0128cac24938cf3d0098de04b9e5f58c Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 26 May 2022 17:40:27 +0200 Subject: [PATCH 265/350] flame: fixing frame range from editorial --- openpype/lib/editorial.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/lib/editorial.py b/openpype/lib/editorial.py index 0de266725f..9f55d1fcb1 100644 --- a/openpype/lib/editorial.py +++ b/openpype/lib/editorial.py @@ -168,7 +168,7 @@ def make_sequence_collection(path, otio_range, metadata): first, last = otio_range_to_frame_range(otio_range) collection = clique.Collection( head=head, tail=tail, padding=metadata["padding"]) - collection.indexes.update([i for i in range(first, (last + 1))]) + collection.indexes.update(list(range(first, last))) return dir_path, collection From 6d4c057a04291da0381af2a1339ec3c68319d50f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 26 May 2022 17:40:42 +0200 Subject: [PATCH 266/350] flame: removing default preset --- .../plugins/publish/extract_subset_resources.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index b91aec15c8..0bad3f7cfc 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -34,21 +34,6 @@ class ExtractSubsetResources(openpype.api.Extractor): "representation_add_range": False, "representation_tags": ["thumbnail"], "path_regex": ".*" - }, - "ftrackpreview": { - "active": True, - "ext": "mov", - "xml_preset_file": "Apple iPad (1920x1080).xml", - "xml_preset_dir": "", - "export_type": "Movie", - "parsed_comment_attrs": False, - "colorspace_out": "Output - Rec.709", - "representation_add_range": True, - "representation_tags": [ - "review", - "delete" - ], - "path_regex": ".*" } } From a4c32639d7bcd1aae3735f763fadd7a334968df9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 26 May 2022 17:51:25 +0200 Subject: [PATCH 267/350] nuke: adding frame range to plugin --- openpype/hosts/nuke/plugins/create/create_write_prerender.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openpype/hosts/nuke/plugins/create/create_write_prerender.py b/openpype/hosts/nuke/plugins/create/create_write_prerender.py index 32ee1fd86f..fec97167fb 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_prerender.py +++ b/openpype/hosts/nuke/plugins/create/create_write_prerender.py @@ -27,6 +27,10 @@ class CreateWritePrerender(plugin.AbstractWriteRender): # add fpath_template write_data["fpath_template"] = self.fpath_template write_data["use_range_limit"] = self.use_range_limit + write_data["frame_range"] = ( + nuke.root()["first_frame"].value(), + nuke.root()["last_frame"].value() + ) if not self.is_legacy(): return create_write_node( From b8cade1009bf4863b12c467fa0cbdef7b8d864e4 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 26 May 2022 18:43:00 +0200 Subject: [PATCH 268/350] Fix - Harmony message length Harmony 21.1 doesn't have QDataStream anymore. This means we aren't able to write bytes into QByteArray so we had modify how content lenght is sent do the server. Content lenght is sent as string of 8 char convertible into integer (instead of 0x00000001[4 bytes] > "000000001"[8 bytes]) --- openpype/hosts/harmony/api/TB_sceneOpened.js | 21 ++++++++++++++++---- openpype/hosts/harmony/api/server.py | 12 +++++++---- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/harmony/api/TB_sceneOpened.js b/openpype/hosts/harmony/api/TB_sceneOpened.js index 610b0a73bb..e7cd555332 100644 --- a/openpype/hosts/harmony/api/TB_sceneOpened.js +++ b/openpype/hosts/harmony/api/TB_sceneOpened.js @@ -35,7 +35,11 @@ function Client() { self.pack = function(num) { var ascii=''; for (var i = 3; i >= 0; i--) { - ascii += String.fromCharCode((num >> (8 * i)) & 255); + var hex = ((num >> (8 * i)) & 255).toString(16); + if (hex.length < 2){ + ascii += "0"; + } + ascii += hex; } return ascii; }; @@ -279,12 +283,21 @@ function Client() { }; self._send = function(message) { - var codec_name = new QByteArray().append("ISO-8859-1"); + /** Harmony 21.1 doesn't have QDataStream anymore. + + This means we aren't able to write bytes into QByteArray so we had + modify how content lenght is sent do the server. + Content lenght is sent as string of 8 char convertible into integer + (instead of 0x00000001[4 bytes] > "000000001"[8 bytes]) */ + var codec_name = new QByteArray().append("UTF-8"); + var codec = QTextCodec.codecForName(codec_name); var msg = codec.fromUnicode(message); var l = msg.size(); - var coded = new QByteArray().append('AH').append(self.pack(l)).append(msg); - self.socket.write(new QByteArray(coded)); + var header = new QByteArray().append('AH').append(self.pack(l)); + var coded = msg.prepend(header); + + self.socket.write(coded); self.logDebug('Sent.'); }; diff --git a/openpype/hosts/harmony/api/server.py b/openpype/hosts/harmony/api/server.py index 88cfe54521..0de359ec61 100644 --- a/openpype/hosts/harmony/api/server.py +++ b/openpype/hosts/harmony/api/server.py @@ -88,21 +88,25 @@ class Server(threading.Thread): """ current_time = time.time() while True: - + self.log.info("wait ttt") # Receive the data in small chunks and retransmit it request = None - header = self.connection.recv(6) + header = self.connection.recv(10) if len(header) == 0: # null data received, socket is closing. self.log.info(f"[{self.timestamp()}] Connection closing.") break + if header[0:2] != b"AH": self.log.error("INVALID HEADER") - length = struct.unpack(">I", header[2:])[0] + content_length_str = header[2:].decode() + + length = int(content_length_str, 16) data = self.connection.recv(length) while (len(data) < length): # we didn't received everything in first try, lets wait for # all data. + self.log.info("loop") time.sleep(0.1) if self.connection is None: self.log.error(f"[{self.timestamp()}] " @@ -113,7 +117,7 @@ class Server(threading.Thread): break data += self.connection.recv(length - len(data)) - + self.log.debug("data:: {} {}".format(data, type(data))) self.received += data.decode("utf-8") pretty = self._pretty(self.received) self.log.debug( From bc3a8bbe2ff52903e0d9ab7f029c51407cd70ec3 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Thu, 26 May 2022 18:37:41 +0000 Subject: [PATCH 269/350] [Automated] Bump version --- CHANGELOG.md | 37 +++++++++++++++++++------------------ openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dd410391a..8437540a49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [3.10.0-nightly.5](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.10.0-nightly.6](https://github.com/pypeclub/OpenPype/tree/HEAD) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.9.8...HEAD) @@ -10,14 +10,17 @@ - General: Creator plugins from addons can be registered [\#3179](https://github.com/pypeclub/OpenPype/pull/3179) - Ftrack: Single image reviewable [\#3157](https://github.com/pypeclub/OpenPype/pull/3157) - Nuke: Expose write attributes to settings [\#3123](https://github.com/pypeclub/OpenPype/pull/3123) -- Hiero: Initial frame publish support [\#3106](https://github.com/pypeclub/OpenPype/pull/3106) **🚀 Enhancements** +- Maya: FBX camera export [\#3253](https://github.com/pypeclub/OpenPype/pull/3253) +- General: updating common vendor `scriptmenu` to 1.5.2 [\#3246](https://github.com/pypeclub/OpenPype/pull/3246) - Project Manager: Allow to paste Tasks into multiple assets at the same time [\#3226](https://github.com/pypeclub/OpenPype/pull/3226) - Project manager: Sped up project load [\#3216](https://github.com/pypeclub/OpenPype/pull/3216) - Loader UI: Speed issues of loader with sync server [\#3199](https://github.com/pypeclub/OpenPype/pull/3199) +- Looks: add basic support for Renderman [\#3190](https://github.com/pypeclub/OpenPype/pull/3190) - Maya: added clean\_import option to Import loader [\#3181](https://github.com/pypeclub/OpenPype/pull/3181) +- Add the scripts menu definition to nuke [\#3168](https://github.com/pypeclub/OpenPype/pull/3168) - Maya: add maya 2023 to default applications [\#3167](https://github.com/pypeclub/OpenPype/pull/3167) - Compressed bgeo publishing in SAP and Houdini loader [\#3153](https://github.com/pypeclub/OpenPype/pull/3153) - General: Add 'dataclasses' to required python modules [\#3149](https://github.com/pypeclub/OpenPype/pull/3149) @@ -28,24 +31,26 @@ - General: Simplified OP modules/addons import [\#3137](https://github.com/pypeclub/OpenPype/pull/3137) - Terminal: Tweak coloring of TrayModuleManager logging enabled states [\#3133](https://github.com/pypeclub/OpenPype/pull/3133) - General: Cleanup some Loader docstrings [\#3131](https://github.com/pypeclub/OpenPype/pull/3131) -- Nuke: render instance with subset name filtered overrides [\#3117](https://github.com/pypeclub/OpenPype/pull/3117) - Unreal: Layout and Camera update and remove functions reimplemented and improvements [\#3116](https://github.com/pypeclub/OpenPype/pull/3116) -- Settings: Remove environment groups from settings [\#3115](https://github.com/pypeclub/OpenPype/pull/3115) -- TVPaint: Match renderlayer key with other hosts [\#3110](https://github.com/pypeclub/OpenPype/pull/3110) -- Tray publisher: Simple families from settings [\#3105](https://github.com/pypeclub/OpenPype/pull/3105) **🐛 Bug fixes** +- nuke: use framerange issue [\#3254](https://github.com/pypeclub/OpenPype/pull/3254) +- Ftrack: Chunk sizes for queries has minimal condition [\#3244](https://github.com/pypeclub/OpenPype/pull/3244) +- Maya: renderman displays needs to be filtered [\#3242](https://github.com/pypeclub/OpenPype/pull/3242) - Ftrack: Validate that the user exists on ftrack [\#3237](https://github.com/pypeclub/OpenPype/pull/3237) +- Maya: Fix support for multiple resolutions [\#3236](https://github.com/pypeclub/OpenPype/pull/3236) - TVPaint: Look for more groups than 12 [\#3228](https://github.com/pypeclub/OpenPype/pull/3228) -- Project Manager: Fix persistent editors on project change [\#3218](https://github.com/pypeclub/OpenPype/pull/3218) +- Hiero: debugging frame range and other 3.10 [\#3222](https://github.com/pypeclub/OpenPype/pull/3222) - Deadline: instance data overwrite fix [\#3214](https://github.com/pypeclub/OpenPype/pull/3214) - Ftrack: Push hierarchical attributes action works [\#3210](https://github.com/pypeclub/OpenPype/pull/3210) - Standalone Publisher: Always create new representation for thumbnail [\#3203](https://github.com/pypeclub/OpenPype/pull/3203) - Photoshop: skip collector when automatic testing [\#3202](https://github.com/pypeclub/OpenPype/pull/3202) - Nuke: render/workfile version sync doesn't work on farm [\#3185](https://github.com/pypeclub/OpenPype/pull/3185) - Ftrack: Review image only if there are no mp4 reviews [\#3183](https://github.com/pypeclub/OpenPype/pull/3183) +- Ftrack: Locations deepcopy issue [\#3177](https://github.com/pypeclub/OpenPype/pull/3177) - General: Avoid creating multiple thumbnails [\#3176](https://github.com/pypeclub/OpenPype/pull/3176) +- General: Avoid creating multiple thumbnails [\#3174](https://github.com/pypeclub/OpenPype/pull/3174) - General/Hiero: better clip duration calculation [\#3169](https://github.com/pypeclub/OpenPype/pull/3169) - General: Oiio conversion for ffmpeg checks for invalid characters [\#3166](https://github.com/pypeclub/OpenPype/pull/3166) - Fix for attaching render to subset [\#3164](https://github.com/pypeclub/OpenPype/pull/3164) @@ -55,19 +60,19 @@ - General: New Session schema [\#3141](https://github.com/pypeclub/OpenPype/pull/3141) - General: Missing version on headless mode crash properly [\#3136](https://github.com/pypeclub/OpenPype/pull/3136) - TVPaint: Composite layers in reversed order [\#3135](https://github.com/pypeclub/OpenPype/pull/3135) -- Nuke: fixing default settings for workfile builder loaders [\#3120](https://github.com/pypeclub/OpenPype/pull/3120) - Nuke: fix anatomy imageio regex default [\#3119](https://github.com/pypeclub/OpenPype/pull/3119) **🔀 Refactored code** -- Avalon repo removed from Jobs workflow [\#3193](https://github.com/pypeclub/OpenPype/pull/3193) - General: Remove remaining imports from avalon [\#3130](https://github.com/pypeclub/OpenPype/pull/3130) **Merged pull requests:** +- Harmony: message length in 21.1 [\#3257](https://github.com/pypeclub/OpenPype/pull/3257) +- Harmony: 21.1 fix [\#3249](https://github.com/pypeclub/OpenPype/pull/3249) +- Webpublish: remove publish highlight when creating subset name [\#3234](https://github.com/pypeclub/OpenPype/pull/3234) - Maya: added jpg to filter for Image Plane Loader [\#3223](https://github.com/pypeclub/OpenPype/pull/3223) - Webpublisher: replace space by underscore in subset names [\#3160](https://github.com/pypeclub/OpenPype/pull/3160) -- StandalonePublisher: removed Extract Background plugins [\#3093](https://github.com/pypeclub/OpenPype/pull/3093) ## [3.9.8](https://github.com/pypeclub/OpenPype/tree/3.9.8) (2022-05-19) @@ -84,11 +89,13 @@ - Standalone Publisher: Always create new representation for thumbnail [\#3204](https://github.com/pypeclub/OpenPype/pull/3204) - Nuke: render/workfile version sync doesn't work on farm [\#3184](https://github.com/pypeclub/OpenPype/pull/3184) - Ftrack: Review image only if there are no mp4 reviews [\#3182](https://github.com/pypeclub/OpenPype/pull/3182) -- Ftrack: Locations deepcopy issue [\#3177](https://github.com/pypeclub/OpenPype/pull/3177) - Ftrack: Locations deepcopy issue [\#3175](https://github.com/pypeclub/OpenPype/pull/3175) -- General: Avoid creating multiple thumbnails [\#3174](https://github.com/pypeclub/OpenPype/pull/3174) - General: TemplateResult can be copied [\#3170](https://github.com/pypeclub/OpenPype/pull/3170) +**🔀 Refactored code** + +- Avalon repo removed from Jobs workflow [\#3193](https://github.com/pypeclub/OpenPype/pull/3193) + **Merged pull requests:** - hiero: otio p3 compatibility issue - metadata on effect use update [\#3194](https://github.com/pypeclub/OpenPype/pull/3194) @@ -123,19 +130,13 @@ - Nuke: render instance with subset name filtered overrides \(3.9.x\) [\#3125](https://github.com/pypeclub/OpenPype/pull/3125) -**🚀 Enhancements** - -- TVPaint: Match renderlayer key with other hosts [\#3109](https://github.com/pypeclub/OpenPype/pull/3109) - **🐛 Bug fixes** - TVPaint: Composite layers in reversed order [\#3134](https://github.com/pypeclub/OpenPype/pull/3134) -- General: Python 3 compatibility in queries [\#3111](https://github.com/pypeclub/OpenPype/pull/3111) **Merged pull requests:** - Ftrack: AssetVersion status on publish [\#3114](https://github.com/pypeclub/OpenPype/pull/3114) -- renderman support for 3.9.x [\#3107](https://github.com/pypeclub/OpenPype/pull/3107) ## [3.9.5](https://github.com/pypeclub/OpenPype/tree/3.9.5) (2022-04-25) diff --git a/openpype/version.py b/openpype/version.py index eee776fd2c..984e4ba426 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.10.0-nightly.5" +__version__ = "3.10.0-nightly.6" diff --git a/pyproject.toml b/pyproject.toml index 50cdefe1bb..1caa2a838a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.10.0-nightly.5" # OpenPype +version = "3.10.0-nightly.6" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From 728079233484fdc277a00e4dbffe4cc8d6fe2529 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Thu, 26 May 2022 18:58:41 +0000 Subject: [PATCH 270/350] [Automated] Release --- CHANGELOG.md | 13 +++++-------- openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8437540a49..15659f8aa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [3.10.0-nightly.6](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.10.0](https://github.com/pypeclub/OpenPype/tree/3.10.0) (2022-05-26) -[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.9.8...HEAD) +[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.9.8...3.10.0) **🆕 New features** @@ -42,6 +42,7 @@ - Maya: Fix support for multiple resolutions [\#3236](https://github.com/pypeclub/OpenPype/pull/3236) - TVPaint: Look for more groups than 12 [\#3228](https://github.com/pypeclub/OpenPype/pull/3228) - Hiero: debugging frame range and other 3.10 [\#3222](https://github.com/pypeclub/OpenPype/pull/3222) +- Project Manager: Fix persistent editors on project change [\#3218](https://github.com/pypeclub/OpenPype/pull/3218) - Deadline: instance data overwrite fix [\#3214](https://github.com/pypeclub/OpenPype/pull/3214) - Ftrack: Push hierarchical attributes action works [\#3210](https://github.com/pypeclub/OpenPype/pull/3210) - Standalone Publisher: Always create new representation for thumbnail [\#3203](https://github.com/pypeclub/OpenPype/pull/3203) @@ -50,7 +51,6 @@ - Ftrack: Review image only if there are no mp4 reviews [\#3183](https://github.com/pypeclub/OpenPype/pull/3183) - Ftrack: Locations deepcopy issue [\#3177](https://github.com/pypeclub/OpenPype/pull/3177) - General: Avoid creating multiple thumbnails [\#3176](https://github.com/pypeclub/OpenPype/pull/3176) -- General: Avoid creating multiple thumbnails [\#3174](https://github.com/pypeclub/OpenPype/pull/3174) - General/Hiero: better clip duration calculation [\#3169](https://github.com/pypeclub/OpenPype/pull/3169) - General: Oiio conversion for ffmpeg checks for invalid characters [\#3166](https://github.com/pypeclub/OpenPype/pull/3166) - Fix for attaching render to subset [\#3164](https://github.com/pypeclub/OpenPype/pull/3164) @@ -64,13 +64,13 @@ **🔀 Refactored code** +- Avalon repo removed from Jobs workflow [\#3193](https://github.com/pypeclub/OpenPype/pull/3193) - General: Remove remaining imports from avalon [\#3130](https://github.com/pypeclub/OpenPype/pull/3130) **Merged pull requests:** - Harmony: message length in 21.1 [\#3257](https://github.com/pypeclub/OpenPype/pull/3257) - Harmony: 21.1 fix [\#3249](https://github.com/pypeclub/OpenPype/pull/3249) -- Webpublish: remove publish highlight when creating subset name [\#3234](https://github.com/pypeclub/OpenPype/pull/3234) - Maya: added jpg to filter for Image Plane Loader [\#3223](https://github.com/pypeclub/OpenPype/pull/3223) - Webpublisher: replace space by underscore in subset names [\#3160](https://github.com/pypeclub/OpenPype/pull/3160) @@ -90,12 +90,9 @@ - Nuke: render/workfile version sync doesn't work on farm [\#3184](https://github.com/pypeclub/OpenPype/pull/3184) - Ftrack: Review image only if there are no mp4 reviews [\#3182](https://github.com/pypeclub/OpenPype/pull/3182) - Ftrack: Locations deepcopy issue [\#3175](https://github.com/pypeclub/OpenPype/pull/3175) +- General: Avoid creating multiple thumbnails [\#3174](https://github.com/pypeclub/OpenPype/pull/3174) - General: TemplateResult can be copied [\#3170](https://github.com/pypeclub/OpenPype/pull/3170) -**🔀 Refactored code** - -- Avalon repo removed from Jobs workflow [\#3193](https://github.com/pypeclub/OpenPype/pull/3193) - **Merged pull requests:** - hiero: otio p3 compatibility issue - metadata on effect use update [\#3194](https://github.com/pypeclub/OpenPype/pull/3194) diff --git a/openpype/version.py b/openpype/version.py index 984e4ba426..31be1f2f02 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.10.0-nightly.6" +__version__ = "3.10.0" diff --git a/pyproject.toml b/pyproject.toml index 1caa2a838a..444af49273 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.10.0-nightly.6" # OpenPype +version = "3.10.0" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From c8a8831f8d7b8afb5f78257fcbeae2dc47e33c52 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 27 May 2022 10:33:46 +0200 Subject: [PATCH 271/350] :bug: fix getting attribute for multilayer pxr --- openpype/hosts/maya/plugins/publish/collect_look.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_look.py b/openpype/hosts/maya/plugins/publish/collect_look.py index d295492f9a..7d258b01fa 100644 --- a/openpype/hosts/maya/plugins/publish/collect_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_look.py @@ -571,7 +571,7 @@ class CollectLook(pyblish.api.InstancePlugin): self.log.debug(" - got {}".format(cmds.nodeType(node))) - attribute = FILE_NODES.get(cmds.nodeType(node)) + attribute = get_attributes(FILE_NODES, cmds.nodeType(node)) source = cmds.getAttr("{}.{}".format( node, attribute From eff55dfce412ccc88666be98c207f5a9fbfe9ab3 Mon Sep 17 00:00:00 2001 From: DMO Date: Fri, 27 May 2022 17:52:33 +0900 Subject: [PATCH 272/350] Expanding the scope of mvLook to publish mipmapped textures too, like TDL's generated by 3delight. During collection, we check to see if the TDL's exist beside the original texture, and if they do they get added to the collection. Validation of these will depend on the publish intent and whether `expectMipMap` is True in the publish set. If mipmaps are expected and the intent is correct, the mipmaps will be published along with the original file, which will accelerate rendering, since 3dl will find that TDL and use it instead of having to generate it. --- .../plugins/create/create_multiverse_look.py | 1 + .../publish/collect_multiverse_look.py | 50 +++++++++- .../publish/validate_mvlook_contents.py | 93 +++++++++++++++++++ 3 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 openpype/hosts/maya/plugins/publish/validate_mvlook_contents.py diff --git a/openpype/hosts/maya/plugins/create/create_multiverse_look.py b/openpype/hosts/maya/plugins/create/create_multiverse_look.py index b2b9b5bb29..44977efca0 100644 --- a/openpype/hosts/maya/plugins/create/create_multiverse_look.py +++ b/openpype/hosts/maya/plugins/create/create_multiverse_look.py @@ -12,3 +12,4 @@ class CreateMultiverseLook(plugin.Creator): def __init__(self, *args, **kwargs): super(CreateMultiverseLook, self).__init__(*args, **kwargs) self.data["fileFormat"] = ["usda", "usd"] + self.data["expectMipMap"] = True diff --git a/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py b/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py index c5ea6a2253..6bf4cecc3a 100644 --- a/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py @@ -17,6 +17,9 @@ SHAPE_ATTRS = ["castsShadows", "opposite"] SHAPE_ATTRS = set(SHAPE_ATTRS) +COLOUR_SPACES = ['sRGB'] +MIPMAP_EXTENSIONS = ['tdl'] + def get_look_attrs(node): """Returns attributes of a node that are important for the look. @@ -103,7 +106,7 @@ def seq_to_glob(path): "": "", "#": "#", "u_v": "|", - "", #noqa - copied from collect_look.py + "", # noqa - copied from collect_look.py "": "" } @@ -189,6 +192,22 @@ def get_file_node_files(node): return [] +def get_mipmap(fname): + for colour_space in COLOUR_SPACES: + for mipmap_ext in MIPMAP_EXTENSIONS: + mipmap_fname = '.'.join([fname, colour_space, mipmap_ext]) + if os.path.exists(mipmap_fname): + return mipmap_fname + return None + + +def is_mipamp(fname): + ext = os.path.splitext(fname)[1][1:] + if ext in MIPMAP_EXTENSIONS: + return True + return False + + class CollectMultiverseLookData(pyblish.api.InstancePlugin): """Collect Multiverse Look @@ -219,6 +238,7 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): files = [] sets = {} instance.data["resources"] = [] + expectMipMap = instance.data["expectMipMap"] for node in nodes: self.log.info("Getting resources for '{}'".format(node)) @@ -242,7 +262,7 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): files = cmds.ls(history, type="file", long=True) for f in files: - resources = self.collect_resource(f) + resources = self.collect_resource(f, expectMipMap) instance.data["resources"].append(resources) elif isinstance(matOver, multiverse.MaterialSourceUsdPath): @@ -255,7 +275,7 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): "relationships": sets } - def collect_resource(self, node): + def collect_resource(self, node, expectMipMap): """Collect the link to the file(s) used (resource) Args: node (str): name of the node @@ -310,6 +330,7 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): source = source.replace("\\", "/") files = get_file_node_files(node) + files = self.handle_files(files, expectMipMap) if len(files) == 0: self.log.error("No valid files found from node `%s`" % node) @@ -326,3 +347,26 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): "source": source, # required for resources "files": files, "color_space": color_space} # required for resources + + def handle_files(self, files, expectMipMap): + """This will go through all the files and make sure that they are + either already mipmapped or have a corresponding mipmap sidecar and + add that to the list.""" + if not expectMipMap: + return files + + extra_files = [] + self.log.debug("Expecting MipMaps, going to look for them.") + for fname in files: + self.log.info("Checking '{}' for mipmaps".format(fname)) + if is_mipamp(fname): + self.log.debug(" - file is already MipMap, skipping.") + continue + + mipmap = get_mipmap(fname) + if mipmap: + self.log.info(" mipmap found for '{}'".format(fname)) + extra_files.append(mipmap) + else: + self.log.warning(" no mipmap found for '{}'".format(fname)) + return files + extra_files diff --git a/openpype/hosts/maya/plugins/publish/validate_mvlook_contents.py b/openpype/hosts/maya/plugins/publish/validate_mvlook_contents.py new file mode 100644 index 0000000000..8f31cd4753 --- /dev/null +++ b/openpype/hosts/maya/plugins/publish/validate_mvlook_contents.py @@ -0,0 +1,93 @@ +import pyblish.api +import openpype.api +import openpype.hosts.maya.api.action + +import os +import pprint + +COLOUR_SPACES = ['sRGB'] +MIPMAP_EXTENSIONS = ['tdl'] + + +class ValidateMvLookContents(pyblish.api.InstancePlugin): + order = openpype.api.ValidateContentsOrder + families = ['mvLook'] + hosts = ['maya'] + label = 'Validate mvLook Data' + actions = [openpype.hosts.maya.api.action.SelectInvalidAction] + + # Allow this validation step to be skipped when you just need to + # get things pushed through. + optional = True + + # These intents get enforced checks, other ones get warnings. + enforced_intents = ['-', 'Final'] + + def process(self, instance): + intent = instance.context.data['intent']['value'] + expectMipMap = instance.data["expectMipMap"] + enforced = True + if intent in self.enforced_intents: + self.log.info("This validation will be enforced: '{}'" + .format(intent)) + else: + enforced = False + self.log.info("This validation will NOT be enforced: '{}'" + .format(intent)) + + if not instance[:]: + raise RuntimeError("Instance is empty") + + invalid = set() + + resources = instance.data.get("resources", []) + for resource in resources: + files = resource["files"] + self.log.debug("Resouce '{}', files: [{}]".format(resource, files)) + node = resource["node"] + if len(files) == 0: + self.log.error("File node '{}' uses no or non-existing " + "files".format(node)) + invalid.add(node) + continue + for fname in files: + if not self.valid_file(fname): + self.log.error("File node '{}'/'{}' is not valid" + .format(node, fname)) + invalid.add(node) + + if expectMipMap and not self.is_or_has_mipmap(fname, files): + msg = "File node '{}'/'{}' does not have a mipmap".format( + node, fname) + if enforced: + invalid.add(node) + self.log.error(msg) + raise RuntimeError(msg) + else: + self.log.warning(msg) + + if invalid: + raise RuntimeError("'{}' has invalid look " + "content".format(instance.name)) + + def valid_file(self, fname): + self.log.debug("Checking validity of '{}'".format(fname)) + if not os.path.exists(fname): + return False + if os.path.getsize(fname) == 0: + return False + return True + + def is_or_has_mipmap(self, fname, files): + ext = os.path.splitext(fname)[1][1:] + if ext in MIPMAP_EXTENSIONS: + self.log.debug("Is a mipmap '{}'".format(fname)) + return True + + for colour_space in COLOUR_SPACES: + for mipmap_ext in MIPMAP_EXTENSIONS: + mipmap_fname = '.'.join([fname, colour_space, mipmap_ext]) + if mipmap_fname in files: + self.log.debug("Has a mipmap '{}'".format(fname)) + return True + return False From c9e4b14a1e470d1f8059b448474657414537d5e9 Mon Sep 17 00:00:00 2001 From: DMO Date: Fri, 27 May 2022 17:53:54 +0900 Subject: [PATCH 273/350] Removed unused pprint import. --- openpype/hosts/maya/plugins/publish/validate_mvlook_contents.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_mvlook_contents.py b/openpype/hosts/maya/plugins/publish/validate_mvlook_contents.py index 8f31cd4753..34a8bc0c85 100644 --- a/openpype/hosts/maya/plugins/publish/validate_mvlook_contents.py +++ b/openpype/hosts/maya/plugins/publish/validate_mvlook_contents.py @@ -3,7 +3,6 @@ import openpype.api import openpype.hosts.maya.api.action import os -import pprint COLOUR_SPACES = ['sRGB'] MIPMAP_EXTENSIONS = ['tdl'] From 67fdfba49f35b585ad5e391271fb6ebe5e43f2d3 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 27 May 2022 11:01:40 +0200 Subject: [PATCH 274/350] OP-2790 - added note about remote publish to documentation --- website/docs/artist_hosts_maya.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/website/docs/artist_hosts_maya.md b/website/docs/artist_hosts_maya.md index 73e89384e8..48e1093753 100644 --- a/website/docs/artist_hosts_maya.md +++ b/website/docs/artist_hosts_maya.md @@ -312,6 +312,10 @@ Example setup: ![Maya - Point Cache Example](assets/maya-pointcache_setup.png) +:::note Publish on farm +If your studio has Deadline configured, artists could choose to offload potentially long running export of pointache and publish it to the farm. +Only thing that is necessary is to toggle `Farm` property in created pointcache instance to True. + ### Loading Point Caches Loading point cache means creating reference to **abc** file with Go **OpenPype → Load...**. From e1deb29da8615c050358da6254c6e9e10d9f0c13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Fri, 27 May 2022 11:06:08 +0200 Subject: [PATCH 275/350] :bug: fix multiple attributes per node --- .../maya/plugins/publish/collect_look.py | 115 +++++++++--------- 1 file changed, 59 insertions(+), 56 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_look.py b/openpype/hosts/maya/plugins/publish/collect_look.py index 7d258b01fa..93c02ce0fb 100644 --- a/openpype/hosts/maya/plugins/publish/collect_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_look.py @@ -28,7 +28,7 @@ SHAPE_ATTRS = set(SHAPE_ATTRS) def get_pxr_multitexture_file_attrs(node): attrs = [] for i in range(9): - if cmds.attributeQuery("filename{}".format(i), node): + if cmds.attributeQuery("filename{}".format(i), node=node, ex=True): file = cmds.getAttr("{}.filename{}".format(node, i)) if file: attrs.append("filename{}".format(i)) @@ -50,10 +50,10 @@ FILE_NODES = { } -def get_attributes(dictionary, attr): - # type: (dict, str) -> list +def get_attributes(dictionary, attr, node=None): + # type: (dict, str, str) -> list if callable(dictionary[attr]): - val = dictionary[attr]() + val = dictionary[attr](node) else: val = dictionary.get(attr, []) @@ -205,7 +205,8 @@ def get_file_node_paths(node): return [texture_pattern] try: - file_attributes = get_attributes(FILE_NODES, cmds.nodeType(node)) + file_attributes = get_attributes( + FILE_NODES, cmds.nodeType(node), node) except AttributeError: file_attributes = "fileTextureName" @@ -434,7 +435,8 @@ class CollectLook(pyblish.api.InstancePlugin): # Collect textures if any file nodes are found instance.data["resources"] = [] for n in files: - instance.data["resources"].append(self.collect_resource(n)) + for res in self.collect_resources(n): + instance.data["resources"].append(res) self.log.info("Collected resources: {}".format(instance.data["resources"])) @@ -554,7 +556,7 @@ class CollectLook(pyblish.api.InstancePlugin): return attributes - def collect_resource(self, node): + def collect_resources(self, node): """Collect the link to the file(s) used (resource) Args: node (str): name of the node @@ -571,60 +573,61 @@ class CollectLook(pyblish.api.InstancePlugin): self.log.debug(" - got {}".format(cmds.nodeType(node))) - attribute = get_attributes(FILE_NODES, cmds.nodeType(node)) - source = cmds.getAttr("{}.{}".format( - node, - attribute - )) - computed_attribute = "{}.{}".format(node, attribute) - if attribute == "fileTextureName": - computed_attribute = node + ".computedFileTextureNamePattern" + attributes = get_attributes(FILE_NODES, cmds.nodeType(node), node) + for attribute in attributes: + source = cmds.getAttr("{}.{}".format( + node, + attribute + )) + computed_attribute = "{}.{}".format(node, attribute) + if attribute == "fileTextureName": + computed_attribute = node + ".computedFileTextureNamePattern" - self.log.info(" - file source: {}".format(source)) - color_space_attr = "{}.colorSpace".format(node) - try: - color_space = cmds.getAttr(color_space_attr) - except ValueError: - # node doesn't have colorspace attribute - color_space = "Raw" - # Compare with the computed file path, e.g. the one with the - # pattern in it, to generate some logging information about this - # difference - # computed_attribute = "{}.computedFileTextureNamePattern".format(node) - computed_source = cmds.getAttr(computed_attribute) - if source != computed_source: - self.log.debug("Detected computed file pattern difference " - "from original pattern: {0} " - "({1} -> {2})".format(node, - source, - computed_source)) + self.log.info(" - file source: {}".format(source)) + color_space_attr = "{}.colorSpace".format(node) + try: + color_space = cmds.getAttr(color_space_attr) + except ValueError: + # node doesn't have colorspace attribute + color_space = "Raw" + # Compare with the computed file path, e.g. the one with the + # pattern in it, to generate some logging information about this + # difference + # computed_attribute = "{}.computedFileTextureNamePattern".format(node) + computed_source = cmds.getAttr(computed_attribute) + if source != computed_source: + self.log.debug("Detected computed file pattern difference " + "from original pattern: {0} " + "({1} -> {2})".format(node, + source, + computed_source)) - # We replace backslashes with forward slashes because V-Ray - # can't handle the UDIM files with the backslashes in the - # paths as the computed patterns - source = source.replace("\\", "/") + # We replace backslashes with forward slashes because V-Ray + # can't handle the UDIM files with the backslashes in the + # paths as the computed patterns + source = source.replace("\\", "/") - files = get_file_node_files(node) - if len(files) == 0: - self.log.error("No valid files found from node `%s`" % node) + files = get_file_node_files(node) + if len(files) == 0: + self.log.error("No valid files found from node `%s`" % node) - self.log.info("collection of resource done:") - self.log.info(" - node: {}".format(node)) - self.log.info(" - attribute: {}".format(attribute)) - self.log.info(" - source: {}".format(source)) - self.log.info(" - file: {}".format(files)) - self.log.info(" - color space: {}".format(color_space)) + self.log.info("collection of resource done:") + self.log.info(" - node: {}".format(node)) + self.log.info(" - attribute: {}".format(attribute)) + self.log.info(" - source: {}".format(source)) + self.log.info(" - file: {}".format(files)) + self.log.info(" - color space: {}".format(color_space)) - # Define the resource - return { - "node": node, - # here we are passing not only attribute, but with node again - # this should be simplified and changed extractor. - "attribute": "{}.{}".format(node, attribute), - "source": source, # required for resources - "files": files, - "color_space": color_space - } # required for resources + # Define the resource + yield { + "node": node, + # here we are passing not only attribute, but with node again + # this should be simplified and changed extractor. + "attribute": "{}.{}".format(node, attribute), + "source": source, # required for resources + "files": files, + "color_space": color_space + } # required for resources class CollectModelRenderSets(CollectLook): From 9c73a4181ed5aa5dcd5a902e8876cbaab55350e2 Mon Sep 17 00:00:00 2001 From: DMO Date: Fri, 27 May 2022 18:06:51 +0900 Subject: [PATCH 276/350] Fixing a typo! --- .../hosts/maya/plugins/publish/collect_multiverse_look.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py b/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py index 6bf4cecc3a..e77245bca5 100644 --- a/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py @@ -201,7 +201,7 @@ def get_mipmap(fname): return None -def is_mipamp(fname): +def is_mipmap(fname): ext = os.path.splitext(fname)[1][1:] if ext in MIPMAP_EXTENSIONS: return True @@ -359,7 +359,7 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): self.log.debug("Expecting MipMaps, going to look for them.") for fname in files: self.log.info("Checking '{}' for mipmaps".format(fname)) - if is_mipamp(fname): + if is_mipmap(fname): self.log.debug(" - file is already MipMap, skipping.") continue From a24896962062e4db576ccb33ce2dbafec77ac789 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 27 May 2022 16:14:17 +0200 Subject: [PATCH 277/350] Nuke: bake reformat was failing on string type --- openpype/hosts/nuke/api/plugin.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 2bad6f2c78..b8b56ef2b8 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -18,7 +18,8 @@ from .lib import ( maintained_selection, set_avalon_knob_data, add_publish_knob, - get_nuke_imageio_settings + get_nuke_imageio_settings, + set_node_knobs_from_settings ) @@ -497,16 +498,7 @@ class ExporterReviewMov(ExporterReview): add_tags.append("reformated") rf_node = nuke.createNode("Reformat") - for kn_conf in reformat_node_config: - _type = kn_conf["type"] - k_name = str(kn_conf["name"]) - k_value = kn_conf["value"] - - # to remove unicode as nuke doesn't like it - if _type == "string": - k_value = str(kn_conf["value"]) - - rf_node[k_name].setValue(k_value) + set_node_knobs_from_settings(rf_node, reformat_node_config) # connect rf_node.setInput(0, self.previous_node) From c3c9cca5c2d1c3b29d5b4beaddbe2c855a32b3b8 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 27 May 2022 17:00:04 +0200 Subject: [PATCH 278/350] :recycle: :dog: fix hound --- openpype/hosts/maya/plugins/publish/collect_look.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_look.py b/openpype/hosts/maya/plugins/publish/collect_look.py index 93c02ce0fb..323bede761 100644 --- a/openpype/hosts/maya/plugins/publish/collect_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_look.py @@ -590,10 +590,9 @@ class CollectLook(pyblish.api.InstancePlugin): except ValueError: # node doesn't have colorspace attribute color_space = "Raw" - # Compare with the computed file path, e.g. the one with the - # pattern in it, to generate some logging information about this - # difference - # computed_attribute = "{}.computedFileTextureNamePattern".format(node) + # Compare with the computed file path, e.g. the one with + # the pattern in it, to generate some logging information + # about this difference computed_source = cmds.getAttr(computed_attribute) if source != computed_source: self.log.debug("Detected computed file pattern difference " From f27176bed1ac255128fdbe3d4f9c1d6100942508 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Sat, 28 May 2022 03:44:32 +0000 Subject: [PATCH 279/350] [Automated] Bump version --- CHANGELOG.md | 23 +++++++++++++++++------ openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15659f8aa4..4a5e1f1067 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,24 @@ # Changelog +## [3.10.1-nightly.1](https://github.com/pypeclub/OpenPype/tree/HEAD) + +[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.10.0...HEAD) + +**🚀 Enhancements** + +- TVPaint: Init file for TVPaint worker also handle guideline images [\#3250](https://github.com/pypeclub/OpenPype/pull/3250) +- Support for Unreal 5 [\#3122](https://github.com/pypeclub/OpenPype/pull/3122) + +**🐛 Bug fixes** + +- Unreal: Fix Camera Loading if Layout is missing [\#3255](https://github.com/pypeclub/OpenPype/pull/3255) +- Unreal: Fixed Animation loading in UE5 [\#3240](https://github.com/pypeclub/OpenPype/pull/3240) +- Unreal: Fixed Render creation in UE5 [\#3239](https://github.com/pypeclub/OpenPype/pull/3239) +- Unreal: Fixed Camera loading in UE5 [\#3238](https://github.com/pypeclub/OpenPype/pull/3238) + ## [3.10.0](https://github.com/pypeclub/OpenPype/tree/3.10.0) (2022-05-26) -[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.9.8...3.10.0) +[Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.10.0-nightly.6...3.10.0) **🆕 New features** @@ -31,7 +47,6 @@ - General: Simplified OP modules/addons import [\#3137](https://github.com/pypeclub/OpenPype/pull/3137) - Terminal: Tweak coloring of TrayModuleManager logging enabled states [\#3133](https://github.com/pypeclub/OpenPype/pull/3133) - General: Cleanup some Loader docstrings [\#3131](https://github.com/pypeclub/OpenPype/pull/3131) -- Unreal: Layout and Camera update and remove functions reimplemented and improvements [\#3116](https://github.com/pypeclub/OpenPype/pull/3116) **🐛 Bug fixes** @@ -131,10 +146,6 @@ - TVPaint: Composite layers in reversed order [\#3134](https://github.com/pypeclub/OpenPype/pull/3134) -**Merged pull requests:** - -- Ftrack: AssetVersion status on publish [\#3114](https://github.com/pypeclub/OpenPype/pull/3114) - ## [3.9.5](https://github.com/pypeclub/OpenPype/tree/3.9.5) (2022-04-25) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.10.0-nightly.2...3.9.5) diff --git a/openpype/version.py b/openpype/version.py index 31be1f2f02..12f25cdcea 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.10.0" +__version__ = "3.10.1-nightly.1" diff --git a/pyproject.toml b/pyproject.toml index 444af49273..47d678b5e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.10.0" # OpenPype +version = "3.10.1-nightly.1" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From d404fbf8a285e0e25f5af3d8695c6df547f0ceab Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 30 May 2022 11:51:19 +0200 Subject: [PATCH 280/350] OP-3277 - added functionality to replace root value with environment variable. Useful for remote workflows where Site Sync is being used. When Load reference is used, real root value (c:/project) is replaced with ${OPENPYPE_ROOT_WORK}. --- openpype/hosts/maya/plugins/load/load_reference.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/load/load_reference.py b/openpype/hosts/maya/plugins/load/load_reference.py index d65b5a2c1e..7fa7362ecc 100644 --- a/openpype/hosts/maya/plugins/load/load_reference.py +++ b/openpype/hosts/maya/plugins/load/load_reference.py @@ -8,6 +8,7 @@ from openpype.pipeline import ( legacy_create, ) import openpype.hosts.maya.api.plugin +from openpype.api import Anatomy from openpype.hosts.maya.api.lib import maintained_selection @@ -51,7 +52,9 @@ class ReferenceLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): with maintained_selection(): cmds.loadPlugin("AbcImport.mll", quiet=True) - nodes = cmds.file(self.fname, + anatomy = Anatomy(context["project"]["code"]) + file_url = anatomy.replace_root_with_env_key(self.fname, '${{{}}}') + nodes = cmds.file(file_url, namespace=namespace, sharedReferenceFile=False, reference=True, From 46ab3b8e3aa8aa258dd49e880e723ee48513ac0b Mon Sep 17 00:00:00 2001 From: DMO Date: Mon, 30 May 2022 20:20:40 +0900 Subject: [PATCH 281/350] Addressed a concern raised for how file_formats are extracted from instance. Renamed `expectMipMap` to `publishMipMap` to make it more clear. Added `linear` & `auto` to possible color spaces. --- .../maya/plugins/create/create_multiverse_look.py | 2 +- .../plugins/publish/collect_multiverse_look.py | 14 +++++++------- .../maya/plugins/publish/extract_multiverse_usd.py | 9 +++------ .../plugins/publish/extract_multiverse_usd_comp.py | 9 +++------ .../plugins/publish/extract_multiverse_usd_over.py | 9 +++------ .../plugins/publish/validate_mvlook_contents.py | 6 +++--- 6 files changed, 20 insertions(+), 29 deletions(-) diff --git a/openpype/hosts/maya/plugins/create/create_multiverse_look.py b/openpype/hosts/maya/plugins/create/create_multiverse_look.py index 44977efca0..3fc834a700 100644 --- a/openpype/hosts/maya/plugins/create/create_multiverse_look.py +++ b/openpype/hosts/maya/plugins/create/create_multiverse_look.py @@ -12,4 +12,4 @@ class CreateMultiverseLook(plugin.Creator): def __init__(self, *args, **kwargs): super(CreateMultiverseLook, self).__init__(*args, **kwargs) self.data["fileFormat"] = ["usda", "usd"] - self.data["expectMipMap"] = True + self.data["publishMipMap"] = True diff --git a/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py b/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py index e77245bca5..edf40a27a6 100644 --- a/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py @@ -17,7 +17,7 @@ SHAPE_ATTRS = ["castsShadows", "opposite"] SHAPE_ATTRS = set(SHAPE_ATTRS) -COLOUR_SPACES = ['sRGB'] +COLOUR_SPACES = ['sRGB', 'linear', 'auto'] MIPMAP_EXTENSIONS = ['tdl'] @@ -238,7 +238,7 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): files = [] sets = {} instance.data["resources"] = [] - expectMipMap = instance.data["expectMipMap"] + publishMipMap = instance.data["publishMipMap"] for node in nodes: self.log.info("Getting resources for '{}'".format(node)) @@ -262,7 +262,7 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): files = cmds.ls(history, type="file", long=True) for f in files: - resources = self.collect_resource(f, expectMipMap) + resources = self.collect_resource(f, publishMipMap) instance.data["resources"].append(resources) elif isinstance(matOver, multiverse.MaterialSourceUsdPath): @@ -275,7 +275,7 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): "relationships": sets } - def collect_resource(self, node, expectMipMap): + def collect_resource(self, node, publishMipMap): """Collect the link to the file(s) used (resource) Args: node (str): name of the node @@ -330,7 +330,7 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): source = source.replace("\\", "/") files = get_file_node_files(node) - files = self.handle_files(files, expectMipMap) + files = self.handle_files(files, publishMipMap) if len(files) == 0: self.log.error("No valid files found from node `%s`" % node) @@ -348,11 +348,11 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): "files": files, "color_space": color_space} # required for resources - def handle_files(self, files, expectMipMap): + def handle_files(self, files, publishMipMap): """This will go through all the files and make sure that they are either already mipmapped or have a corresponding mipmap sidecar and add that to the list.""" - if not expectMipMap: + if not publishMipMap: return files extra_files = [] diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py index 4bc0322fa8..fe071b08a5 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd.py @@ -133,18 +133,15 @@ class ExtractMultiverseUsd(openpype.api.Extractor): return options - def get_file_format(self, instance): - fileFormat = instance.data["fileFormat"] - if fileFormat in range(len(self.file_formats)): - self.scene_type = self.file_formats[fileFormat] - def process(self, instance): # Load plugin first cmds.loadPlugin("MultiverseForMaya", quiet=True) # Define output file path staging_dir = self.staging_dir(instance) - self.get_file_format(instance) + file_format = instance.data.get("fileFormat", 0) + if file_format in range(len(self.file_formats)): + self.scene_type = self.file_formats[file_format] file_name = "{0}.{1}".format(instance.name, self.scene_type) file_path = os.path.join(staging_dir, file_name) file_path = file_path.replace('\\', '/') diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py index f76a24f7ff..7be6b101d9 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_comp.py @@ -75,18 +75,15 @@ class ExtractMultiverseUsdComposition(openpype.api.Extractor): return options - def get_file_format(self, instance): - fileFormat = instance.data["fileFormat"] - if fileFormat in range(len(self.file_formats)): - self.scene_type = self.file_formats[fileFormat] - def process(self, instance): # Load plugin first cmds.loadPlugin("MultiverseForMaya", quiet=True) # Define output file path staging_dir = self.staging_dir(instance) - self.get_file_format(instance) + file_format = instance.data.get("fileFormat", 0) + if file_format in range(len(self.file_formats)): + self.scene_type = self.file_formats[file_format] file_name = "{0}.{1}".format(instance.name, self.scene_type) file_path = os.path.join(staging_dir, file_name) file_path = file_path.replace('\\', '/') diff --git a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py index 3b101ab6cf..091750c32b 100644 --- a/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py +++ b/openpype/hosts/maya/plugins/publish/extract_multiverse_usd_over.py @@ -60,18 +60,15 @@ class ExtractMultiverseUsdOverride(openpype.api.Extractor): "timeSamplesSpan": 0.0 } - def get_file_format(self, instance): - fileFormat = instance.data["fileFormat"] - if fileFormat in range(len(self.file_formats)): - self.scene_type = self.file_formats[fileFormat] - def process(self, instance): # Load plugin first cmds.loadPlugin("MultiverseForMaya", quiet=True) # Define output file path staging_dir = self.staging_dir(instance) - self.get_file_format(instance) + file_format = instance.data.get("fileFormat", 0) + if file_format in range(len(self.file_formats)): + self.scene_type = self.file_formats[file_format] file_name = "{0}.{1}".format(instance.name, self.scene_type) file_path = os.path.join(staging_dir, file_name) file_path = file_path.replace("\\", "/") diff --git a/openpype/hosts/maya/plugins/publish/validate_mvlook_contents.py b/openpype/hosts/maya/plugins/publish/validate_mvlook_contents.py index 34a8bc0c85..bac2c030c8 100644 --- a/openpype/hosts/maya/plugins/publish/validate_mvlook_contents.py +++ b/openpype/hosts/maya/plugins/publish/validate_mvlook_contents.py @@ -4,7 +4,7 @@ import openpype.hosts.maya.api.action import os -COLOUR_SPACES = ['sRGB'] +COLOUR_SPACES = ['sRGB', 'linear', 'auto'] MIPMAP_EXTENSIONS = ['tdl'] @@ -24,7 +24,7 @@ class ValidateMvLookContents(pyblish.api.InstancePlugin): def process(self, instance): intent = instance.context.data['intent']['value'] - expectMipMap = instance.data["expectMipMap"] + publishMipMap = instance.data["publishMipMap"] enforced = True if intent in self.enforced_intents: self.log.info("This validation will be enforced: '{}'" @@ -55,7 +55,7 @@ class ValidateMvLookContents(pyblish.api.InstancePlugin): .format(node, fname)) invalid.add(node) - if expectMipMap and not self.is_or_has_mipmap(fname, files): + if publishMipMap and not self.is_or_has_mipmap(fname, files): msg = "File node '{}'/'{}' does not have a mipmap".format( node, fname) if enforced: From 277024de81843a3198c47402e7b251f937ab0817 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 30 May 2022 13:23:24 +0200 Subject: [PATCH 282/350] OP-3277 - extracted logic to ReferenceLoader All inheriting plugins implementing shared method. Flag 'use_env_var_as_root' set to True for testing temporarily, proper location in Setting should be decided. --- openpype/hosts/maya/api/plugin.py | 25 +++++++++++++++++++ .../maya/plugins/load/_load_animation.py | 5 ++-- openpype/hosts/maya/plugins/load/load_ass.py | 12 ++++++--- openpype/hosts/maya/plugins/load/load_look.py | 4 ++- .../hosts/maya/plugins/load/load_reference.py | 5 ++-- .../hosts/maya/plugins/load/load_yeti_rig.py | 4 ++- 6 files changed, 45 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/maya/api/plugin.py b/openpype/hosts/maya/api/plugin.py index 3721868823..93b0793d9c 100644 --- a/openpype/hosts/maya/api/plugin.py +++ b/openpype/hosts/maya/api/plugin.py @@ -10,6 +10,7 @@ from openpype.pipeline import ( get_representation_path, AVALON_CONTAINER_ID, ) +from openpype.api import Anatomy from .pipeline import containerise from . import lib @@ -132,6 +133,7 @@ class ReferenceLoader(Loader): " imported representation ?" ) ] + use_env_var_as_root = True def load( self, @@ -191,6 +193,25 @@ class ReferenceLoader(Loader): """To be implemented by subclass""" raise NotImplementedError("Must be implemented by subclass") + def prepare_root_value(self, file_url, project_name): + """Replace root value with env var placeholder. + + Use ${OPENPYPE_ROOT_WORK} (or any other root) instead of proper root + value when storing referenced url into a workfile. + Useful for remote workflows with SiteSync. + + Args: + file_url (str) + project_name (dict) + Returns: + (str) + """ + if self.use_env_var_as_root: + anatomy = Anatomy(project_name) + file_url = anatomy.replace_root_with_env_key(file_url, '${{{}}}') + + return file_url + def update(self, container, representation): from maya import cmds from openpype.hosts.maya.api.lib import get_container_members @@ -230,6 +251,10 @@ class ReferenceLoader(Loader): self.log.debug("No alembic nodes found in {}".format(members)) try: + path = self.prepare_root_value(path, + representation["context"] + ["project"] + ["code"]) content = cmds.file(path, loadReference=reference_node, type=file_type, diff --git a/openpype/hosts/maya/plugins/load/_load_animation.py b/openpype/hosts/maya/plugins/load/_load_animation.py index 9c37e498ef..0010efb829 100644 --- a/openpype/hosts/maya/plugins/load/_load_animation.py +++ b/openpype/hosts/maya/plugins/load/_load_animation.py @@ -35,8 +35,9 @@ class AbcLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): # hero_001 (abc) # asset_counter{optional} - - nodes = cmds.file(self.fname, + file_url = self.prepare_root_value(self.fname, + context["project"]["code"]) + nodes = cmds.file(file_url, namespace=namespace, sharedReferenceFile=False, groupReference=True, diff --git a/openpype/hosts/maya/plugins/load/load_ass.py b/openpype/hosts/maya/plugins/load/load_ass.py index a284b7ec1f..1f0eb88995 100644 --- a/openpype/hosts/maya/plugins/load/load_ass.py +++ b/openpype/hosts/maya/plugins/load/load_ass.py @@ -64,9 +64,11 @@ class AssProxyLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): path = os.path.join(publish_folder, filename) proxyPath = proxyPath_base + ".ma" - self.log.info - nodes = cmds.file(proxyPath, + file_url = self.prepare_root_value(proxyPath, + context["project"]["code"]) + + nodes = cmds.file(file_url, namespace=namespace, reference=True, returnNewNodes=True, @@ -123,7 +125,11 @@ class AssProxyLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): assert os.path.exists(proxyPath), "%s does not exist." % proxyPath try: - content = cmds.file(proxyPath, + file_url = self.prepare_root_value(proxyPath, + representation["context"] + ["project"] + ["code"]) + content = cmds.file(file_url, loadReference=reference_node, type="mayaAscii", returnNewNodes=True) diff --git a/openpype/hosts/maya/plugins/load/load_look.py b/openpype/hosts/maya/plugins/load/load_look.py index 80eac8e0b5..ae3a683241 100644 --- a/openpype/hosts/maya/plugins/load/load_look.py +++ b/openpype/hosts/maya/plugins/load/load_look.py @@ -31,7 +31,9 @@ class LookLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): import maya.cmds as cmds with lib.maintained_selection(): - nodes = cmds.file(self.fname, + file_url = self.prepare_root_value(self.fname, + context["project"]["code"]) + nodes = cmds.file(file_url, namespace=namespace, reference=True, returnNewNodes=True) diff --git a/openpype/hosts/maya/plugins/load/load_reference.py b/openpype/hosts/maya/plugins/load/load_reference.py index 7fa7362ecc..e4355ed3d4 100644 --- a/openpype/hosts/maya/plugins/load/load_reference.py +++ b/openpype/hosts/maya/plugins/load/load_reference.py @@ -8,7 +8,6 @@ from openpype.pipeline import ( legacy_create, ) import openpype.hosts.maya.api.plugin -from openpype.api import Anatomy from openpype.hosts.maya.api.lib import maintained_selection @@ -52,8 +51,8 @@ class ReferenceLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): with maintained_selection(): cmds.loadPlugin("AbcImport.mll", quiet=True) - anatomy = Anatomy(context["project"]["code"]) - file_url = anatomy.replace_root_with_env_key(self.fname, '${{{}}}') + file_url = self.prepare_root_value(self.fname, + context["project"]["code"]) nodes = cmds.file(file_url, namespace=namespace, sharedReferenceFile=False, diff --git a/openpype/hosts/maya/plugins/load/load_yeti_rig.py b/openpype/hosts/maya/plugins/load/load_yeti_rig.py index b4d31b473f..241c28467a 100644 --- a/openpype/hosts/maya/plugins/load/load_yeti_rig.py +++ b/openpype/hosts/maya/plugins/load/load_yeti_rig.py @@ -53,7 +53,9 @@ class YetiRigLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): # load rig with lib.maintained_selection(): - nodes = cmds.file(self.fname, + file_url = self.prepare_root_value(self.fname, + context["project"]["code"]) + nodes = cmds.file(file_url, namespace=namespace, reference=True, returnNewNodes=True, From 38c8d2c8fe63c81fbc55c4f079e4f72519575c3c Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 30 May 2022 15:27:15 +0200 Subject: [PATCH 283/350] Fix udim support for e.g. uppercase tag --- openpype/hosts/maya/plugins/publish/collect_look.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_look.py b/openpype/hosts/maya/plugins/publish/collect_look.py index 323bede761..dc17ddc605 100644 --- a/openpype/hosts/maya/plugins/publish/collect_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_look.py @@ -109,16 +109,18 @@ def node_uses_image_sequence(node, node_path): """ # useFrameExtension indicates an explicit image sequence - # The following tokens imply a sequence - patterns = ["", "", "", - "u_v", ""] try: use_frame_extension = cmds.getAttr('%s.useFrameExtension' % node) except ValueError: use_frame_extension = False + if use_frame_extension: + return True - return (use_frame_extension or - any(pattern in node_path for pattern in patterns)) + # The following tokens imply a sequence + patterns = ["", "", "", + "u_v", ""] + node_path_lowered = node_path.lower() + return any(pattern in node_path_lowered for pattern in patterns) def seq_to_glob(path): From 254455e786c50ef20d0f953bebd57d50af077b1e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 30 May 2022 18:05:56 +0200 Subject: [PATCH 284/350] OP-3277 - introduced Settings variable Configured via Maya/Maya-dirmap to use in all Loaders --- openpype/hosts/maya/api/plugin.py | 45 ++++++++++--------- .../defaults/project_settings/maya.json | 1 + .../projects_schema/schema_project_maya.json | 6 +++ 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/openpype/hosts/maya/api/plugin.py b/openpype/hosts/maya/api/plugin.py index 93b0793d9c..f05893a7b4 100644 --- a/openpype/hosts/maya/api/plugin.py +++ b/openpype/hosts/maya/api/plugin.py @@ -11,7 +11,7 @@ from openpype.pipeline import ( AVALON_CONTAINER_ID, ) from openpype.api import Anatomy - +from openpype.settings import get_project_settings from .pipeline import containerise from . import lib @@ -133,7 +133,6 @@ class ReferenceLoader(Loader): " imported representation ?" ) ] - use_env_var_as_root = True def load( self, @@ -193,25 +192,6 @@ class ReferenceLoader(Loader): """To be implemented by subclass""" raise NotImplementedError("Must be implemented by subclass") - def prepare_root_value(self, file_url, project_name): - """Replace root value with env var placeholder. - - Use ${OPENPYPE_ROOT_WORK} (or any other root) instead of proper root - value when storing referenced url into a workfile. - Useful for remote workflows with SiteSync. - - Args: - file_url (str) - project_name (dict) - Returns: - (str) - """ - if self.use_env_var_as_root: - anatomy = Anatomy(project_name) - file_url = anatomy.replace_root_with_env_key(file_url, '${{{}}}') - - return file_url - def update(self, container, representation): from maya import cmds from openpype.hosts.maya.api.lib import get_container_members @@ -344,6 +324,29 @@ class ReferenceLoader(Loader): except RuntimeError: pass + def prepare_root_value(self, file_url, project_name): + """Replace root value with env var placeholder. + + Use ${OPENPYPE_ROOT_WORK} (or any other root) instead of proper root + value when storing referenced url into a workfile. + Useful for remote workflows with SiteSync. + + Args: + file_url (str) + project_name (dict) + Returns: + (str) + """ + settings = get_project_settings(project_name) + use_env_var_as_root = (settings["maya"] + ["maya-dirmap"] + ["use_env_var_as_root"]) + if use_env_var_as_root: + anatomy = Anatomy(project_name) + file_url = anatomy.replace_root_with_env_key(file_url, '${{{}}}') + + return file_url + @staticmethod def _organize_containers(nodes, container): # type: (list, str) -> None diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index e03bdcecc3..a42f889e85 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -8,6 +8,7 @@ "yetiRig": "ma" }, "maya-dirmap": { + "use_env_var_as_root": true, "enabled": false, "paths": { "source-path": [], diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json index 0c7943447b..f9523b1baa 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json @@ -22,6 +22,12 @@ "label": "Maya Directory Mapping", "is_group": true, "children": [ + { + "type": "boolean", + "key": "use_env_var_as_root", + "label": "Use env var placeholder in referenced url", + "docstring": "Use ${} placeholder instead of physical value of root when storing into workfile metadata." + }, { "type": "boolean", "key": "enabled", From 99b6050cbec6c35d088e106a7ef5aebb182fbb6a Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Mon, 30 May 2022 18:47:09 +0200 Subject: [PATCH 285/350] Replace by last nuke familly icon --- openpype/resources/app_icons/hiero.png | Bin 46366 -> 87054 bytes openpype/resources/app_icons/nuke.png | Bin 49012 -> 86832 bytes openpype/resources/app_icons/nukestudio.png | Bin 46080 -> 101945 bytes openpype/resources/app_icons/nukex.png | Bin 44709 -> 99787 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/openpype/resources/app_icons/hiero.png b/openpype/resources/app_icons/hiero.png index 04bbf6265bb63f0615c2b98ab48891d03483f6b2..ba666c2fe0819e7c769bc2dc6d96c853b349fd80 100644 GIT binary patch literal 87054 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

BNYumfy0?yyj<=Shl->j>O&F$!;w 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